diff --git a/src/auth/auth.service.spec.ts b/src/auth/auth.service.spec.ts index 94c516f41..13c5a9007 100644 --- a/src/auth/auth.service.spec.ts +++ b/src/auth/auth.service.spec.ts @@ -112,7 +112,7 @@ describe('AuthService', () => { it('getAuthToken', async () => { const token = 'testToken'; authToken.accessTokenHash = await service.hashPassword(token); - const authTokenFromCall = await service.getAuthToken( + const authTokenFromCall = await service.getAuthTokenAndValidate( authToken.keyId, token, ); @@ -154,4 +154,19 @@ describe('AuthService', () => { expect(token.lastUsed).toBeUndefined(); expect(token.secret.startsWith(token.keyId)).toBeTruthy(); }); + + it('BufferToBase64Url', () => { + expect( + service.BufferToBase64Url(Buffer.from('testsentence is a test sentence')), + ).toEqual('dGVzdHNlbnRlbmNlIGlzIGEgdGVzdCBzZW50ZW5jZQ'); + }); + + it('toAuthTokenDto', async () => { + const tokenDto = await service.toAuthTokenDto(authToken); + expect(tokenDto.keyId).toEqual(authToken.keyId); + expect(tokenDto.lastUsed).toBeNull(); + expect(tokenDto.label).toEqual(authToken.identifier); + expect(tokenDto.validUntil).toBeNull(); + expect(tokenDto.created).toEqual(authToken.createdAt.getTime()); + }); }); diff --git a/src/auth/auth.service.ts b/src/auth/auth.service.ts index 3354a031b..636d7a776 100644 --- a/src/auth/auth.service.ts +++ b/src/auth/auth.service.ts @@ -30,7 +30,7 @@ export class AuthService { async validateToken(token: string): Promise { const parts = token.split('.'); - const accessToken = await this.getAuthToken(parts[0], parts[1]); + const accessToken = await this.getAuthTokenAndValidate(parts[0], parts[1]); const user = await this.usersService.getUserByUsername( accessToken.user.userName, ); @@ -42,20 +42,26 @@ export class AuthService { } async hashPassword(cleartext: string): Promise { - // hash the password with bcrypt and 2^16 iterations + // hash the password with bcrypt and 2^12 iterations return hash(cleartext, 12); } async checkPassword(cleartext: string, password: string): Promise { - // hash the password with bcrypt and 2^16 iterations return compare(cleartext, password); } - randomBase64UrlString(length = 64): string { + async randomString(length: number): Promise { // This is necessary as the is no base64url encoding in the toString method // but as can be seen on https://tools.ietf.org/html/rfc4648#page-7 // base64url is quite easy buildable from base64 - return randomBytes(length) + if (length <= 0) { + return null; + } + return randomBytes(length); + } + + BufferToBase64Url(text: Buffer): string { + return text .toString('base64') .replace('+', '-') .replace('/', '_') @@ -68,9 +74,10 @@ export class AuthService { until: number, ): Promise { const user = await this.usersService.getUserByUsername(userName); - const secret = this.randomBase64UrlString(); - const keyId = this.randomBase64UrlString(8); - const accessToken = await this.hashPassword(secret); + const secret = await this.randomString(64); + const keyId = this.BufferToBase64Url(await this.randomString(8)); + const accessTokenString = await this.hashPassword(secret.toString()); + const accessToken = this.BufferToBase64Url(Buffer.from(accessTokenString)); let token; if (until === 0) { token = AuthToken.create(user, identifier, keyId, accessToken); @@ -89,7 +96,10 @@ export class AuthService { await this.authTokenRepository.save(accessToken); } - async getAuthToken(keyId: string, token: string): Promise { + async getAuthTokenAndValidate( + keyId: string, + token: string, + ): Promise { const accessToken = await this.authTokenRepository.findOne({ where: { keyId: keyId }, relations: ['user'], @@ -149,9 +159,9 @@ export class AuthService { authToken: AuthToken | null | undefined, secret: string, ): AuthTokenWithSecretDto | null { - const tokeDto = this.toAuthTokenDto(authToken); + const tokenDto = this.toAuthTokenDto(authToken); return { - ...tokeDto, + ...tokenDto, secret: secret, }; }