@memberjunction/server 5.38.0 → 5.40.0

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 (180) hide show
  1. package/README.md +67 -0
  2. package/dist/apolloServer/index.d.ts +0 -8
  3. package/dist/apolloServer/index.d.ts.map +1 -1
  4. package/dist/apolloServer/index.js +61 -0
  5. package/dist/apolloServer/index.js.map +1 -1
  6. package/dist/auth/index.js +1 -1
  7. package/dist/auth/index.js.map +1 -1
  8. package/dist/auth/magicLink/MagicLinkKeys.d.ts +58 -0
  9. package/dist/auth/magicLink/MagicLinkKeys.d.ts.map +1 -0
  10. package/dist/auth/magicLink/MagicLinkKeys.js +99 -0
  11. package/dist/auth/magicLink/MagicLinkKeys.js.map +1 -0
  12. package/dist/auth/magicLink/MagicLinkRouter.d.ts +33 -0
  13. package/dist/auth/magicLink/MagicLinkRouter.d.ts.map +1 -0
  14. package/dist/auth/magicLink/MagicLinkRouter.js +184 -0
  15. package/dist/auth/magicLink/MagicLinkRouter.js.map +1 -0
  16. package/dist/auth/magicLink/MagicLinkService.d.ts +123 -0
  17. package/dist/auth/magicLink/MagicLinkService.d.ts.map +1 -0
  18. package/dist/auth/magicLink/MagicLinkService.js +605 -0
  19. package/dist/auth/magicLink/MagicLinkService.js.map +1 -0
  20. package/dist/auth/magicLink/index.d.ts +6 -0
  21. package/dist/auth/magicLink/index.d.ts.map +1 -0
  22. package/dist/auth/magicLink/index.js +6 -0
  23. package/dist/auth/magicLink/index.js.map +1 -0
  24. package/dist/auth/magicLink/magicLinkCore.d.ts +82 -0
  25. package/dist/auth/magicLink/magicLinkCore.d.ts.map +1 -0
  26. package/dist/auth/magicLink/magicLinkCore.js +164 -0
  27. package/dist/auth/magicLink/magicLinkCore.js.map +1 -0
  28. package/dist/auth/magicLink/redeemLanding.d.ts +22 -0
  29. package/dist/auth/magicLink/redeemLanding.d.ts.map +1 -0
  30. package/dist/auth/magicLink/redeemLanding.js +61 -0
  31. package/dist/auth/magicLink/redeemLanding.js.map +1 -0
  32. package/dist/auth/magicLink/types.d.ts +131 -0
  33. package/dist/auth/magicLink/types.d.ts.map +1 -0
  34. package/dist/auth/magicLink/types.js +6 -0
  35. package/dist/auth/magicLink/types.js.map +1 -0
  36. package/dist/config.d.ts +479 -0
  37. package/dist/config.d.ts.map +1 -1
  38. package/dist/config.js +84 -0
  39. package/dist/config.js.map +1 -1
  40. package/dist/context.d.ts.map +1 -1
  41. package/dist/context.js +223 -19
  42. package/dist/context.js.map +1 -1
  43. package/dist/generated/generated.d.ts +952 -4
  44. package/dist/generated/generated.d.ts.map +1 -1
  45. package/dist/generated/generated.js +25663 -20321
  46. package/dist/generated/generated.js.map +1 -1
  47. package/dist/generic/FireAndForgetHeartbeat.d.ts +51 -0
  48. package/dist/generic/FireAndForgetHeartbeat.d.ts.map +1 -0
  49. package/dist/generic/FireAndForgetHeartbeat.js +44 -0
  50. package/dist/generic/FireAndForgetHeartbeat.js.map +1 -0
  51. package/dist/generic/ResolverBase.d.ts.map +1 -1
  52. package/dist/generic/ResolverBase.js +35 -7
  53. package/dist/generic/ResolverBase.js.map +1 -1
  54. package/dist/index.d.ts +5 -0
  55. package/dist/index.d.ts.map +1 -1
  56. package/dist/index.js +145 -2
  57. package/dist/index.js.map +1 -1
  58. package/dist/logging/NoLog.d.ts +50 -0
  59. package/dist/logging/NoLog.d.ts.map +1 -0
  60. package/dist/logging/NoLog.js +80 -0
  61. package/dist/logging/NoLog.js.map +1 -0
  62. package/dist/logging/bootAudit.d.ts +43 -0
  63. package/dist/logging/bootAudit.d.ts.map +1 -0
  64. package/dist/logging/bootAudit.js +83 -0
  65. package/dist/logging/bootAudit.js.map +1 -0
  66. package/dist/logging/boundaryLogPayload.d.ts +18 -0
  67. package/dist/logging/boundaryLogPayload.d.ts.map +1 -0
  68. package/dist/logging/boundaryLogPayload.js +18 -0
  69. package/dist/logging/boundaryLogPayload.js.map +1 -0
  70. package/dist/logging/secretRedactor.d.ts +23 -0
  71. package/dist/logging/secretRedactor.d.ts.map +1 -0
  72. package/dist/logging/secretRedactor.js +53 -0
  73. package/dist/logging/secretRedactor.js.map +1 -0
  74. package/dist/logging/shortenForLog.d.ts +8 -0
  75. package/dist/logging/shortenForLog.d.ts.map +1 -0
  76. package/dist/logging/shortenForLog.js +21 -0
  77. package/dist/logging/shortenForLog.js.map +1 -0
  78. package/dist/logging/variablesLoggingMiddleware.d.ts +22 -0
  79. package/dist/logging/variablesLoggingMiddleware.d.ts.map +1 -0
  80. package/dist/logging/variablesLoggingMiddleware.js +127 -0
  81. package/dist/logging/variablesLoggingMiddleware.js.map +1 -0
  82. package/dist/resolvers/CurrentUserContextResolver.d.ts +9 -3
  83. package/dist/resolvers/CurrentUserContextResolver.d.ts.map +1 -1
  84. package/dist/resolvers/CurrentUserContextResolver.js +19 -5
  85. package/dist/resolvers/CurrentUserContextResolver.js.map +1 -1
  86. package/dist/resolvers/EntityResolver.d.ts.map +1 -1
  87. package/dist/resolvers/EntityResolver.js +13 -2
  88. package/dist/resolvers/EntityResolver.js.map +1 -1
  89. package/dist/resolvers/GenerateSeedTaxonomyResolver.d.ts +28 -0
  90. package/dist/resolvers/GenerateSeedTaxonomyResolver.d.ts.map +1 -0
  91. package/dist/resolvers/GenerateSeedTaxonomyResolver.js +100 -0
  92. package/dist/resolvers/GenerateSeedTaxonomyResolver.js.map +1 -0
  93. package/dist/resolvers/GetDataResolver.d.ts.map +1 -1
  94. package/dist/resolvers/GetDataResolver.js +8 -4
  95. package/dist/resolvers/GetDataResolver.js.map +1 -1
  96. package/dist/resolvers/IntegrationDiscoveryResolver.d.ts +259 -2
  97. package/dist/resolvers/IntegrationDiscoveryResolver.d.ts.map +1 -1
  98. package/dist/resolvers/IntegrationDiscoveryResolver.js +1276 -117
  99. package/dist/resolvers/IntegrationDiscoveryResolver.js.map +1 -1
  100. package/dist/resolvers/IntegrationProgressResolver.d.ts +90 -0
  101. package/dist/resolvers/IntegrationProgressResolver.d.ts.map +1 -0
  102. package/dist/resolvers/IntegrationProgressResolver.js +196 -0
  103. package/dist/resolvers/IntegrationProgressResolver.js.map +1 -0
  104. package/dist/resolvers/MCPResolver.d.ts.map +1 -1
  105. package/dist/resolvers/MCPResolver.js +19 -14
  106. package/dist/resolvers/MCPResolver.js.map +1 -1
  107. package/dist/resolvers/RunAIAgentResolver.d.ts.map +1 -1
  108. package/dist/resolvers/RunAIAgentResolver.js +26 -5
  109. package/dist/resolvers/RunAIAgentResolver.js.map +1 -1
  110. package/dist/resolvers/RunClusterAnalysisResolver.d.ts +74 -0
  111. package/dist/resolvers/RunClusterAnalysisResolver.d.ts.map +1 -0
  112. package/dist/resolvers/RunClusterAnalysisResolver.js +243 -0
  113. package/dist/resolvers/RunClusterAnalysisResolver.js.map +1 -0
  114. package/dist/resolvers/RunTestResolver.d.ts.map +1 -1
  115. package/dist/resolvers/RunTestResolver.js +12 -2
  116. package/dist/resolvers/RunTestResolver.js.map +1 -1
  117. package/dist/resolvers/SearchEntitiesResolver.d.ts +46 -0
  118. package/dist/resolvers/SearchEntitiesResolver.d.ts.map +1 -0
  119. package/dist/resolvers/SearchEntitiesResolver.js +216 -0
  120. package/dist/resolvers/SearchEntitiesResolver.js.map +1 -0
  121. package/dist/resolvers/UserResolver.d.ts +16 -2
  122. package/dist/resolvers/UserResolver.d.ts.map +1 -1
  123. package/dist/resolvers/UserResolver.js +45 -2
  124. package/dist/resolvers/UserResolver.js.map +1 -1
  125. package/dist/resolvers/VectorizeEntityResolver.d.ts.map +1 -1
  126. package/dist/resolvers/VectorizeEntityResolver.js +14 -1
  127. package/dist/resolvers/VectorizeEntityResolver.js.map +1 -1
  128. package/dist/rest/SignatureWebhookHandler.d.ts +19 -0
  129. package/dist/rest/SignatureWebhookHandler.d.ts.map +1 -0
  130. package/dist/rest/SignatureWebhookHandler.js +86 -0
  131. package/dist/rest/SignatureWebhookHandler.js.map +1 -0
  132. package/dist/services/ScheduledJobsService.d.ts.map +1 -1
  133. package/dist/services/ScheduledJobsService.js +14 -2
  134. package/dist/services/ScheduledJobsService.js.map +1 -1
  135. package/package.json +79 -74
  136. package/src/__tests__/NoLog.test.ts +76 -0
  137. package/src/__tests__/bootAudit.test.ts +188 -0
  138. package/src/__tests__/boundaryLogPayload.test.ts +31 -0
  139. package/src/__tests__/getDataTokenRedaction.test.ts +84 -0
  140. package/src/__tests__/magicLink.test.ts +387 -0
  141. package/src/__tests__/secretRedactor.test.ts +163 -0
  142. package/src/__tests__/subscriptionRedaction.test.ts +217 -0
  143. package/src/apolloServer/index.ts +58 -0
  144. package/src/auth/index.ts +2 -2
  145. package/src/auth/magicLink/MagicLinkKeys.ts +122 -0
  146. package/src/auth/magicLink/MagicLinkRouter.ts +209 -0
  147. package/src/auth/magicLink/MagicLinkService.ts +724 -0
  148. package/src/auth/magicLink/index.ts +17 -0
  149. package/src/auth/magicLink/magicLinkCore.ts +216 -0
  150. package/src/auth/magicLink/redeemLanding.ts +62 -0
  151. package/src/auth/magicLink/types.ts +137 -0
  152. package/src/config.ts +89 -0
  153. package/src/context.ts +249 -17
  154. package/src/generated/generated.ts +12528 -8866
  155. package/src/generic/FireAndForgetHeartbeat.ts +85 -0
  156. package/src/generic/ResolverBase.ts +35 -7
  157. package/src/generic/__tests__/FireAndForgetHeartbeat.test.ts +99 -0
  158. package/src/index.ts +165 -2
  159. package/src/logging/NoLog.ts +88 -0
  160. package/src/logging/bootAudit.ts +117 -0
  161. package/src/logging/boundaryLogPayload.ts +19 -0
  162. package/src/logging/secretRedactor.ts +82 -0
  163. package/src/logging/shortenForLog.ts +17 -0
  164. package/src/logging/variablesLoggingMiddleware.ts +191 -0
  165. package/src/resolvers/CurrentUserContextResolver.ts +21 -5
  166. package/src/resolvers/EntityResolver.ts +17 -5
  167. package/src/resolvers/GenerateSeedTaxonomyResolver.ts +90 -0
  168. package/src/resolvers/GetDataResolver.ts +9 -5
  169. package/src/resolvers/IntegrationDiscoveryResolver.ts +1111 -120
  170. package/src/resolvers/IntegrationProgressResolver.ts +220 -0
  171. package/src/resolvers/MCPResolver.ts +18 -14
  172. package/src/resolvers/RunAIAgentResolver.ts +28 -5
  173. package/src/resolvers/RunClusterAnalysisResolver.ts +249 -0
  174. package/src/resolvers/RunTestResolver.ts +14 -2
  175. package/src/resolvers/SearchEntitiesResolver.ts +173 -0
  176. package/src/resolvers/UserResolver.ts +38 -2
  177. package/src/resolvers/VectorizeEntityResolver.ts +14 -1
  178. package/src/resolvers/__tests__/IntegrationProgressResolver.test.ts +170 -0
  179. package/src/rest/SignatureWebhookHandler.ts +103 -0
  180. package/src/services/ScheduledJobsService.ts +15 -2
