fix and update
This commit is contained in:
99
apps/sso-core/src/domain/fedcm.service.ts
Normal file
99
apps/sso-core/src/domain/fedcm.service.ts
Normal file
@@ -0,0 +1,99 @@
|
||||
import { BadRequestException, Injectable, UnauthorizedException } from '@nestjs/common';
|
||||
import { PrismaService } from '../infra/prisma.service';
|
||||
import { OAuthCoreService } from './oauth-core.service';
|
||||
import { SessionService } from './session.service';
|
||||
import { assertHumanAccount, HUMAN_USER_WHERE } from './system-account.util';
|
||||
|
||||
@Injectable()
|
||||
export class FedcmService {
|
||||
constructor(
|
||||
private readonly prisma: PrismaService,
|
||||
private readonly session: SessionService,
|
||||
private readonly oauthCore: OAuthCoreService
|
||||
) {}
|
||||
|
||||
async getAccounts(userId: string, sessionId: string) {
|
||||
await this.assertUnlockedSession(userId, sessionId);
|
||||
|
||||
const user = await this.prisma.user.findFirst({
|
||||
where: { id: userId, deletedAt: null, status: 'ACTIVE', ...HUMAN_USER_WHERE }
|
||||
});
|
||||
if (!user) {
|
||||
return { accounts: [] };
|
||||
}
|
||||
assertHumanAccount(user, { asAuth: true });
|
||||
|
||||
const consents = await this.prisma.oAuthConsent.findMany({
|
||||
where: { userId },
|
||||
include: { client: { select: { clientId: true, isActive: true } } }
|
||||
});
|
||||
|
||||
const approvedClients = consents
|
||||
.filter((item) => item.client.isActive)
|
||||
.map((item) => item.client.clientId);
|
||||
|
||||
const givenName = user.displayName.trim().split(/\s+/)[0] || user.displayName;
|
||||
|
||||
return {
|
||||
accounts: [
|
||||
{
|
||||
id: user.id,
|
||||
name: user.displayName,
|
||||
given_name: givenName,
|
||||
email: user.email ?? undefined,
|
||||
picture: user.avatarUrl ?? undefined,
|
||||
approved_clients: approvedClients
|
||||
}
|
||||
]
|
||||
};
|
||||
}
|
||||
|
||||
async issueIdAssertion(userId: string, sessionId: string, clientId: string, accountId: string) {
|
||||
if (accountId !== userId) {
|
||||
throw new BadRequestException('account_id не совпадает с активной сессией');
|
||||
}
|
||||
|
||||
await this.assertUnlockedSession(userId, sessionId);
|
||||
|
||||
const client = await this.prisma.oAuthClient.findUnique({
|
||||
where: { clientId },
|
||||
include: { scopes: { include: { scope: true } } }
|
||||
});
|
||||
if (!client?.isActive) {
|
||||
throw new BadRequestException('OAuth-приложение не найдено или отключено');
|
||||
}
|
||||
|
||||
const scopeSlugs = client.scopes.map((item) => item.scope.slug);
|
||||
const scope = scopeSlugs.length > 0 ? scopeSlugs.join(' ') : 'openid profile email';
|
||||
|
||||
const consent = await this.oauthCore.checkConsent(userId, clientId, scope);
|
||||
if (!consent.granted) {
|
||||
await this.oauthCore.grantConsent(userId, clientId, scope);
|
||||
}
|
||||
|
||||
const tokens = await this.oauthCore.issueFedcmTokens(userId, clientId, scopeSlugs.length > 0 ? scopeSlugs : ['openid', 'profile', 'email']);
|
||||
return { token: tokens.idToken };
|
||||
}
|
||||
|
||||
async getClientMetadata(clientId: string) {
|
||||
const client = await this.prisma.oAuthClient.findUnique({ where: { clientId } });
|
||||
if (!client?.isActive) {
|
||||
throw new BadRequestException('OAuth-приложение не найдено или отключено');
|
||||
}
|
||||
|
||||
return {
|
||||
privacy_policy_url: 'https://id.lendry.ru/data',
|
||||
terms_of_service_url: 'https://id.lendry.ru/data'
|
||||
};
|
||||
}
|
||||
|
||||
private async assertUnlockedSession(userId: string, sessionId: string) {
|
||||
const state = await this.session.resolveSessionState(sessionId);
|
||||
if (!state || state.userId !== userId) {
|
||||
throw new UnauthorizedException('Сессия недействительна или истекла');
|
||||
}
|
||||
if (state.requiresPin) {
|
||||
throw new UnauthorizedException('Требуется подтверждение PIN-кода');
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user