mirror of
https://github.com/hedgedoc/hedgedoc.git
synced 2024-11-26 19:53:59 -05:00
auth: Split randomBase64UrlString in two functions
add test for BufferToBase64Url and toAuthTokenDto Signed-off-by: Philip Molares <philip.molares@udo.edu>
This commit is contained in:
parent
508ad26771
commit
e6dc8c7678
2 changed files with 37 additions and 12 deletions
|
@ -112,7 +112,7 @@ describe('AuthService', () => {
|
||||||
it('getAuthToken', async () => {
|
it('getAuthToken', async () => {
|
||||||
const token = 'testToken';
|
const token = 'testToken';
|
||||||
authToken.accessTokenHash = await service.hashPassword(token);
|
authToken.accessTokenHash = await service.hashPassword(token);
|
||||||
const authTokenFromCall = await service.getAuthToken(
|
const authTokenFromCall = await service.getAuthTokenAndValidate(
|
||||||
authToken.keyId,
|
authToken.keyId,
|
||||||
token,
|
token,
|
||||||
);
|
);
|
||||||
|
@ -154,4 +154,19 @@ describe('AuthService', () => {
|
||||||
expect(token.lastUsed).toBeUndefined();
|
expect(token.lastUsed).toBeUndefined();
|
||||||
expect(token.secret.startsWith(token.keyId)).toBeTruthy();
|
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());
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -30,7 +30,7 @@ export class AuthService {
|
||||||
|
|
||||||
async validateToken(token: string): Promise<User> {
|
async validateToken(token: string): Promise<User> {
|
||||||
const parts = token.split('.');
|
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(
|
const user = await this.usersService.getUserByUsername(
|
||||||
accessToken.user.userName,
|
accessToken.user.userName,
|
||||||
);
|
);
|
||||||
|
@ -42,20 +42,26 @@ export class AuthService {
|
||||||
}
|
}
|
||||||
|
|
||||||
async hashPassword(cleartext: string): Promise<string> {
|
async hashPassword(cleartext: string): Promise<string> {
|
||||||
// hash the password with bcrypt and 2^16 iterations
|
// hash the password with bcrypt and 2^12 iterations
|
||||||
return hash(cleartext, 12);
|
return hash(cleartext, 12);
|
||||||
}
|
}
|
||||||
|
|
||||||
async checkPassword(cleartext: string, password: string): Promise<boolean> {
|
async checkPassword(cleartext: string, password: string): Promise<boolean> {
|
||||||
// hash the password with bcrypt and 2^16 iterations
|
|
||||||
return compare(cleartext, password);
|
return compare(cleartext, password);
|
||||||
}
|
}
|
||||||
|
|
||||||
randomBase64UrlString(length = 64): string {
|
async randomString(length: number): Promise<Buffer> {
|
||||||
// This is necessary as the is no base64url encoding in the toString method
|
// 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
|
// but as can be seen on https://tools.ietf.org/html/rfc4648#page-7
|
||||||
// base64url is quite easy buildable from base64
|
// 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')
|
.toString('base64')
|
||||||
.replace('+', '-')
|
.replace('+', '-')
|
||||||
.replace('/', '_')
|
.replace('/', '_')
|
||||||
|
@ -68,9 +74,10 @@ export class AuthService {
|
||||||
until: number,
|
until: number,
|
||||||
): Promise<AuthTokenWithSecretDto> {
|
): Promise<AuthTokenWithSecretDto> {
|
||||||
const user = await this.usersService.getUserByUsername(userName);
|
const user = await this.usersService.getUserByUsername(userName);
|
||||||
const secret = this.randomBase64UrlString();
|
const secret = await this.randomString(64);
|
||||||
const keyId = this.randomBase64UrlString(8);
|
const keyId = this.BufferToBase64Url(await this.randomString(8));
|
||||||
const accessToken = await this.hashPassword(secret);
|
const accessTokenString = await this.hashPassword(secret.toString());
|
||||||
|
const accessToken = this.BufferToBase64Url(Buffer.from(accessTokenString));
|
||||||
let token;
|
let token;
|
||||||
if (until === 0) {
|
if (until === 0) {
|
||||||
token = AuthToken.create(user, identifier, keyId, accessToken);
|
token = AuthToken.create(user, identifier, keyId, accessToken);
|
||||||
|
@ -89,7 +96,10 @@ export class AuthService {
|
||||||
await this.authTokenRepository.save(accessToken);
|
await this.authTokenRepository.save(accessToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
async getAuthToken(keyId: string, token: string): Promise<AuthToken> {
|
async getAuthTokenAndValidate(
|
||||||
|
keyId: string,
|
||||||
|
token: string,
|
||||||
|
): Promise<AuthToken> {
|
||||||
const accessToken = await this.authTokenRepository.findOne({
|
const accessToken = await this.authTokenRepository.findOne({
|
||||||
where: { keyId: keyId },
|
where: { keyId: keyId },
|
||||||
relations: ['user'],
|
relations: ['user'],
|
||||||
|
@ -149,9 +159,9 @@ export class AuthService {
|
||||||
authToken: AuthToken | null | undefined,
|
authToken: AuthToken | null | undefined,
|
||||||
secret: string,
|
secret: string,
|
||||||
): AuthTokenWithSecretDto | null {
|
): AuthTokenWithSecretDto | null {
|
||||||
const tokeDto = this.toAuthTokenDto(authToken);
|
const tokenDto = this.toAuthTokenDto(authToken);
|
||||||
return {
|
return {
|
||||||
...tokeDto,
|
...tokenDto,
|
||||||
secret: secret,
|
secret: secret,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue