162 lines
3.8 KiB
TypeScript
162 lines
3.8 KiB
TypeScript
import { Injectable } from '@nestjs/common';
|
|
import { JwtService } from '@nestjs/jwt';
|
|
import { TenantDatabaseService } from '../tenant/tenant-database.service';
|
|
import { getCentralPrisma } from '../prisma/central-prisma.service';
|
|
import * as bcrypt from 'bcrypt';
|
|
|
|
@Injectable()
|
|
export class AuthService {
|
|
constructor(
|
|
private tenantDbService: TenantDatabaseService,
|
|
private jwtService: JwtService,
|
|
) {}
|
|
|
|
private isCentralSubdomain(subdomain: string): boolean {
|
|
const centralSubdomains = (process.env.CENTRAL_SUBDOMAINS || 'central,admin').split(',');
|
|
return centralSubdomains.includes(subdomain);
|
|
}
|
|
|
|
async validateUser(
|
|
tenantId: string,
|
|
email: string,
|
|
password: string,
|
|
subdomain?: string,
|
|
): Promise<any> {
|
|
|
|
// Check if this is a central subdomain
|
|
if (subdomain && this.isCentralSubdomain(subdomain)) {
|
|
return this.validateCentralUser(email, password);
|
|
}
|
|
|
|
// Otherwise, validate as tenant user
|
|
const tenantDb = await this.tenantDbService.getTenantKnex(tenantId);
|
|
|
|
const user = await tenantDb('users')
|
|
.where({ email })
|
|
.first();
|
|
|
|
if (!user) {
|
|
return null;
|
|
}
|
|
|
|
if (await bcrypt.compare(password, user.password)) {
|
|
// Load user roles and permissions
|
|
const userRoles = await tenantDb('user_roles')
|
|
.where({ userId: user.id })
|
|
.join('roles', 'user_roles.roleId', 'roles.id')
|
|
.select('roles.*');
|
|
|
|
const { password: _, ...result } = user;
|
|
return {
|
|
...result,
|
|
tenantId,
|
|
userRoles,
|
|
};
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
private async validateCentralUser(
|
|
email: string,
|
|
password: string,
|
|
): Promise<any> {
|
|
const centralPrisma = getCentralPrisma();
|
|
|
|
const user = await centralPrisma.user.findUnique({
|
|
where: { email },
|
|
});
|
|
|
|
if (!user) {
|
|
return null;
|
|
}
|
|
|
|
if (await bcrypt.compare(password, user.password)) {
|
|
const { password: _, ...result } = user;
|
|
return {
|
|
...result,
|
|
isCentralAdmin: true,
|
|
};
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
async login(user: any) {
|
|
const payload = {
|
|
sub: user.id,
|
|
email: user.email,
|
|
};
|
|
|
|
return {
|
|
access_token: this.jwtService.sign(payload),
|
|
user: {
|
|
id: user.id,
|
|
email: user.email,
|
|
firstName: user.firstName,
|
|
lastName: user.lastName,
|
|
},
|
|
};
|
|
}
|
|
|
|
async register(
|
|
tenantId: string,
|
|
email: string,
|
|
password: string,
|
|
firstName?: string,
|
|
lastName?: string,
|
|
subdomain?: string,
|
|
) {
|
|
// Check if this is a central subdomain
|
|
if (subdomain && this.isCentralSubdomain(subdomain)) {
|
|
return this.registerCentralUser(email, password, firstName, lastName);
|
|
}
|
|
|
|
// Otherwise, register as tenant user
|
|
const tenantDb = await this.tenantDbService.getTenantKnex(tenantId);
|
|
|
|
const hashedPassword = await bcrypt.hash(password, 10);
|
|
|
|
const [userId] = await tenantDb('users').insert({
|
|
email,
|
|
password: hashedPassword,
|
|
firstName,
|
|
lastName,
|
|
isActive: true,
|
|
created_at: new Date(),
|
|
updated_at: new Date(),
|
|
});
|
|
|
|
const user = await tenantDb('users')
|
|
.where({ id: userId })
|
|
.first();
|
|
|
|
const { password: _, ...result } = user;
|
|
return result;
|
|
}
|
|
|
|
private async registerCentralUser(
|
|
email: string,
|
|
password: string,
|
|
firstName?: string,
|
|
lastName?: string,
|
|
) {
|
|
const centralPrisma = getCentralPrisma();
|
|
|
|
const hashedPassword = await bcrypt.hash(password, 10);
|
|
|
|
const user = await centralPrisma.user.create({
|
|
data: {
|
|
email,
|
|
password: hashedPassword,
|
|
firstName: firstName || null,
|
|
lastName: lastName || null,
|
|
isActive: true,
|
|
},
|
|
});
|
|
|
|
const { password: _, ...result } = user;
|
|
return result;
|
|
}
|
|
}
|