@openora/core 0.4.1-canary.113 → 0.4.1-canary.115

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.
Files changed (206) hide show
  1. package/dist/.tsbuildinfo +1 -1
  2. package/dist/admin-console/plugin.d.ts +11 -0
  3. package/dist/admin-console/plugin.d.ts.map +1 -1
  4. package/dist/analytics/plugin.d.ts +11 -0
  5. package/dist/analytics/plugin.d.ts.map +1 -1
  6. package/dist/audit/__tests__/map-event.test.js +34 -0
  7. package/dist/audit/__tests__/map-event.test.js.map +1 -1
  8. package/dist/audit/plugin.d.ts +11 -0
  9. package/dist/audit/plugin.d.ts.map +1 -1
  10. package/dist/audit/plugin.js +63 -7
  11. package/dist/audit/plugin.js.map +1 -1
  12. package/dist/casino/gaming/plugin.d.ts +11 -0
  13. package/dist/casino/gaming/plugin.d.ts.map +1 -1
  14. package/dist/casino/lobby/plugin.d.ts +11 -0
  15. package/dist/casino/lobby/plugin.d.ts.map +1 -1
  16. package/dist/cms/plugin.d.ts +11 -0
  17. package/dist/cms/plugin.d.ts.map +1 -1
  18. package/dist/compliance/plugin.d.ts +11 -0
  19. package/dist/compliance/plugin.d.ts.map +1 -1
  20. package/dist/contracts/adapters/admin-security.d.ts +27 -0
  21. package/dist/contracts/adapters/admin-security.d.ts.map +1 -0
  22. package/dist/contracts/adapters/admin-security.js +9 -0
  23. package/dist/contracts/adapters/admin-security.js.map +1 -0
  24. package/dist/contracts/adapters/index.d.ts +3 -1
  25. package/dist/contracts/adapters/index.d.ts.map +1 -1
  26. package/dist/contracts/adapters/index.js +1 -0
  27. package/dist/contracts/adapters/index.js.map +1 -1
  28. package/dist/contracts/adapters/realtime.d.ts +36 -3
  29. package/dist/contracts/adapters/realtime.d.ts.map +1 -1
  30. package/dist/contracts/adapters/realtime.js.map +1 -1
  31. package/dist/contracts/schemas/common.d.ts +3 -1
  32. package/dist/contracts/schemas/common.d.ts.map +1 -1
  33. package/dist/contracts/schemas/common.js +2 -0
  34. package/dist/contracts/schemas/common.js.map +1 -1
  35. package/dist/contracts/schemas/events.d.ts +114 -0
  36. package/dist/contracts/schemas/events.d.ts.map +1 -1
  37. package/dist/contracts/schemas/events.js +77 -0
  38. package/dist/contracts/schemas/events.js.map +1 -1
  39. package/dist/contracts/schemas/identity.d.ts +26 -0
  40. package/dist/contracts/schemas/identity.d.ts.map +1 -1
  41. package/dist/contracts/schemas/identity.js +32 -1
  42. package/dist/contracts/schemas/identity.js.map +1 -1
  43. package/dist/contracts/schemas/platform-config.d.ts +39 -0
  44. package/dist/contracts/schemas/platform-config.d.ts.map +1 -1
  45. package/dist/contracts/schemas/platform-config.js +43 -0
  46. package/dist/contracts/schemas/platform-config.js.map +1 -1
  47. package/dist/engagement/chat/__tests__/chat.router.test.d.ts +2 -0
  48. package/dist/engagement/chat/__tests__/chat.router.test.d.ts.map +1 -0
  49. package/dist/engagement/chat/__tests__/chat.router.test.js +44 -0
  50. package/dist/engagement/chat/__tests__/chat.router.test.js.map +1 -0
  51. package/dist/engagement/chat/__tests__/chat.service.int.test.js +590 -6
  52. package/dist/engagement/chat/__tests__/chat.service.int.test.js.map +1 -1
  53. package/dist/engagement/chat/contract/constants.d.ts +2 -0
  54. package/dist/engagement/chat/contract/constants.d.ts.map +1 -1
  55. package/dist/engagement/chat/contract/constants.js +7 -0
  56. package/dist/engagement/chat/contract/constants.js.map +1 -1
  57. package/dist/engagement/chat/contract/index.d.ts +39 -0
  58. package/dist/engagement/chat/contract/index.d.ts.map +1 -1
  59. package/dist/engagement/chat/contract/index.js +25 -1
  60. package/dist/engagement/chat/contract/index.js.map +1 -1
  61. package/dist/engagement/chat/drizzle/migrations/0009_massive_bill_hollister.sql +1 -0
  62. package/dist/engagement/chat/drizzle/migrations/0010_backfill_role_assigned_at.sql +9 -0
  63. package/dist/engagement/chat/drizzle/migrations/meta/0009_snapshot.json +1468 -0
  64. package/dist/engagement/chat/drizzle/migrations/meta/0010_snapshot.json +1468 -0
  65. package/dist/engagement/chat/drizzle/migrations/meta/_journal.json +14 -0
  66. package/dist/engagement/chat/plugin.d.ts +11 -0
  67. package/dist/engagement/chat/plugin.d.ts.map +1 -1
  68. package/dist/engagement/chat/router/index.d.ts +19 -0
  69. package/dist/engagement/chat/router/index.d.ts.map +1 -1
  70. package/dist/engagement/chat/router/index.js +31 -2
  71. package/dist/engagement/chat/router/index.js.map +1 -1
  72. package/dist/engagement/chat/schema/index.d.ts +17 -0
  73. package/dist/engagement/chat/schema/index.d.ts.map +1 -1
  74. package/dist/engagement/chat/schema/index.js +3 -0
  75. package/dist/engagement/chat/schema/index.js.map +1 -1
  76. package/dist/engagement/chat/service/chat-ban.service.d.ts.map +1 -1
  77. package/dist/engagement/chat/service/chat-ban.service.js +6 -6
  78. package/dist/engagement/chat/service/chat-ban.service.js.map +1 -1
  79. package/dist/engagement/chat/service/chat-room-ban.service.js +1 -1
  80. package/dist/engagement/chat/service/chat-room-ban.service.js.map +1 -1
  81. package/dist/engagement/chat/service/chat-room-membership.service.d.ts +15 -0
  82. package/dist/engagement/chat/service/chat-room-membership.service.d.ts.map +1 -1
  83. package/dist/engagement/chat/service/chat-room-membership.service.js +96 -4
  84. package/dist/engagement/chat/service/chat-room-membership.service.js.map +1 -1
  85. package/dist/engagement/chat/service/chat.service.d.ts +3 -2
  86. package/dist/engagement/chat/service/chat.service.d.ts.map +1 -1
  87. package/dist/engagement/chat/service/chat.service.js +73 -24
  88. package/dist/engagement/chat/service/chat.service.js.map +1 -1
  89. package/dist/engagement/chat/service/errors/chat-moderation.errors.d.ts +1 -0
  90. package/dist/engagement/chat/service/errors/chat-moderation.errors.d.ts.map +1 -1
  91. package/dist/engagement/chat/service/errors/chat-moderation.errors.js +1 -0
  92. package/dist/engagement/chat/service/errors/chat-moderation.errors.js.map +1 -1
  93. package/dist/engagement/chat-commands/plugin.d.ts +11 -0
  94. package/dist/engagement/chat-commands/plugin.d.ts.map +1 -1
  95. package/dist/engagement/notifications/plugin.d.ts +11 -0
  96. package/dist/engagement/notifications/plugin.d.ts.map +1 -1
  97. package/dist/engagement/social/plugin.d.ts +11 -0
  98. package/dist/engagement/social/plugin.d.ts.map +1 -1
  99. package/dist/iam/plugin.d.ts +11 -0
  100. package/dist/iam/plugin.d.ts.map +1 -1
  101. package/dist/pam/identity/__tests__/admin-security.int.test.d.ts +2 -0
  102. package/dist/pam/identity/__tests__/admin-security.int.test.d.ts.map +1 -0
  103. package/dist/pam/identity/__tests__/admin-security.int.test.js +137 -0
  104. package/dist/pam/identity/__tests__/admin-security.int.test.js.map +1 -0
  105. package/dist/pam/identity/__tests__/device-fingerprint.test.d.ts +2 -0
  106. package/dist/pam/identity/__tests__/device-fingerprint.test.d.ts.map +1 -0
  107. package/dist/pam/identity/__tests__/device-fingerprint.test.js +105 -0
  108. package/dist/pam/identity/__tests__/device-fingerprint.test.js.map +1 -0
  109. package/dist/pam/identity/__tests__/identity.rate-limit.int.test.js +3 -3
  110. package/dist/pam/identity/__tests__/identity.rate-limit.int.test.js.map +1 -1
  111. package/dist/pam/identity/__tests__/identity.service.int.test.js +221 -1
  112. package/dist/pam/identity/__tests__/identity.service.int.test.js.map +1 -1
  113. package/dist/pam/identity/contract/index.d.ts +144 -0
  114. package/dist/pam/identity/contract/index.d.ts.map +1 -1
  115. package/dist/pam/identity/contract/index.js +84 -1
  116. package/dist/pam/identity/contract/index.js.map +1 -1
  117. package/dist/pam/identity/drizzle/migrations/0008_pink_bucky.sql +23 -0
  118. package/dist/pam/identity/drizzle/migrations/0009_hard_sauron.sql +2 -0
  119. package/dist/pam/identity/drizzle/migrations/meta/0008_snapshot.json +913 -0
  120. package/dist/pam/identity/drizzle/migrations/meta/0009_snapshot.json +926 -0
  121. package/dist/pam/identity/drizzle/migrations/meta/_journal.json +14 -0
  122. package/dist/pam/identity/plugin.d.ts +11 -0
  123. package/dist/pam/identity/plugin.d.ts.map +1 -1
  124. package/dist/pam/identity/plugin.js +81 -26
  125. package/dist/pam/identity/plugin.js.map +1 -1
  126. package/dist/pam/identity/react/account.d.ts +5 -0
  127. package/dist/pam/identity/react/account.d.ts.map +1 -1
  128. package/dist/pam/identity/react/auth.d.ts +2 -0
  129. package/dist/pam/identity/react/auth.d.ts.map +1 -1
  130. package/dist/pam/identity/router/index.d.ts +105 -1
  131. package/dist/pam/identity/router/index.d.ts.map +1 -1
  132. package/dist/pam/identity/router/index.js +44 -3
  133. package/dist/pam/identity/router/index.js.map +1 -1
  134. package/dist/pam/identity/schema/index.d.ts +314 -0
  135. package/dist/pam/identity/schema/index.d.ts.map +1 -1
  136. package/dist/pam/identity/schema/index.js +38 -0
  137. package/dist/pam/identity/schema/index.js.map +1 -1
  138. package/dist/pam/identity/service/admin-security.service.d.ts +82 -0
  139. package/dist/pam/identity/service/admin-security.service.d.ts.map +1 -0
  140. package/dist/pam/identity/service/admin-security.service.js +277 -0
  141. package/dist/pam/identity/service/admin-security.service.js.map +1 -0
  142. package/dist/pam/identity/service/device-fingerprint.service.d.ts +32 -0
  143. package/dist/pam/identity/service/device-fingerprint.service.d.ts.map +1 -0
  144. package/dist/pam/identity/service/device-fingerprint.service.js +79 -0
  145. package/dist/pam/identity/service/device-fingerprint.service.js.map +1 -0
  146. package/dist/pam/identity/service/identity.service.d.ts +37 -2
  147. package/dist/pam/identity/service/identity.service.d.ts.map +1 -1
  148. package/dist/pam/identity/service/identity.service.js +233 -19
  149. package/dist/pam/identity/service/identity.service.js.map +1 -1
  150. package/dist/pam/identity/service/phone-login.service.d.ts +1 -0
  151. package/dist/pam/identity/service/phone-login.service.d.ts.map +1 -1
  152. package/dist/pam/identity/service/phone-login.service.js +2 -0
  153. package/dist/pam/identity/service/phone-login.service.js.map +1 -1
  154. package/dist/pam/identity/service/session.service.d.ts +45 -1
  155. package/dist/pam/identity/service/session.service.d.ts.map +1 -1
  156. package/dist/pam/identity/service/session.service.js +81 -12
  157. package/dist/pam/identity/service/session.service.js.map +1 -1
  158. package/dist/pam/identity/service/trusted-device.service.d.ts +54 -0
  159. package/dist/pam/identity/service/trusted-device.service.d.ts.map +1 -0
  160. package/dist/pam/identity/service/trusted-device.service.js +157 -0
  161. package/dist/pam/identity/service/trusted-device.service.js.map +1 -0
  162. package/dist/pam/identity/service/two-factor-lockout.service.d.ts +25 -0
  163. package/dist/pam/identity/service/two-factor-lockout.service.d.ts.map +1 -0
  164. package/dist/pam/identity/service/two-factor-lockout.service.js +121 -0
  165. package/dist/pam/identity/service/two-factor-lockout.service.js.map +1 -0
  166. package/dist/pam/player-management/plugin.d.ts +11 -0
  167. package/dist/pam/player-management/plugin.d.ts.map +1 -1
  168. package/dist/pam/player-note/plugin.d.ts +11 -0
  169. package/dist/pam/player-note/plugin.d.ts.map +1 -1
  170. package/dist/pam/profile/plugin.d.ts +11 -0
  171. package/dist/pam/profile/plugin.d.ts.map +1 -1
  172. package/dist/pam/tag/plugin.d.ts +11 -0
  173. package/dist/pam/tag/plugin.d.ts.map +1 -1
  174. package/dist/react/context/__tests__/realtime-client.test.d.ts +2 -0
  175. package/dist/react/context/__tests__/realtime-client.test.d.ts.map +1 -0
  176. package/dist/react/context/__tests__/realtime-client.test.js +75 -0
  177. package/dist/react/context/__tests__/realtime-client.test.js.map +1 -0
  178. package/dist/react/context/realtime-client.d.ts +14 -0
  179. package/dist/react/context/realtime-client.d.ts.map +1 -1
  180. package/dist/react/context/realtime-client.js.map +1 -1
  181. package/dist/server/auth/__tests__/admin-guard.int.test.js +3 -1
  182. package/dist/server/auth/__tests__/admin-guard.int.test.js.map +1 -1
  183. package/dist/server/auth/admin-guard.d.ts +3 -2
  184. package/dist/server/auth/admin-guard.d.ts.map +1 -1
  185. package/dist/server/auth/admin-guard.js +18 -2
  186. package/dist/server/auth/admin-guard.js.map +1 -1
  187. package/dist/server/auth/auth.d.ts +14 -0
  188. package/dist/server/auth/auth.d.ts.map +1 -1
  189. package/dist/server/auth/auth.js +18 -1
  190. package/dist/server/auth/auth.js.map +1 -1
  191. package/dist/server/kernel/realtime-transport.d.ts +11 -3
  192. package/dist/server/kernel/realtime-transport.d.ts.map +1 -1
  193. package/dist/server/kernel/realtime-transport.js +53 -10
  194. package/dist/server/kernel/realtime-transport.js.map +1 -1
  195. package/dist/server/runtime/core-token-catalog.d.ts +11 -0
  196. package/dist/server/runtime/core-token-catalog.d.ts.map +1 -1
  197. package/dist/server/runtime/core-token-catalog.js +2 -1
  198. package/dist/server/runtime/core-token-catalog.js.map +1 -1
  199. package/dist/server/runtime/create-app.d.ts.map +1 -1
  200. package/dist/server/runtime/create-app.js +2 -2
  201. package/dist/server/runtime/create-app.js.map +1 -1
  202. package/dist/testing/seed-player.d.ts +10 -2
  203. package/dist/testing/seed-player.d.ts.map +1 -1
  204. package/dist/wallet/plugin.d.ts +11 -0
  205. package/dist/wallet/plugin.d.ts.map +1 -1
  206. package/package.json +1 -1
