@betterportal/auth-default 10.6.21 → 10.6.23

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 (128) hide show
  1. package/README.md +140 -10
  2. package/bsb-plugin.json +1 -1
  3. package/lib/account.d.ts +16 -0
  4. package/lib/account.d.ts.map +1 -0
  5. package/lib/account.js +274 -0
  6. package/lib/account.js.map +1 -0
  7. package/lib/accountUI.d.ts +5 -0
  8. package/lib/accountUI.d.ts.map +1 -0
  9. package/lib/accountUI.js +68 -0
  10. package/lib/accountUI.js.map +1 -0
  11. package/lib/bp-contracts/org.betterportal.auth.default.json +2031 -707
  12. package/lib/clientAddress.d.ts +10 -0
  13. package/lib/clientAddress.d.ts.map +1 -0
  14. package/lib/clientAddress.js +35 -0
  15. package/lib/clientAddress.js.map +1 -0
  16. package/lib/config.d.ts +3 -0
  17. package/lib/config.d.ts.map +1 -0
  18. package/lib/config.js +28 -0
  19. package/lib/config.js.map +1 -0
  20. package/lib/defaultAuthManifest.d.ts +7 -0
  21. package/lib/defaultAuthManifest.d.ts.map +1 -1
  22. package/lib/factors.d.ts +18 -0
  23. package/lib/factors.d.ts.map +1 -0
  24. package/lib/factors.js +95 -0
  25. package/lib/factors.js.map +1 -0
  26. package/lib/identity.d.ts +106 -0
  27. package/lib/identity.d.ts.map +1 -0
  28. package/lib/identity.js +315 -0
  29. package/lib/identity.js.map +1 -0
  30. package/lib/index.d.ts +4 -0
  31. package/lib/index.d.ts.map +1 -1
  32. package/lib/index.js +4 -0
  33. package/lib/index.js.map +1 -1
  34. package/lib/mail.d.ts +19 -0
  35. package/lib/mail.d.ts.map +1 -0
  36. package/lib/mail.js +102 -0
  37. package/lib/mail.js.map +1 -0
  38. package/lib/plugins/service-betterportal-auth-default/.bp-generated/registry.d.ts +435 -11
  39. package/lib/plugins/service-betterportal-auth-default/.bp-generated/registry.d.ts.map +1 -1
  40. package/lib/plugins/service-betterportal-auth-default/.bp-generated/registry.js +85 -0
  41. package/lib/plugins/service-betterportal-auth-default/.bp-generated/registry.js.map +1 -1
  42. package/lib/plugins/service-betterportal-auth-default/bp-routes/account/GET.d.ts +34 -0
  43. package/lib/plugins/service-betterportal-auth-default/bp-routes/account/GET.d.ts.map +1 -0
  44. package/lib/plugins/service-betterportal-auth-default/bp-routes/account/GET.js +25 -0
  45. package/lib/plugins/service-betterportal-auth-default/bp-routes/account/GET.js.map +1 -0
  46. package/lib/plugins/service-betterportal-auth-default/bp-routes/account/POST.d.ts +42 -0
  47. package/lib/plugins/service-betterportal-auth-default/bp-routes/account/POST.d.ts.map +1 -0
  48. package/lib/plugins/service-betterportal-auth-default/bp-routes/account/POST.js +27 -0
  49. package/lib/plugins/service-betterportal-auth-default/bp-routes/account/POST.js.map +1 -0
  50. package/lib/plugins/service-betterportal-auth-default/bp-routes/account/_renderer.bootstrap5/GET.d.ts +2 -0
  51. package/lib/plugins/service-betterportal-auth-default/bp-routes/account/_renderer.bootstrap5/GET.d.ts.map +1 -0
  52. package/lib/plugins/service-betterportal-auth-default/bp-routes/account/_renderer.bootstrap5/GET.js +2 -0
  53. package/lib/plugins/service-betterportal-auth-default/bp-routes/account/_renderer.bootstrap5/GET.js.map +1 -0
  54. package/lib/plugins/service-betterportal-auth-default/bp-routes/account/_renderer.bootstrap5/POST.d.ts +2 -0
  55. package/lib/plugins/service-betterportal-auth-default/bp-routes/account/_renderer.bootstrap5/POST.d.ts.map +1 -0
  56. package/lib/plugins/service-betterportal-auth-default/bp-routes/account/_renderer.bootstrap5/POST.js +2 -0
  57. package/lib/plugins/service-betterportal-auth-default/bp-routes/account/_renderer.bootstrap5/POST.js.map +1 -0
  58. package/lib/plugins/service-betterportal-auth-default/bp-routes/account/index.d.ts +3 -0
  59. package/lib/plugins/service-betterportal-auth-default/bp-routes/account/index.d.ts.map +1 -0
  60. package/lib/plugins/service-betterportal-auth-default/bp-routes/account/index.js +3 -0
  61. package/lib/plugins/service-betterportal-auth-default/bp-routes/account/index.js.map +1 -0
  62. package/lib/plugins/service-betterportal-auth-default/bp-routes/login/_renderer.bootstrap5/GET.d.ts.map +1 -1
  63. package/lib/plugins/service-betterportal-auth-default/bp-routes/login/_renderer.bootstrap5/GET.js +11 -8
  64. package/lib/plugins/service-betterportal-auth-default/bp-routes/login/_renderer.bootstrap5/GET.js.map +1 -1
  65. package/lib/plugins/service-betterportal-auth-default/bp-routes/refresh/POST.d.ts +3 -1
  66. package/lib/plugins/service-betterportal-auth-default/bp-routes/refresh/POST.d.ts.map +1 -1
  67. package/lib/plugins/service-betterportal-auth-default/bp-routes/refresh/POST.js +10 -23
  68. package/lib/plugins/service-betterportal-auth-default/bp-routes/refresh/POST.js.map +1 -1
  69. package/lib/plugins/service-betterportal-auth-default/bp-routes/register/_renderer.bootstrap5/GET.d.ts.map +1 -1
  70. package/lib/plugins/service-betterportal-auth-default/bp-routes/register/_renderer.bootstrap5/GET.js +2 -2
  71. package/lib/plugins/service-betterportal-auth-default/bp-routes/register/_renderer.bootstrap5/GET.js.map +1 -1
  72. package/lib/plugins/service-betterportal-auth-default/bp-routes/social/GET.d.ts +34 -0
  73. package/lib/plugins/service-betterportal-auth-default/bp-routes/social/GET.d.ts.map +1 -0
  74. package/lib/plugins/service-betterportal-auth-default/bp-routes/social/GET.js +26 -0
  75. package/lib/plugins/service-betterportal-auth-default/bp-routes/social/GET.js.map +1 -0
  76. package/lib/plugins/service-betterportal-auth-default/bp-routes/social/POST.d.ts +31 -0
  77. package/lib/plugins/service-betterportal-auth-default/bp-routes/social/POST.d.ts.map +1 -0
  78. package/lib/plugins/service-betterportal-auth-default/bp-routes/social/POST.js +23 -0
  79. package/lib/plugins/service-betterportal-auth-default/bp-routes/social/POST.js.map +1 -0
  80. package/lib/plugins/service-betterportal-auth-default/bp-routes/social/_renderer.bootstrap5/GET.d.ts +3 -0
  81. package/lib/plugins/service-betterportal-auth-default/bp-routes/social/_renderer.bootstrap5/GET.d.ts.map +1 -0
  82. package/lib/plugins/service-betterportal-auth-default/bp-routes/social/_renderer.bootstrap5/GET.js +36 -0
  83. package/lib/plugins/service-betterportal-auth-default/bp-routes/social/_renderer.bootstrap5/GET.js.map +1 -0
  84. package/lib/plugins/service-betterportal-auth-default/bp-routes/social/index.d.ts +3 -0
  85. package/lib/plugins/service-betterportal-auth-default/bp-routes/social/index.d.ts.map +1 -0
  86. package/lib/plugins/service-betterportal-auth-default/bp-routes/social/index.js +3 -0
  87. package/lib/plugins/service-betterportal-auth-default/bp-routes/social/index.js.map +1 -0
  88. package/lib/plugins/service-betterportal-auth-default/bp-routes/users/GET.d.ts +32 -0
  89. package/lib/plugins/service-betterportal-auth-default/bp-routes/users/GET.d.ts.map +1 -0
  90. package/lib/plugins/service-betterportal-auth-default/bp-routes/users/GET.js +39 -0
  91. package/lib/plugins/service-betterportal-auth-default/bp-routes/users/GET.js.map +1 -0
  92. package/lib/plugins/service-betterportal-auth-default/bp-routes/users/POST.d.ts +41 -0
  93. package/lib/plugins/service-betterportal-auth-default/bp-routes/users/POST.d.ts.map +1 -0
  94. package/lib/plugins/service-betterportal-auth-default/bp-routes/users/POST.js +103 -0
  95. package/lib/plugins/service-betterportal-auth-default/bp-routes/users/POST.js.map +1 -0
  96. package/lib/plugins/service-betterportal-auth-default/bp-routes/users/_renderer.bootstrap5/GET.d.ts +3 -0
  97. package/lib/plugins/service-betterportal-auth-default/bp-routes/users/_renderer.bootstrap5/GET.d.ts.map +1 -0
  98. package/lib/plugins/service-betterportal-auth-default/bp-routes/users/_renderer.bootstrap5/GET.js +19 -0
  99. package/lib/plugins/service-betterportal-auth-default/bp-routes/users/_renderer.bootstrap5/GET.js.map +1 -0
  100. package/lib/plugins/service-betterportal-auth-default/bp-routes/users/index.d.ts +3 -0
  101. package/lib/plugins/service-betterportal-auth-default/bp-routes/users/index.d.ts.map +1 -0
  102. package/lib/plugins/service-betterportal-auth-default/bp-routes/users/index.js +3 -0
  103. package/lib/plugins/service-betterportal-auth-default/bp-routes/users/index.js.map +1 -0
  104. package/lib/plugins/service-betterportal-auth-default/index.d.ts +41 -4
  105. package/lib/plugins/service-betterportal-auth-default/index.d.ts.map +1 -1
  106. package/lib/plugins/service-betterportal-auth-default/index.js +205 -9
  107. package/lib/plugins/service-betterportal-auth-default/index.js.map +1 -1
  108. package/lib/plugins/service-betterportal-auth-default/loginFlow.d.ts +17 -2
  109. package/lib/plugins/service-betterportal-auth-default/loginFlow.d.ts.map +1 -1
  110. package/lib/plugins/service-betterportal-auth-default/loginFlow.js +83 -62
  111. package/lib/plugins/service-betterportal-auth-default/loginFlow.js.map +1 -1
  112. package/lib/plugins/service-betterportal-auth-default/logoutFlow.js +1 -1
  113. package/lib/plugins/service-betterportal-auth-default/logoutFlow.js.map +1 -1
  114. package/lib/plugins/service-betterportal-auth-default/registrationFlow.d.ts +4 -2
  115. package/lib/plugins/service-betterportal-auth-default/registrationFlow.d.ts.map +1 -1
  116. package/lib/plugins/service-betterportal-auth-default/registrationFlow.js +15 -17
  117. package/lib/plugins/service-betterportal-auth-default/registrationFlow.js.map +1 -1
  118. package/lib/schemas/service-betterportal-auth-default.json +26 -2
  119. package/lib/schemas/service-betterportal-auth-default.plugin.json +27 -3
  120. package/lib/social.d.ts +40 -0
  121. package/lib/social.d.ts.map +1 -0
  122. package/lib/social.js +178 -0
  123. package/lib/social.js.map +1 -0
  124. package/lib/storage.d.ts +72 -0
  125. package/lib/storage.d.ts.map +1 -0
  126. package/lib/storage.js +427 -0
  127. package/lib/storage.js.map +1 -0
  128. package/package.json +13 -6
