Fixed/cleaned auth validation. Added 404 response when registrations are disabled.

This commit is contained in:
Tom
2025-06-19 15:25:18 +00:00
parent bde574ccad
commit cc337d22f2
6 changed files with 57 additions and 46 deletions

View File

@ -4,7 +4,7 @@ import { config } from './config';
@Controller('asset') @Controller('asset')
export class ConfigController { export class ConfigController {
@Get('config') @Get('config')
async login( async config(
@Request() req, @Request() req,
) { ) {
return { return {

View File

@ -1,3 +1,5 @@
export const config = { export const config = {
register_enabled: false, features: {
registration: false,
},
} }

View File

@ -11,6 +11,7 @@ import { PinoLogger } from 'nestjs-pino';
import { JwtAccessGuard } from './guards/jwt-access.guard'; import { JwtAccessGuard } from './guards/jwt-access.guard';
import { LoginDto } from './dto/login.dto'; import { LoginDto } from './dto/login.dto';
import { AuthenticationDto } from './dto/authentication.dto'; import { AuthenticationDto } from './dto/authentication.dto';
import { config } from 'src/asset/config/config';
@Controller('auth') @Controller('auth')
export class AuthController { export class AuthController {
@ -187,6 +188,14 @@ export class AuthController {
@Res({ passthrough: true }) response: Response, @Res({ passthrough: true }) response: Response,
@Body() body: RegisterUserDto, @Body() body: RegisterUserDto,
) { ) {
if (!config.features.registration) {
response.statusCode = 404;
return {
success: false,
error_message: 'Registration disabled.',
};
}
let user: UserEntity | null; let user: UserEntity | null;
let data: AuthenticationDto | null; let data: AuthenticationDto | null;
try { try {

View File

@ -6,7 +6,7 @@ import { AuthController } from './auth.controller';
import { ConfigModule, ConfigService } from '@nestjs/config'; import { ConfigModule, ConfigService } from '@nestjs/config';
import { JwtModule } from '@nestjs/jwt'; import { JwtModule } from '@nestjs/jwt';
import { JwtOptions } from './jwt.options'; import { JwtOptions } from './jwt.options';
import { JwtStrategy } from './strategies/jwt.strategy'; import { JwtAccessStrategy } from './strategies/jwt-access.strategy';
import { AuthRefreshService } from './auth.refresh.service'; import { AuthRefreshService } from './auth.refresh.service';
import { TypeOrmModule } from '@nestjs/typeorm'; import { TypeOrmModule } from '@nestjs/typeorm';
import { AuthRefreshTokenEntity } from './entities/auth.refresh-token.entity'; import { AuthRefreshTokenEntity } from './entities/auth.refresh-token.entity';
@ -34,7 +34,7 @@ import { JwtRefreshStrategy } from './strategies/jwt-refresh.strategy';
AuthAccessService, AuthAccessService,
AuthRefreshService, AuthRefreshService,
AuthService, AuthService,
JwtStrategy, JwtAccessStrategy,
JwtRefreshStrategy, JwtRefreshStrategy,
], ],
controllers: [AuthController] controllers: [AuthController]

View File

@ -60,60 +60,60 @@ export class AuthService {
accessToken: string, accessToken: string,
refreshToken: string refreshToken: string
): Promise<{ validation: boolean, userId: UUID | null, username: string | null }> { ): Promise<{ validation: boolean, userId: UUID | null, username: string | null }> {
if (!accessToken) { let access: any = null;
if (!refreshToken) { let refresh: any = null;
return {
validation: false,
userId: null,
username: null,
}
}
const refresh = await this.refreshTokens.verify(refreshToken); if (accessToken) {
if (refresh.message || !refresh.exp || refresh.exp * 1000 <= new Date().getTime()) { access = await this.accessTokens.verify(accessToken);
if (!access.username || !access.sub) {
return { return {
validation: false, validation: false,
userId: null, userId: null,
username: null, username: null,
}; };
} }
}
if (refreshToken) {
refresh = await this.refreshTokens.verify(refreshToken);
if (!refresh.username || !refresh.sub) {
return {
validation: false,
userId: null,
username: null,
};
}
}
if (accessToken && refreshToken) {
if (access.username != refresh.username || access.sub != refresh.sub) {
return {
validation: false,
userId: null,
username: null,
};
}
}
if (!accessToken || !access.exp || access.exp * 1000 <= new Date().getTime()) {
if (!refreshToken || !refresh.exp || refresh.exp * 1000 <= new Date().getTime()) {
// Both expired.
return {
validation: false,
userId: null,
username: null,
};
}
// Refresh token is still active.
return { return {
validation: null, validation: null,
userId: refresh.sub, userId: refresh.sub,
username: refresh.username, username: refresh.username,
}; };
} }
const access = await this.accessTokens.verify(accessToken);
const refresh = await this.refreshTokens.verify(refreshToken);
if (!access.username || !refresh.username || access.username != refresh.username) {
return {
validation: false,
userId: null,
username: null,
};
}
if (!access.sub || !refresh.sub || access.sub != refresh.sub) {
return {
validation: false,
userId: null,
username: null,
};
}
if (access.message || !access.exp || access.exp * 1000 <= new Date().getTime()) { // Access still active, at least.
if (refresh.message || !refresh.exp || refresh.exp * 1000 <= new Date().getTime()) {
return {
validation: false,
userId: null,
username: null,
};
}
return {
validation: null,
userId: access.sub,
username: access.username,
};
}
return { return {
validation: true, validation: true,
userId: access.sub, userId: access.sub,

View File

@ -6,12 +6,12 @@ import { ConfigService } from '@nestjs/config';
import { UsersService } from 'src/users/users.service'; import { UsersService } from 'src/users/users.service';
@Injectable() @Injectable()
export class JwtStrategy extends PassportStrategy(Strategy, 'jwt-access') { export class JwtAccessStrategy extends PassportStrategy(Strategy, 'jwt-access') {
constructor(private users: UsersService, private config: ConfigService) { constructor(private users: UsersService, private config: ConfigService) {
super({ super({
jwtFromRequest: ExtractJwt.fromExtractors([ jwtFromRequest: ExtractJwt.fromExtractors([
//ExtractJwt.fromAuthHeaderAsBearerToken(), //ExtractJwt.fromAuthHeaderAsBearerToken(),
JwtStrategy.extract, JwtAccessStrategy.extract,
]), ]),
ignoreExpiration: false, ignoreExpiration: false,
secretOrKey: config.getOrThrow<string>('AUTH_JWT_ACCESS_TOKEN_SECRET'), secretOrKey: config.getOrThrow<string>('AUTH_JWT_ACCESS_TOKEN_SECRET'),