@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.
- package/dist/.tsbuildinfo +1 -1
- package/dist/admin-console/plugin.d.ts +11 -0
- package/dist/admin-console/plugin.d.ts.map +1 -1
- package/dist/analytics/plugin.d.ts +11 -0
- package/dist/analytics/plugin.d.ts.map +1 -1
- package/dist/audit/__tests__/map-event.test.js +34 -0
- package/dist/audit/__tests__/map-event.test.js.map +1 -1
- package/dist/audit/plugin.d.ts +11 -0
- package/dist/audit/plugin.d.ts.map +1 -1
- package/dist/audit/plugin.js +63 -7
- package/dist/audit/plugin.js.map +1 -1
- package/dist/casino/gaming/plugin.d.ts +11 -0
- package/dist/casino/gaming/plugin.d.ts.map +1 -1
- package/dist/casino/lobby/plugin.d.ts +11 -0
- package/dist/casino/lobby/plugin.d.ts.map +1 -1
- package/dist/cms/plugin.d.ts +11 -0
- package/dist/cms/plugin.d.ts.map +1 -1
- package/dist/compliance/plugin.d.ts +11 -0
- package/dist/compliance/plugin.d.ts.map +1 -1
- package/dist/contracts/adapters/admin-security.d.ts +27 -0
- package/dist/contracts/adapters/admin-security.d.ts.map +1 -0
- package/dist/contracts/adapters/admin-security.js +9 -0
- package/dist/contracts/adapters/admin-security.js.map +1 -0
- package/dist/contracts/adapters/index.d.ts +3 -1
- package/dist/contracts/adapters/index.d.ts.map +1 -1
- package/dist/contracts/adapters/index.js +1 -0
- package/dist/contracts/adapters/index.js.map +1 -1
- package/dist/contracts/adapters/realtime.d.ts +36 -3
- package/dist/contracts/adapters/realtime.d.ts.map +1 -1
- package/dist/contracts/adapters/realtime.js.map +1 -1
- package/dist/contracts/schemas/common.d.ts +3 -1
- package/dist/contracts/schemas/common.d.ts.map +1 -1
- package/dist/contracts/schemas/common.js +2 -0
- package/dist/contracts/schemas/common.js.map +1 -1
- package/dist/contracts/schemas/events.d.ts +114 -0
- package/dist/contracts/schemas/events.d.ts.map +1 -1
- package/dist/contracts/schemas/events.js +77 -0
- package/dist/contracts/schemas/events.js.map +1 -1
- package/dist/contracts/schemas/identity.d.ts +26 -0
- package/dist/contracts/schemas/identity.d.ts.map +1 -1
- package/dist/contracts/schemas/identity.js +32 -1
- package/dist/contracts/schemas/identity.js.map +1 -1
- package/dist/contracts/schemas/platform-config.d.ts +39 -0
- package/dist/contracts/schemas/platform-config.d.ts.map +1 -1
- package/dist/contracts/schemas/platform-config.js +43 -0
- package/dist/contracts/schemas/platform-config.js.map +1 -1
- package/dist/engagement/chat/__tests__/chat.router.test.d.ts +2 -0
- package/dist/engagement/chat/__tests__/chat.router.test.d.ts.map +1 -0
- package/dist/engagement/chat/__tests__/chat.router.test.js +44 -0
- package/dist/engagement/chat/__tests__/chat.router.test.js.map +1 -0
- package/dist/engagement/chat/__tests__/chat.service.int.test.js +590 -6
- package/dist/engagement/chat/__tests__/chat.service.int.test.js.map +1 -1
- package/dist/engagement/chat/contract/constants.d.ts +2 -0
- package/dist/engagement/chat/contract/constants.d.ts.map +1 -1
- package/dist/engagement/chat/contract/constants.js +7 -0
- package/dist/engagement/chat/contract/constants.js.map +1 -1
- package/dist/engagement/chat/contract/index.d.ts +39 -0
- package/dist/engagement/chat/contract/index.d.ts.map +1 -1
- package/dist/engagement/chat/contract/index.js +25 -1
- package/dist/engagement/chat/contract/index.js.map +1 -1
- package/dist/engagement/chat/drizzle/migrations/0009_massive_bill_hollister.sql +1 -0
- package/dist/engagement/chat/drizzle/migrations/0010_backfill_role_assigned_at.sql +9 -0
- package/dist/engagement/chat/drizzle/migrations/meta/0009_snapshot.json +1468 -0
- package/dist/engagement/chat/drizzle/migrations/meta/0010_snapshot.json +1468 -0
- package/dist/engagement/chat/drizzle/migrations/meta/_journal.json +14 -0
- package/dist/engagement/chat/plugin.d.ts +11 -0
- package/dist/engagement/chat/plugin.d.ts.map +1 -1
- package/dist/engagement/chat/router/index.d.ts +19 -0
- package/dist/engagement/chat/router/index.d.ts.map +1 -1
- package/dist/engagement/chat/router/index.js +31 -2
- package/dist/engagement/chat/router/index.js.map +1 -1
- package/dist/engagement/chat/schema/index.d.ts +17 -0
- package/dist/engagement/chat/schema/index.d.ts.map +1 -1
- package/dist/engagement/chat/schema/index.js +3 -0
- package/dist/engagement/chat/schema/index.js.map +1 -1
- package/dist/engagement/chat/service/chat-ban.service.d.ts.map +1 -1
- package/dist/engagement/chat/service/chat-ban.service.js +6 -6
- package/dist/engagement/chat/service/chat-ban.service.js.map +1 -1
- package/dist/engagement/chat/service/chat-room-ban.service.js +1 -1
- package/dist/engagement/chat/service/chat-room-ban.service.js.map +1 -1
- package/dist/engagement/chat/service/chat-room-membership.service.d.ts +15 -0
- package/dist/engagement/chat/service/chat-room-membership.service.d.ts.map +1 -1
- package/dist/engagement/chat/service/chat-room-membership.service.js +96 -4
- package/dist/engagement/chat/service/chat-room-membership.service.js.map +1 -1
- package/dist/engagement/chat/service/chat.service.d.ts +3 -2
- package/dist/engagement/chat/service/chat.service.d.ts.map +1 -1
- package/dist/engagement/chat/service/chat.service.js +73 -24
- package/dist/engagement/chat/service/chat.service.js.map +1 -1
- package/dist/engagement/chat/service/errors/chat-moderation.errors.d.ts +1 -0
- package/dist/engagement/chat/service/errors/chat-moderation.errors.d.ts.map +1 -1
- package/dist/engagement/chat/service/errors/chat-moderation.errors.js +1 -0
- package/dist/engagement/chat/service/errors/chat-moderation.errors.js.map +1 -1
- package/dist/engagement/chat-commands/plugin.d.ts +11 -0
- package/dist/engagement/chat-commands/plugin.d.ts.map +1 -1
- package/dist/engagement/notifications/plugin.d.ts +11 -0
- package/dist/engagement/notifications/plugin.d.ts.map +1 -1
- package/dist/engagement/social/plugin.d.ts +11 -0
- package/dist/engagement/social/plugin.d.ts.map +1 -1
- package/dist/iam/plugin.d.ts +11 -0
- package/dist/iam/plugin.d.ts.map +1 -1
- package/dist/pam/identity/__tests__/admin-security.int.test.d.ts +2 -0
- package/dist/pam/identity/__tests__/admin-security.int.test.d.ts.map +1 -0
- package/dist/pam/identity/__tests__/admin-security.int.test.js +137 -0
- package/dist/pam/identity/__tests__/admin-security.int.test.js.map +1 -0
- package/dist/pam/identity/__tests__/device-fingerprint.test.d.ts +2 -0
- package/dist/pam/identity/__tests__/device-fingerprint.test.d.ts.map +1 -0
- package/dist/pam/identity/__tests__/device-fingerprint.test.js +105 -0
- package/dist/pam/identity/__tests__/device-fingerprint.test.js.map +1 -0
- package/dist/pam/identity/__tests__/identity.rate-limit.int.test.js +3 -3
- package/dist/pam/identity/__tests__/identity.rate-limit.int.test.js.map +1 -1
- package/dist/pam/identity/__tests__/identity.service.int.test.js +221 -1
- package/dist/pam/identity/__tests__/identity.service.int.test.js.map +1 -1
- package/dist/pam/identity/contract/index.d.ts +144 -0
- package/dist/pam/identity/contract/index.d.ts.map +1 -1
- package/dist/pam/identity/contract/index.js +84 -1
- package/dist/pam/identity/contract/index.js.map +1 -1
- package/dist/pam/identity/drizzle/migrations/0008_pink_bucky.sql +23 -0
- package/dist/pam/identity/drizzle/migrations/0009_hard_sauron.sql +2 -0
- package/dist/pam/identity/drizzle/migrations/meta/0008_snapshot.json +913 -0
- package/dist/pam/identity/drizzle/migrations/meta/0009_snapshot.json +926 -0
- package/dist/pam/identity/drizzle/migrations/meta/_journal.json +14 -0
- package/dist/pam/identity/plugin.d.ts +11 -0
- package/dist/pam/identity/plugin.d.ts.map +1 -1
- package/dist/pam/identity/plugin.js +81 -26
- package/dist/pam/identity/plugin.js.map +1 -1
- package/dist/pam/identity/react/account.d.ts +5 -0
- package/dist/pam/identity/react/account.d.ts.map +1 -1
- package/dist/pam/identity/react/auth.d.ts +2 -0
- package/dist/pam/identity/react/auth.d.ts.map +1 -1
- package/dist/pam/identity/router/index.d.ts +105 -1
- package/dist/pam/identity/router/index.d.ts.map +1 -1
- package/dist/pam/identity/router/index.js +44 -3
- package/dist/pam/identity/router/index.js.map +1 -1
- package/dist/pam/identity/schema/index.d.ts +314 -0
- package/dist/pam/identity/schema/index.d.ts.map +1 -1
- package/dist/pam/identity/schema/index.js +38 -0
- package/dist/pam/identity/schema/index.js.map +1 -1
- package/dist/pam/identity/service/admin-security.service.d.ts +82 -0
- package/dist/pam/identity/service/admin-security.service.d.ts.map +1 -0
- package/dist/pam/identity/service/admin-security.service.js +277 -0
- package/dist/pam/identity/service/admin-security.service.js.map +1 -0
- package/dist/pam/identity/service/device-fingerprint.service.d.ts +32 -0
- package/dist/pam/identity/service/device-fingerprint.service.d.ts.map +1 -0
- package/dist/pam/identity/service/device-fingerprint.service.js +79 -0
- package/dist/pam/identity/service/device-fingerprint.service.js.map +1 -0
- package/dist/pam/identity/service/identity.service.d.ts +37 -2
- package/dist/pam/identity/service/identity.service.d.ts.map +1 -1
- package/dist/pam/identity/service/identity.service.js +233 -19
- package/dist/pam/identity/service/identity.service.js.map +1 -1
- package/dist/pam/identity/service/phone-login.service.d.ts +1 -0
- package/dist/pam/identity/service/phone-login.service.d.ts.map +1 -1
- package/dist/pam/identity/service/phone-login.service.js +2 -0
- package/dist/pam/identity/service/phone-login.service.js.map +1 -1
- package/dist/pam/identity/service/session.service.d.ts +45 -1
- package/dist/pam/identity/service/session.service.d.ts.map +1 -1
- package/dist/pam/identity/service/session.service.js +81 -12
- package/dist/pam/identity/service/session.service.js.map +1 -1
- package/dist/pam/identity/service/trusted-device.service.d.ts +54 -0
- package/dist/pam/identity/service/trusted-device.service.d.ts.map +1 -0
- package/dist/pam/identity/service/trusted-device.service.js +157 -0
- package/dist/pam/identity/service/trusted-device.service.js.map +1 -0
- package/dist/pam/identity/service/two-factor-lockout.service.d.ts +25 -0
- package/dist/pam/identity/service/two-factor-lockout.service.d.ts.map +1 -0
- package/dist/pam/identity/service/two-factor-lockout.service.js +121 -0
- package/dist/pam/identity/service/two-factor-lockout.service.js.map +1 -0
- package/dist/pam/player-management/plugin.d.ts +11 -0
- package/dist/pam/player-management/plugin.d.ts.map +1 -1
- package/dist/pam/player-note/plugin.d.ts +11 -0
- package/dist/pam/player-note/plugin.d.ts.map +1 -1
- package/dist/pam/profile/plugin.d.ts +11 -0
- package/dist/pam/profile/plugin.d.ts.map +1 -1
- package/dist/pam/tag/plugin.d.ts +11 -0
- package/dist/pam/tag/plugin.d.ts.map +1 -1
- package/dist/react/context/__tests__/realtime-client.test.d.ts +2 -0
- package/dist/react/context/__tests__/realtime-client.test.d.ts.map +1 -0
- package/dist/react/context/__tests__/realtime-client.test.js +75 -0
- package/dist/react/context/__tests__/realtime-client.test.js.map +1 -0
- package/dist/react/context/realtime-client.d.ts +14 -0
- package/dist/react/context/realtime-client.d.ts.map +1 -1
- package/dist/react/context/realtime-client.js.map +1 -1
- package/dist/server/auth/__tests__/admin-guard.int.test.js +3 -1
- package/dist/server/auth/__tests__/admin-guard.int.test.js.map +1 -1
- package/dist/server/auth/admin-guard.d.ts +3 -2
- package/dist/server/auth/admin-guard.d.ts.map +1 -1
- package/dist/server/auth/admin-guard.js +18 -2
- package/dist/server/auth/admin-guard.js.map +1 -1
- package/dist/server/auth/auth.d.ts +14 -0
- package/dist/server/auth/auth.d.ts.map +1 -1
- package/dist/server/auth/auth.js +18 -1
- package/dist/server/auth/auth.js.map +1 -1
- package/dist/server/kernel/realtime-transport.d.ts +11 -3
- package/dist/server/kernel/realtime-transport.d.ts.map +1 -1
- package/dist/server/kernel/realtime-transport.js +53 -10
- package/dist/server/kernel/realtime-transport.js.map +1 -1
- package/dist/server/runtime/core-token-catalog.d.ts +11 -0
- package/dist/server/runtime/core-token-catalog.d.ts.map +1 -1
- package/dist/server/runtime/core-token-catalog.js +2 -1
- package/dist/server/runtime/core-token-catalog.js.map +1 -1
- package/dist/server/runtime/create-app.d.ts.map +1 -1
- package/dist/server/runtime/create-app.js +2 -2
- package/dist/server/runtime/create-app.js.map +1 -1
- package/dist/testing/seed-player.d.ts +10 -2
- package/dist/testing/seed-player.d.ts.map +1 -1
- package/dist/wallet/plugin.d.ts +11 -0
- package/dist/wallet/plugin.d.ts.map +1 -1
- 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 {
|
|
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
|
-
|
|
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;
|
|
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,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AACxE,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,iCAAiC,CAAC;AAC/E,OAAO,KAAK,EACV,YAAY,EACZ,kBAAkB,EAClB,YAAY,EACZ,aAAa,EACb,qBAAqB,EACrB,UAAU,EACV,aAAa,EACb,cAAc,EACd,cAAc,EACd,eAAe,EACf,0BAA0B,EAC1B,uBAAuB,EACvB,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;AAwJjC,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;IACrB,cAAc,CAAC,EAAE,oBAAoB,CAAC;IACtC,gBAAgB,CAAC,EAAE,uBAAuB,CAAC;IAG3C,QAAQ,CAAC,EAAE,cAAc,CAAC;CAC3B,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;IAC5D,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAuB;IACvD,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAC,CAA0B;IAC5D,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAiB;gBAE/B,EACV,OAAO,EACP,MAAM,EACN,cAAc,EACd,KAAK,EACL,gBAAgB,EAChB,OAAO,EACP,OAAO,EACP,cAAc,EACd,QAAQ,EACR,kBAAkB,EAClB,KAAK,EACL,cAAc,EACd,gBAAgB,EAChB,QAAQ,GACT,EAAE,mBAAmB;YAkDR,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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAwU3E,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;;;IA+DzF;;;;;OAKG;IACG,kBAAkB,CACtB,KAAK,EAAE,uBAAuB,EAC9B,UAAU,EAAE,WAAW,EACvB,UAAU,EAAE,OAAO;;;IAiErB;;;;;OAKG;YACW,uBAAuB;IAmB/B,qBAAqB,CACzB,KAAK,EAAE,0BAA0B,EACjC,UAAU,EAAE,WAAW,EACvB,UAAU,EAAE,OAAO;;;IAqCf,gBAAgB,CAAC,KAAK,EAAE,eAAe,EAAE,UAAU,EAAE,WAAW,EAAE,UAAU,EAAE,OAAO;;;IAqCrF,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"}
|