@uniorganization/uni-lib 5.0.3 → 5.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2,6 +2,7 @@ export declare enum ChannelType {
2
2
  VOICEMAIL = "voicemail",
3
3
  CHAT = "chat",
4
4
  SMS = "sms",
5
+ MMS = "mms",
5
6
  EMAIL = "email",
6
7
  WHATSAPP = "whatsapp",
7
8
  OTHER = "other"
@@ -6,6 +6,7 @@ var ChannelType;
6
6
  ChannelType["VOICEMAIL"] = "voicemail";
7
7
  ChannelType["CHAT"] = "chat";
8
8
  ChannelType["SMS"] = "sms";
9
+ ChannelType["MMS"] = "mms";
9
10
  ChannelType["EMAIL"] = "email";
10
11
  ChannelType["WHATSAPP"] = "whatsapp";
11
12
  ChannelType["OTHER"] = "other";
@@ -39,6 +39,8 @@ let JwtStrategy = class JwtStrategy extends (0, passport_1.PassportStrategy)(pas
39
39
  const signedUser = payload === null || payload === void 0 ? void 0 : payload.user;
40
40
  const effectiveClientId = Number(signedUser === null || signedUser === void 0 ? void 0 : signedUser.clientId);
41
41
  const originalClientId = (_a = signedUser === null || signedUser === void 0 ? void 0 : signedUser.originalClientId) !== null && _a !== void 0 ? _a : null;
42
+ const originalUserId = (_b = signedUser === null || signedUser === void 0 ? void 0 : signedUser.originalUserId) !== null && _b !== void 0 ? _b : null;
43
+ const impersonationType = (_c = signedUser === null || signedUser === void 0 ? void 0 : signedUser.impersonationType) !== null && _c !== void 0 ? _c : null;
42
44
  const now = Math.floor(Date.now() / 1000);
43
45
  if ((payload === null || payload === void 0 ? void 0 : payload.type) !== 'access' ||
44
46
  !signedUser ||
@@ -56,18 +58,23 @@ let JwtStrategy = class JwtStrategy extends (0, passport_1.PassportStrategy)(pas
56
58
  if (yield this.securityState.isAccessTokenRevoked(payload.jti)) {
57
59
  throw new common_1.UnauthorizedException();
58
60
  }
59
- const impersonating = originalClientId !== null;
61
+ const impersonating = originalUserId !== null;
60
62
  if ((impersonating &&
61
63
  (originalClientId !== tenant_1.NEWTECH_CLIENT_ID ||
62
64
  effectiveClientId === tenant_1.NEWTECH_CLIENT_ID ||
63
- !((_b = signedUser.roles) === null || _b === void 0 ? void 0 : _b.includes(tenant_1.TENANT_IMPERSONATOR_ROLE)) ||
65
+ !Number.isInteger(originalUserId) ||
66
+ originalUserId <= 0 ||
67
+ originalUserId === signedUser.id ||
68
+ impersonationType !== 'user' ||
64
69
  !signedUser.impersonatedAt ||
65
70
  !signedUser.impersonationReason)) ||
66
- (!impersonating && ((_c = signedUser.roles) === null || _c === void 0 ? void 0 : _c.includes(tenant_1.TENANT_IMPERSONATOR_ROLE)))) {
71
+ (!impersonating &&
72
+ (originalClientId !== null || impersonationType !== null)) ||
73
+ (impersonating && originalClientId === null)) {
67
74
  throw new common_1.UnauthorizedException();
68
75
  }
69
76
  const resolved = impersonating
70
- ? yield this.authorization.resolveImpersonation(signedUser.id, originalClientId, effectiveClientId)
77
+ ? yield this.authorization.resolveUserImpersonation(originalUserId, originalClientId, signedUser.id, effectiveClientId)
71
78
  : yield this.authorization.resolve(signedUser.id, effectiveClientId);
72
79
  const { identity, snapshot } = resolved;
73
80
  const isMasterTenantAdmin = !impersonating &&
@@ -93,6 +100,8 @@ let JwtStrategy = class JwtStrategy extends (0, passport_1.PassportStrategy)(pas
93
100
  jti: payload.jti,
94
101
  tokenExpiresAt: payload.exp,
95
102
  originalClientId,
103
+ originalUserId,
104
+ impersonationType: impersonating ? 'user' : null,
96
105
  impersonatedAt: impersonating ? signedUser.impersonatedAt : null,
97
106
  impersonationReason: impersonating
98
107
  ? signedUser.impersonationReason
@@ -0,0 +1,27 @@
1
+ import { DataSource } from 'typeorm';
2
+ type MutationAuditInput = {
3
+ actorUserId: number | null;
4
+ effectiveUserId: number | null;
5
+ clientId: number;
6
+ reason: string | null;
7
+ correlationId: string;
8
+ method: string;
9
+ route: string;
10
+ };
11
+ type LifecycleAuditInput = {
12
+ event: 'USER_IMPERSONATION_START' | 'USER_IMPERSONATION_END';
13
+ actorUserId: number;
14
+ targetUserId: number;
15
+ clientId: number;
16
+ reason: string | null;
17
+ correlationId: string;
18
+ result: 'SUCCESS' | 'DENIED';
19
+ };
20
+ export declare class ImpersonationAuditService {
21
+ private readonly dataSource;
22
+ constructor(dataSource: DataSource);
23
+ beginMutation(input: MutationAuditInput): Promise<number>;
24
+ completeMutation(auditId: number, result: 'SUCCESS' | 'FAILURE', statusCode?: number | null): Promise<void>;
25
+ recordLifecycle(input: LifecycleAuditInput): Promise<void>;
26
+ }
27
+ export {};
@@ -0,0 +1,85 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
12
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
13
+ return new (P || (P = Promise))(function (resolve, reject) {
14
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
15
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
16
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
17
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
18
+ });
19
+ };
20
+ Object.defineProperty(exports, "__esModule", { value: true });
21
+ exports.ImpersonationAuditService = void 0;
22
+ const common_1 = require("@nestjs/common");
23
+ const typeorm_1 = require("typeorm");
24
+ let ImpersonationAuditService = class ImpersonationAuditService {
25
+ constructor(dataSource) {
26
+ this.dataSource = dataSource;
27
+ }
28
+ beginMutation(input) {
29
+ return __awaiter(this, void 0, void 0, function* () {
30
+ var _a, _b, _c;
31
+ const rows = yield this.dataSource.query(`INSERT INTO stm."ACCESS_AUDIT_LOG" (
32
+ client_id, actor_user_id, target_user_id, event,
33
+ reason, correlation_id, details
34
+ ) VALUES ($1, $2, $3, $4, $5, $6, $7::jsonb)
35
+ RETURNING id`, [
36
+ input.clientId,
37
+ input.actorUserId,
38
+ input.effectiveUserId,
39
+ 'USER_IMPERSONATED_MUTATION',
40
+ input.reason,
41
+ input.correlationId,
42
+ JSON.stringify({
43
+ service: (_b = (_a = process.env.SERVICE_NAME) !== null && _a !== void 0 ? _a : process.env.npm_package_name) !== null && _b !== void 0 ? _b : 'unknown',
44
+ method: input.method,
45
+ route: input.route.split('?')[0],
46
+ effectiveUserId: input.effectiveUserId,
47
+ result: 'STARTED',
48
+ }),
49
+ ]);
50
+ const auditId = Number((_c = rows[0]) === null || _c === void 0 ? void 0 : _c.id);
51
+ if (!Number.isInteger(auditId) || auditId <= 0) {
52
+ throw new Error('The impersonation audit record was not created');
53
+ }
54
+ return auditId;
55
+ });
56
+ }
57
+ completeMutation(auditId_1, result_1) {
58
+ return __awaiter(this, arguments, void 0, function* (auditId, result, statusCode = null) {
59
+ yield this.dataSource.query(`UPDATE stm."ACCESS_AUDIT_LOG"
60
+ SET details = details || $2::jsonb
61
+ WHERE id = $1`, [auditId, JSON.stringify({ result, statusCode })]);
62
+ });
63
+ }
64
+ recordLifecycle(input) {
65
+ return __awaiter(this, void 0, void 0, function* () {
66
+ yield this.dataSource.query(`INSERT INTO stm."ACCESS_AUDIT_LOG" (
67
+ client_id, actor_user_id, target_user_id, event,
68
+ reason, correlation_id, details
69
+ ) VALUES ($1, $2, $3, $4, $5, $6, $7::jsonb)`, [
70
+ input.clientId,
71
+ input.actorUserId,
72
+ input.targetUserId,
73
+ input.event,
74
+ input.reason,
75
+ input.correlationId,
76
+ JSON.stringify({ result: input.result }),
77
+ ]);
78
+ });
79
+ }
80
+ };
81
+ exports.ImpersonationAuditService = ImpersonationAuditService;
82
+ exports.ImpersonationAuditService = ImpersonationAuditService = __decorate([
83
+ (0, common_1.Injectable)(),
84
+ __metadata("design:paramtypes", [typeorm_1.DataSource])
85
+ ], ImpersonationAuditService);
@@ -1,6 +1,7 @@
1
1
  export * from './current-tenant.decorator';
2
2
  export * from './master-tenant.decorator';
3
3
  export * from './master-tenant.guard';
4
+ export * from './impersonation-audit.service';
4
5
  export * from './redis-tenant-state.store';
5
6
  export * from './tenant-audit.types';
6
7
  export * from './tenant-authorization.keys';
@@ -17,6 +17,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
17
17
  __exportStar(require("./current-tenant.decorator"), exports);
18
18
  __exportStar(require("./master-tenant.decorator"), exports);
19
19
  __exportStar(require("./master-tenant.guard"), exports);
20
+ __exportStar(require("./impersonation-audit.service"), exports);
20
21
  __exportStar(require("./redis-tenant-state.store"), exports);
21
22
  __exportStar(require("./tenant-audit.types"), exports);
22
23
  __exportStar(require("./tenant-authorization.keys"), exports);
@@ -18,7 +18,7 @@ let MasterTenantGuard = class MasterTenantGuard {
18
18
  this.reflector = reflector;
19
19
  }
20
20
  canActivate(context) {
21
- var _a, _b, _c, _d;
21
+ var _a, _b, _c, _d, _e;
22
22
  const required = this.reflector.getAllAndOverride(tenant_constants_1.MASTER_TENANT_METADATA_KEY, [context.getHandler(), context.getClass()]);
23
23
  if (!required) {
24
24
  return true;
@@ -29,8 +29,10 @@ let MasterTenantGuard = class MasterTenantGuard {
29
29
  }
30
30
  const effectiveClientId = ((_a = request.tenantContext) === null || _a === void 0 ? void 0 : _a.clientId) || request.user.clientId;
31
31
  const originalClientId = (_d = (_c = (_b = request.tenantContext) === null || _b === void 0 ? void 0 : _b.originalClientId) !== null && _c !== void 0 ? _c : request.user.originalClientId) !== null && _d !== void 0 ? _d : null;
32
+ const originalUserId = (_e = request.user.originalUserId) !== null && _e !== void 0 ? _e : null;
32
33
  if (effectiveClientId !== tenant_constants_1.NEWTECH_CLIENT_ID ||
33
34
  originalClientId !== null ||
35
+ originalUserId !== null ||
34
36
  !request.user.isMasterTenantAdmin) {
35
37
  throw new common_1.ForbiddenException();
36
38
  }
@@ -1,6 +1,7 @@
1
1
  import { TenantAuthenticationType } from './tenant.types';
2
2
  export interface TenantAuditMetadata {
3
3
  actorUserId: number | null;
4
+ effectiveUserId: number | null;
4
5
  originalClientId: number | null;
5
6
  effectiveClientId: number;
6
7
  authenticationType: TenantAuthenticationType;
@@ -13,7 +13,7 @@ export declare class TenantAuthorizationService {
13
13
  private readonly logger;
14
14
  constructor(store: TenantAuthorizationStore, userRepository: Repository<Users>, clientRepository: Repository<Client>, userRoleRepository: Repository<UserRoles>);
15
15
  resolve(userId: number, clientId: number, _legacyOriginClientId?: number): Promise<ResolvedTenantAuthorization>;
16
- resolveImpersonation(userId: number, originClientId: number, targetClientIdOrLegacyOriginClientId: number, legacyTargetClientId?: number): Promise<ResolvedTenantAuthorization>;
16
+ resolveUserImpersonation(actorUserId: number, originClientId: number, targetUserId: number, targetClientId: number): Promise<ResolvedTenantAuthorization>;
17
17
  invalidate(userId: number, clientId: number): Promise<void>;
18
18
  invalidateMany(clientId: number, userIds: readonly number[]): Promise<void>;
19
19
  private loadFromDatabase;
@@ -63,50 +63,19 @@ let TenantAuthorizationService = TenantAuthorizationService_1 = class TenantAuth
63
63
  return resolved;
64
64
  });
65
65
  }
66
- resolveImpersonation(userId, originClientId, targetClientIdOrLegacyOriginClientId, legacyTargetClientId) {
66
+ resolveUserImpersonation(actorUserId, originClientId, targetUserId, targetClientId) {
67
67
  return __awaiter(this, void 0, void 0, function* () {
68
- const targetClientId = legacyTargetClientId !== null && legacyTargetClientId !== void 0 ? legacyTargetClientId : targetClientIdOrLegacyOriginClientId;
69
68
  if (originClientId !== tenant_constants_1.NEWTECH_CLIENT_ID ||
70
- targetClientId === tenant_constants_1.NEWTECH_CLIENT_ID) {
69
+ targetClientId === tenant_constants_1.NEWTECH_CLIENT_ID ||
70
+ actorUserId === targetUserId) {
71
71
  throw new common_1.UnauthorizedException();
72
72
  }
73
- const origin = yield this.resolve(userId, originClientId);
74
- const isNewtechMaster = origin.snapshot.permissions.includes('master.users.read') ||
75
- origin.snapshot.roles.some((role) => role.moduleName.toLowerCase() === 'root' &&
76
- role.roleName.toLowerCase() === 'sysadmin');
77
- const targetClient = yield this.clientRepository.findOne({
78
- where: { id: targetClientId, deletedAt: (0, typeorm_2.IsNull)() },
79
- });
80
- if (!isNewtechMaster || !targetClient) {
73
+ const origin = yield this.resolve(actorUserId, originClientId);
74
+ if (!origin.snapshot.permissions.includes('master.users.read') ||
75
+ !origin.snapshot.permissions.includes('master.users.impersonate')) {
81
76
  throw new common_1.UnauthorizedException();
82
77
  }
83
- const snapshot = {
84
- userId,
85
- clientId: targetClientId,
86
- clientName: targetClient.name,
87
- clientAlias: targetClient.alias,
88
- roles: [
89
- {
90
- roleId: 0,
91
- roleName: tenant_constants_1.TENANT_IMPERSONATOR_ROLE,
92
- moduleId: 0,
93
- moduleName: tenant_constants_1.TENANT_IMPERSONATOR_ROLE,
94
- },
95
- ],
96
- privileges: [],
97
- accessRole: {
98
- id: 0,
99
- code: tenant_constants_1.TENANT_IMPERSONATOR_ROLE,
100
- name: 'Tenant impersonator',
101
- scope: 'GLOBAL',
102
- clientId: null,
103
- },
104
- permissions: [],
105
- authzVersion: 1,
106
- identity: origin.identity,
107
- cachedAt: new Date().toISOString(),
108
- };
109
- return { identity: origin.identity, snapshot };
78
+ return this.resolve(targetUserId, targetClientId);
110
79
  });
111
80
  }
112
81
  invalidate(userId, clientId) {
@@ -1,9 +1,14 @@
1
1
  import { CallHandler, ExecutionContext, NestInterceptor } from '@nestjs/common';
2
2
  import { Observable } from 'rxjs';
3
3
  import { TenantContextStorage } from './tenant-context.storage';
4
+ import { ImpersonationAuditService } from './impersonation-audit.service';
4
5
  export declare class TenantContextInterceptor implements NestInterceptor {
5
6
  private readonly tenantContextStorage;
6
- constructor(tenantContextStorage: TenantContextStorage);
7
- intercept(context: ExecutionContext, next: CallHandler): Observable<unknown>;
7
+ private readonly impersonationAudit;
8
+ private readonly logger;
9
+ constructor(tenantContextStorage: TenantContextStorage, impersonationAudit: ImpersonationAuditService);
10
+ intercept(context: ExecutionContext, next: CallHandler): Promise<Observable<unknown>>;
11
+ private beginImpersonatedMutation;
12
+ private errorStatus;
8
13
  private fromAuthenticatedUser;
9
14
  }
@@ -8,33 +8,97 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
8
8
  var __metadata = (this && this.__metadata) || function (k, v) {
9
9
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
10
  };
11
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
12
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
13
+ return new (P || (P = Promise))(function (resolve, reject) {
14
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
15
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
16
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
17
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
18
+ });
19
+ };
20
+ var TenantContextInterceptor_1;
11
21
  Object.defineProperty(exports, "__esModule", { value: true });
12
22
  exports.TenantContextInterceptor = void 0;
13
23
  const crypto_1 = require("crypto");
14
24
  const common_1 = require("@nestjs/common");
15
25
  const rxjs_1 = require("rxjs");
16
26
  const tenant_context_storage_1 = require("./tenant-context.storage");
17
- let TenantContextInterceptor = class TenantContextInterceptor {
18
- constructor(tenantContextStorage) {
27
+ const impersonation_audit_service_1 = require("./impersonation-audit.service");
28
+ let TenantContextInterceptor = TenantContextInterceptor_1 = class TenantContextInterceptor {
29
+ constructor(tenantContextStorage, impersonationAudit) {
19
30
  this.tenantContextStorage = tenantContextStorage;
31
+ this.impersonationAudit = impersonationAudit;
32
+ this.logger = new common_1.Logger(TenantContextInterceptor_1.name);
20
33
  }
21
34
  intercept(context, next) {
22
- if (context.getType() !== 'http') {
23
- return next.handle();
24
- }
25
- const request = context.switchToHttp().getRequest();
26
- const state = request.tenantContext || this.fromAuthenticatedUser(request);
27
- if (!state) {
28
- return next.handle();
29
- }
30
- request.tenantContext = Object.freeze(state);
31
- return new rxjs_1.Observable((subscriber) => {
32
- const subscription = this.tenantContextStorage.run(state, () => next.handle().subscribe(subscriber));
33
- return () => subscription.unsubscribe();
35
+ return __awaiter(this, void 0, void 0, function* () {
36
+ if (context.getType() !== 'http') {
37
+ return next.handle();
38
+ }
39
+ const request = context.switchToHttp().getRequest();
40
+ const state = request.tenantContext || this.fromAuthenticatedUser(request);
41
+ if (!state) {
42
+ return next.handle();
43
+ }
44
+ request.tenantContext = Object.freeze(state);
45
+ const auditId = yield this.beginImpersonatedMutation(request, state);
46
+ return new rxjs_1.Observable((subscriber) => {
47
+ const subscription = this.tenantContextStorage.run(state, () => next
48
+ .handle()
49
+ .pipe((0, rxjs_1.concatMap)((value) => auditId === null
50
+ ? (0, rxjs_1.of)(value)
51
+ : (0, rxjs_1.from)(this.impersonationAudit.completeMutation(auditId, 'SUCCESS')).pipe((0, rxjs_1.map)(() => value), (0, rxjs_1.catchError)((error) => {
52
+ this.logger.error(`Could not complete impersonation audit ${auditId}`, error instanceof Error ? error.stack : String(error));
53
+ return (0, rxjs_1.of)(value);
54
+ }))), (0, rxjs_1.catchError)((error) => {
55
+ if (auditId === null)
56
+ return (0, rxjs_1.throwError)(() => error);
57
+ return (0, rxjs_1.from)(this.impersonationAudit.completeMutation(auditId, 'FAILURE', this.errorStatus(error))).pipe((0, rxjs_1.catchError)((auditError) => {
58
+ this.logger.error(`Could not complete failed impersonation audit ${auditId}`, auditError instanceof Error
59
+ ? auditError.stack
60
+ : String(auditError));
61
+ return (0, rxjs_1.of)(undefined);
62
+ }), (0, rxjs_1.concatMap)(() => (0, rxjs_1.throwError)(() => error)));
63
+ }))
64
+ .subscribe(subscriber));
65
+ return () => subscription.unsubscribe();
66
+ });
34
67
  });
35
68
  }
69
+ beginImpersonatedMutation(request, state) {
70
+ return __awaiter(this, void 0, void 0, function* () {
71
+ var _a;
72
+ const method = String(request.method || '').toUpperCase();
73
+ if (!['POST', 'PUT', 'PATCH', 'DELETE'].includes(method))
74
+ return null;
75
+ if (!state.impersonatedAt || state.actorUserId === state.effectiveUserId) {
76
+ return null;
77
+ }
78
+ const route = request.originalUrl || ((_a = request.route) === null || _a === void 0 ? void 0 : _a.path) || 'unknown';
79
+ if (route.split('?')[0].endsWith('/auth/end-impersonation'))
80
+ return null;
81
+ return this.impersonationAudit.beginMutation({
82
+ actorUserId: state.actorUserId,
83
+ effectiveUserId: state.effectiveUserId,
84
+ clientId: state.clientId,
85
+ reason: state.impersonationReason,
86
+ correlationId: state.correlationId,
87
+ method,
88
+ route,
89
+ });
90
+ });
91
+ }
92
+ errorStatus(error) {
93
+ var _a;
94
+ if (!error || typeof error !== 'object')
95
+ return null;
96
+ const candidate = error;
97
+ const status = Number((_a = candidate.status) !== null && _a !== void 0 ? _a : candidate.statusCode);
98
+ return Number.isInteger(status) ? status : null;
99
+ }
36
100
  fromAuthenticatedUser(request) {
37
- var _a, _b, _c, _d;
101
+ var _a, _b, _c, _d, _e;
38
102
  if (!request.user || request.user === true) {
39
103
  return undefined;
40
104
  }
@@ -53,17 +117,19 @@ let TenantContextInterceptor = class TenantContextInterceptor {
53
117
  return {
54
118
  clientId: user.clientId,
55
119
  originalClientId: (_b = user.originalClientId) !== null && _b !== void 0 ? _b : null,
56
- actorUserId: user.id,
120
+ actorUserId: (_c = user.originalUserId) !== null && _c !== void 0 ? _c : user.id,
121
+ effectiveUserId: user.id,
57
122
  authenticationType: 'jwt',
58
- impersonatedAt: (_c = user.impersonatedAt) !== null && _c !== void 0 ? _c : null,
59
- impersonationReason: (_d = user.impersonationReason) !== null && _d !== void 0 ? _d : null,
123
+ impersonatedAt: (_d = user.impersonatedAt) !== null && _d !== void 0 ? _d : null,
124
+ impersonationReason: (_e = user.impersonationReason) !== null && _e !== void 0 ? _e : null,
60
125
  correlationId,
61
126
  roles: user.roles || [],
62
127
  };
63
128
  }
64
129
  };
65
130
  exports.TenantContextInterceptor = TenantContextInterceptor;
66
- exports.TenantContextInterceptor = TenantContextInterceptor = __decorate([
131
+ exports.TenantContextInterceptor = TenantContextInterceptor = TenantContextInterceptor_1 = __decorate([
67
132
  (0, common_1.Injectable)(),
68
- __metadata("design:paramtypes", [tenant_context_storage_1.TenantContextStorage])
133
+ __metadata("design:paramtypes", [tenant_context_storage_1.TenantContextStorage,
134
+ impersonation_audit_service_1.ImpersonationAuditService])
69
135
  ], TenantContextInterceptor);
@@ -8,6 +8,7 @@ export declare class TenantContext {
8
8
  getClientId(): number;
9
9
  getOriginalClientId(): number | null;
10
10
  getActorUserId(): number | null;
11
+ getEffectiveUserId(): number | null;
11
12
  getAuthenticationType(): TenantAuthenticationType;
12
13
  getImpersonationReason(): string | null;
13
14
  getCorrelationId(): string;
@@ -36,6 +36,9 @@ let TenantContext = class TenantContext {
36
36
  getActorUserId() {
37
37
  return this.getState().actorUserId;
38
38
  }
39
+ getEffectiveUserId() {
40
+ return this.getState().effectiveUserId;
41
+ }
39
42
  getAuthenticationType() {
40
43
  return this.getState().authenticationType;
41
44
  }
@@ -65,6 +65,7 @@ let TenantCredentialGuard = class TenantCredentialGuard {
65
65
  clientId: credential.clientId,
66
66
  originalClientId: null,
67
67
  actorUserId: null,
68
+ effectiveUserId: null,
68
69
  authenticationType: 'client-credential',
69
70
  impersonatedAt: null,
70
71
  impersonationReason: null,
@@ -18,7 +18,7 @@ let TenantRunner = class TenantRunner {
18
18
  this.tenantContextStorage = tenantContextStorage;
19
19
  }
20
20
  run(clientId, metadata, callback) {
21
- var _a, _b;
21
+ var _a, _b, _c;
22
22
  if (!Number.isInteger(clientId) || clientId <= 0) {
23
23
  throw new Error('TenantRunner requires a valid client ID');
24
24
  }
@@ -26,11 +26,12 @@ let TenantRunner = class TenantRunner {
26
26
  clientId,
27
27
  originalClientId: null,
28
28
  actorUserId: (_a = metadata.actorUserId) !== null && _a !== void 0 ? _a : null,
29
+ effectiveUserId: (_b = metadata.actorUserId) !== null && _b !== void 0 ? _b : null,
29
30
  authenticationType: metadata.authenticationType,
30
31
  impersonatedAt: null,
31
32
  impersonationReason: null,
32
33
  correlationId: metadata.correlationId || (0, crypto_1.randomUUID)(),
33
- credentialId: (_b = metadata.credentialId) !== null && _b !== void 0 ? _b : null,
34
+ credentialId: (_c = metadata.credentialId) !== null && _c !== void 0 ? _c : null,
34
35
  }, callback);
35
36
  }
36
37
  };
@@ -1,6 +1,5 @@
1
1
  export declare const NEWTECH_CLIENT_ID = 1;
2
2
  export declare const ALTERA_CLIENT_ID = 2;
3
- export declare const TENANT_IMPERSONATOR_ROLE = "TENANT_IMPERSONATOR";
4
3
  export declare const MASTER_TENANT_METADATA_KEY = "masterTenant";
5
4
  export declare const PUBLIC_ROUTE_METADATA_KEY = "publicRoute";
6
5
  export declare const TENANT_CONTEXT_REQUEST_KEY = "tenantContext";
@@ -1,9 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.TENANT_CREDENTIAL_HEADER = exports.TENANT_CONTEXT_REQUEST_KEY = exports.PUBLIC_ROUTE_METADATA_KEY = exports.MASTER_TENANT_METADATA_KEY = exports.TENANT_IMPERSONATOR_ROLE = exports.ALTERA_CLIENT_ID = exports.NEWTECH_CLIENT_ID = void 0;
3
+ exports.TENANT_CREDENTIAL_HEADER = exports.TENANT_CONTEXT_REQUEST_KEY = exports.PUBLIC_ROUTE_METADATA_KEY = exports.MASTER_TENANT_METADATA_KEY = exports.ALTERA_CLIENT_ID = exports.NEWTECH_CLIENT_ID = void 0;
4
4
  exports.NEWTECH_CLIENT_ID = 1;
5
5
  exports.ALTERA_CLIENT_ID = 2;
6
- exports.TENANT_IMPERSONATOR_ROLE = 'TENANT_IMPERSONATOR';
7
6
  exports.MASTER_TENANT_METADATA_KEY = 'masterTenant';
8
7
  exports.PUBLIC_ROUTE_METADATA_KEY = 'publicRoute';
9
8
  exports.TENANT_CONTEXT_REQUEST_KEY = 'tenantContext';
@@ -25,6 +25,7 @@ const tenant_credential_guard_1 = require("./tenant-credential.guard");
25
25
  const master_tenant_guard_1 = require("./master-tenant.guard");
26
26
  const tenant_ownership_service_1 = require("./tenant-ownership.service");
27
27
  const tenant_runner_service_1 = require("./tenant-runner.service");
28
+ const impersonation_audit_service_1 = require("./impersonation-audit.service");
28
29
  let TenantModule = class TenantModule {
29
30
  };
30
31
  exports.TenantModule = TenantModule;
@@ -49,6 +50,7 @@ exports.TenantModule = TenantModule = __decorate([
49
50
  tenant_context_storage_1.TenantContextStorage,
50
51
  tenant_context_service_1.TenantContext,
51
52
  tenant_runner_service_1.TenantRunner,
53
+ impersonation_audit_service_1.ImpersonationAuditService,
52
54
  tenant_context_interceptor_1.TenantContextInterceptor,
53
55
  tenant_credential_guard_1.TenantCredentialGuard,
54
56
  master_tenant_guard_1.MasterTenantGuard,
@@ -61,6 +63,7 @@ exports.TenantModule = TenantModule = __decorate([
61
63
  tenant_security_state_service_1.TenantSecurityStateService,
62
64
  tenant_context_service_1.TenantContext,
63
65
  tenant_runner_service_1.TenantRunner,
66
+ impersonation_audit_service_1.ImpersonationAuditService,
64
67
  tenant_context_interceptor_1.TenantContextInterceptor,
65
68
  tenant_credential_guard_1.TenantCredentialGuard,
66
69
  master_tenant_guard_1.MasterTenantGuard,
@@ -3,6 +3,7 @@ export interface TenantContextState {
3
3
  readonly clientId: number;
4
4
  readonly originalClientId: number | null;
5
5
  readonly actorUserId: number | null;
6
+ readonly effectiveUserId: number | null;
6
7
  readonly authenticationType: TenantAuthenticationType;
7
8
  readonly impersonatedAt: string | null;
8
9
  readonly impersonationReason: string | null;
@@ -18,6 +19,8 @@ export interface AuthenticatedTenantUser {
18
19
  jti: string;
19
20
  tokenExpiresAt: number;
20
21
  originalClientId: number | null;
22
+ originalUserId: number | null;
23
+ impersonationType: 'user' | null;
21
24
  impersonatedAt: string | null;
22
25
  impersonationReason: string | null;
23
26
  roles: string[];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uniorganization/uni-lib",
3
- "version": "5.0.3",
3
+ "version": "5.0.5",
4
4
  "description": "UNI Library",
5
5
  "author": "Jhomiguel",
6
6
  "main": "dist/index.js",
@@ -74,7 +74,7 @@
74
74
  },
75
75
  "scripts": {
76
76
  "start:dev": "tsc -w",
77
- "build": "tsc",
77
+ "build": "tsc -p tsconfig.build.json",
78
78
  "format": "prettier --write \"src/**/*.ts\"",
79
79
  "lint": "tslint -p tsconfig.json -c tslint.json",
80
80
  "test": "jest",