07dfd7e840
Backend 958→0 errors, frontend 98→0 errors. Builds and tsc clean. Echte Fixes: - Auth: AuthenticatedUser/AuthenticatedRequest, JwtStrategy + alle 5 Controller von `@Request() req: any` auf typisierten Request umgestellt - Error-Handling: neuer getErrorMessage/Stack/Code/getResponseData-Helper; alle 50 `catch (err: any)`-Blöcke auf `unknown` + Helper umgestellt - 24 echte Bugs: require-await, require-imports→ES-Imports, useless-escape, misused-promises, tote Imports/Vars, leere catch-Blöcke kommentiert - document-pipeline: OCR-Ergebnis wird nicht gespeichert (als TODO markiert) Pragmatisch auf warn herabgestuft (untypisierte Paperless-NGX-API): no-unsafe-*, restrict-template-expressions, no-base-to-string, no-explicit-any (FE), react-refresh/only-export-components Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
48 lines
1.4 KiB
TypeScript
48 lines
1.4 KiB
TypeScript
import { Injectable } from '@nestjs/common';
|
|
import { PassportStrategy } from '@nestjs/passport';
|
|
import { Strategy, ExtractJwt } from 'passport-jwt';
|
|
import { ConfigService } from '@nestjs/config';
|
|
import { passportJwtSecret } from 'jwks-rsa';
|
|
import { mapGroupsToPermissions } from './permissions.enum';
|
|
import type { AuthenticatedUser } from './authenticated-request';
|
|
|
|
interface JwtPayload {
|
|
sub: string;
|
|
email: string;
|
|
name?: string;
|
|
preferred_username?: string;
|
|
groups?: string[];
|
|
}
|
|
|
|
@Injectable()
|
|
export class JwtStrategy extends PassportStrategy(Strategy, 'jwt') {
|
|
constructor(configService: ConfigService) {
|
|
const issuer = configService.get<string>('OIDC_ISSUER', '');
|
|
|
|
super({
|
|
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
|
|
ignoreExpiration: false,
|
|
issuer,
|
|
algorithms: ['RS256'],
|
|
secretOrKeyProvider: passportJwtSecret({
|
|
cache: true,
|
|
rateLimit: true,
|
|
jwksRequestsPerMinute: 5,
|
|
jwksUri: `${issuer.endsWith('/') ? issuer.slice(0, -1) : issuer}/jwks/`,
|
|
}),
|
|
});
|
|
}
|
|
|
|
validate(payload: JwtPayload): AuthenticatedUser {
|
|
const groups = payload.groups ?? [];
|
|
return {
|
|
userId: payload.sub,
|
|
email: payload.email,
|
|
name: payload.name || payload.preferred_username || '',
|
|
preferredUsername: payload.preferred_username ?? null,
|
|
groups: groups,
|
|
permissions: mapGroupsToPermissions(groups),
|
|
};
|
|
}
|
|
}
|