Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 | 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 23x 23x 23x 23x 1x 1x 23x 23x 23x 23x 23x 23x 23x 23x 23x 23x 23x 23x 23x 23x 23x 23x 23x 23x 23x 23x 23x 23x 23x 23x 23x 23x 23x 23x 23x 23x 20x 20x 20x 20x 20x 20x 20x 20x 20x 20x 20x 20x 20x 23x 23x 23x 23x 23x 23x 23x 23x 12x 12x 12x 12x 12x 17x 17x 23x 5x 5x 5x 5x 5x 5x 5x 5x 5x 15x 15x 23x 2x 2x 2x 2x 2x 2x 15x 15x 15x 15x 15x 15x 15x 15x 15x 15x 15x 1x | import { ForbiddenException, NotFoundException, ServiceUnavailableException } from '@nestjs/common';
import { assert } from '@amalia/ext/typescript';
import { JwtPayloadAmaliaRoles } from '@amalia/kernel/auth/types';
import { isInMaintenance } from '@amalia/kernel/maintenance-mode';
import { Company } from '@amalia/tenants/companies/types';
import { AmaliaRole, UserRole, UserStatus } from '@amalia/tenants/users/types';
import { InjectAuthConfig, type AuthConfig } from '../config/auth.config';
import { UserAuthenticationRepository } from '../repositories/user-authentication.repository';
export type JwtPayload = Record<string, string[] | string> & {
[kEmail: `${AuthConfig['audience']}email`]: string | undefined;
[kAmaliaRoles: `${AuthConfig['audience']}amalia_roles`]: JwtPayloadAmaliaRoles;
};
export class ImpersonateUserUseCase {
public constructor(
@InjectAuthConfig()
private readonly authConfig: Pick<AuthConfig, 'audience'>,
private readonly userAuthenticationRepository: UserAuthenticationRepository,
) {}
public async execute({ payload }: { payload: JwtPayload }) {
const { audience } = this.authConfig;
const email: string = payload[`${audience}email`] ?? '';
const amaliaRoles: AmaliaRole[] = payload[`${audience}amalia_roles`]?.roles ?? [];
const companyIdsThatUserCanImpersonate: Company['id'][] =
payload[`${audience}amalia_roles`]?.company_ids_user_can_impersonate ?? [];
const canImpersonateEveryone =
amaliaRoles.includes(AmaliaRole.TECH_ADMIN) || amaliaRoles.includes(AmaliaRole.CSM_ADMIN);
const { impersonateSettings, maintenanceWindow } = await this.userAuthenticationRepository.getMasterSettings();
assert(
canImpersonateEveryone || !isInMaintenance(maintenanceWindow ?? null),
new ServiceUnavailableException({
message:
maintenanceWindow?.comment ||
'Your app is currently under maintenance, come back later to access your account.',
}),
);
const superAdminImpersonatingEmail = impersonateSettings?.[email];
const canImpersonateAsSuperAdmin = canImpersonateEveryone || companyIdsThatUserCanImpersonate.length > 0;
const connectingUserEmail =
canImpersonateAsSuperAdmin && superAdminImpersonatingEmail ? superAdminImpersonatingEmail : email;
const { loggedUser, impersonator } = await this.userAuthenticationRepository.connect(
connectingUserEmail,
companyIdsThatUserCanImpersonate,
);
assert(
loggedUser,
new NotFoundException({
message: `User with email ${connectingUserEmail} doesn't exist.`,
email: connectingUserEmail,
connectedUserEmail: email,
}),
);
// If the user is inactive throw, unless we are SA or business impersonating him.
assert(
loggedUser.status !== UserStatus.INACTIVE ||
canImpersonateEveryone ||
impersonator ||
companyIdsThatUserCanImpersonate.includes(loggedUser.company.id),
new ForbiddenException({ message: 'User is not invited yet', email: connectingUserEmail, loggedUser }),
);
// Check for the SA impersonating (if CSM can access 1 company or more and reset his impersonate, he can access his base account that is not part of his companies that he can access to).
if (canImpersonateAsSuperAdmin && loggedUser.email !== email) {
assert(
companyIdsThatUserCanImpersonate.includes(loggedUser.company.id) || canImpersonateEveryone,
new ForbiddenException("You can't access this company"),
);
}
// Check for business impersonation: if a user is impersonating another user, he should have the right to impersonate this user.
if (impersonator) {
assert(
loggedUser.company.id === impersonator.company.id,
new ForbiddenException('You are not allowed to impersonate someone from another company'),
);
assert(
impersonator.role === UserRole.ADMIN,
new ForbiddenException('You are not allowed to impersonate another user.'),
);
}
// Push in masterSettings Impersonate
if (canImpersonateAsSuperAdmin && !superAdminImpersonatingEmail) {
await this.userAuthenticationRepository.addImpersonatorUserToMasterSettings({
impersonatorEmail: email,
// If a csm admin is impersonating a user that is currently impersonating another user (business impersonation), we want to set the email in master settings to the email of the user that is impersonating and not the email of the user impersonated.
impersonatedEmail: impersonator?.email ?? loggedUser.email,
});
}
return {
loggedUser,
impersonator,
impersonatorEmail: email,
canImpersonateEveryone,
amaliaRoles,
canImpersonateAsSuperAdmin,
companyIdsThatUserCanImpersonate,
};
}
}
|