import {IAuthClient, IAuthUser} from '@bleco/authentication'; // import {AuthorizationBindings, UserPermissionsFn} from '@bleco/authorization'; import {inject, Provider} from '@loopback/core'; import {AnyObject, repository} from '@loopback/repository'; import {AuthErrors, ConfigKey, getAge, ILogger, LOGGER} from '@loopx/core'; import { RoleRepository, TenantConfigRepository, User, UserLevelPermissionRepository, UserTenant, UserTenantRepository, } from '@loopx/user-core'; import {AuthUser} from '../modules/auth/models/auth-user.model'; import {JwtPayloadFn} from './types'; export class JwtPayloadProvider implements Provider { constructor( @repository(RoleRepository) private readonly roleRepo: RoleRepository, @repository(UserLevelPermissionRepository) private readonly utPermsRepo: UserLevelPermissionRepository, @repository(UserTenantRepository) private readonly userTenantRepo: UserTenantRepository, @repository(TenantConfigRepository) private readonly tenantConfigRepo: TenantConfigRepository, // @inject(AuthorizationBindings.USER_PERMISSIONS) // private readonly getUserPermissions: UserPermissionsFn, @inject(LOGGER.LOGGER_INJECT) private readonly logger: ILogger, ) {} value() { return async (authUserData: IAuthUser, authClient: IAuthClient, tenantId?: string) => { const user = authUserData as User; const userTenant = await this.userTenantRepo.findOne({ where: { userId: (user as User).id, tenantId: tenantId ?? user.defaultTenantId, }, }); if (!userTenant) { throw new AuthErrors.UserDoesNotExist(); } // TODO - Uncomment this once we can deal with auth clients in a better way // if ( // // eslint-disable-next-line @typescript-eslint/ban-ts-comment // // @ts-ignore // user.authClientIds.indexOf(authClient.id || 0) < 0 // ) { // throw new AuthenticationErrors.ClientInvalid(); // } delete user.authClientIds; // Create user DTO for payload to JWT const authUser: AuthUser = new AuthUser(Object.assign({}, user)); this._removeUnnecessaryData(authUser); // Add locale info await this._setLocale(authUser, userTenant); authUser.tenantId = userTenant.tenantId; authUser.userTenantId = userTenant.id; authUser.status = userTenant.status; const role = await this.roleRepo.findById(userTenant.roleId); if (!role) { this.logger.error('Role not found for the user'); throw new AuthErrors.UnprocessableData(); } // const utPerms = await this.utPermsRepo.find({ // where: { // userTenantId: userTenant.id, // }, // fields: { // permission: true, // allowed: true, // }, // }); // authUser.permissions = this.getUserPermissions(utPerms, role.permissions); authUser.role = role.code; if (authUser.dob) { const age = getAge(new Date(authUser.dob)); authUser.age = age; } return authUser.toJSON(); }; } private _removeUnnecessaryData(authUser: AnyObject) { delete authUser.externalAuthToken; delete authUser.externalRefreshToken; delete authUser.deleted; delete authUser.createdBy; delete authUser.createdAt; delete authUser.deletedBy; delete authUser.deletedAt; delete authUser.updatedBy; delete authUser.updatedAt; return authUser; } private async _setLocale(authUser: AuthUser, userTenant: UserTenant) { if (userTenant.locale && userTenant.locale.length > 0) { // Use locale from user preferences first authUser.userPreferences = {locale: userTenant.locale}; } else { // Use tenant config locale at second priority const config = await this.tenantConfigRepo.findOne({ where: { configKey: ConfigKey.Profile, }, }); // Use locale from environment as fallback overall let locale = process.env.LOCALE ?? 'en'; if (config?.configValue) { // eslint-disable-next-line @typescript-eslint/no-explicit-any locale = (config.configValue as any).locale; } authUser.userPreferences = { locale, }; } } }