81 lines
2.4 KiB
TypeScript
81 lines
2.4 KiB
TypeScript
import { Injectable, NotFoundException, ForbiddenException } from '@nestjs/common';
|
|
import { JwtService } from '@nestjs/jwt';
|
|
import { ConfigService } from '@nestjs/config';
|
|
import { TenantPrismaService } from '../prisma/tenant-prisma.service';
|
|
import { AuditService } from '../audit/audit.service';
|
|
|
|
@Injectable()
|
|
export class ImpersonateService {
|
|
private readonly mainJwtSecret: string;
|
|
|
|
constructor(
|
|
private readonly tenantDb: TenantPrismaService,
|
|
private readonly jwt: JwtService,
|
|
private readonly config: ConfigService,
|
|
private readonly audit: AuditService,
|
|
) {
|
|
// Use the MAIN API's JWT secret so the token works with the tenant API
|
|
this.mainJwtSecret = this.config.get<string>('MAIN_API_JWT_SECRET', 'your-secret-key');
|
|
}
|
|
|
|
async startImpersonation(tenantId: string, adminId: string, adminName: string) {
|
|
const tenant = await this.tenantDb.tenant.findUnique({
|
|
where: { id: tenantId, deletedAt: null, isActive: true },
|
|
});
|
|
if (!tenant) throw new NotFoundException('Tenant not found or inactive');
|
|
|
|
// Find the tenant's first admin user
|
|
const adminUser = await this.tenantDb.user.findFirst({
|
|
where: {
|
|
tenantId,
|
|
deletedAt: null,
|
|
isActive: true,
|
|
roles: { some: { role: 'tenant_admin' } },
|
|
},
|
|
});
|
|
if (!adminUser) throw new NotFoundException('No tenant admin found for this tenant');
|
|
|
|
// Generate a JWT compatible with the main API
|
|
const token = this.jwt.sign(
|
|
{
|
|
sub: adminUser.id,
|
|
tenantId,
|
|
roles: ['tenant_admin'],
|
|
permissions: 'all',
|
|
impersonatedBy: adminId,
|
|
},
|
|
{
|
|
secret: this.mainJwtSecret,
|
|
expiresIn: '1h',
|
|
},
|
|
);
|
|
|
|
// Audit the impersonation
|
|
await this.audit.log(adminId, 'impersonate.start', tenantId, {
|
|
tenantName: tenant.name,
|
|
impersonatedUserId: adminUser.id,
|
|
});
|
|
|
|
return {
|
|
accessToken: token,
|
|
impersonatedUser: {
|
|
id: adminUser.id,
|
|
email: adminUser.email,
|
|
firstName: adminUser.firstName,
|
|
lastName: adminUser.lastName,
|
|
},
|
|
tenant: {
|
|
id: tenant.id,
|
|
name: tenant.name,
|
|
slug: tenant.slug,
|
|
},
|
|
expiresAt: new Date(Date.now() + 3600000).toISOString(),
|
|
};
|
|
}
|
|
|
|
async endImpersonation(adminId: string) {
|
|
await this.audit.log(adminId, 'impersonate.end');
|
|
return { message: 'Impersonation ended' };
|
|
}
|
|
}
|