refactor(api/private/tokens): validate POST data with DTO

This adds a `AuthTokenCreateDto` which allows
to fully validate incoming JSON data.

Signed-off-by: David Mehren <git@herrmehren.de>
This commit is contained in:
David Mehren 2022-03-04 18:01:45 +01:00
parent fd3fde9cc8
commit 552cb05d92
3 changed files with 24 additions and 7 deletions

View file

@ -16,6 +16,7 @@ import {
import { ApiTags } from '@nestjs/swagger'; import { ApiTags } from '@nestjs/swagger';
import { import {
AuthTokenCreateDto,
AuthTokenDto, AuthTokenDto,
AuthTokenWithSecretDto, AuthTokenWithSecretDto,
} from '../../../auth/auth-token.dto'; } from '../../../auth/auth-token.dto';
@ -23,7 +24,6 @@ import { AuthService } from '../../../auth/auth.service';
import { SessionGuard } from '../../../identity/session.guard'; import { SessionGuard } from '../../../identity/session.guard';
import { ConsoleLoggerService } from '../../../logger/console-logger.service'; import { ConsoleLoggerService } from '../../../logger/console-logger.service';
import { User } from '../../../users/user.entity'; import { User } from '../../../users/user.entity';
import { TimestampMillis } from '../../../utils/timestamp';
import { OpenApi } from '../../utils/openapi.decorator'; import { OpenApi } from '../../utils/openapi.decorator';
import { RequestUser } from '../../utils/request-user.decorator'; import { RequestUser } from '../../utils/request-user.decorator';
@ -50,11 +50,14 @@ export class TokensController {
@Post() @Post()
@OpenApi(201) @OpenApi(201)
async postTokenRequest( async postTokenRequest(
@Body('label') label: string, @Body() createDto: AuthTokenCreateDto,
@Body('validUntil') validUntil: TimestampMillis,
@RequestUser() user: User, @RequestUser() user: User,
): Promise<AuthTokenWithSecretDto> { ): Promise<AuthTokenWithSecretDto> {
return await this.authService.createTokenForUser(user, label, validUntil); return await this.authService.createTokenForUser(
user,
createDto.label,
createDto.validUntil,
);
} }
@Delete('/:keyId') @Delete('/:keyId')

View file

@ -4,9 +4,10 @@
* SPDX-License-Identifier: AGPL-3.0-only * SPDX-License-Identifier: AGPL-3.0-only
*/ */
import { Type } from 'class-transformer'; import { Type } from 'class-transformer';
import { IsDate, IsOptional, IsString } from 'class-validator'; import { IsDate, IsNumber, IsOptional, IsString } from 'class-validator';
import { BaseDto } from '../utils/base.dto.'; import { BaseDto } from '../utils/base.dto.';
import { TimestampMillis } from '../utils/timestamp';
export class AuthTokenDto extends BaseDto { export class AuthTokenDto extends BaseDto {
@IsString() @IsString()
@ -33,3 +34,11 @@ export class AuthTokenWithSecretDto extends AuthTokenDto {
@IsString() @IsString()
secret: string; secret: string;
} }
export class AuthTokenCreateDto extends BaseDto {
@IsString()
label: string;
@IsNumber()
validUntil: TimestampMillis;
}

View file

@ -45,12 +45,15 @@ describe('Tokens', () => {
.post('/api/private/tokens') .post('/api/private/tokens')
.send({ .send({
label: tokenName, label: tokenName,
validUntil: 0,
}) })
.expect('Content-Type', /json/) .expect('Content-Type', /json/)
.expect(201); .expect(201);
keyId = response.body.keyId; keyId = response.body.keyId;
expect(response.body.label).toBe(tokenName); expect(response.body.label).toBe(tokenName);
expect(response.body.validUntil).toBe(null); expect(new Date(response.body.validUntil).getTime()).toBeGreaterThan(
Date.now(),
);
expect(response.body.lastUsedAt).toBe(null); expect(response.body.lastUsedAt).toBe(null);
expect(response.body.secret.length).toBe(98); expect(response.body.secret.length).toBe(98);
}); });
@ -62,7 +65,9 @@ describe('Tokens', () => {
.expect('Content-Type', /json/) .expect('Content-Type', /json/)
.expect(200); .expect(200);
expect(response.body[0].label).toBe(tokenName); expect(response.body[0].label).toBe(tokenName);
expect(response.body[0].validUntil).toBe(null); expect(new Date(response.body[0].validUntil).getTime()).toBeGreaterThan(
Date.now(),
);
expect(response.body[0].lastUsedAt).toBe(null); expect(response.body[0].lastUsedAt).toBe(null);
expect(response.body[0].secret).not.toBeDefined(); expect(response.body[0].secret).not.toBeDefined();
}); });