mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-09-09 04:48:18 +00:00
chore( iam ): remove dead auth DTOs and @nestjs/jwt; migrate fayda/passenger to iamUserId
This commit is contained in:
@@ -7,8 +7,6 @@ import {
|
||||
} from '@nestjs/common';
|
||||
import { ConfigService } from '@nestjs/config';
|
||||
import axios, { AxiosInstance } from 'axios';
|
||||
import * as bcrypt from 'bcrypt';
|
||||
import { randomBytes } from 'crypto';
|
||||
import { PrismaService } from '../../common/prisma.service';
|
||||
import { FaydaConfig, FaydaPlatform } from '../../config/fayda.config';
|
||||
import {
|
||||
@@ -142,7 +140,8 @@ export class VerifaydaService {
|
||||
purpose: input.purpose,
|
||||
platform: input.platform ?? 'WEB',
|
||||
saveToAccount: input.saveToAccount ?? false,
|
||||
userId: input.userId ?? null,
|
||||
iamUserId: input.userId ?? null,
|
||||
userId: null,
|
||||
bookingId: input.bookingId ?? null,
|
||||
expiresAt,
|
||||
},
|
||||
@@ -283,16 +282,15 @@ export class VerifaydaService {
|
||||
});
|
||||
}
|
||||
|
||||
async getVerificationStatus(userId: string): Promise<VerificationStatusDto> {
|
||||
const user = await this.prisma.user.findUnique({
|
||||
where: { id: userId },
|
||||
select: { faydaVerified: true, faydaVerifiedAt: true, fullName: true },
|
||||
async getVerificationStatus(iamUserId: string): Promise<VerificationStatusDto> {
|
||||
const passenger = await this.prisma.passenger.findUnique({
|
||||
where: { iamUserId },
|
||||
include: { user: { select: { faydaVerified: true, faydaVerifiedAt: true, fullName: true } } },
|
||||
});
|
||||
|
||||
return {
|
||||
verified: user?.faydaVerified ?? false,
|
||||
verifiedAt: user?.faydaVerifiedAt ?? undefined,
|
||||
fullName: user?.fullName ?? undefined,
|
||||
verified: passenger?.user?.faydaVerified ?? false,
|
||||
verifiedAt: passenger?.user?.faydaVerifiedAt ?? undefined,
|
||||
fullName: passenger?.user?.fullName ?? undefined,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -422,6 +420,7 @@ export class VerifaydaService {
|
||||
private async handlePurchaseSuccess(
|
||||
session: {
|
||||
id: string;
|
||||
iamUserId: string | null;
|
||||
userId: string | null;
|
||||
bookingId: string | null;
|
||||
saveToAccount: boolean;
|
||||
@@ -439,129 +438,38 @@ export class VerifaydaService {
|
||||
});
|
||||
}
|
||||
|
||||
if (session.userId && session.saveToAccount) {
|
||||
const iamUserId = session.iamUserId;
|
||||
if (iamUserId && session.saveToAccount) {
|
||||
const passenger = await this.prisma.passenger.findUnique({
|
||||
where: { iamUserId },
|
||||
select: { userId: true },
|
||||
});
|
||||
const localUserId = passenger?.userId;
|
||||
if (!localUserId) return;
|
||||
|
||||
const conflict = await this.prisma.user.findFirst({
|
||||
where: {
|
||||
faydaSub: normalized.sub,
|
||||
NOT: { id: session.userId },
|
||||
},
|
||||
where: { faydaSub: normalized.sub, NOT: { id: localUserId } },
|
||||
select: { id: true },
|
||||
});
|
||||
if (conflict) {
|
||||
throw new FaydaIdentityConflictException();
|
||||
}
|
||||
if (conflict) throw new FaydaIdentityConflictException();
|
||||
|
||||
await this.prisma.user.update({
|
||||
where: { id: session.userId },
|
||||
data: {
|
||||
faydaVerified: true,
|
||||
faydaVerifiedAt: new Date(),
|
||||
faydaSub: normalized.sub,
|
||||
},
|
||||
where: { id: localUserId },
|
||||
data: { faydaVerified: true, faydaVerifiedAt: new Date(), faydaSub: normalized.sub },
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves the User for a LOGIN flow and returns its id (the caller mints the
|
||||
* JWT via {@link issueLoginToken}). Resolution order:
|
||||
* 1. Existing user already linked to this Fayda `sub`.
|
||||
* 2. Existing account whose email/phone matches — linked to this `sub`.
|
||||
* 3. Otherwise a fresh Fayda-backed account is created.
|
||||
*/
|
||||
// LOGIN via Fayda is now handled entirely by the IAM package's own OIDC flow.
|
||||
// This method is kept as a stub so completeVerification() still compiles;
|
||||
// it throws immediately without touching the database.
|
||||
private async handleLoginSuccess(
|
||||
normalized: NormalizedFaydaUserInfo,
|
||||
_normalized: NormalizedFaydaUserInfo,
|
||||
): Promise<{ userId: string }> {
|
||||
let userId: string;
|
||||
|
||||
const bySub = await this.prisma.user.findUnique({
|
||||
where: { faydaSub: normalized.sub },
|
||||
select: { id: true },
|
||||
throw new UnauthorizedException({
|
||||
code: 'FAYDA_LOGIN_MIGRATED_TO_IAM',
|
||||
message: 'Fayda login tokens are issued by the IAM package at /v1/auth/fayda endpoints.',
|
||||
});
|
||||
|
||||
if (bySub) {
|
||||
userId = bySub.id;
|
||||
} else {
|
||||
const matchers: Array<{ email?: string; phone?: string }> = [];
|
||||
if (normalized.email) matchers.push({ email: normalized.email });
|
||||
if (normalized.phoneNumber) matchers.push({ phone: normalized.phoneNumber });
|
||||
|
||||
const existing = matchers.length
|
||||
? await this.prisma.user.findFirst({
|
||||
where: { OR: matchers },
|
||||
select: { id: true, faydaSub: true },
|
||||
})
|
||||
: null;
|
||||
|
||||
if (existing) {
|
||||
if (existing.faydaSub && existing.faydaSub !== normalized.sub) {
|
||||
// The matched account is already tied to a different Fayda identity.
|
||||
throw new FaydaIdentityConflictException();
|
||||
}
|
||||
await this.prisma.user.update({
|
||||
where: { id: existing.id },
|
||||
data: {
|
||||
faydaSub: normalized.sub,
|
||||
faydaVerified: true,
|
||||
faydaVerifiedAt: new Date(),
|
||||
},
|
||||
});
|
||||
userId = existing.id;
|
||||
this.logger.log(`Fayda login linked existing user ${existing.id}`);
|
||||
} else {
|
||||
userId = await this.createFaydaUser(normalized);
|
||||
this.logger.log(`Fayda login created new user ${userId}`);
|
||||
}
|
||||
}
|
||||
|
||||
return { userId };
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a Fayda-backed User plus the same satellite rows registration makes
|
||||
* (Passenger, LoyaltyAccount, WalletAccount, UserPreferences).
|
||||
*
|
||||
* The user has no password — `passwordHash` is set to a bcrypt of random bytes
|
||||
* so password login is impossible; they authenticate only via Fayda. When
|
||||
* Fayda doesn't supply an email/phone, a deterministic placeholder derived from
|
||||
* the (unique) `sub` keeps the NOT NULL + unique columns satisfied.
|
||||
*/
|
||||
private async createFaydaUser(
|
||||
normalized: NormalizedFaydaUserInfo,
|
||||
): Promise<string> {
|
||||
const passwordHash = await bcrypt.hash(
|
||||
randomBytes(32).toString('hex'),
|
||||
10,
|
||||
);
|
||||
const email = normalized.email ?? `fayda_${normalized.sub}@users.fayda.local`;
|
||||
const phone = normalized.phoneNumber ?? `fayda:${normalized.sub}`;
|
||||
const fullName = normalized.fullName ?? 'Fayda User';
|
||||
|
||||
const user = await this.prisma.user.create({
|
||||
data: {
|
||||
fullName,
|
||||
email,
|
||||
phone,
|
||||
passwordHash,
|
||||
faydaVerified: true,
|
||||
faydaVerifiedAt: new Date(),
|
||||
faydaSub: normalized.sub,
|
||||
},
|
||||
select: { id: true },
|
||||
});
|
||||
const passenger = await this.prisma.passenger.create({
|
||||
data: { userId: user.id },
|
||||
select: { id: true },
|
||||
});
|
||||
await this.prisma.loyaltyAccount.create({
|
||||
data: { passengerId: passenger.id },
|
||||
});
|
||||
await this.prisma.walletAccount.create({
|
||||
data: { passengerId: passenger.id },
|
||||
});
|
||||
await this.prisma.userPreferences.create({ data: { userId: user.id } });
|
||||
|
||||
return user.id;
|
||||
}
|
||||
|
||||
private async markSessionFailed(
|
||||
|
||||
Reference in New Issue
Block a user