@@ -0,0 +1,277 @@
1
+ import { ORPCError } from '@orpc/server';
2
+ import { createLogger, makeConflictError, } from '@openora/core/server';
3
+ import { and, eq, gt, sql } from 'drizzle-orm';
4
+ import { AuthGuardReasonSchema, } from '@openora/core/contracts';
5
+ import { session, twoFactor, user, } from '../schema/index.js';
6
+ import { isSameDevice, isSuspiciousIpChange } from './device-fingerprint.service.js';
7
+ import { UserNotFoundError } from './identity.service.js';
8
+ const logger = createLogger('admin-security');
9
+ // A Super Admin cannot clear their own second factor - that would let a single
10
+ // compromised account walk itself back to the unenrolled state. The reset always
11
+ // goes through another Super Admin.
12
+ export const SelfTwoFactorResetError = makeConflictError('SelfTwoFactorResetError', 'An admin cannot reset their own second factor - ask another Super Admin');
13
+ // Recording activity on every admin request would be one write per call; the session
14
+ // list only needs minute-level resolution.
15
+ const LAST_SEEN_THROTTLE_MS = 5 * 60 * 1000;
16
+ /**
17
+ * Enforcement half of the Backoffice session policy, resolved by `AdminGuard` on every
18
+ * admin request through ADMIN_SECURITY_POLICY.
19
+ *
20
+ * Both checks throw rather than return a verdict: a caller that forgets to branch on a
21
+ * boolean would silently grant access, which is the one failure mode this class exists
22
+ * to prevent.
23
+ */
24
+ export class AdminSecurityService {
25
+ drizzle;
26
+ events;
27
+ sessions;
28
+ trustedDevices;
29
+ identityReader;
30
+ config;
31
+ geoIp;
32
+ constructor({ drizzle, events, sessions, trustedDevices, identityReader, config, geoIp, }) {
33
+ this.drizzle = drizzle;
34
+ this.events = events;
35
+ this.sessions = sessions;
36
+ this.trustedDevices = trustedDevices;
37
+ this.identityReader = identityReader;
38
+ this.config = config;
39
+ this.geoIp = geoIp;
40
+ if (config.bindSessionToDevice && config.ipChangePolicy === 'country' && !geoIp) {
41
+ logger.warn('adminSecurity.ipChangePolicy is "country" but no GEO_IP_ADAPTER is bound - ' +
42
+ 'IP changes will not end a session. Bind a geo-ip adapter or set the policy explicitly.');
43
+ }
44
+ }
45
+ async assertEnrolled({ userId, ip, userAgent }) {
46
+ if (!this.config.requireTwoFactor) {
47
+ return;
48
+ }
49
+ const [row] = await this.drizzle.db
50
+ .select({ twoFactorEnabled: user.twoFactorEnabled })
51
+ .from(user)
52
+ .where(eq(user.id, userId))
53
+ .limit(1);
54
+ if (row?.twoFactorEnabled === true) {
55
+ return;
56
+ }
57
+ this.events.emit('identity.2fa.enrollment_blocked', { userId, ip, userAgent });
58
+ throw new ORPCError('FORBIDDEN', {
59
+ message: 'Two-factor authentication must be configured before using the back office',
60
+ data: { reason: AuthGuardReasonSchema.enum.two_factor_required },
61
+ });
62
+ }
63
+ async assertSessionIntact({ userId, sessionId, ip, userAgent, }) {
64
+ if (!this.config.bindSessionToDevice || !sessionId) {
65
+ return;
66
+ }
67
+ const [row] = await this.drizzle.db
68
+ .select({
69
+ ipAddress: session.ipAddress,
70
+ userAgent: session.userAgent,
71
+ lastSeenAt: session.lastSeenAt,
72
+ })
73
+ .from(session)
74
+ .where(and(eq(session.id, sessionId), eq(session.userId, userId)))
75
+ .limit(1);
76
+ if (!row) {
77
+ return;
78
+ }
79
+ if (!isSameDevice(row.userAgent, userAgent)) {
80
+ await this.endCompromisedSession({ userId, sessionId, ip, userAgent }, 'user_agent');
81
+ }
82
+ if (await this.hasSuspiciousIpChange(row.ipAddress, ip)) {
83
+ await this.endCompromisedSession({ userId, sessionId, ip, userAgent }, 'ip');
84
+ }
85
+ await this.touchLastSeen(sessionId, row.lastSeenAt);
86
+ }
87
+ async hasSuspiciousIpChange(sessionIp, requestIp) {
88
+ const policy = this.config.ipChangePolicy;
89
+ if (policy === 'off' || !sessionIp || !requestIp || sessionIp === requestIp) {
90
+ return false;
91
+ }
92
+ if (policy === 'any') {
93
+ return true;
94
+ }
95
+ if (!this.geoIp) {
96
+ return false;
97
+ }
98
+ const [sessionCountry, requestCountry] = await Promise.all([
99
+ this.lookupCountry(sessionIp),
100
+ this.lookupCountry(requestIp),
101
+ ]);
102
+ return isSuspiciousIpChange({
103
+ policy,
104
+ sessionIp,
105
+ requestIp,
106
+ sessionCountry,
107
+ requestCountry,
108
+ });
109
+ }
110
+ async lookupCountry(ipAddress) {
111
+ try {
112
+ return (await this.geoIp?.lookup(ipAddress))?.countryCode ?? null;
113
+ }
114
+ catch (error) {
115
+ logger.warn(`geo-ip lookup failed for a session check: ${String(error)}`);
116
+ return null;
117
+ }
118
+ }
119
+ /**
120
+ * Ends a session whose device or network no longer matches, and drops the trust that
121
+ * device held - otherwise the next login would silently skip the second factor on the
122
+ * very device that just failed the check.
123
+ */
124
+ async endCompromisedSession({ userId, sessionId, ip, userAgent }, mismatch) {
125
+ // No actorId: the guard forced this itself, not the device owner nor an admin -
126
+ // passing `userId` here would read in the audit trail as a self-revoke.
127
+ await this.sessions.revokeSession(userId, sessionId, undefined, { ip, userAgent });
128
+ await this.trustedDevices.revokeForDevice(userId, userAgent, undefined);
129
+ this.events.emit('identity.session.fingerprint_mismatch', {
130
+ userId,
131
+ playerId: await this.identityReader.getPlayerIdByUserIdSafe(userId),
132
+ sessionId,
133
+ mismatch,
134
+ ip,
135
+ userAgent,
136
+ });
137
+ throw new ORPCError('UNAUTHORIZED', {
138
+ message: 'Session ended because the device or network changed',
139
+ data: { reason: AuthGuardReasonSchema.enum.session_fingerprint_mismatch },
140
+ });
141
+ }
142
+ async touchLastSeen(sessionId, lastSeenAt) {
143
+ if (lastSeenAt && Date.now() - lastSeenAt.getTime() < LAST_SEEN_THROTTLE_MS) {
144
+ return;
145
+ }
146
+ await this.drizzle.db
147
+ .update(session)
148
+ .set({ lastSeenAt: sql `now()` })
149
+ .where(eq(session.id, sessionId));
150
+ }
151
+ /**
152
+ * What the Backoffice needs before it renders anything: whether this account still
153
+ * has to enrol, and whether the browser it is on holds an unexpired trust grant.
154
+ */
155
+ async status(userId, userAgent) {
156
+ const [row] = await this.drizzle.db
157
+ .select({
158
+ twoFactorEnabled: user.twoFactorEnabled,
159
+ twoFactorLockoutUntil: user.twoFactorLockoutUntil,
160
+ })
161
+ .from(user)
162
+ .where(eq(user.id, userId))
163
+ .limit(1);
164
+ const twoFactorEnabled = row?.twoFactorEnabled === true;
165
+ const devices = await this.trustedDevices.list(userId, userAgent);
166
+ const currentDevice = devices.find((device) => device.isCurrent);
167
+ const lockedUntil = row?.twoFactorLockoutUntil ?? null;
168
+ return {
169
+ twoFactorEnabled,
170
+ backupCodesRemaining: twoFactorEnabled ? await this.countBackupCodes(userId) : null,
171
+ enrollmentRequired: this.config.requireTwoFactor && !twoFactorEnabled,
172
+ trustedDeviceDays: this.config.trustedDeviceDays,
173
+ trustedDeviceUntil: currentDevice?.expiresAt ?? null,
174
+ lockedUntil: lockedUntil ? lockedUntil.toISOString() : null,
175
+ };
176
+ }
177
+ /**
178
+ * Counts what is left of the recovery set. better-auth stores the codes as a JSON
179
+ * array unless the operator opts into encryption, so an unreadable column is reported
180
+ * as unknown rather than as zero - claiming no codes remain would be worse than
181
+ * admitting the count cannot be taken.
182
+ */
183
+ async countBackupCodes(userId) {
184
+ const [row] = await this.drizzle.db
185
+ .select({ backupCodes: twoFactor.backupCodes })
186
+ .from(twoFactor)
187
+ .where(eq(twoFactor.userId, userId))
188
+ .limit(1);
189
+ if (!row) {
190
+ return null;
191
+ }
192
+ try {
193
+ const parsed = JSON.parse(row.backupCodes);
194
+ return Array.isArray(parsed) ? parsed.length : null;
195
+ }
196
+ catch {
197
+ return null;
198
+ }
199
+ }
200
+ listTrustedDevices(userId, userAgent) {
201
+ return this.trustedDevices.list(userId, userAgent);
202
+ }
203
+ async revokeTrustedDevice(userId, deviceId, actorId, meta, keepSessionId) {
204
+ const { userAgent } = await this.trustedDevices.revoke(userId, deviceId, actorId, meta);
205
+ await this.endSessionsOnDevice(userId, userAgent, actorId, meta, keepSessionId);
206
+ return { success: true };
207
+ }
208
+ /**
209
+ * A revoked device loses its live sessions in the same breath, so the grant cannot
210
+ * outlive the revoke on the browser that already holds one.
211
+ *
212
+ * `keepSessionId` spares the caller's own session: revoking trust on the browser you
213
+ * are sitting in means "ask me for a code next time", not "sign me out now" - the same
214
+ * line `SessionService.revokeOwnSession` draws for sessions.
215
+ */
216
+ async endSessionsOnDevice(userId, deviceUserAgent, actorId, meta, keepSessionId) {
217
+ const active = await this.drizzle.db
218
+ .select({ id: session.id, userAgent: session.userAgent })
219
+ .from(session)
220
+ .where(and(eq(session.userId, userId), gt(session.expiresAt, sql `now()`)));
221
+ for (const row of active) {
222
+ if (row.id !== keepSessionId && isSameDevice(row.userAgent, deviceUserAgent)) {
223
+ await this.sessions.revokeSession(userId, row.id, actorId, meta);
224
+ }
225
+ }
226
+ }
227
+ /**
228
+ * Returns an account to the unenrolled state so its owner can set a second factor up
229
+ * again: the shared recovery path for a lost authenticator, since better-auth's own
230
+ * disable endpoint asks for the account's password and a locked-out admin has no way
231
+ * to reach it. The trust grants and live sessions go with it - leaving either behind
232
+ * would let a browser keep the access the reset exists to withdraw.
233
+ */
234
+ async resetTwoFactor(userId, actorId, reason, meta) {
235
+ if (userId === actorId) {
236
+ throw new SelfTwoFactorResetError();
237
+ }
238
+ const [account] = await this.drizzle.db
239
+ .select({ id: user.id })
240
+ .from(user)
241
+ .where(eq(user.id, userId))
242
+ .limit(1);
243
+ if (!account) {
244
+ throw new UserNotFoundError(userId);
245
+ }
246
+ // Both writes commit together: a process death between them would leave
247
+ // twoFactorEnabled true with no twoFactor row - locked out with no repair
248
+ // route, since resetting requires a Super Admin who is themselves gated on
249
+ // AdminGuard.assertEnrolled.
250
+ await this.drizzle.db.transaction(async (tx) => {
251
+ await tx.delete(twoFactor).where(eq(twoFactor.userId, userId));
252
+ await tx
253
+ .update(user)
254
+ .set({
255
+ twoFactorEnabled: false,
256
+ failedTwoFactorAttempts: 0,
257
+ twoFactorLockoutUntil: null,
258
+ })
259
+ .where(eq(user.id, userId));
260
+ });
261
+ await this.trustedDevices.revokeAllForUser(userId, actorId);
262
+ await this.sessions.revokeAllSessions(userId, actorId, meta);
263
+ this.events.emit('identity.2fa.reset', {
264
+ userId,
265
+ playerId: await this.identityReader.getPlayerIdByUserIdSafe(userId),
266
+ actorId,
267
+ reason,
268
+ ip: meta?.ip ?? null,
269
+ userAgent: meta?.userAgent ?? null,
270
+ });
271
+ return { success: true };
272
+ }
273
+ isTrustedDevice(userId, userAgent) {
274
+ return this.trustedDevices.isTrusted(userId, userAgent);
275
+ }
276
+ }
277
+ //# sourceMappingURL=admin-security.service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"admin-security.service.js","sourceRoot":"","sources":["../../../../src/pam/identity/service/admin-security.service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ export type IpChangePolicy = 'off' | 'country' | 'any';
2
+ export type DeviceDescription = {
3
+ label: string;
4
+ browser: string | null;
5
+ os: string | null;
6
+ };
7
+ export declare function normalizeUserAgent(userAgent: string | null | undefined): string;
8
+ export declare function deviceHash(userAgent: string | null | undefined): string;
9
+ export declare function isSameDevice(left: string | null | undefined, right: string | null | undefined): boolean;
10
+ /**
11
+ * Turns a raw User-Agent into the browser/OS pair the session list shows. Deliberately
12
+ * a handful of patterns rather than a UA-parsing dependency: the value is a display
13
+ * label, and a wrong guess costs a cosmetic string, never an access decision.
14
+ */
15
+ export declare function describeDevice(userAgent: string | null | undefined): DeviceDescription;
16
+ /**
17
+ * Whether a mid-session IP change is suspicious enough to end the session.
18
+ *
19
+ * `country` needs both countries resolved - an unbound or failing geo-ip lookup
20
+ * yields nulls, and an unresolved lookup must never end a session on its own.
21
+ * `any` is the strictest setting and will log users out across NAT and mobile
22
+ * network hops, which is why it is not the default.
23
+ */
24
+ export declare function isSuspiciousIpChange({ policy, sessionIp, requestIp, sessionCountry, requestCountry, }: {
25
+ policy: IpChangePolicy;
26
+ sessionIp: string | null;
27
+ requestIp: string | null;
28
+ sessionCountry?: string | null;
29
+ requestCountry?: string | null;
30
+ }): boolean;
31
+ export declare function trustedDeviceExpiry(trustedDeviceDays: number, now?: Date): Date;
32
+ //# sourceMappingURL=device-fingerprint.service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"device-fingerprint.service.d.ts","sourceRoot":"","sources":["../../../../src/pam/identity/service/device-fingerprint.service.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,cAAc,GAAG,KAAK,GAAG,SAAS,GAAG,KAAK,CAAC;AAEvD,MAAM,MAAM,iBAAiB,GAAG;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;CACnB,CAAC;AAOF,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,CAS/E;AAED,wBAAgB,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,CAEvE;AAED,wBAAgB,YAAY,CAC1B,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAC/B,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAC/B,OAAO,CAET;AAyBD;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,iBAAiB,CAWtF;AAED;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAAC,EACnC,MAAM,EACN,SAAS,EACT,SAAS,EACT,cAAc,EACd,cAAc,GACf,EAAE;IACD,MAAM,EAAE,cAAc,CAAC;IACvB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAChC,GAAG,OAAO,CAWV;AAED,wBAAgB,mBAAmB,CAAC,iBAAiB,EAAE,MAAM,EAAE,GAAG,OAAa,GAAG,IAAI,CAErF"}
@@ -0,0 +1,79 @@
1
+ import { createHash } from 'node:crypto';
2
+ const UNKNOWN_DEVICE_LABEL = 'Unknown device';
3
+ // Browsers ship a new build every few weeks and every one of them changes the
4
+ // User-Agent. Comparing raw strings would revoke every Backoffice session on each
5
+ // auto-update, so the fingerprint keeps only the major version of each token.
6
+ export function normalizeUserAgent(userAgent) {
7
+ if (!userAgent) {
8
+ return '';
9
+ }
10
+ return userAgent
11
+ .toLowerCase()
12
+ .replace(/(\d+)(?:\.\d+)+/g, '$1')
13
+ .replace(/\s+/g, ' ')
14
+ .trim();
15
+ }
16
+ export function deviceHash(userAgent) {
17
+ return createHash('sha256').update(normalizeUserAgent(userAgent)).digest('hex');
18
+ }
19
+ export function isSameDevice(left, right) {
20
+ return normalizeUserAgent(left) === normalizeUserAgent(right);
21
+ }
22
+ const BROWSER_PATTERNS = [
23
+ [/edg[ea]?\//i, 'Edge'],
24
+ [/opr\/|opera/i, 'Opera'],
25
+ [/chrome\/|crios\//i, 'Chrome'],
26
+ [/firefox\/|fxios\//i, 'Firefox'],
27
+ [/safari\//i, 'Safari'],
28
+ ];
29
+ const OS_PATTERNS = [
30
+ [/windows nt/i, 'Windows'],
31
+ [/iphone|ipad|ipod/i, 'iOS'],
32
+ [/mac os x|macintosh/i, 'macOS'],
33
+ [/android/i, 'Android'],
34
+ [/linux/i, 'Linux'],
35
+ ];
36
+ function matchFirst(userAgent, patterns) {
37
+ return patterns.find(([pattern]) => pattern.test(userAgent))?.[1] ?? null;
38
+ }
39
+ /**
40
+ * Turns a raw User-Agent into the browser/OS pair the session list shows. Deliberately
41
+ * a handful of patterns rather than a UA-parsing dependency: the value is a display
42
+ * label, and a wrong guess costs a cosmetic string, never an access decision.
43
+ */
44
+ export function describeDevice(userAgent) {
45
+ if (!userAgent) {
46
+ return { label: UNKNOWN_DEVICE_LABEL, browser: null, os: null };
47
+ }
48
+ const browser = matchFirst(userAgent, BROWSER_PATTERNS);
49
+ const os = matchFirst(userAgent, OS_PATTERNS);
50
+ if (!browser && !os) {
51
+ return { label: UNKNOWN_DEVICE_LABEL, browser: null, os: null };
52
+ }
53
+ const label = [browser, os].filter((part) => part !== null).join(' on ');
54
+ return { label, browser, os };
55
+ }
56
+ /**
57
+ * Whether a mid-session IP change is suspicious enough to end the session.
58
+ *
59
+ * `country` needs both countries resolved - an unbound or failing geo-ip lookup
60
+ * yields nulls, and an unresolved lookup must never end a session on its own.
61
+ * `any` is the strictest setting and will log users out across NAT and mobile
62
+ * network hops, which is why it is not the default.
63
+ */
64
+ export function isSuspiciousIpChange({ policy, sessionIp, requestIp, sessionCountry, requestCountry, }) {
65
+ if (policy === 'off' || !sessionIp || !requestIp || sessionIp === requestIp) {
66
+ return false;
67
+ }
68
+ if (policy === 'any') {
69
+ return true;
70
+ }
71
+ if (!sessionCountry || !requestCountry) {
72
+ return false;
73
+ }
74
+ return sessionCountry.toUpperCase() !== requestCountry.toUpperCase();
75
+ }
76
+ export function trustedDeviceExpiry(trustedDeviceDays, now = new Date()) {
77
+ return new Date(now.getTime() + trustedDeviceDays * 24 * 60 * 60 * 1000);
78
+ }
79
+ //# sourceMappingURL=device-fingerprint.service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"device-fingerprint.service.js","sourceRoot":"","sources":["../../../../src/pam/identity/service/device-fingerprint.service.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,8 @@
1
1
  import { type EventBus, type NodeHeaders, DrizzleService } from '@openora/core/server';
2
- import type { CacheAdapter, RateLimiterAdapter, RateLimitKey, SendEmailPort, EmailTemplateRenderer, LoginInput, RegisterInput, Enable2faInput, Verify2faInput, Disable2faInput, RequestPasswordResetInput, VerifyPasswordResetOtpInput, ResetPasswordInput, ResendEmailVerificationInput, VerifyEmailInput, UpdateProfileInput, User, IdentityReader, ChangePasswordInput, ChangeEmailInput, IdentityServiceOptions, PlatformConfig, ClientMeta, GeoCheckCommands, PlayerProvisioning } from '@openora/core/contracts';
2
+ import type { SessionService } from './session.service.js';
3
+ import type { TrustedDeviceService } from './trusted-device.service.js';
4
+ import type { TwoFactorLockoutService } from './two-factor-lockout.service.js';
5
+ import type { CacheAdapter, RateLimiterAdapter, RateLimitKey, SendEmailPort, EmailTemplateRenderer, LoginInput, RegisterInput, Enable2faInput, Verify2faInput, Disable2faInput, RegenerateBackupCodesInput, TrustCurrentDeviceInput, RequestPasswordResetInput, VerifyPasswordResetOtpInput, ResetPasswordInput, ResendEmailVerificationInput, VerifyEmailInput, UpdateProfileInput, User, IdentityReader, ChangePasswordInput, ChangeEmailInput, IdentityServiceOptions, PlatformConfig, ClientMeta, GeoCheckCommands, PlayerProvisioning } from '@openora/core/contracts';
3
6
  export declare const UserNotFoundError: new (id: string) => Error;
4
7
  export declare const UsernameConflictError: new () => Error;
5
8
  export declare const SESSION_DURATION_IN_SECONDS: number;
@@ -15,6 +18,9 @@ export type IdentityServiceDeps = {
15
18
  geoCheck?: GeoCheckCommands;
16
19
  playerProvisioning?: PlayerProvisioning;
17
20
  cache?: CacheAdapter;
21
+ trustedDevices?: TrustedDeviceService;
22
+ twoFactorLockout?: TwoFactorLockoutService;
23
+ sessions?: SessionService;
18
24
  };
19
25
  /**
20
26
  * Thin wrapper over the shared better-auth instance (register/login/2FA/
@@ -39,7 +45,10 @@ export declare class IdentityService {
39
45
  private readonly geoCheck?;
40
46
  private readonly cache?;
41
47
  private readonly existingAccountSignUps;
42
- constructor({ drizzle, events, identityReader, email, templateRenderer, options, limiter, platformConfig, geoCheck, playerProvisioning, cache, }: IdentityServiceDeps);
48
+ private readonly trustedDevices?;
49
+ private readonly twoFactorLockout?;
50
+ private readonly sessions?;
51
+ constructor({ drizzle, events, identityReader, email, templateRenderer, options, limiter, platformConfig, geoCheck, playerProvisioning, cache, trustedDevices, twoFactorLockout, sessions, }: IdentityServiceDeps);
43
52
  private findUserByEmail;
44
53
  private resolveUserLanguage;
45
54
  private get api();
@@ -92,6 +101,7 @@ export declare class IdentityService {
92
101
  emailVerified: boolean;
93
102
  theme: "light" | "dark" | "system";
94
103
  language: string;
104
+ twoFactorEnabled: boolean;
95
105
  createdAt: string;
96
106
  updatedAt: string;
97
107
  } | {
@@ -103,6 +113,7 @@ export declare class IdentityService {
103
113
  emailVerified: boolean;
104
114
  theme: "light" | "dark" | "system";
105
115
  language: string;
116
+ twoFactorEnabled: boolean;
106
117
  createdAt: string;
107
118
  updatedAt: string;
108
119
  };
@@ -138,6 +149,7 @@ export declare class IdentityService {
138
149
  emailVerified: boolean;
139
150
  theme: "light" | "dark" | "system";
140
151
  language: string;
152
+ twoFactorEnabled: boolean;
141
153
  createdAt: string;
142
154
  updatedAt: string;
143
155
  } | null>;
@@ -148,6 +160,25 @@ export declare class IdentityService {
148
160
  verifyTwoFactor(input: Verify2faInput, reqHeaders: NodeHeaders, resHeaders: Headers): Promise<{
149
161
  success: true;
150
162
  }>;
163
+ /**
164
+ * Grants this browser its trust window without a sign-out. better-auth issues the
165
+ * trust cookie only on the sign-in leg of a challenge, so the grant has to replay
166
+ * that leg: the account proves its password and a fresh second factor, and the
167
+ * cookies better-auth returns are the ones the browser keeps.
168
+ */
169
+ trustCurrentDevice(input: TrustCurrentDeviceInput, reqHeaders: NodeHeaders, resHeaders: Headers): Promise<{
170
+ success: true;
171
+ }>;
172
+ /**
173
+ * A step-up gate for the self-service routes that change standing 2FA state: the
174
+ * caller has to clear a live authenticator code, not just the account password.
175
+ * Routed through TwoFactorLockoutService so a hijacked session plus a reused
176
+ * password cannot grind the second factor here the way the password-only paths let it.
177
+ */
178
+ private assertFreshSecondFactor;
179
+ regenerateBackupCodes(input: RegenerateBackupCodesInput, reqHeaders: NodeHeaders, resHeaders: Headers): Promise<{
180
+ backupCodes: string[];
181
+ }>;
151
182
  disableTwoFactor(input: Disable2faInput, reqHeaders: NodeHeaders, resHeaders: Headers): Promise<{
152
183
  success: true;
153
184
  }>;
@@ -193,6 +224,7 @@ export declare class IdentityService {
193
224
  emailVerified: boolean;
194
225
  theme: "light" | "dark" | "system";
195
226
  language: string;
227
+ twoFactorEnabled: boolean;
196
228
  createdAt: string;
197
229
  updatedAt: string;
198
230
  } | {
@@ -204,6 +236,7 @@ export declare class IdentityService {
204
236
  emailVerified: boolean;
205
237
  theme: "light" | "dark" | "system";
206
238
  language: string;
239
+ twoFactorEnabled: boolean;
207
240
  createdAt: string;
208
241
  updatedAt: string;
209
242
  };
@@ -225,6 +258,7 @@ export declare class IdentityService {
225
258
  emailVerified: boolean;
226
259
  theme: "light" | "dark" | "system";
227
260
  language: string;
261
+ twoFactorEnabled: boolean;
228
262
  createdAt: string;
229
263
  updatedAt: string;
230
264
  } | {
@@ -236,6 +270,7 @@ export declare class IdentityService {
236
270
  emailVerified: boolean;
237
271
  theme: "light" | "dark" | "system";
238
272
  language: string;
273
+ twoFactorEnabled: boolean;
239
274
  createdAt: string;
240
275
  updatedAt: string;
241
276
  };
@@ -1 +1 @@
1
- {"version":3,"file":"identity.service.d.ts","sourceRoot":"","sources":["../../../../src/pam/identity/service/identity.service.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,KAAK,QAAQ,EACb,KAAK,WAAW,EAChB,cAAc,EAQf,MAAM,sBAAsB,CAAC;AAK9B,OAAO,KAAK,EACV,YAAY,EACZ,kBAAkB,EAClB,YAAY,EACZ,aAAa,EACb,qBAAqB,EACrB,UAAU,EACV,aAAa,EACb,cAAc,EACd,cAAc,EACd,eAAe,EACf,yBAAyB,EACzB,2BAA2B,EAC3B,kBAAkB,EAClB,4BAA4B,EAC5B,gBAAgB,EAChB,kBAAkB,EAElB,IAAI,EACJ,cAAc,EACd,mBAAmB,EACnB,gBAAgB,EAChB,sBAAsB,EACtB,cAAc,EACd,UAAU,EAEV,gBAAgB,EAChB,kBAAkB,EACnB,MAAM,yBAAyB,CAAC;AAqGjC,eAAO,MAAM,iBAAiB,2BAA4B,CAAC;AAC3D,eAAO,MAAM,qBAAqB,iBAA8D,CAAC;AA+CjG,eAAO,MAAM,2BAA2B,QAAoB,CAAC;AAkF7D,MAAM,MAAM,mBAAmB,GAAG;IAChC,OAAO,EAAE,cAAc,CAAC;IACxB,MAAM,EAAE,QAAQ,CAAC;IACjB,cAAc,EAAE,cAAc,CAAC;IAC/B,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB,gBAAgB,EAAE,qBAAqB,CAAC;IACxC,OAAO,CAAC,EAAE,sBAAsB,CAAC;IACjC,OAAO,CAAC,EAAE,kBAAkB,CAAC,YAAY,CAAC,CAAC;IAC3C,cAAc,CAAC,EAAE,cAAc,CAAC;IAChC,QAAQ,CAAC,EAAE,gBAAgB,CAAC;IAC5B,kBAAkB,CAAC,EAAE,kBAAkB,CAAC;IACxC,KAAK,CAAC,EAAE,YAAY,CAAC;CACtB,CAAC;AAEF;;;;;;;;GAQG;AACH,qBAAa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAgC;IACrD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAiB;IACzC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAW;IAClC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAiB;IAChD,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAgB;IACvC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAwB;IACzD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAyB;IAClD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAmC;IAC5D,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAiB;IACjD,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAC,CAAqB;IACzD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAmB;IAC7C,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAe;IAMtC,OAAO,CAAC,QAAQ,CAAC,sBAAsB,CAAqB;gBAEhD,EACV,OAAO,EACP,MAAM,EACN,cAAc,EACd,KAAK,EACL,gBAAgB,EAChB,OAAO,EACP,OAAO,EACP,cAAc,EACd,QAAQ,EACR,kBAAkB,EAClB,KAAK,GACN,EAAE,mBAAmB;YA+CR,eAAe;YAaf,mBAAmB;IAKjC,OAAO,KAAK,GAAG,GAId;IAED,OAAO,CAAC,cAAc;YAOR,aAAa;IAM3B,OAAO,CAAC,uBAAuB;IAU/B;;;;OAIG;IACH,OAAO,CAAC,sBAAsB;IAcxB,QAAQ,CAAC,KAAK,EAAE,aAAa,EAAE,UAAU,EAAE,WAAW;;;YA0G9C,oBAAoB;YASpB,iBAAiB;IAS/B;;;;OAIG;YACW,yBAAyB;IAoCjC,iBAAiB,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,WAAW;;;IAUjE;;;;;;;;;;;OAWG;IACG,KAAK,CAAC,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,WAAW,EAAE,UAAU,EAAE,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IA6T3E,OAAO,CAAC,YAAY;IAOpB,OAAO,CAAC,gBAAgB;YAaV,cAAc;YAYd,cAAc;IAc5B,OAAO,CAAC,2BAA2B;IAI7B,yBAAyB,CAAC,MAAM,EAAE,IAAI,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,IAAI,CAAC,EAAE,IAAI,CAAC,EAAE,UAAU;;;IAwCpF,UAAU,CAAC,MAAM,EAAE,IAAI,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,IAAI,CAAC,EAAE,IAAI,CAAC,EAAE,UAAU;;;IAiCrE,MAAM,CAAC,UAAU,EAAE,WAAW,EAAE,UAAU,EAAE,OAAO;;;IAmBnD,EAAE,CAAC,UAAU,EAAE,WAAW;;;;;;;;;;;IAS1B,eAAe,CAAC,KAAK,EAAE,cAAc,EAAE,UAAU,EAAE,WAAW,EAAE,UAAU,EAAE,OAAO;;;;IAmBnF,eAAe,CAAC,KAAK,EAAE,cAAc,EAAE,UAAU,EAAE,WAAW,EAAE,UAAU,EAAE,OAAO;;;IAyBnF,gBAAgB,CAAC,KAAK,EAAE,eAAe,EAAE,UAAU,EAAE,WAAW,EAAE,UAAU,EAAE,OAAO;;;IA2BrF,oBAAoB,CAAC,KAAK,EAAE,yBAAyB;;;IAsBrD,sBAAsB,CAAC,KAAK,EAAE,2BAA2B;;;IAgBzD,aAAa,CAAC,KAAK,EAAE,kBAAkB;;;IAqBvC,cAAc,CAAC,KAAK,EAAE,mBAAmB,EAAE,UAAU,EAAE,WAAW,EAAE,UAAU,EAAE,OAAO;;;IAkB7F;;;;;;OAMG;IACG,qBAAqB,CAAC,KAAK,EAAE,4BAA4B,EAAE,UAAU,EAAE,WAAW;;;IAsBxF;;;;;;OAMG;IACG,WAAW,CAAC,KAAK,EAAE,gBAAgB,EAAE,UAAU,EAAE,WAAW,EAAE,UAAU,EAAE,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IA8EjF,WAAW,CAAC,KAAK,EAAE,gBAAgB,EAAE,UAAU,EAAE,WAAW,EAAE,UAAU,EAAE,OAAO;;;IAYjF,aAAa,CAAC,KAAK,EAAE,kBAAkB,EAAE,UAAU,EAAE,WAAW,EAAE,UAAU,EAAE,OAAO;;;;;;;;;;;;;;;;;;;;;;;;CAgC5F"}
1
+ {"version":3,"file":"identity.service.d.ts","sourceRoot":"","sources":["../../../../src/pam/identity/service/identity.service.ts"],"names":[],"mappings":"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"}