chore: apply ESLint auto-fix across entire backend
Build and Push Multi-Platform Images / build-and-push (push) Successful in 41s

Reformats code style (line breaks, indentation, type annotations)
without changing logic. Also includes minor feature additions bundled
in the same lint run (stats service, user-settings groups, agrarmonitor
polling improvements).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-08 09:02:02 +02:00
parent 4c75a1ded2
commit dad0136365
74 changed files with 4022 additions and 1052 deletions
+15 -5
View File
@@ -1,4 +1,10 @@
import { CanActivate, ExecutionContext, Injectable, Logger, UnauthorizedException } from '@nestjs/common';
import {
CanActivate,
ExecutionContext,
Injectable,
Logger,
UnauthorizedException,
} from '@nestjs/common';
import { ApiKeysService } from './api-keys.service';
@Injectable()
@@ -33,8 +39,8 @@ export class ApiKeyGuard implements CanActivate {
this.logger.log(
`[${method} ${url}] key source: ${apiKey ? source : 'NONE'} | ` +
`headers: ${JSON.stringify(Object.keys(request.headers))} | ` +
`key prefix: ${apiKey ? String(apiKey).slice(0, 8) + '…' : 'n/a'}`,
`headers: ${JSON.stringify(Object.keys(request.headers))} | ` +
`key prefix: ${apiKey ? String(apiKey).slice(0, 8) + '…' : 'n/a'}`,
);
if (!apiKey) {
@@ -44,11 +50,15 @@ export class ApiKeyGuard implements CanActivate {
try {
const keyEntry = await this.apiKeysService.validateKey(apiKey as string);
this.logger.log(`[${method} ${url}] accepted key "${keyEntry.name}" (id=${keyEntry.id})`);
this.logger.log(
`[${method} ${url}] accepted key "${keyEntry.name}" (id=${keyEntry.id})`,
);
request.apiKeyMetadata = { id: keyEntry.id, name: keyEntry.name };
return true;
} catch (err) {
this.logger.warn(`[${method} ${url}] rejected validation failed: ${err.message}`);
this.logger.warn(
`[${method} ${url}] rejected validation failed: ${err.message}`,
);
throw new UnauthorizedException(err.message || 'Invalid API Key');
}
}
@@ -1,4 +1,12 @@
import { Controller, Get, Post, Delete, Body, Param, UseGuards } from '@nestjs/common';
import {
Controller,
Get,
Post,
Delete,
Body,
Param,
UseGuards,
} from '@nestjs/common';
import { ApiKeysService } from './api-keys.service';
import { JwtAuthGuard } from './jwt-auth.guard';
+16 -7
View File
@@ -13,22 +13,27 @@ export class ApiKeysService {
private readonly apiKeyRepo: Repository<ApiKey>,
) {}
async createApiKey(name: string, expiresDays?: number): Promise<{ plainKey: string; entity: ApiKey }> {
async createApiKey(
name: string,
expiresDays?: number,
): Promise<{ plainKey: string; entity: ApiKey }> {
const prefix = 'pm_';
const randomPart = crypto.randomBytes(24).toString('hex'); // 48 chars hex
const plainKey = `${prefix}${randomPart}`;
const keyHash = this.hashKey(plainKey);
const apiKey = this.apiKeyRepo.create({
name,
keyPrefix: prefix,
keyHash,
expiresAt: expiresDays ? new Date(Date.now() + expiresDays * 24 * 60 * 60 * 1000) : null,
expiresAt: expiresDays
? new Date(Date.now() + expiresDays * 24 * 60 * 60 * 1000)
: null,
});
const savedKey = await this.apiKeyRepo.save(apiKey);
return {
plainKey,
entity: savedKey,
@@ -37,7 +42,7 @@ export class ApiKeysService {
async validateKey(plainKey: string): Promise<ApiKey> {
const keyHash = this.hashKey(plainKey);
const apiKey = await this.apiKeyRepo.findOne({
where: { keyHash },
});
@@ -52,7 +57,11 @@ export class ApiKeysService {
// Update last used timestamp (async, don't wait for it to return response faster)
apiKey.lastUsedAt = new Date();
this.apiKeyRepo.save(apiKey).catch(err => this.logger.error('Fehler beim Aktualisieren von lastUsedAt', err));
this.apiKeyRepo
.save(apiKey)
.catch((err) =>
this.logger.error('Fehler beim Aktualisieren von lastUsedAt', err),
);
return apiKey;
}
+9 -1
View File
@@ -33,6 +33,14 @@ import { PermissionsGuard } from './permissions.guard';
useClass: PermissionsGuard,
},
],
exports: [PassportModule, ApiKeysService, ApiKeyGuard, JwtAuthGuard, JwtOrApiKeyGuard, PermissionsGuard, TypeOrmModule],
exports: [
PassportModule,
ApiKeysService,
ApiKeyGuard,
JwtAuthGuard,
JwtOrApiKeyGuard,
PermissionsGuard,
TypeOrmModule,
],
})
export class AuthModule {}
@@ -1,4 +1,9 @@
import { CanActivate, ExecutionContext, Injectable, Logger } from '@nestjs/common';
import {
CanActivate,
ExecutionContext,
Injectable,
Logger,
} from '@nestjs/common';
import { Reflector } from '@nestjs/core';
import { JwtAuthGuard } from './jwt-auth.guard';
import { ApiKeyGuard } from './api-key.guard';
@@ -28,7 +33,9 @@ export class JwtOrApiKeyGuard implements CanActivate {
// Try JWT first
try {
const result = this.jwtGuard.canActivate(context);
const jwtOk = isObservable(result) ? await lastValueFrom(result) : await result;
const jwtOk = isObservable(result)
? await lastValueFrom(result)
: await result;
if (jwtOk) {
this.logger.log(`${tag} authenticated via JWT`);
return true;
+8 -1
View File
@@ -24,7 +24,14 @@ export class JwtStrategy extends PassportStrategy(Strategy, 'jwt') {
});
}
validate(payload: any): { userId: string; email: string; name: string; preferredUsername: string | null; groups: string[]; permissions: any[] } {
validate(payload: any): {
userId: string;
email: string;
name: string;
preferredUsername: string | null;
groups: string[];
permissions: any[];
} {
const groups = payload.groups || [];
return {
userId: payload.sub,
@@ -2,4 +2,5 @@ import { SetMetadata } from '@nestjs/common';
import { Permission } from './permissions.enum';
export const PERMISSIONS_KEY = 'permissions';
export const RequirePermissions = (...permissions: Permission[]) => SetMetadata(PERMISSIONS_KEY, permissions);
export const RequirePermissions = (...permissions: Permission[]) =>
SetMetadata(PERMISSIONS_KEY, permissions);
@@ -8,9 +8,11 @@ export const Permission = {
VIEW_FREIGABE: 'VIEW_FREIGABE',
} as const;
export type Permission = typeof Permission[keyof typeof Permission];
export type Permission = (typeof Permission)[keyof typeof Permission];
export function mapGroupsToPermissions(groups: string[] | undefined | null): Permission[] {
export function mapGroupsToPermissions(
groups: string[] | undefined | null,
): Permission[] {
const permissions = new Set<Permission>();
if (!groups || !Array.isArray(groups)) {
@@ -28,7 +30,8 @@ export function mapGroupsToPermissions(groups: string[] | undefined | null): Per
return Array.from(permissions);
}
if (groups.includes('PM_Belege')) permissions.add(Permission.PROCESS_MANUALLY);
if (groups.includes('PM_Belege'))
permissions.add(Permission.PROCESS_MANUALLY);
if (groups.includes('PM_Maileingang')) permissions.add(Permission.VIEW_MAIL);
if (groups.includes('PM_Posteingang')) permissions.add(Permission.VIEW_INBOX);
if (groups.includes('PM_Scanner')) permissions.add(Permission.VIEW_SCANNER);
+13 -11
View File
@@ -8,32 +8,34 @@ export class PermissionsGuard implements CanActivate {
constructor(private reflector: Reflector) {}
canActivate(context: ExecutionContext): boolean {
const requiredPermissions = this.reflector.getAllAndOverride<Permission[]>(PERMISSIONS_KEY, [
context.getHandler(),
context.getClass(),
]);
const requiredPermissions = this.reflector.getAllAndOverride<Permission[]>(
PERMISSIONS_KEY,
[context.getHandler(), context.getClass()],
);
if (!requiredPermissions) {
return true;
}
const request = context.switchToHttp().getRequest();
const { user } = request;
if (request.apiKeyMetadata) {
return true;
}
if (!user || !user.permissions) {
return false;
}
const userPermissions = user.permissions as Permission[];
if (userPermissions.includes(Permission.MANAGE_ALL)) {
return true;
}
return requiredPermissions.some((permission) => userPermissions.includes(permission));
return requiredPermissions.some((permission) =>
userPermissions.includes(permission),
);
}
}