first commit

This commit is contained in:
lendry
2026-06-24 14:37:15 +03:00
commit 995adeedd4
188 changed files with 28810 additions and 0 deletions

View File

@@ -0,0 +1,62 @@
import { ForbiddenException, UnauthorizedException } from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';
import { firstValueFrom } from 'rxjs';
import { extractBearerToken } from './auth-token';
import { CoreGrpcService } from './core-grpc.service';
export interface AccessTokenPayload {
sub: string;
sessionId?: string;
pinVerified?: boolean;
isSuperAdmin?: boolean;
}
export async function verifyAccessToken(jwt: JwtService, authorization?: string): Promise<AccessTokenPayload> {
const token = extractBearerToken(authorization);
try {
return await jwt.verifyAsync<AccessTokenPayload>(token, {
secret: process.env.JWT_ACCESS_SECRET ?? 'docker-access-secret',
issuer: 'id.lendry.ru'
});
} catch {
throw new UnauthorizedException({
statusCode: 401,
message: 'Токен доступа недействителен или истёк',
code: 'TOKEN_EXPIRED'
});
}
}
export async function assertSessionUnlocked(core: CoreGrpcService, payload: AccessTokenPayload) {
if (!payload.sessionId) {
return;
}
const validation = (await firstValueFrom(
core.auth.ValidateSession({
userId: payload.sub,
sessionId: payload.sessionId,
touchActivity: true
})
)) as { requiresPin: boolean; sessionId: string };
if (validation.requiresPin) {
throw new ForbiddenException({
statusCode: 403,
message: 'Требуется подтверждение PIN-кода',
code: 'PIN_REQUIRED',
sessionId: validation.sessionId
});
}
}
export async function resolveAuthorizedPayload(
jwt: JwtService,
core: CoreGrpcService,
authorization?: string
): Promise<AccessTokenPayload> {
const payload = await verifyAccessToken(jwt, authorization);
await assertSessionUnlocked(core, payload);
return payload;
}