mirror of
https://github.com/hedgedoc/hedgedoc.git
synced 2024-11-21 17:26:29 -05:00
enhancement(api-tokens): add prefix and more strict validation
Signed-off-by: Erik Michelson <github@erik.michelson.eu>
This commit is contained in:
parent
0db5a0856b
commit
92bde4d281
3 changed files with 28 additions and 9 deletions
|
@ -230,7 +230,7 @@ describe('AuthService', () => {
|
|||
return authToken;
|
||||
});
|
||||
const userByToken = await service.validateToken(
|
||||
`${authToken.keyId}.${testSecret}`,
|
||||
`hd2.${authToken.keyId}.${testSecret}`,
|
||||
);
|
||||
expect(userByToken).toEqual({
|
||||
...user,
|
||||
|
@ -238,14 +238,31 @@ describe('AuthService', () => {
|
|||
});
|
||||
});
|
||||
describe('fails:', () => {
|
||||
it('the prefix is missing', async () => {
|
||||
await expect(
|
||||
service.validateToken(`${authToken.keyId}.${'a'.repeat(73)}`),
|
||||
).rejects.toThrow(TokenNotValidError);
|
||||
});
|
||||
it('the prefix is wrong', async () => {
|
||||
await expect(
|
||||
service.validateToken(`hd1.${authToken.keyId}.${'a'.repeat(73)}`),
|
||||
).rejects.toThrow(TokenNotValidError);
|
||||
});
|
||||
it('the secret is missing', async () => {
|
||||
await expect(
|
||||
service.validateToken(`${authToken.keyId}`),
|
||||
service.validateToken(`hd2.${authToken.keyId}`),
|
||||
).rejects.toThrow(TokenNotValidError);
|
||||
});
|
||||
it('the secret is too long', async () => {
|
||||
await expect(
|
||||
service.validateToken(`${authToken.keyId}.${'a'.repeat(73)}`),
|
||||
service.validateToken(`hd2.${authToken.keyId}.${'a'.repeat(73)}`),
|
||||
).rejects.toThrow(TokenNotValidError);
|
||||
});
|
||||
it('the token contains sections after the secret', async () => {
|
||||
await expect(
|
||||
service.validateToken(
|
||||
`hd2.${authToken.keyId}.${'a'.repeat(73)}.extra`,
|
||||
),
|
||||
).rejects.toThrow(TokenNotValidError);
|
||||
});
|
||||
});
|
||||
|
@ -296,7 +313,7 @@ describe('AuthService', () => {
|
|||
(new Date().getTime() + 2 * 365 * 24 * 60 * 60 * 1000),
|
||||
).toBeLessThanOrEqual(10000);
|
||||
expect(token.lastUsedAt).toBeNull();
|
||||
expect(token.secret.startsWith(token.keyId)).toBeTruthy();
|
||||
expect(token.secret.startsWith('hd2.' + token.keyId)).toBeTruthy();
|
||||
});
|
||||
it('with validUntil not 0', async () => {
|
||||
jest.spyOn(authTokenRepo, 'find').mockResolvedValueOnce([authToken]);
|
||||
|
@ -313,7 +330,7 @@ describe('AuthService', () => {
|
|||
expect(token.label).toEqual(identifier);
|
||||
expect(token.validUntil.getTime()).toEqual(validUntil);
|
||||
expect(token.lastUsedAt).toBeNull();
|
||||
expect(token.secret.startsWith(token.keyId)).toBeTruthy();
|
||||
expect(token.secret.startsWith('hd2.' + token.keyId)).toBeTruthy();
|
||||
});
|
||||
it('should throw TooManyTokensError when number of tokens >= 200', async () => {
|
||||
jest
|
||||
|
|
|
@ -21,6 +21,8 @@ import { TimestampMillis } from '../utils/timestamp';
|
|||
import { AuthTokenDto, AuthTokenWithSecretDto } from './auth-token.dto';
|
||||
import { AuthToken } from './auth-token.entity';
|
||||
|
||||
export const AUTH_TOKEN_PREFIX = 'hd2';
|
||||
|
||||
@Injectable()
|
||||
export class AuthService {
|
||||
constructor(
|
||||
|
@ -32,8 +34,8 @@ export class AuthService {
|
|||
}
|
||||
|
||||
async validateToken(tokenString: string): Promise<User> {
|
||||
const [keyId, secret] = tokenString.split('.');
|
||||
if (!secret) {
|
||||
const [prefix, keyId, secret, ...rest] = tokenString.split('.');
|
||||
if (!keyId || !secret || prefix !== AUTH_TOKEN_PREFIX || rest.length > 0) {
|
||||
throw new TokenNotValidError('Invalid AuthToken format');
|
||||
}
|
||||
if (secret.length != 86) {
|
||||
|
@ -105,7 +107,7 @@ export class AuthService {
|
|||
)) as AuthToken;
|
||||
return this.toAuthTokenWithSecretDto(
|
||||
createdToken,
|
||||
`${createdToken.keyId}.${secret}`,
|
||||
`${AUTH_TOKEN_PREFIX}.${createdToken.keyId}.${secret}`,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -51,7 +51,7 @@ describe('Tokens', () => {
|
|||
Date.now(),
|
||||
);
|
||||
expect(response.body.lastUsedAt).toBe(null);
|
||||
expect(response.body.secret.length).toBe(98);
|
||||
expect(response.body.secret.length).toBe(102);
|
||||
});
|
||||
|
||||
it(`GET /tokens`, async () => {
|
||||
|
|
Loading…
Reference in a new issue