forked from novuhq/novu
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'main' into fix/api-script-e2e
- Loading branch information
Showing
56 changed files
with
1,549 additions
and
436 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
import { UserSession } from '@novu/testing'; | ||
import { expect } from 'chai'; | ||
|
||
describe('Environment - Regenerate Api Key', async () => { | ||
let session: UserSession; | ||
|
||
before(async () => { | ||
session = new UserSession(); | ||
await session.initialize(); | ||
}); | ||
|
||
it('should regenerate an Api Key', async () => { | ||
const { | ||
body: { data: oldApiKeys }, | ||
} = await session.testAgent.get('/v1/environments/api-keys').send({}); | ||
const oldApiKey = oldApiKeys[0].key; | ||
|
||
const { | ||
body: { data: newApiKeys }, | ||
} = await session.testAgent.post('/v1/environments/api-keys/regenerate').send({}); | ||
const newApiKey = newApiKeys[0].key; | ||
|
||
expect(oldApiKey).to.not.equal(newApiKey); | ||
|
||
const { | ||
body: { data: organizations }, | ||
} = await session.testAgent.get('/v1/organizations').send({}); | ||
|
||
expect(organizations).not.to.be.empty; | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
13 changes: 9 additions & 4 deletions
13
apps/api/src/app/environments/usecases/create-environment/create-environment.usecase.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
64 changes: 64 additions & 0 deletions
64
...api/src/app/environments/usecases/generate-unique-api-key/generate-unique-api-key.spec.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
import { EnvironmentRepository } from '@novu/dal'; | ||
import { InternalServerErrorException } from '@nestjs/common'; | ||
import { expect } from 'chai'; | ||
import * as sinon from 'sinon'; | ||
|
||
import { GenerateUniqueApiKey } from './generate-unique-api-key.usecase'; | ||
|
||
const environmentRepository = new EnvironmentRepository(); | ||
const generateUniqueApiKey = new GenerateUniqueApiKey(environmentRepository); | ||
|
||
let generateApiKeyStub; | ||
let findByApiKeyStub; | ||
describe('Generate Unique Api Key', () => { | ||
beforeEach(() => { | ||
findByApiKeyStub = sinon.stub(environmentRepository, 'findByApiKey'); | ||
generateApiKeyStub = sinon.stub(generateUniqueApiKey, 'generateApiKey' as any); | ||
}); | ||
|
||
afterEach(() => { | ||
findByApiKeyStub.restore(); | ||
generateApiKeyStub.restore(); | ||
}); | ||
|
||
it('should generate an API key for the environment without any clashing', async () => { | ||
const expectedApiKey = 'expected-api-key'; | ||
generateApiKeyStub.onFirstCall().returns(expectedApiKey); | ||
|
||
const apiKey = await generateUniqueApiKey.execute(); | ||
|
||
expect(typeof apiKey).to.be.string; | ||
expect(apiKey).to.be.equal(expectedApiKey); | ||
}); | ||
|
||
it('should generate a different valid API key after first one clashes with an existing one', async () => { | ||
const clashingApiKey = 'clashing-api-key'; | ||
const expectedApiKey = 'expected-api-key'; | ||
generateApiKeyStub.onFirstCall().returns(clashingApiKey); | ||
generateApiKeyStub.onSecondCall().returns(expectedApiKey); | ||
findByApiKeyStub.onFirstCall().returns({ key: clashingApiKey }); | ||
findByApiKeyStub.onSecondCall().returns(undefined); | ||
|
||
const apiKey = await generateUniqueApiKey.execute(); | ||
expect(typeof apiKey).to.be.string; | ||
expect(apiKey).to.be.equal(expectedApiKey); | ||
}); | ||
|
||
it('should throw an error if the generation clashes 3 times', async () => { | ||
const clashingApiKey = 'clashing-api-key'; | ||
generateApiKeyStub.onFirstCall().returns(clashingApiKey); | ||
generateApiKeyStub.onSecondCall().returns(clashingApiKey); | ||
generateApiKeyStub.onThirdCall().returns(clashingApiKey); | ||
findByApiKeyStub.onFirstCall().returns({ key: clashingApiKey }); | ||
findByApiKeyStub.onSecondCall().returns({ key: clashingApiKey }); | ||
findByApiKeyStub.onThirdCall().returns({ key: clashingApiKey }); | ||
|
||
try { | ||
await generateUniqueApiKey.execute(); | ||
throw new Error('Should not reach here'); | ||
} catch (e) { | ||
expect(e).to.be.instanceOf(InternalServerErrorException); | ||
expect(e.message).to.eql('Clashing of the API key generation'); | ||
} | ||
}); | ||
}); |
39 changes: 39 additions & 0 deletions
39
.../src/app/environments/usecases/generate-unique-api-key/generate-unique-api-key.usecase.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
import { Injectable, InternalServerErrorException } from '@nestjs/common'; | ||
import { EnvironmentRepository } from '@novu/dal'; | ||
import * as hat from 'hat'; | ||
|
||
const API_KEY_GENERATION_MAX_RETRIES = 3; | ||
|
||
@Injectable() | ||
export class GenerateUniqueApiKey { | ||
constructor(private environmentRepository: EnvironmentRepository) {} | ||
|
||
async execute(): Promise<string> { | ||
let apiKey: string; | ||
let count = 0; | ||
let isApiKeyUsed = true; | ||
while (isApiKeyUsed) { | ||
apiKey = this.generateApiKey(); | ||
const environment = await this.environmentRepository.findByApiKey(apiKey); | ||
isApiKeyUsed = environment ? true : false; | ||
count += 1; | ||
|
||
if (count === API_KEY_GENERATION_MAX_RETRIES) { | ||
const errorMessage = 'Clashing of the API key generation'; | ||
throw new InternalServerErrorException(new Error(errorMessage), errorMessage); | ||
} | ||
} | ||
|
||
return apiKey; | ||
} | ||
|
||
/** | ||
* Extracting the generation functionality so it can be stubbed for functional testing | ||
* | ||
* @requires hat | ||
* @todo Dependency is no longer accessible to source code due of removal from Github. Consider look for an alternative. | ||
*/ | ||
private generateApiKey(): string { | ||
return hat(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
25 changes: 25 additions & 0 deletions
25
apps/api/src/app/environments/usecases/regenerate-api-keys/regenerate-api-keys.usecase.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
import { Injectable } from '@nestjs/common'; | ||
import { IApiKey, EnvironmentRepository } from '@novu/dal'; | ||
import { ApiException } from '../../../shared/exceptions/api.exception'; | ||
import { GenerateUniqueApiKey } from '../generate-unique-api-key/generate-unique-api-key.usecase'; | ||
import { GetApiKeysCommand } from '../get-api-keys/get-api-keys.command'; | ||
|
||
@Injectable() | ||
export class RegenerateApiKeys { | ||
constructor( | ||
private environmentRepository: EnvironmentRepository, | ||
private generateUniqueApiKey: GenerateUniqueApiKey | ||
) {} | ||
|
||
async execute(command: GetApiKeysCommand): Promise<IApiKey[]> { | ||
const environment = await this.environmentRepository.findById(command.environmentId); | ||
|
||
if (!environment) { | ||
throw new ApiException(`Environment id: ${command.environmentId} not found`); | ||
} | ||
|
||
const key = await this.generateUniqueApiKey.execute(); | ||
|
||
return await this.environmentRepository.updateApiKey(command.environmentId, key, command.userId); | ||
} | ||
} |
Oops, something went wrong.