@@ -0,0 +1,605 @@
1
+ /**
2
+ * @fileoverview Imperative shell for magic links: invite creation, redemption,
3
+ * user provisioning, and session-token minting. The pure logic lives in
4
+ * `magicLinkCore.ts`; this module wires it to the DB, key manager, and
5
+ * communication engine.
6
+ *
7
+ * @module @memberjunction/server/auth/magicLink
8
+ */
9
+ import { Metadata, RunView, UserInfo, LogError, LogStatus, } from '@memberjunction/core';
10
+ import { UUIDsEqual } from '@memberjunction/global';
11
+ import { UserCache } from '@memberjunction/sqlserver-dataprovider';
12
+ import { CommunicationEngine } from '@memberjunction/communication-engine';
13
+ import { Message } from '@memberjunction/communication-types';
14
+ import { configInfo } from '../../config.js';
15
+ import { MagicLinkKeyManager } from './MagicLinkKeys.js';
16
+ import { generateRawToken, generateSessionId, hashToken, evaluateInvite, buildSessionClaims, buildConsumeInviteSQL, canIssueInvites, isRoleGrantable, MAGIC_LINK_TOKEN_PREFIX } from './magicLinkCore.js';
17
+ const INVITE_ENTITY = 'MJ: Magic Link Invites';
18
+ const REDEMPTION_ENTITY = 'MJ: Magic Link Redemptions';
19
+ /** Shared Anonymous principal — seeded by the Phase-4 migration; must match that UUID. */
20
+ const ANONYMOUS_USER_ID = '273910DF-28F1-45C1-A8F8-6E9AD8E5F008';
21
+ /**
22
+ * Magic-link service. One instance per server, constructed with the resolved
23
+ * public URL and the validated config.
24
+ */
25
+ export class MagicLinkService {
26
+ constructor(publicUrl, config) {
27
+ this.publicUrl = publicUrl;
28
+ this.config = config;
29
+ }
30
+ /**
31
+ * Creates a single-use, app-scoped invite, persists its hashed token, and
32
+ * (when a communication provider is configured) emails the link.
33
+ *
34
+ * @param params invite parameters
35
+ * @param creatingUser the authenticated internal user issuing the invite
36
+ * @param provider the request's metadata provider; falls back to the global default
37
+ */
38
+ async CreateInvite(params, creatingUser, provider) {
39
+ try {
40
+ const md = provider ?? Metadata.Provider;
41
+ // Authorization: only Owners (or members of configured issuer roles) may
42
+ // mint invites. Without this, ANY authenticated user — including an
43
+ // external user already holding a restricted magic-link session — could
44
+ // issue invites and escalate.
45
+ const callerRoleNames = (creatingUser.UserRoles ?? []).map((r) => r.Role).filter((n) => !!n);
46
+ if (!canIssueInvites(creatingUser.Type, callerRoleNames, this.config.inviteIssuerRoleNames)) {
47
+ return { success: false, errorCode: 'forbidden', error: 'Not authorized to issue magic-link invites.' };
48
+ }
49
+ const roleId = params.roleId ?? this.resolveRestrictedRoleId(md);
50
+ if (!roleId) {
51
+ return { success: false, error: `Restricted role '${this.config.restrictedRoleName}' not found and no roleId supplied.` };
52
+ }
53
+ // Role allow-list: an invite may only grant the restricted role (or roles
54
+ // the deployment explicitly opted into). Blocks the escalation where a
55
+ // caller supplies the roleId of a privileged role (e.g. Owner).
56
+ const roleToGrant = md.Roles.find((r) => UUIDsEqual(r.ID, roleId));
57
+ if (!roleToGrant) {
58
+ return { success: false, errorCode: 'invalid_role', error: `Role '${roleId}' not found.` };
59
+ }
60
+ if (!isRoleGrantable(roleToGrant.Name, this.config.restrictedRoleName, this.config.grantableRoleNames)) {
61
+ return {
62
+ success: false,
63
+ errorCode: 'invalid_role',
64
+ error: `Role '${roleToGrant.Name}' is not grantable via magic-link. Add it to magicLink.grantableRoleNames to allow it.`,
65
+ };
66
+ }
67
+ const app = md.Applications.find((a) => UUIDsEqual(a.ID, params.applicationId));
68
+ if (!app) {
69
+ return { success: false, error: `Application '${params.applicationId}' not found.` };
70
+ }
71
+ const rawToken = generateRawToken();
72
+ const expiresInHours = params.expiresInHours ?? this.config.defaultExpiresInHours;
73
+ const expiresAt = new Date(Date.now() + expiresInHours * 3600 * 1000);
74
+ const invite = await md.GetEntityObject(INVITE_ENTITY, creatingUser);
75
+ invite.NewRecord();
76
+ invite.TokenHash = hashToken(rawToken);
77
+ invite.Email = params.email;
78
+ invite.ApplicationID = params.applicationId;
79
+ invite.RoleID = roleId;
80
+ invite.ExpiresAt = expiresAt;
81
+ invite.MaxUses = params.maxUses ?? 1;
82
+ invite.UseCount = 0;
83
+ invite.CreatedByUserID = creatingUser.ID;
84
+ invite.Status = 'Active';
85
+ if (!(await invite.Save())) {
86
+ return { success: false, error: `Failed to create invite: ${invite.LatestResult?.CompleteMessage ?? 'unknown error'}` };
87
+ }
88
+ // Phase 2: pre-stage the multi-scope child rows (one app + one role) mirroring
89
+ // the single ApplicationID/RoleID. Additive — the columns stay authoritative for
90
+ // redemption today; this populates the child tables for the eventual switch to
91
+ // multi-scope reads. Best-effort so a child-row hiccup never fails issuance.
92
+ await this.writeInviteScopeChildRows(invite.ID, params.applicationId, roleId, creatingUser, md);
93
+ const redemptionUrl = this.buildRedemptionUrl(rawToken);
94
+ let emailSent = false;
95
+ if (this.config.communicationProvider) {
96
+ emailSent = await this.sendInviteEmail(params.email, redemptionUrl, app.Name, creatingUser);
97
+ }
98
+ return {
99
+ success: true,
100
+ inviteId: invite.ID,
101
+ redemptionUrl,
102
+ // Surface the raw token only when we couldn't deliver it ourselves.
103
+ rawToken: emailSent ? undefined : rawToken,
104
+ emailSent,
105
+ expiresAt: expiresAt.toISOString(),
106
+ };
107
+ }
108
+ catch (e) {
109
+ LogError(e);
110
+ return { success: false, error: e instanceof Error ? e.message : String(e) };
111
+ }
112
+ }
113
+ /**
114
+ * Redeems a raw token: validates the invite, atomically consumes one use,
115
+ * provisions/links the user with the restricted role + app, and mints a
116
+ * session JWT. Runs in the public (pre-auth) path, so it uses the global
117
+ * provider and a configured provisioning context user.
118
+ *
119
+ * Single-use is enforced by a compare-and-swap UPDATE ({@link consumeInvite})
120
+ * BEFORE the token is minted — two concurrent redemptions of a single-use
121
+ * link race on the same row and exactly one wins. The consume is the gate:
122
+ * if a later step fails, the use is already burned (fail-closed). That is the
123
+ * correct trade-off for a single-use credential — burning a token on a server
124
+ * error is recoverable (re-issue); allowing replay is not.
125
+ */
126
+ async RedeemInvite(rawToken, audit) {
127
+ // Captured by the `done` closure below so every exit path — success or any
128
+ // failure — records exactly one MagicLinkRedemption row with the outcome and
129
+ // whatever attribution we'd resolved by then.
130
+ let inviteId;
131
+ let provisionedUserId;
132
+ let ctxUser = null;
133
+ const done = async (result) => {
134
+ await this.recordRedemption(result, inviteId, provisionedUserId, audit, ctxUser);
135
+ return result;
136
+ };
137
+ try {
138
+ if (!rawToken || !rawToken.startsWith(MAGIC_LINK_TOKEN_PREFIX)) {
139
+ return done({ success: false, errorCode: 'invalid', error: 'Malformed token.' });
140
+ }
141
+ ctxUser = this.resolveProvisioningContextUser();
142
+ if (!ctxUser) {
143
+ LogError('[MagicLink] No provisioning context user available for redemption.');
144
+ return done({ success: false, errorCode: 'server_error', error: 'Server not configured for provisioning.' });
145
+ }
146
+ const contextUser = ctxUser;
147
+ // global-provider-ok: redemption runs in the pre-auth flow, no per-request provider yet
148
+ const md = Metadata.Provider; // global-provider-ok: server-side magic-link service; runs under the server's single default provider
149
+ const provider = md;
150
+ const tokenHash = hashToken(rawToken);
151
+ const rv = new RunView();
152
+ const found = await rv.RunView({
153
+ EntityName: INVITE_ENTITY,
154
+ ExtraFilter: `TokenHash = '${tokenHash}'`,
155
+ ResultType: 'entity_object',
156
+ }, contextUser);
157
+ if (!found.Success) {
158
+ LogError(`[MagicLink] Invite lookup failed: ${found.ErrorMessage}`);
159
+ return done({ success: false, errorCode: 'server_error', error: 'Lookup failed.' });
160
+ }
161
+ const invite = found.Results?.[0];
162
+ if (!invite) {
163
+ return done({ success: false, errorCode: 'not_found', error: 'Invite not found.' });
164
+ }
165
+ inviteId = invite.ID;
166
+ // Fast, friendly pre-check (returns a precise reason). NOT the authority —
167
+ // the atomic consume below is what actually enforces single-use.
168
+ const eligibility = evaluateInvite(invite, Date.now());
169
+ if (!eligibility.ok) {
170
+ return done({ success: false, errorCode: eligibility.errorCode, error: `Invite is ${eligibility.errorCode}.` });
171
+ }
172
+ // Fail-closed on the inviter: if the user who issued this link is no longer
173
+ // an active account, the link dies with them. Without this, a deactivated
174
+ // employee's outstanding invites would keep working (and provisioning would
175
+ // silently fall back to an Owner context). The invite is only as trustworthy
176
+ // as the still-active person who minted it.
177
+ if (!this.isInviterActive(invite.CreatedByUserID)) {
178
+ LogError(`[MagicLink] Invite ${invite.ID} rejected: inviter ${invite.CreatedByUserID} is not an active user.`);
179
+ return done({ success: false, errorCode: 'invalid', error: 'The user who issued this invite is no longer active.' });
180
+ }
181
+ const role = md.Roles.find((r) => UUIDsEqual(r.ID, invite.RoleID));
182
+ if (!role) {
183
+ LogError(`[MagicLink] Invite ${invite.ID} references missing role ${invite.RoleID}.`);
184
+ return done({ success: false, errorCode: 'server_error', error: 'Invite role not found.' });
185
+ }
186
+ // Atomic consume BEFORE minting. If we lose the race (0 rows updated), the
187
+ // invite was concurrently consumed/expired — re-evaluate the now-stale
188
+ // in-memory copy only to surface a precise code; default to 'consumed'.
189
+ if (!(await this.consumeInvite(invite, provider, contextUser))) {
190
+ // Lost the race or the invite expired between the pre-check and the
191
+ // consume. The in-memory copy still looks eligible if only the DB-side
192
+ // use count changed, so default that case to 'consumed'.
193
+ const recheck = evaluateInvite(invite, Date.now());
194
+ return done({ success: false, errorCode: recheck.ok ? 'consumed' : recheck.errorCode, error: 'Invite already redeemed or expired.' });
195
+ }
196
+ const provision = await this.provisionUser(invite, role, contextUser);
197
+ if (!provision.success) {
198
+ // Token already consumed (fail-closed). The link cannot be reused.
199
+ LogError(`[MagicLink] Provisioning failed after consuming invite ${invite.ID}: ${provision.error}`);
200
+ return done({ success: false, errorCode: 'provisioning_failed', error: provision.error });
201
+ }
202
+ provisionedUserId = provision.userId;
203
+ const nowSeconds = Math.floor(Date.now() / 1000);
204
+ const isAnon = invite.IdentityMode === 'anonymous';
205
+ const claims = buildSessionClaims({
206
+ issuer: this.publicUrl,
207
+ audience: this.config.audience,
208
+ inviteId: invite.ID,
209
+ email: provision.email,
210
+ firstName: provision.firstName,
211
+ lastName: provision.lastName,
212
+ applicationId: invite.ApplicationID,
213
+ roleName: role.Name,
214
+ invitedByUserId: invite.CreatedByUserID,
215
+ anonymous: isAnon,
216
+ // Per-session id for anon forensics (correlates one session's activity since all
217
+ // anon redemptions share the Anonymous principal). Carried into the redemption audit row.
218
+ sessionId: isAnon ? generateSessionId() : undefined,
219
+ // Resource-share scope (Phase 5): the single shared resource this link grants.
220
+ resourceId: invite.ResourceID ?? undefined,
221
+ nowSeconds,
222
+ ttlSeconds: this.config.sessionTokenTtlHours * 3600,
223
+ });
224
+ const token = MagicLinkKeyManager.Instance.Sign(claims);
225
+ const app = md.Applications.find((a) => UUIDsEqual(a.ID, invite.ApplicationID));
226
+ return done({
227
+ success: true,
228
+ token,
229
+ expiresAt: new Date(claims.exp * 1000).toISOString(),
230
+ applicationId: invite.ApplicationID,
231
+ applicationName: app?.Name,
232
+ applicationPath: app?.Path || undefined,
233
+ email: provision.email,
234
+ });
235
+ }
236
+ catch (e) {
237
+ LogError(e);
238
+ return done({ success: false, errorCode: 'server_error', error: e instanceof Error ? e.message : String(e) });
239
+ }
240
+ }
241
+ /**
242
+ * Writes one MagicLinkRedemption audit row for a redemption attempt. Best-effort:
243
+ * a failure here is logged but never fails the redemption (the user already has,
244
+ * or has been denied, their session — losing an audit row must not change that).
245
+ *
246
+ * InviteID/ProvisionedUserID are null when the attempt didn't get far enough to
247
+ * resolve them (e.g. a malformed or unknown token — exactly the scan/brute-force
248
+ * signal we want recorded). IP/User-Agent/Origin are stored as supplied by the
249
+ * router per the deployment's audit policy.
250
+ */
251
+ async recordRedemption(result, inviteId, provisionedUserId, audit, contextUser) {
252
+ try {
253
+ const ctx = contextUser ?? this.resolveProvisioningContextUser();
254
+ if (!ctx) {
255
+ LogError('[MagicLink] Cannot record redemption audit row: no context user available.');
256
+ return;
257
+ }
258
+ // global-provider-ok: redemption runs pre-auth, no per-request provider yet.
259
+ const md = Metadata.Provider; // global-provider-ok: server-side magic-link service; runs under the server's single default provider
260
+ const row = await md.GetEntityObject(REDEMPTION_ENTITY, ctx);
261
+ row.NewRecord();
262
+ if (inviteId) {
263
+ row.InviteID = inviteId;
264
+ }
265
+ row.AttemptedAt = new Date();
266
+ row.Outcome = result.success ? 'success' : result.errorCode ?? 'server_error';
267
+ row.IPAddress = audit?.ipAddress ?? null;
268
+ row.UserAgent = audit?.userAgent ?? null;
269
+ row.Origin = audit?.origin ?? null;
270
+ if (provisionedUserId) {
271
+ row.ProvisionedUserID = provisionedUserId;
272
+ }
273
+ if (!(await row.Save())) {
274
+ LogError(`[MagicLink] Failed to write redemption audit row: ${row.LatestResult?.CompleteMessage ?? 'unknown error'}`);
275
+ }
276
+ }
277
+ catch (e) {
278
+ LogError(`[MagicLink] Redemption audit write threw: ${e instanceof Error ? e.message : String(e)}`);
279
+ }
280
+ }
281
+ /**
282
+ * Writes the Phase-2 multi-scope child rows (one application + one role) that
283
+ * mirror the invite's single ApplicationID/RoleID. The columns remain the
284
+ * source of truth for redemption today; these rows pre-stage the data for the
285
+ * eventual switch to multi-scope reads, avoiding a breaking migration later.
286
+ * Best-effort: a child-write failure is logged but does not fail invite
287
+ * issuance (the columns alone keep the one-of-each flow working).
288
+ */
289
+ async writeInviteScopeChildRows(inviteId, applicationId, roleId, creatingUser, md) {
290
+ try {
291
+ const appRow = await md.GetEntityObject('MJ: Magic Link Invite Applications', creatingUser);
292
+ appRow.NewRecord();
293
+ appRow.InviteID = inviteId;
294
+ appRow.ApplicationID = applicationId;
295
+ if (!(await appRow.Save())) {
296
+ LogError(`[MagicLink] Failed to write invite-application child row: ${appRow.LatestResult?.CompleteMessage ?? 'unknown error'}`);
297
+ }
298
+ const roleRow = await md.GetEntityObject('MJ: Magic Link Invite Roles', creatingUser);
299
+ roleRow.NewRecord();
300
+ roleRow.InviteID = inviteId;
301
+ roleRow.RoleID = roleId;
302
+ if (!(await roleRow.Save())) {
303
+ LogError(`[MagicLink] Failed to write invite-role child row: ${roleRow.LatestResult?.CompleteMessage ?? 'unknown error'}`);
304
+ }
305
+ }
306
+ catch (e) {
307
+ LogError(`[MagicLink] Writing invite scope child rows threw: ${e instanceof Error ? e.message : String(e)}`);
308
+ }
309
+ }
310
+ /** Resolves the configured restricted role's ID, if present. */
311
+ resolveRestrictedRoleId(md) {
312
+ const name = this.config.restrictedRoleName.trim().toLowerCase();
313
+ const role = md.Roles.find((r) => r.Name.trim().toLowerCase() === name);
314
+ return role?.ID;
315
+ }
316
+ /** Builds the shareable redemption URL. */
317
+ buildRedemptionUrl(rawToken) {
318
+ const base = this.publicUrl.replace(/\/$/, '');
319
+ return `${base}/magic-link/redeem?token=${encodeURIComponent(rawToken)}`;
320
+ }
321
+ /**
322
+ * Provisions the redeeming user: finds them by email or creates them, then
323
+ * ensures the restricted role and the single app assignment exist.
324
+ */
325
+ async provisionUser(invite, role, contextUser) {
326
+ // Ensure the invite's role can ACCESS the invite's app (Application Role with
327
+ // CanAccess) — otherwise Explorer's app-access gate bounces the user off the
328
+ // scoped app to a default. The invite is the authorization for that role to
329
+ // reach that app. Idempotent + role/app-level (independent of the user/identity mode).
330
+ await this.ensureAppAccess(invite.RoleID, invite.ApplicationID, contextUser);
331
+ // Anonymous mode: resolve the shared Anonymous principal. CRITICALLY, we do NOT
332
+ // write any UserRole/UserApplication for it — the anon user must never accrete
333
+ // scope (that would make every anon visitor a superuser). Scope rides on the
334
+ // per-session JWT claims; enforcement is claims-based, not role-based.
335
+ if (invite.IdentityMode === 'anonymous') {
336
+ return this.resolveAnonymousPrincipal();
337
+ }
338
+ const email = invite.Email;
339
+ if (!email) {
340
+ return { success: false, error: 'Email-mode invite is missing an email address.' };
341
+ }
342
+ const existing = UserCache.Instance.Users.find((u) => !!u.Email && u.Email.trim().toLowerCase() === email.trim().toLowerCase());
343
+ if (existing) {
344
+ // Provisioning guard: never silently attach an external role/app to a
345
+ // privileged existing account (Owner, or anyone holding a role OUTSIDE the
346
+ // set of roles magic-link may legitimately grant). The invite's own granted
347
+ // role is part of that allowed set, so a prior magic-link guest holding only
348
+ // that role can re-redeem a multi-use link.
349
+ if (this.isProtectedAccount(existing, role.Name)) {
350
+ const detail = `existing account '${existing.Email}' is an Owner or already holds non-restricted roles`;
351
+ if (this.config.provisioningGuard === 'block') {
352
+ LogError(`[MagicLink] Blocked provisioning onto protected account: ${detail} (provisioningGuard=block).`);
353
+ return { success: false, error: 'This email matches an existing privileged account; magic-link provisioning was blocked.' };
354
+ }
355
+ LogError(`[MagicLink] WARNING: provisioning external scope onto protected account — ${detail} (provisioningGuard=warn); proceeding.`);
356
+ }
357
+ const ok = await this.ensureRoleAndApp(existing.ID, invite.RoleID, invite.ApplicationID, contextUser);
358
+ return ok
359
+ ? { success: true, userId: existing.ID, email: existing.Email, firstName: existing.FirstName ?? undefined, lastName: existing.LastName ?? undefined }
360
+ : { success: false, error: 'Failed to assign role/application to existing user.' };
361
+ }
362
+ return this.createScopedUser(invite, role, contextUser);
363
+ }
364
+ /**
365
+ * Resolves the shared Anonymous principal for an anonymous-mode redemption. This
366
+ * principal is an ATTRIBUTION ANCHOR only — it holds no scenario roles and gets no
367
+ * UserRole/UserApplication rows here, so concurrent anon visitors can never accrete
368
+ * scope onto a shared identity. Their actual scope lives in the per-session JWT
369
+ * claims (mj_scopes) and is enforced claims-side. Fail-closed if the principal was
370
+ * never seeded (the Phase-4 migration is required).
371
+ */
372
+ resolveAnonymousPrincipal() {
373
+ const anon = UserCache.Instance.Users.find((u) => UUIDsEqual(u.ID, ANONYMOUS_USER_ID));
374
+ if (!anon) {
375
+ LogError(`[MagicLink] Anonymous principal ${ANONYMOUS_USER_ID} not found in cache; run the Phase-4 migration.`);
376
+ return { success: false, error: 'Anonymous access is not configured on this server.' };
377
+ }
378
+ return { success: true, userId: anon.ID, email: anon.Email ?? undefined, firstName: 'Anonymous', lastName: undefined };
379
+ }
380
+ /**
381
+ * True if an existing account is "protected" from magic-link provisioning: an
382
+ * Owner, or a user holding any role OUTSIDE the set of roles magic-link may
383
+ * legitimately grant. That allowed set is: the configured restricted role, the
384
+ * deployment's `grantableRoleNames`, AND the role THIS invite grants. So a prior
385
+ * magic-link guest holding only magic-link-grantable roles (e.g. the invite's own
386
+ * granted role) is NOT protected — re-redeeming a multi-use link is the intended
387
+ * flow. A user holding e.g. Developer/Admin is still protected and blocked.
388
+ *
389
+ * @param user the existing account being re-provisioned
390
+ * @param invitedRoleName the role name this invite grants
391
+ */
392
+ isProtectedAccount(user, invitedRoleName) {
393
+ if ((user.Type ?? '').trim().toLowerCase() === 'owner') {
394
+ return true;
395
+ }
396
+ const allowed = new Set([this.config.restrictedRoleName, ...this.config.grantableRoleNames, invitedRoleName]
397
+ .filter((n) => !!n)
398
+ .map((n) => n.trim().toLowerCase()));
399
+ return (user.UserRoles ?? []).some((r) => !!r.Role && !allowed.has(r.Role.trim().toLowerCase()));
400
+ }
401
+ /** Creates a new user with exactly the restricted role + single app, transactionally. */
402
+ async createScopedUser(invite, role, contextUser) {
403
+ // Single provider for BOTH the transaction and the entity writes, so the
404
+ // BeginTransaction/Save/Commit are provably on the same connection.
405
+ // global-provider-ok: redemption runs in the pre-auth flow, no per-request provider yet.
406
+ const provider = Metadata.Provider; // global-provider-ok: server-side magic-link service; runs under the server's single default provider
407
+ const email = invite.Email;
408
+ // The invite does not persist a name; provision a sensible default. (The
409
+ // create-invite params accept first/last name but there is no column to
410
+ // store them yet — see types.ts CreateMagicLinkInviteParams.)
411
+ const firstName = 'Guest';
412
+ const lastName = email;
413
+ await provider.BeginTransaction();
414
+ try {
415
+ const user = await provider.GetEntityObject('MJ: Users', contextUser);
416
+ user.NewRecord();
417
+ user.Name = email;
418
+ user.Email = email;
419
+ user.FirstName = firstName;
420
+ user.LastName = lastName;
421
+ user.Type = 'User';
422
+ user.IsActive = true;
423
+ if (!(await user.Save())) {
424
+ throw new Error(`user save failed: ${user.LatestResult?.CompleteMessage ?? 'unknown'}`);
425
+ }
426
+ const userRole = await provider.GetEntityObject('MJ: User Roles', contextUser);
427
+ userRole.NewRecord();
428
+ userRole.UserID = user.ID;
429
+ userRole.RoleID = invite.RoleID;
430
+ if (!(await userRole.Save())) {
431
+ throw new Error(`user role save failed: ${userRole.LatestResult?.CompleteMessage ?? 'unknown'}`);
432
+ }
433
+ const userApp = await provider.GetEntityObject('MJ: User Applications', contextUser);
434
+ userApp.NewRecord();
435
+ userApp.UserID = user.ID;
436
+ userApp.ApplicationID = invite.ApplicationID;
437
+ userApp.Sequence = 0;
438
+ userApp.IsActive = true;
439
+ if (!(await userApp.Save())) {
440
+ throw new Error(`user application save failed: ${userApp.LatestResult?.CompleteMessage ?? 'unknown'}`);
441
+ }
442
+ await provider.CommitTransaction();
443
+ // Seed the UserCache so the very next request (carrying the minted JWT)
444
+ // resolves this user without a full cache refresh.
445
+ this.pushUserToCache(user, role);
446
+ LogStatus(`[MagicLink] Provisioned external user ${email} with role '${role.Name}'.`);
447
+ return { success: true, userId: user.ID, email, firstName, lastName };
448
+ }
449
+ catch (txErr) {
450
+ await provider.RollbackTransaction();
451
+ LogError(txErr);
452
+ return { success: false, error: txErr instanceof Error ? txErr.message : String(txErr) };
453
+ }
454
+ }
455
+ /** Idempotently ensures an existing user has the given role and app assignment. */
456
+ async ensureRoleAndApp(userId, roleId, applicationId, contextUser) {
457
+ try {
458
+ const md = new Metadata(); // global-provider-ok: server-side magic-link provisioning; runs under the server's single default provider
459
+ const rv = new RunView();
460
+ const [roleRes, appRes] = await rv.RunViews([
461
+ { EntityName: 'MJ: User Roles', ExtraFilter: `UserID = '${userId}' AND RoleID = '${roleId}'`, ResultType: 'simple' },
462
+ { EntityName: 'MJ: User Applications', ExtraFilter: `UserID = '${userId}' AND ApplicationID = '${applicationId}'`, ResultType: 'simple' },
463
+ ], contextUser);
464
+ if (roleRes.Success && (roleRes.Results?.length ?? 0) === 0) {
465
+ const userRole = await md.GetEntityObject('MJ: User Roles', contextUser);
466
+ userRole.NewRecord();
467
+ userRole.UserID = userId;
468
+ userRole.RoleID = roleId;
469
+ if (!(await userRole.Save())) {
470
+ LogError(`[MagicLink] Failed to add role to existing user: ${userRole.LatestResult?.CompleteMessage}`);
471
+ return false;
472
+ }
473
+ }
474
+ if (appRes.Success && (appRes.Results?.length ?? 0) === 0) {
475
+ const userApp = await md.GetEntityObject('MJ: User Applications', contextUser);
476
+ userApp.NewRecord();
477
+ userApp.UserID = userId;
478
+ userApp.ApplicationID = applicationId;
479
+ userApp.Sequence = 0;
480
+ userApp.IsActive = true;
481
+ if (!(await userApp.Save())) {
482
+ LogError(`[MagicLink] Failed to add application to existing user: ${userApp.LatestResult?.CompleteMessage}`);
483
+ return false;
484
+ }
485
+ }
486
+ return true;
487
+ }
488
+ catch (e) {
489
+ LogError(e);
490
+ return false;
491
+ }
492
+ }
493
+ /** Idempotently ensures the role has CanAccess to the application (Application Role). */
494
+ async ensureAppAccess(roleId, applicationId, contextUser) {
495
+ try {
496
+ const rv = new RunView();
497
+ const res = await rv.RunView({
498
+ EntityName: 'MJ: Application Roles',
499
+ ExtraFilter: `RoleID = '${roleId}' AND ApplicationID = '${applicationId}'`,
500
+ ResultType: 'simple',
501
+ }, contextUser);
502
+ if (res.Success && (res.Results?.length ?? 0) > 0) {
503
+ return; // already granted
504
+ }
505
+ const md = new Metadata(); // global-provider-ok: server-side magic-link provisioning; runs under the server's single default provider
506
+ const appRole = await md.GetEntityObject('MJ: Application Roles', contextUser);
507
+ appRole.NewRecord();
508
+ appRole.ApplicationID = applicationId;
509
+ appRole.RoleID = roleId;
510
+ appRole.CanAccess = true;
511
+ appRole.CanAdmin = false;
512
+ if (!(await appRole.Save())) {
513
+ LogError(`[MagicLink] Failed to grant app access: ${appRole.LatestResult?.CompleteMessage ?? 'unknown'}`);
514
+ }
515
+ }
516
+ catch (e) {
517
+ LogError(e);
518
+ }
519
+ }
520
+ /**
521
+ * Atomically consumes one use of the invite via a compare-and-swap UPDATE.
522
+ * The WHERE clause re-checks every eligibility condition (Active, not
523
+ * exhausted, not expired) at the DB level, so the increment and the guard are
524
+ * a single atomic operation. Returns true ONLY when this call updated the row
525
+ * (won the race); concurrent redemptions of a single-use link see 0 rows.
526
+ *
527
+ * Fail-closed: any DB error returns false and the redemption is rejected.
528
+ */
529
+ async consumeInvite(invite, provider, contextUser) {
530
+ try {
531
+ const entityInfo = provider.EntityByName(INVITE_ENTITY);
532
+ if (!entityInfo) {
533
+ LogError(`[MagicLink] Entity metadata for '${INVITE_ENTITY}' not found; cannot consume invite.`);
534
+ return false;
535
+ }
536
+ const table = `[${entityInfo.SchemaName}].[${entityInfo.BaseTable}]`;
537
+ // OUTPUT returns one row iff the WHERE matched — the atomic single-use gate.
538
+ const sql = buildConsumeInviteSQL(table);
539
+ const rows = await provider.ExecuteSQL(sql, [invite.ID], { isMutation: true }, contextUser);
540
+ return Array.isArray(rows) && rows.length === 1;
541
+ }
542
+ catch (e) {
543
+ LogError(`[MagicLink] Atomic consume failed for invite ${invite.ID}: ${e instanceof Error ? e.message : String(e)}`);
544
+ return false;
545
+ }
546
+ }
547
+ /** Pushes a freshly created user into the UserCache with its single role. */
548
+ pushUserToCache(user, role) {
549
+ const initData = user.GetAll();
550
+ initData.UserRoles = [{ UserID: user.ID, RoleName: role.Name, RoleID: role.ID }];
551
+ const ui = new UserInfo(Metadata.Provider, initData); // global-provider-ok: redemption runs pre-auth, seeding the shared cache
552
+ UserCache.Instance.Users.push(ui);
553
+ }
554
+ /**
555
+ * True iff the invite's creator resolves to a still-active user. Used to
556
+ * fail-closed at redeem time so a deactivated/removed inviter's outstanding
557
+ * links stop working. A missing/blank CreatedByUserID is treated as inactive.
558
+ */
559
+ isInviterActive(createdByUserId) {
560
+ if (!createdByUserId) {
561
+ return false;
562
+ }
563
+ const inviter = UserCache.Instance.Users.find((u) => UUIDsEqual(u.ID, createdByUserId));
564
+ return !!inviter && inviter.IsActive === true;
565
+ }
566
+ /** Resolves the user whose context provisions magic-link users. */
567
+ resolveProvisioningContextUser() {
568
+ const candidate = this.config.contextUserForProvisioning || configInfo.userHandling?.contextUserForNewUserCreation;
569
+ if (candidate) {
570
+ const byName = UserCache.Instance.UserByName(candidate);
571
+ if (byName) {
572
+ return byName;
573
+ }
574
+ LogError(`[MagicLink] Configured provisioning user '${candidate}' not found; falling back to an Owner.`);
575
+ }
576
+ return UserCache.Users.find((u) => u.Type?.trim().toLowerCase() === 'owner') ?? null;
577
+ }
578
+ /** Sends the invite email via the configured communication provider. Best-effort. */
579
+ async sendInviteEmail(email, redemptionUrl, appName, contextUser) {
580
+ try {
581
+ const engine = CommunicationEngine.Instance;
582
+ await engine.Config(false, contextUser);
583
+ const msg = new Message();
584
+ msg.From = this.config.fromAddress ?? '';
585
+ msg.To = email;
586
+ msg.Subject = `You've been invited to ${appName}`;
587
+ msg.Body = `You've been invited to access ${appName}. Open this link to sign in:\n\n${redemptionUrl}\n\nThis link is single-use and will expire.`;
588
+ msg.HTMLBody =
589
+ `<p>You've been invited to access <strong>${appName}</strong>.</p>` +
590
+ `<p><a href="${redemptionUrl}">Click here to sign in</a></p>` +
591
+ `<p>This link is single-use and will expire.</p>`;
592
+ const result = await engine.SendSingleMessage(this.config.communicationProvider, 'Email', msg);
593
+ if (!result?.Success) {
594
+ LogError(`[MagicLink] Email send failed: ${result?.Error ?? 'unknown error'}`);
595
+ return false;
596
+ }
597
+ return true;
598
+ }
599
+ catch (e) {
600
+ LogError(`[MagicLink] Email send threw: ${e instanceof Error ? e.message : String(e)}`);
601
+ return false;
602
+ }
603
+ }
604
+ }
605
+ //# sourceMappingURL=MagicLinkService.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MagicLinkService.js","sourceRoot":"","sources":["../../../src/auth/magicLink/MagicLinkService.ts"],"names":[],"mappings":"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"}