chore( iam ): remove dead auth DTOs and @nestjs/jwt; migrate fayda/passenger to iamUserId

This commit is contained in:
Abubeker Yasin
2026-06-08 09:02:54 +03:00
parent b509fccf93
commit ac153fb0d0
5 changed files with 58 additions and 262 deletions

View File

@@ -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(