@@ -0,0 +1,315 @@
1
+ import { createCipheriv, createDecipheriv, createHash, randomBytes, timingSafeEqual } from "node:crypto";
2
+ import argon2 from "argon2";
3
+ import bcrypt from "bcrypt";
4
+ import * as av from "anyvali";
5
+ import { uuidv7 } from "@betterportal/framework";
6
+ export class AuthError extends Error {
7
+ status;
8
+ constructor(message, status = 400) {
9
+ super(message);
10
+ this.status = status;
11
+ }
12
+ }
13
+ const tenantScope = (tenantId) => ({ tenantId, appId: "" });
14
+ export const secretHash = (value) => createHash("sha256").update(value).digest("hex");
15
+ export const newSecret = () => randomBytes(32).toString("base64url");
16
+ export const normalizeAccountIdentifier = (value) => value.trim().toLowerCase();
17
+ const EmailSchema = av.string().maxLength(254).format("email");
18
+ export function isValidEmail(value) {
19
+ // Bound input before parsing: AnyVali collects issues rather than stopping at maxLength.
20
+ return value.length <= 254 && EmailSchema.safeParse(value).success;
21
+ }
22
+ export function equalSecret(a, b) {
23
+ const aa = Buffer.from(secretHash(a));
24
+ const bb = Buffer.from(secretHash(b));
25
+ return timingSafeEqual(aa, bb);
26
+ }
27
+ export class SecretCipher {
28
+ key;
29
+ constructor(key) {
30
+ this.key = key;
31
+ if (key.length !== 32)
32
+ throw new Error("Invalid auth encryption key");
33
+ }
34
+ encrypt(value) {
35
+ const iv = randomBytes(12);
36
+ const cipher = createCipheriv("aes-256-gcm", this.key, iv);
37
+ const encrypted = Buffer.concat([cipher.update(value, "utf8"), cipher.final()]);
38
+ return Buffer.concat([iv, cipher.getAuthTag(), encrypted]).toString("base64url");
39
+ }
40
+ decrypt(value) {
41
+ const input = Buffer.from(value, "base64url");
42
+ const decipher = createDecipheriv("aes-256-gcm", this.key, input.subarray(0, 12));
43
+ decipher.setAuthTag(input.subarray(12, 28));
44
+ return Buffer.concat([decipher.update(input.subarray(28)), decipher.final()]).toString("utf8");
45
+ }
46
+ }
47
+ export function validatePassword(value) {
48
+ if (value.length < 12 || Buffer.byteLength(value, "utf8") > 1024)
49
+ throw new AuthError("Use a password between 12 and 1024 bytes.");
50
+ if (/^(password|qwerty|letmein|welcome|123456|betterportal|admin)/i.test(value))
51
+ throw new AuthError("Choose a less common password.");
52
+ }
53
+ export async function hashPassword(value) { validatePassword(value); return argon2.hash(value, { type: argon2.argon2id, memoryCost: 19456, timeCost: 2, parallelism: 1 }); }
54
+ let dummyHash;
55
+ export async function verifyPassword(hash, value) {
56
+ // Legacy bcrypt accepted UTF-8 input beyond its 72-byte effective key length.
57
+ if (hash?.startsWith("$2"))
58
+ return bcrypt.compare(value, hash);
59
+ if (Buffer.byteLength(value, "utf8") > 1024)
60
+ return false;
61
+ if (!hash) {
62
+ dummyHash ??= hashPassword("unavailable account timing check");
63
+ await argon2.verify(await dummyHash, value);
64
+ return false;
65
+ }
66
+ if (hash.startsWith("$argon2"))
67
+ return argon2.verify(hash, value);
68
+ return false;
69
+ }
70
+ export class IdentityService {
71
+ storage;
72
+ cipher;
73
+ constructor(storage, cipher) {
74
+ this.storage = storage;
75
+ this.cipher = cipher;
76
+ }
77
+ async directory(tx, scope, isolation, lock = false) {
78
+ const root = tenantScope(scope.tenantId);
79
+ const settings = await tx.get("tenant", scope.tenantId, root);
80
+ if (settings && settings.isolation !== isolation)
81
+ throw new AuthError("User isolation is locked for this tenant.", 409);
82
+ if (lock) {
83
+ if (this.storage.mode === "simple") {
84
+ const tenants = await tx.list("tenant");
85
+ if (tenants.some(t => t.id !== scope.tenantId))
86
+ throw new AuthError("Simple auth supports one tenant. Upgrade to Advanced.", 426);
87
+ }
88
+ await tx.put("tenant", root, { ...settings, id: scope.tenantId, isolation, lockedAt: settings?.lockedAt ?? Date.now() });
89
+ }
90
+ return { tenantId: scope.tenantId, appId: (settings?.lockedAt ? settings.isolation : isolation) === "tenant" ? "" : scope.appId };
91
+ }
92
+ async effectiveIsolation(tenantId, requested) {
93
+ return this.storage.transaction(tenantScope(tenantId), async (tx) => {
94
+ const settings = await tx.get("tenant", tenantId, tenantScope(tenantId));
95
+ if (settings?.lockedAt && requested && requested !== settings.isolation)
96
+ throw new AuthError("User isolation cannot change after account creation.", 409);
97
+ return requested ?? settings?.isolation ?? "app";
98
+ });
99
+ }
100
+ async hasNoUsers() { return this.storage.transaction(tenantScope(""), async (tx) => !(await tx.list("user")).length); }
101
+ async bootstrapAvailable(scope) {
102
+ return this.storage.transaction(scope, async (tx) => !(await tx.get("tenant", scope.tenantId, tenantScope(scope.tenantId)))?.bootstrapComplete);
103
+ }
104
+ async createUser(scope, policy, input, roles, root = false) {
105
+ const passwordHash = input.password ? await hashPassword(input.password) : undefined;
106
+ return this.storage.transaction(scope, async (tx) => this.createInTransaction(tx, scope, policy, input, passwordHash, roles, root));
107
+ }
108
+ async createInTransaction(tx, scope, policy, input, passwordHash, roles, root = false) {
109
+ const dir = await this.directory(tx, scope, policy.isolation, true);
110
+ if (this.storage.mode === "simple" && (await tx.list("user")).length >= 10)
111
+ throw new AuthError("Simple auth is limited to 10 stored users. Upgrade to Advanced.", 426);
112
+ const username = normalizeAccountIdentifier(input.username);
113
+ const email = input.email ? normalizeAccountIdentifier(input.email) : undefined;
114
+ if (!username || username.length > 254 || (email !== undefined && !isValidEmail(email)))
115
+ throw new AuthError("Enter a valid account identifier and email.");
116
+ for (const id of new Set([username, ...(email ? [email] : [])]))
117
+ if (await tx.get("identifier", id, dir))
118
+ throw new AuthError("This account cannot be registered.", 409);
119
+ if (roles?.includes("*") && !root)
120
+ throw new AuthError("Root cannot be assigned by account provisioning.", 403);
121
+ if (root) {
122
+ if ((await tx.get("tenant", scope.tenantId, tenantScope(scope.tenantId)))?.bootstrapComplete)
123
+ throw new AuthError("Bootstrap already completed.", 409);
124
+ const settings = await tx.get("tenant", scope.tenantId, tenantScope(scope.tenantId));
125
+ await tx.put("tenant", tenantScope(scope.tenantId), { ...settings, bootstrapComplete: true });
126
+ }
127
+ const user = { id: uuidv7(), username, tenantId: dir.tenantId, appId: dir.appId, passwordHash, email, emailVerified: input.verified ?? false, name: input.name, enabled: true, bootstrapAdmin: root, refreshVersion: 0, createdAt: Date.now(), updatedAt: Date.now() };
128
+ await tx.put("user", dir, user);
129
+ for (const id of new Set([username, ...(email ? [email] : [])]))
130
+ await tx.put("identifier", dir, { id, userId: user.id });
131
+ if (roles)
132
+ await tx.put("roles", scope, { id: user.id, roles, initialized: true });
133
+ await this.audit(tx, scope, user.id, "user.created");
134
+ return user;
135
+ }
136
+ async findUser(scope, policy, identifier, byId = false) {
137
+ return this.storage.transaction(scope, async (tx) => {
138
+ const dir = await this.directory(tx, scope, policy.isolation);
139
+ const id = byId ? identifier : (await tx.get("identifier", normalizeAccountIdentifier(identifier), dir))?.userId;
140
+ return id ? tx.get("user", id, dir) : undefined;
141
+ });
142
+ }
143
+ async authenticate(scope, policy, username, password) {
144
+ const before = await this.storage.transaction(scope, async (tx) => {
145
+ const dir = await this.directory(tx, scope, policy.isolation);
146
+ // Only password sign-in accepts exact legacy usernames for ambiguous identifiers.
147
+ // Email recovery and all other lookups continue to reject ambiguous ownership.
148
+ const index = await tx.get("legacy-username", username, dir) ?? await tx.get("identifier", normalizeAccountIdentifier(username), dir);
149
+ return typeof index?.userId === "string" ? tx.get("user", index.userId, dir) : undefined;
150
+ });
151
+ const verified = await verifyPassword(before?.passwordHash, password);
152
+ if (!before?.enabled || !verified)
153
+ return undefined;
154
+ const nextHash = before.passwordHash?.startsWith("$2") && Buffer.byteLength(password, "utf8") <= 1024 ? await argon2.hash(password, { type: argon2.argon2id, memoryCost: 19456, timeCost: 2, parallelism: 1 }) : undefined;
155
+ return this.storage.transaction(scope, async (tx) => {
156
+ const dir = await this.directory(tx, scope, policy.isolation);
157
+ const current = await tx.get("user", before.id, dir);
158
+ if (!current?.enabled || current.passwordHash !== before.passwordHash || current.refreshVersion !== before.refreshVersion)
159
+ return undefined;
160
+ if (nextHash) {
161
+ current.passwordHash = nextHash;
162
+ await tx.put("user", dir, current);
163
+ }
164
+ return current;
165
+ });
166
+ }
167
+ async updateUser(scope, policy, id, update) {
168
+ return this.storage.transaction(scope, async (tx) => {
169
+ const dir = await this.directory(tx, scope, policy.isolation);
170
+ const user = await tx.get("user", id, dir);
171
+ if (!user)
172
+ throw new AuthError("Account unavailable.", 404);
173
+ await update(user, tx);
174
+ user.updatedAt = Date.now();
175
+ await tx.put("user", dir, user);
176
+ return user;
177
+ });
178
+ }
179
+ async roles(tx, scope, user, policy, initialize = false) {
180
+ let assignment = await tx.get("roles", user.id, scope);
181
+ if (!assignment?.initialized && initialize) {
182
+ if (policy.defaultRoleIds.some(id => id === "*" || !policy.allowedRoleIds.includes(id)))
183
+ throw new AuthError("Default roles reference unavailable roles.", 503);
184
+ assignment = { id: user.id, roles: [...new Set(policy.defaultRoleIds)], initialized: true };
185
+ await tx.put("roles", scope, assignment);
186
+ await this.audit(tx, scope, user.id, "roles.initialized", { roles: assignment.roles });
187
+ }
188
+ const groups = await tx.list("group", { tenantId: user.tenantId, appId: user.appId });
189
+ const groupRoles = groups.filter(g => g.members.includes(user.id)).flatMap(g => g.appRoles[scope.appId] ?? []);
190
+ return [...new Set([...(assignment?.roles ?? []), ...groupRoles])].filter(id => id === "*" || policy.allowedRoleIds.includes(id));
191
+ }
192
+ async issueSession(scope, policy, user, issuer, refreshSeconds) {
193
+ return this.storage.transaction(scope, async (tx) => {
194
+ const dir = await this.directory(tx, scope, policy.isolation);
195
+ const current = await tx.get("user", user.id, dir);
196
+ if (!current?.enabled || current.refreshVersion !== user.refreshVersion)
197
+ throw new AuthError("Account changed; sign in again.", 401);
198
+ await tx.pruneSessions(scope, Date.now());
199
+ const id = uuidv7();
200
+ const roles = await this.roles(tx, scope, current, policy, true);
201
+ const issued = issuer.issueTokenPair({ sub: user.id, ...scope, roles, sessionId: id, sessionVersion: user.refreshVersion, name: current.name ?? current.username, email: current.email, picture: current.picture, authProvider: "betterportal.default", refreshContext: { sessionId: id, version: user.refreshVersion } });
202
+ await tx.put("session", scope, { id, userId: user.id, userAppId: dir.appId, version: user.refreshVersion, jti: issued.tokenId, previousJtis: [], expiresAt: Date.now() + refreshSeconds * 1000, createdAt: Date.now(), revoked: false });
203
+ await this.audit(tx, scope, user.id, "login.success");
204
+ return issued;
205
+ });
206
+ }
207
+ async refresh(scope, policy, claims, issuer) {
208
+ return this.storage.transaction(scope, async (tx) => {
209
+ const id = String(claims.refreshContext?.sessionId ?? "");
210
+ const session = await tx.get("session", id, scope);
211
+ const dir = await this.directory(tx, scope, policy.isolation);
212
+ const user = session ? await tx.get("user", session.userId, dir) : undefined;
213
+ if (!session || !user?.enabled || session.revoked || session.expiresAt <= Date.now() || user.id !== claims.sub || user.refreshVersion !== session.version)
214
+ return undefined;
215
+ if (session.jti !== claims.jti) {
216
+ session.revoked = true;
217
+ await tx.put("session", scope, session);
218
+ await this.audit(tx, scope, user.id, "refresh.replay");
219
+ return undefined;
220
+ }
221
+ const roles = await this.roles(tx, scope, user, policy);
222
+ const issued = issuer.issueTokenPair({ sub: user.id, ...scope, roles, sessionId: id, sessionVersion: user.refreshVersion, name: user.name ?? user.username, email: user.email, picture: user.picture, authProvider: "betterportal.default", refreshContext: { sessionId: id, version: user.refreshVersion } });
223
+ session.previousJtis = [...session.previousJtis.slice(-4), session.jti];
224
+ session.jti = issued.tokenId;
225
+ await tx.put("session", scope, session);
226
+ return issued;
227
+ });
228
+ }
229
+ async assertActiveSession(tx, scope, claims, user) {
230
+ const session = await tx.get("session", claims.sessionId ?? "", scope);
231
+ if (!session || session.revoked || session.expiresAt <= Date.now() || session.userId !== user.id || session.version !== user.refreshVersion
232
+ || claims.sessionVersion !== user.refreshVersion)
233
+ throw new AuthError("Session changed; sign in again.", 401);
234
+ }
235
+ async revokeSession(scope, claims) {
236
+ await this.storage.transaction(scope, async (tx) => {
237
+ const session = await tx.get("session", String(claims.refreshContext?.sessionId ?? ""), scope);
238
+ if (session?.userId === claims.sub) {
239
+ session.revoked = true;
240
+ await tx.put("session", scope, session);
241
+ await this.audit(tx, scope, claims.sub, "session.revoked");
242
+ }
243
+ });
244
+ }
245
+ async challenge(scope, purpose, data, userId, lifetimeSeconds = 600) {
246
+ return this.storage.transaction(scope, async (tx) => this.challengeInTransaction(tx, scope, purpose, data, userId, lifetimeSeconds));
247
+ }
248
+ async challengeInTransaction(tx, scope, purpose, data, userId, lifetimeSeconds = 600) {
249
+ const id = uuidv7();
250
+ const secret = newSecret();
251
+ const records = await tx.list("challenge", scope);
252
+ for (const record of records)
253
+ if (record.expiresAt <= Date.now())
254
+ await tx.remove("challenge", record.id, scope);
255
+ if (records.filter(c => c.expiresAt > Date.now()).length >= 1000)
256
+ throw new AuthError("Too many pending requests. Try later.", 429);
257
+ await tx.put("challenge", scope, { id, purpose, data, userId, hash: secretHash(secret), attempts: 0, expiresAt: Date.now() + lifetimeSeconds * 1000 });
258
+ return { id, secret };
259
+ }
260
+ async consume(scope, purpose, id, secret, complete) {
261
+ return this.consumeWithPreparation(scope, purpose, id, secret, async () => undefined, complete);
262
+ }
263
+ async consumeWithPreparation(scope, purpose, id, secret, prepare, complete) {
264
+ // Charge the attempt independently. The application transaction must roll back
265
+ // every side effect on failure, while a failed factor still consumes an attempt.
266
+ const accepted = await this.storage.transaction(scope, async (tx) => {
267
+ const challenge = await tx.get("challenge", id, scope);
268
+ if (!challenge || challenge.purpose !== purpose || challenge.expiresAt <= Date.now() || challenge.attempts >= 5)
269
+ return false;
270
+ challenge.attempts++;
271
+ await tx.put("challenge", scope, challenge);
272
+ return equalSecret(challenge.hash, secretHash(secret)) ? challenge : false;
273
+ });
274
+ if (!accepted)
275
+ throw new AuthError("Verification expired or unavailable.");
276
+ // Remote work happens without a store/tenant lock. Revalidate and consume only on commit.
277
+ const prepared = await prepare(accepted);
278
+ return this.storage.transaction(scope, async (tx) => {
279
+ const challenge = await tx.get("challenge", id, scope);
280
+ if (!challenge || challenge.purpose !== purpose || challenge.expiresAt <= Date.now()
281
+ || !equalSecret(challenge.hash, secretHash(secret)))
282
+ throw new AuthError("Verification expired or unavailable.");
283
+ const value = await complete(challenge, tx, prepared);
284
+ await tx.remove("challenge", id, scope);
285
+ return value;
286
+ });
287
+ }
288
+ async rateLimit(scope, action, actor, max = 10, seconds = 600) {
289
+ const allowed = await this.storage.transaction(scope, async (tx) => {
290
+ const records = await tx.list("limit", scope);
291
+ for (const row of records)
292
+ if (Number(row.reset) <= Date.now())
293
+ await tx.remove("limit", row.id, scope);
294
+ if (records.filter(row => Number(row.reset) > Date.now()).length >= 10000)
295
+ return false;
296
+ const id = secretHash(`${action}:${actor}`);
297
+ const old = await tx.get("limit", id, scope);
298
+ const reset = Number(old?.reset ?? 0) > Date.now() ? Number(old.reset) : Date.now() + seconds * 1000;
299
+ const count = Number(old?.reset ?? 0) > Date.now() ? Number(old?.count ?? 0) + 1 : 1;
300
+ await tx.put("limit", scope, { id, reset, count });
301
+ return count <= max;
302
+ });
303
+ if (!allowed)
304
+ throw new AuthError("Too many attempts. Try again later.", 429);
305
+ }
306
+ async audit(tx, scope, actor, event, data = {}) {
307
+ await tx.put("audit", scope, { id: uuidv7(), actor, event, data, at: Date.now() });
308
+ if (this.storage.mode === "simple") {
309
+ const entries = await tx.list("audit", scope);
310
+ for (const row of entries.slice(0, Math.max(0, entries.length - 1000)))
311
+ await tx.remove("audit", row.id, scope);
312
+ }
313
+ }
314
+ }
315
+ //# sourceMappingURL=identity.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"identity.js","sourceRoot":"","sources":["../src/identity.ts"],"names":[],"mappings":"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"}
package/lib/index.d.ts CHANGED
@@ -1,4 +1,8 @@
1
1
  export * from "./defaultAuthManifest.js";
2
2
  export * from "./userStore.js";
3
3
  export * from "./plugins/service-betterportal-auth-default/index.js";
4
+ export * from "./storage.js";
5
+ export * from "./identity.js";
6
+ export * from "./factors.js";
7
+ export * from "./social.js";
4
8
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,0BAA0B,CAAC;AACzC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,sDAAsD,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,0BAA0B,CAAC;AACzC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,sDAAsD,CAAC;AAErE,cAAc,cAAc,CAAC;AAC7B,cAAc,eAAe,CAAC;AAC9B,cAAc,cAAc,CAAC;AAC7B,cAAc,aAAa,CAAC"}
package/lib/index.js CHANGED
@@ -1,4 +1,8 @@
1
1
  export * from "./defaultAuthManifest.js";
2
2
  export * from "./userStore.js";
3
3
  export * from "./plugins/service-betterportal-auth-default/index.js";
4
+ export * from "./storage.js";
5
+ export * from "./identity.js";
6
+ export * from "./factors.js";
7
+ export * from "./social.js";
4
8
  //# sourceMappingURL=index.js.map
package/lib/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,0BAA0B,CAAC;AACzC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,sDAAsD,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,0BAA0B,CAAC;AACzC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,sDAAsD,CAAC;AAErE,cAAc,cAAc,CAAC;AAC7B,cAAc,eAAe,CAAC;AAC9B,cAAc,cAAc,CAAC;AAC7B,cAAc,aAAa,CAAC"}
package/lib/mail.d.ts ADDED
@@ -0,0 +1,19 @@
1
+ import { type IdentityService } from "./identity.js";
2
+ import type { AuthTransaction, Scope } from "./storage.js";
3
+ export interface MailConfig {
4
+ transport: "postal" | "http";
5
+ url: string;
6
+ from: string;
7
+ apiKey?: string;
8
+ headers?: Record<string, string>;
9
+ }
10
+ export declare function parseMailHeaders(configured: unknown): Record<string, string> | undefined;
11
+ export declare function validateMailUrl(value: unknown): void;
12
+ export declare class MailQueue {
13
+ private readonly identity;
14
+ private readonly config;
15
+ constructor(identity: IdentityService, config: (scope: Scope) => MailConfig | undefined);
16
+ enqueue(tx: AuthTransaction, scope: Scope, to: string, subject: string, text: string): Promise<void>;
17
+ drain(): Promise<void>;
18
+ }
19
+ //# sourceMappingURL=mail.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mail.d.ts","sourceRoot":"","sources":["../src/mail.ts"],"names":[],"mappings":"AAEA,OAAO,EAAa,KAAK,eAAe,EAAE,MAAM,eAAe,CAAC;AAChE,OAAO,KAAK,EAAE,eAAe,EAAe,KAAK,EAAE,MAAM,cAAc,CAAC;AAExE,MAAM,WAAW,UAAU;IAAG,SAAS,EAAE,QAAQ,GAAG,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE;AAE1I,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,CAUxF;AAGD,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI,CAKpD;AACD,qBAAa,SAAS;IACR,OAAO,CAAC,QAAQ,CAAC,QAAQ;IAAmB,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAlD,QAAQ,EAAE,eAAe,EAAmB,MAAM,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,UAAU,GAAG,SAAS;IACnH,OAAO,CAAC,EAAE,EAAE,eAAe,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAepG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAkC7B"}
package/lib/mail.js ADDED
@@ -0,0 +1,102 @@
1
+ import { uuidv7 } from "@betterportal/framework";
2
+ import * as av from "anyvali";
3
+ import { AuthError } from "./identity.js";
4
+ const MailHeadersSchema = av.record(av.string());
5
+ export function parseMailHeaders(configured) {
6
+ if (configured === undefined || configured === "")
7
+ return undefined;
8
+ let value;
9
+ try {
10
+ value = typeof configured === "string" ? JSON.parse(configured) : configured;
11
+ }
12
+ catch {
13
+ throw new AuthError("Custom mail headers must be a valid JSON object of strings.", 503);
14
+ }
15
+ const result = MailHeadersSchema.safeParse(value);
16
+ if (!result.success)
17
+ throw new AuthError("Custom mail headers must be a JSON object of strings.", 503);
18
+ try {
19
+ new Headers(result.data);
20
+ }
21
+ catch {
22
+ throw new AuthError("Custom mail headers contain an invalid HTTP header name or value.", 503);
23
+ }
24
+ return result.data;
25
+ }
26
+ const MailUrlSchema = av.string().format("url");
27
+ export function validateMailUrl(value) {
28
+ const result = MailUrlSchema.safeParse(value);
29
+ if (!result.success)
30
+ throw new AuthError("Email delivery requires a valid absolute URL.", 503);
31
+ const url = new URL(result.data);
32
+ if (url.protocol !== "https:" && !(url.protocol === "http:" && ["localhost", "127.0.0.1"].includes(url.hostname)))
33
+ throw new AuthError("Email delivery requires HTTPS.", 503);
34
+ }
35
+ export class MailQueue {
36
+ identity;
37
+ config;
38
+ constructor(identity, config) {
39
+ this.identity = identity;
40
+ this.config = config;
41
+ }
42
+ async enqueue(tx, scope, to, subject, text) {
43
+ const config = this.config(scope);
44
+ if (!config)
45
+ throw new AuthError("Email delivery has not been configured.", 503);
46
+ validateMailUrl(config.url);
47
+ if (this.identity.storage.mode === "simple") {
48
+ const rows = await tx.list("mail", scope);
49
+ if (rows.filter(row => row.state !== "sent").length >= 500)
50
+ throw new AuthError("Email queue is full. Contact your administrator.", 503);
51
+ const sent = rows.filter(row => row.state === "sent");
52
+ for (const row of sent.slice(0, Math.max(0, sent.length - 99)))
53
+ await tx.remove("mail", row.id, scope);
54
+ }
55
+ await tx.put("mail", scope, {
56
+ id: uuidv7(), scope, encrypted: this.identity.cipher.encrypt(JSON.stringify({ to, subject, text })),
57
+ attempts: 0, nextAttempt: Date.now(), state: "pending", updatedAt: Date.now()
58
+ });
59
+ }
60
+ async drain() {
61
+ const rows = await this.identity.storage.transaction({ tenantId: "", appId: "" }, tx => tx.dueMail(Date.now(), 100));
62
+ for (const row of rows) {
63
+ if (row.state === "sent" || row.state === "failed" || row.nextAttempt > Date.now())
64
+ continue;
65
+ const lease = uuidv7();
66
+ const claimed = await this.identity.storage.transaction(row.scope, async (tx) => {
67
+ const current = await tx.get("mail", row.id, row.scope);
68
+ if (!current || current.state === "sent" || current.state === "failed" || current.nextAttempt > Date.now())
69
+ return false;
70
+ await tx.put("mail", row.scope, { ...current, lease, state: "sending", nextAttempt: Date.now() + 60000 });
71
+ return true;
72
+ });
73
+ if (!claimed)
74
+ continue;
75
+ let success = false;
76
+ try {
77
+ const config = this.config(row.scope);
78
+ if (!config)
79
+ throw new Error("Mail not configured");
80
+ validateMailUrl(config.url);
81
+ const payload = JSON.parse(this.identity.cipher.decrypt(row.encrypted));
82
+ const body = { from: config.from, to: payload.to, subject: payload.subject, text: payload.text, html: "" };
83
+ const url = config.transport === "postal" ? `${config.url.replace(/\/+$/, "")}/api/v1/send/message` : config.url;
84
+ const response = await fetch(url, {
85
+ method: "POST", redirect: "error", signal: AbortSignal.timeout(15000),
86
+ headers: { ...config.headers, "Content-Type": "application/json", ...(config.transport === "postal" ? { "X-Server-API-Key": config.apiKey ?? "" } : {}) },
87
+ body: JSON.stringify(config.transport === "postal" ? { from: body.from, to: [body.to], subject: body.subject, plain_body: body.text, html_body: body.html } : body)
88
+ });
89
+ success = response.ok && (config.transport !== "postal" || (await response.json()).status === "success");
90
+ }
91
+ catch { /* Persist a bounded delivery status, never provider bodies or secrets. */ }
92
+ await this.identity.storage.transaction(row.scope, async (tx) => {
93
+ const current = await tx.get("mail", row.id, row.scope);
94
+ if (current?.lease !== lease)
95
+ return;
96
+ const attempts = current.attempts + 1;
97
+ await tx.put("mail", row.scope, { ...current, encrypted: success ? "" : current.encrypted, attempts, state: success ? "sent" : attempts >= 5 ? "failed" : "pending", nextAttempt: Date.now() + Math.min(3600000, 30000 * 2 ** attempts), updatedAt: Date.now() });
98
+ });
99
+ }
100
+ }
101
+ }
102
+ //# sourceMappingURL=mail.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mail.js","sourceRoot":"","sources":["../src/mail.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AACjD,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,EAAE,SAAS,EAAwB,MAAM,eAAe,CAAC;AAIhE,MAAM,iBAAiB,GAAG,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,CAAC;AACjD,MAAM,UAAU,gBAAgB,CAAC,UAAmB;IAClD,IAAI,UAAU,KAAK,SAAS,IAAI,UAAU,KAAK,EAAE;QAAE,OAAO,SAAS,CAAC;IACpE,IAAI,KAAc,CAAC;IACnB,IAAI,CAAC;QAAC,KAAK,GAAG,OAAO,UAAU,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC;IAAC,CAAC;IACrF,MAAM,CAAC;QAAC,MAAM,IAAI,SAAS,CAAC,6DAA6D,EAAE,GAAG,CAAC,CAAC;IAAC,CAAC;IAClG,MAAM,MAAM,GAAG,iBAAiB,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;IAClD,IAAI,CAAC,MAAM,CAAC,OAAO;QAAE,MAAM,IAAI,SAAS,CAAC,uDAAuD,EAAE,GAAG,CAAC,CAAC;IACvG,IAAI,CAAC;QAAC,IAAI,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAAC,CAAC;IACjC,MAAM,CAAC;QAAC,MAAM,IAAI,SAAS,CAAC,mEAAmE,EAAE,GAAG,CAAC,CAAC;IAAC,CAAC;IACxG,OAAO,MAAM,CAAC,IAAI,CAAC;AACrB,CAAC;AAED,MAAM,aAAa,GAAG,EAAE,CAAC,MAAM,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAChD,MAAM,UAAU,eAAe,CAAC,KAAc;IAC5C,MAAM,MAAM,GAAG,aAAa,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;IAC9C,IAAI,CAAC,MAAM,CAAC,OAAO;QAAE,MAAM,IAAI,SAAS,CAAC,+CAA+C,EAAE,GAAG,CAAC,CAAC;IAC/F,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IACjC,IAAI,GAAG,CAAC,QAAQ,KAAK,QAAQ,IAAI,CAAC,CAAC,GAAG,CAAC,QAAQ,KAAK,OAAO,IAAI,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QAAE,MAAM,IAAI,SAAS,CAAC,gCAAgC,EAAE,GAAG,CAAC,CAAC;AAChL,CAAC;AACD,MAAM,OAAO,SAAS;IACS;IAA4C;IAAzE,YAA6B,QAAyB,EAAmB,MAAgD;QAA5F,aAAQ,GAAR,QAAQ,CAAiB;QAAmB,WAAM,GAAN,MAAM,CAA0C;IAAG,CAAC;IAC7H,KAAK,CAAC,OAAO,CAAC,EAAmB,EAAE,KAAY,EAAE,EAAU,EAAE,OAAe,EAAE,IAAY;QACxF,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAClC,IAAI,CAAC,MAAM;YAAE,MAAM,IAAI,SAAS,CAAC,yCAAyC,EAAE,GAAG,CAAC,CAAC;QACjF,eAAe,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAC5B,IAAI,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YAC5C,MAAM,IAAI,GAAG,MAAM,EAAE,CAAC,IAAI,CAAO,MAAM,EAAE,KAAK,CAAC,CAAC;YAChD,IAAI,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,KAAK,MAAM,CAAC,CAAC,MAAM,IAAI,GAAG;gBAAE,MAAM,IAAI,SAAS,CAAC,kDAAkD,EAAE,GAAG,CAAC,CAAC;YACzI,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,KAAK,MAAM,CAAC,CAAC;YACtD,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC;gBAAE,MAAM,EAAE,CAAC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;QACzG,CAAC;QACD,MAAM,EAAE,CAAC,GAAG,CAAC,MAAM,EAAE,KAAK,EAAE;YAC1B,EAAE,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;YACnG,QAAQ,EAAE,CAAC,EAAE,WAAW,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;SAC9E,CAAC,CAAC;IACL,CAAC;IACD,KAAK,CAAC,KAAK;QACT,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,OAAO,CAAO,IAAI,CAAC,GAAG,EAAE,EAAE,GAAG,CAAC,CAAC,CAAC;QAC3H,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;YACvB,IAAI,GAAG,CAAC,KAAK,KAAK,MAAM,IAAI,GAAG,CAAC,KAAK,KAAK,QAAQ,IAAI,GAAG,CAAC,WAAW,GAAG,IAAI,CAAC,GAAG,EAAE;gBAAE,SAAS;YAC7F,MAAM,KAAK,GAAG,MAAM,EAAE,CAAC;YACvB,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,WAAW,CAAC,GAAG,CAAC,KAAK,EAAE,KAAK,EAAC,EAAE,EAAC,EAAE;gBAC5E,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,GAAG,CAAO,MAAM,EAAE,GAAG,CAAC,EAAE,EAAE,GAAG,CAAC,KAAK,CAAC,CAAC;gBAC9D,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC,KAAK,KAAK,MAAM,IAAI,OAAO,CAAC,KAAK,KAAK,QAAQ,IAAI,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,GAAG,EAAE;oBAAE,OAAO,KAAK,CAAC;gBACzH,MAAM,EAAE,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,KAAK,EAAE,EAAE,GAAG,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,EAAE,CAAC,CAAC;gBAAC,OAAO,IAAI,CAAC;YACzH,CAAC,CAAC,CAAC;YACH,IAAI,CAAC,OAAO;gBAAE,SAAS;YACvB,IAAI,OAAO,GAAG,KAAK,CAAC;YACpB,IAAI,CAAC;gBACH,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;gBACtC,IAAI,CAAC,MAAM;oBAAE,MAAM,IAAI,KAAK,CAAC,qBAAqB,CAAC,CAAC;gBACpD,eAAe,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;gBAC5B,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,CAAkD,CAAC;gBACzH,MAAM,IAAI,GAAG,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,EAAE,EAAE,OAAO,CAAC,EAAE,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC;gBAC3G,MAAM,GAAG,GAAG,MAAM,CAAC,SAAS,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,sBAAsB,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC;gBACjH,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;oBAChC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,KAAK,CAAC;oBACrE,OAAO,EAAE,EAAE,GAAG,MAAM,CAAC,OAAO,EAAE,cAAc,EAAE,kBAAkB,EAAE,GAAG,CAAC,MAAM,CAAC,SAAS,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,kBAAkB,EAAE,MAAM,CAAC,MAAM,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE;oBACzJ,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,SAAS,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,EAAE,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,UAAU,EAAE,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;iBACpK,CAAC,CAAC;gBACH,OAAO,GAAG,QAAQ,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,SAAS,KAAK,QAAQ,IAAI,CAAC,MAAM,QAAQ,CAAC,IAAI,EAA0B,CAAA,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC;YAClI,CAAC;YAAC,MAAM,CAAC,CAAC,0EAA0E,CAAC,CAAC;YACtF,MAAM,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,WAAW,CAAC,GAAG,CAAC,KAAK,EAAE,KAAK,EAAC,EAAE,EAAC,EAAE;gBAC5D,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,GAAG,CAAO,MAAM,EAAE,GAAG,CAAC,EAAE,EAAE,GAAG,CAAC,KAAK,CAAC,CAAC;gBAC9D,IAAI,OAAO,EAAE,KAAK,KAAK,KAAK;oBAAE,OAAO;gBACrC,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;gBACtC,MAAM,EAAE,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,KAAK,EAAE,EAAE,GAAG,OAAO,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,SAAS,EAAE,QAAQ,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,IAAI,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,EAAE,WAAW,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,KAAK,GAAG,CAAC,IAAI,QAAQ,CAAC,EAAE,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;YACpQ,CAAC,CAAC,CAAC;QACL,CAAC;IACH,CAAC;CACF"}