fluxmail 0.4.0 → 0.5.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 (108) hide show
  1. package/README.md +7 -5
  2. package/dist/accounts/defaultGoogleOAuth.d.ts +4 -0
  3. package/dist/accounts/defaultGoogleOAuth.d.ts.map +1 -0
  4. package/dist/accounts/defaultGoogleOAuth.js +7 -0
  5. package/dist/accounts/defaultGoogleOAuth.js.map +1 -0
  6. package/dist/accounts/gmailConnection.js +2 -2
  7. package/dist/accounts/gmailConnection.js.map +1 -1
  8. package/dist/accounts/googleAuth.d.ts +10 -7
  9. package/dist/accounts/googleAuth.d.ts.map +1 -1
  10. package/dist/accounts/googleAuth.js +48 -17
  11. package/dist/accounts/googleAuth.js.map +1 -1
  12. package/dist/accounts/microsoftAuth.js +1 -1
  13. package/dist/accounts/microsoftAuth.js.map +1 -1
  14. package/dist/accounts/registry.d.ts +9 -8
  15. package/dist/accounts/registry.d.ts.map +1 -1
  16. package/dist/accounts/registry.js +166 -96
  17. package/dist/accounts/registry.js.map +1 -1
  18. package/dist/auth.d.ts +106 -0
  19. package/dist/auth.d.ts.map +1 -0
  20. package/dist/auth.js +452 -0
  21. package/dist/auth.js.map +1 -0
  22. package/dist/authorization.d.ts +9 -0
  23. package/dist/authorization.d.ts.map +1 -0
  24. package/dist/authorization.js +23 -0
  25. package/dist/authorization.js.map +1 -0
  26. package/dist/cli.d.ts +7 -1
  27. package/dist/cli.d.ts.map +1 -1
  28. package/dist/cli.js +734 -358
  29. package/dist/cli.js.map +1 -1
  30. package/dist/cliInstances.d.ts +37 -0
  31. package/dist/cliInstances.d.ts.map +1 -0
  32. package/dist/cliInstances.js +170 -0
  33. package/dist/cliInstances.js.map +1 -0
  34. package/dist/config.d.ts +16 -10
  35. package/dist/config.d.ts.map +1 -1
  36. package/dist/config.js +125 -35
  37. package/dist/config.js.map +1 -1
  38. package/dist/context.d.ts.map +1 -1
  39. package/dist/context.js +8 -4
  40. package/dist/context.js.map +1 -1
  41. package/dist/http/admin.d.ts +57 -3
  42. package/dist/http/admin.d.ts.map +1 -1
  43. package/dist/http/admin.js +188 -67
  44. package/dist/http/admin.js.map +1 -1
  45. package/dist/http/app.d.ts.map +1 -1
  46. package/dist/http/app.js +78 -54
  47. package/dist/http/app.js.map +1 -1
  48. package/dist/http/identity.d.ts +114 -0
  49. package/dist/http/identity.d.ts.map +1 -0
  50. package/dist/http/identity.js +931 -0
  51. package/dist/http/identity.js.map +1 -0
  52. package/dist/http/operationRoutes.d.ts +8 -0
  53. package/dist/http/operationRoutes.d.ts.map +1 -0
  54. package/dist/http/operationRoutes.js +13 -0
  55. package/dist/http/operationRoutes.js.map +1 -0
  56. package/dist/http/rest.d.ts +11 -3
  57. package/dist/http/rest.d.ts.map +1 -1
  58. package/dist/http/rest.js +138 -66
  59. package/dist/http/rest.js.map +1 -1
  60. package/dist/index.d.ts +4 -3
  61. package/dist/index.d.ts.map +1 -1
  62. package/dist/index.js +4 -3
  63. package/dist/index.js.map +1 -1
  64. package/dist/mcp/buildServer.d.ts +1 -1
  65. package/dist/mcp/buildServer.d.ts.map +1 -1
  66. package/dist/mcp/buildServer.js +14 -19
  67. package/dist/mcp/buildServer.js.map +1 -1
  68. package/dist/permissions.d.ts +1 -1
  69. package/dist/permissions.d.ts.map +1 -1
  70. package/dist/permissions.js +7 -1
  71. package/dist/permissions.js.map +1 -1
  72. package/dist/scheduler/sendScheduler.d.ts +1 -2
  73. package/dist/scheduler/sendScheduler.d.ts.map +1 -1
  74. package/dist/scheduler/sendScheduler.js +1 -2
  75. package/dist/scheduler/sendScheduler.js.map +1 -1
  76. package/dist/service/emailService.d.ts +8 -16
  77. package/dist/service/emailService.d.ts.map +1 -1
  78. package/dist/service/emailService.js +25 -38
  79. package/dist/service/emailService.js.map +1 -1
  80. package/dist/storage/adminAudit.d.ts +15 -2
  81. package/dist/storage/adminAudit.d.ts.map +1 -1
  82. package/dist/storage/adminAudit.js +22 -27
  83. package/dist/storage/adminAudit.js.map +1 -1
  84. package/dist/storage/apiKeys.d.ts +8 -8
  85. package/dist/storage/apiKeys.d.ts.map +1 -1
  86. package/dist/storage/apiKeys.js +16 -11
  87. package/dist/storage/apiKeys.js.map +1 -1
  88. package/dist/storage/db.d.ts +593 -31
  89. package/dist/storage/db.d.ts.map +1 -1
  90. package/dist/storage/db.js +330 -45
  91. package/dist/storage/db.js.map +1 -1
  92. package/dist/storage/fileLock.d.ts +7 -0
  93. package/dist/storage/fileLock.d.ts.map +1 -0
  94. package/dist/storage/fileLock.js +183 -0
  95. package/dist/storage/fileLock.js.map +1 -0
  96. package/dist/storage/gmailConnectionGrants.d.ts +3 -4
  97. package/dist/storage/gmailConnectionGrants.d.ts.map +1 -1
  98. package/dist/storage/gmailConnectionGrants.js +6 -6
  99. package/dist/storage/gmailConnectionGrants.js.map +1 -1
  100. package/dist/storage/members.d.ts +11 -0
  101. package/dist/storage/members.d.ts.map +1 -1
  102. package/dist/storage/members.js +70 -6
  103. package/dist/storage/members.js.map +1 -1
  104. package/dist/telemetry.d.ts +14 -0
  105. package/dist/telemetry.d.ts.map +1 -1
  106. package/dist/telemetry.js +22 -0
  107. package/dist/telemetry.js.map +1 -1
  108. package/package.json +9 -8
package/dist/auth.js ADDED
@@ -0,0 +1,452 @@
1
+ import { createHash, randomBytes } from 'node:crypto';
2
+ import { hostname } from 'node:os';
3
+ import { hash, verify } from '@node-rs/argon2';
4
+ import { and, eq, gt, isNull, lte, sql } from 'drizzle-orm';
5
+ import { EmailError } from '@fluxmail/core';
6
+ import { accounts, apiKeys, authRateLimits, instanceSettings, memberAuthTokens, memberCredentials, memberSessions, members, } from './storage/db.js';
7
+ import { authenticateApiKey } from './storage/apiKeys.js';
8
+ import { addMember, findMember, getMember } from './storage/members.js';
9
+ import { FULL_PERMISSION_POLICY } from './permissions.js';
10
+ import { assertMemberLimit, getEntitlements } from './licensing/entitlements.js';
11
+ const SESSION_TTL_MS = 90 * 24 * 60 * 60 * 1000;
12
+ const ENROLLMENT_TTL_MS = 7 * 24 * 60 * 60 * 1000;
13
+ const PASSWORD_RESET_TTL_MS = 60 * 60 * 1000;
14
+ const RATE_WINDOW_MS = 15 * 60 * 1000;
15
+ const SESSION_TOUCH_INTERVAL_MS = 60 * 60 * 1000;
16
+ const COMMON_PASSWORDS = new Set([
17
+ '123456789012345',
18
+ 'correcthorsebatterystaple',
19
+ 'letmeinletmeinletmein',
20
+ 'passwordpassword',
21
+ 'qwertyqwertyqwerty',
22
+ ]);
23
+ const ARGON_OPTIONS = {
24
+ algorithm: 2,
25
+ memoryCost: 19_456,
26
+ timeCost: 2,
27
+ parallelism: 1,
28
+ outputLen: 32,
29
+ };
30
+ const dummyPasswordHash = hash('fluxmail-invalid-login-padding', ARGON_OPTIONS);
31
+ function secretHash(secret) {
32
+ return createHash('sha256').update(secret).digest('hex');
33
+ }
34
+ function normalizedEmail(email) {
35
+ const normalized = email.trim().toLowerCase();
36
+ if (normalized.length > 320 || !/^[^\s@]+@[^\s@]+\.[^\s@]+$/u.test(normalized)) {
37
+ throw new EmailError('invalid_request', 'Enter a valid member email address.');
38
+ }
39
+ return normalized;
40
+ }
41
+ function rateKey(kind, value) {
42
+ return `${kind}:${secretHash(value.trim().toLowerCase())}`;
43
+ }
44
+ function reserveLoginAttempt(db, emailKey, ipKey, now) {
45
+ return db.transaction((tx) => {
46
+ tx.delete(authRateLimits)
47
+ .where(lte(authRateLimits.windowStartedAt, now - RATE_WINDOW_MS))
48
+ .run();
49
+ const emailRow = tx.select().from(authRateLimits).where(eq(authRateLimits.key, emailKey)).get();
50
+ const ipRow = tx.select().from(authRateLimits).where(eq(authRateLimits.key, ipKey)).get();
51
+ if ((emailRow?.attempts ?? 0) >= 5 || (ipRow?.attempts ?? 0) >= 30)
52
+ return null;
53
+ const reserve = (key, row) => {
54
+ if (!row) {
55
+ tx.insert(authRateLimits).values({ key, attempts: 1, windowStartedAt: now }).run();
56
+ return now;
57
+ }
58
+ tx.update(authRateLimits)
59
+ .set({ attempts: row.attempts + 1 })
60
+ .where(eq(authRateLimits.key, key))
61
+ .run();
62
+ return row.windowStartedAt;
63
+ };
64
+ reserve(emailKey, emailRow);
65
+ return { ipWindowStartedAt: reserve(ipKey, ipRow) };
66
+ });
67
+ }
68
+ function releaseLoginAttempt(db, key, windowStartedAt) {
69
+ db.transaction((tx) => {
70
+ const row = tx
71
+ .select()
72
+ .from(authRateLimits)
73
+ .where(and(eq(authRateLimits.key, key), eq(authRateLimits.windowStartedAt, windowStartedAt)))
74
+ .get();
75
+ if (!row)
76
+ return;
77
+ if (row.attempts <= 1) {
78
+ tx.delete(authRateLimits).where(eq(authRateLimits.key, key)).run();
79
+ return;
80
+ }
81
+ tx.update(authRateLimits)
82
+ .set({ attempts: row.attempts - 1 })
83
+ .where(and(eq(authRateLimits.key, key), eq(authRateLimits.windowStartedAt, windowStartedAt)))
84
+ .run();
85
+ });
86
+ }
87
+ export function normalizeAndValidatePassword(password, member) {
88
+ const normalized = password.normalize('NFC');
89
+ const length = [...normalized].length;
90
+ if (length < 15 || length > 256) {
91
+ throw new EmailError('invalid_request', 'Password must contain between 15 and 256 characters.');
92
+ }
93
+ const lower = normalized.toLowerCase();
94
+ const context = [member?.name, member?.email, member?.email?.split('@')[0], 'fluxmail']
95
+ .filter((value) => Boolean(value && value.length >= 3))
96
+ .map((value) => value.toLowerCase());
97
+ if (COMMON_PASSWORDS.has(lower.trim()) || context.some((value) => lower.includes(value))) {
98
+ throw new EmailError('invalid_request', 'Choose a password that is not common or based on your member details.');
99
+ }
100
+ return normalized;
101
+ }
102
+ export async function hashPassword(password, member) {
103
+ return hash(normalizeAndValidatePassword(password, member), ARGON_OPTIONS);
104
+ }
105
+ async function passwordMatches(passwordHash, password) {
106
+ try {
107
+ return await verify(passwordHash, password.normalize('NFC'));
108
+ }
109
+ catch {
110
+ return false;
111
+ }
112
+ }
113
+ export function isBootstrapComplete(db) {
114
+ return db.select().from(instanceSettings).where(eq(instanceSettings.key, 'bootstrap_complete')).get()?.value === '1';
115
+ }
116
+ function markBootstrapComplete(db) {
117
+ db.insert(instanceSettings)
118
+ .values({ key: 'bootstrap_complete', value: '1' })
119
+ .onConflictDoUpdate({ target: instanceSettings.key, set: { value: '1' } })
120
+ .run();
121
+ }
122
+ async function replacePassword(db, member, password) {
123
+ const passwordHash = await hashPassword(password, member);
124
+ storePasswordHash(db, member.id, passwordHash);
125
+ }
126
+ function storePasswordHash(db, memberId, passwordHash) {
127
+ const current = db.select().from(memberCredentials).where(eq(memberCredentials.memberId, memberId)).get();
128
+ db.insert(memberCredentials)
129
+ .values({
130
+ memberId,
131
+ passwordHash,
132
+ passwordVersion: (current?.passwordVersion ?? 0) + 1,
133
+ updatedAt: Date.now(),
134
+ })
135
+ .onConflictDoUpdate({
136
+ target: memberCredentials.memberId,
137
+ set: {
138
+ passwordHash,
139
+ passwordVersion: (current?.passwordVersion ?? 0) + 1,
140
+ updatedAt: Date.now(),
141
+ },
142
+ })
143
+ .run();
144
+ }
145
+ export async function setupInitialAdmin(db, input) {
146
+ if (isBootstrapComplete(db))
147
+ throw new EmailError('invalid_request', 'This instance has already been set up.');
148
+ const existing = db.select().from(members).all();
149
+ let member;
150
+ if (existing.length === 0) {
151
+ if (!input.name?.trim())
152
+ throw new EmailError('invalid_request', 'Administrator name is required.');
153
+ const email = normalizedEmail(input.email);
154
+ const passwordHash = await hashPassword(input.password, {
155
+ name: input.name.trim(),
156
+ email,
157
+ });
158
+ member = addMember(db, {
159
+ name: input.name,
160
+ email,
161
+ role: 'admin',
162
+ status: 'pending',
163
+ completeBootstrap: false,
164
+ });
165
+ storePasswordHash(db, member.id, passwordHash);
166
+ }
167
+ else {
168
+ if (!input.existingAdmin) {
169
+ const candidates = existing
170
+ .filter((candidate) => candidate.role === 'admin')
171
+ .map((candidate) => `${candidate.id} (${candidate.name}${candidate.email ? `, ${candidate.email}` : ''})`)
172
+ .join(', ');
173
+ throw new EmailError('invalid_request', `Choose an existing administrator with --existing-admin. Available: ${candidates || 'none'}.`);
174
+ }
175
+ member = findMember(db, input.existingAdmin);
176
+ if (member.role !== 'admin')
177
+ throw new EmailError('permission_denied', 'The claimed member must be an administrator.');
178
+ const email = normalizedEmail(input.email);
179
+ const passwordHash = await hashPassword(input.password, { ...member, email });
180
+ db.update(members).set({ email, status: 'pending' }).where(eq(members.id, member.id)).run();
181
+ storePasswordHash(db, member.id, passwordHash);
182
+ db.update(accounts).set({ ownerMemberId: member.id }).where(isNull(accounts.ownerMemberId)).run();
183
+ member = getMember(db, member.id);
184
+ }
185
+ db.update(members).set({ status: 'active' }).where(eq(members.id, member.id)).run();
186
+ member = getMember(db, member.id);
187
+ markBootstrapComplete(db);
188
+ return { member, session: issueSession(db, member.id, input.deviceName ?? `CLI on ${hostname()}`) };
189
+ }
190
+ export function issueMemberAuthToken(db, input) {
191
+ const member = getMember(db, input.memberId);
192
+ if (member.status === 'suspended')
193
+ throw new EmailError('permission_denied', 'Suspended members cannot enroll or reset passwords.');
194
+ if (input.kind === 'enrollment') {
195
+ if (member.status !== 'pending') {
196
+ throw new EmailError('invalid_request', 'Enrollment codes can only be issued to pending members.');
197
+ }
198
+ if (!member.email) {
199
+ throw new EmailError('invalid_request', 'Set the member email before issuing an enrollment code.');
200
+ }
201
+ }
202
+ else if (member.status !== 'active') {
203
+ throw new EmailError('invalid_request', 'Password resets can only be issued to active members.');
204
+ }
205
+ const now = Date.now();
206
+ const expiresAt = now + (input.kind === 'enrollment' ? ENROLLMENT_TTL_MS : PASSWORD_RESET_TTL_MS);
207
+ const token = `fmt_${randomBytes(32).toString('hex')}`;
208
+ db.transaction((tx) => {
209
+ tx.delete(memberAuthTokens)
210
+ .where(and(eq(memberAuthTokens.memberId, member.id), eq(memberAuthTokens.kind, input.kind)))
211
+ .run();
212
+ tx.insert(memberAuthTokens)
213
+ .values({
214
+ id: `token_${randomBytes(8).toString('hex')}`,
215
+ memberId: member.id,
216
+ kind: input.kind,
217
+ tokenHash: secretHash(token),
218
+ createdByMemberId: input.createdByMemberId ?? null,
219
+ createdAt: now,
220
+ expiresAt,
221
+ })
222
+ .run();
223
+ });
224
+ return { token, expiresAt };
225
+ }
226
+ async function consumeMemberAuthToken(db, input) {
227
+ const now = Date.now();
228
+ const row = db
229
+ .select()
230
+ .from(memberAuthTokens)
231
+ .where(and(eq(memberAuthTokens.tokenHash, secretHash(input.token)), eq(memberAuthTokens.kind, input.kind), isNull(memberAuthTokens.usedAt), gt(memberAuthTokens.expiresAt, now)))
232
+ .get();
233
+ if (!row)
234
+ throw new EmailError('auth_expired', 'The enrollment or reset code is invalid, expired, or already used.');
235
+ let member = getMember(db, row.memberId);
236
+ if (member.status === 'suspended')
237
+ throw new EmailError('permission_denied', 'This member is suspended.');
238
+ if (input.kind === 'enrollment' && member.status !== 'pending') {
239
+ throw new EmailError('auth_expired', 'The enrollment or reset code is invalid, expired, or already used.');
240
+ }
241
+ if (input.kind === 'password_reset' && member.status !== 'active') {
242
+ throw new EmailError('auth_expired', 'The enrollment or reset code is invalid, expired, or already used.');
243
+ }
244
+ if (input.kind === 'enrollment') {
245
+ assertMemberLimit(Math.max(db.select().from(members).all().length - 1, 0), getEntitlements(db));
246
+ }
247
+ const passwordHash = await hashPassword(input.password, member);
248
+ const claimedAt = Date.now();
249
+ db.transaction((tx) => {
250
+ const claimed = tx
251
+ .update(memberAuthTokens)
252
+ .set({ usedAt: claimedAt })
253
+ .where(and(eq(memberAuthTokens.id, row.id), isNull(memberAuthTokens.usedAt), gt(memberAuthTokens.expiresAt, claimedAt)))
254
+ .run();
255
+ if (claimed.changes !== 1) {
256
+ throw new EmailError('auth_expired', 'The enrollment or reset code is invalid, expired, or already used.');
257
+ }
258
+ const credential = tx.select().from(memberCredentials).where(eq(memberCredentials.memberId, member.id)).get();
259
+ tx.insert(memberCredentials)
260
+ .values({
261
+ memberId: member.id,
262
+ passwordHash,
263
+ passwordVersion: (credential?.passwordVersion ?? 0) + 1,
264
+ updatedAt: claimedAt,
265
+ })
266
+ .onConflictDoUpdate({
267
+ target: memberCredentials.memberId,
268
+ set: {
269
+ passwordHash,
270
+ passwordVersion: (credential?.passwordVersion ?? 0) + 1,
271
+ updatedAt: claimedAt,
272
+ },
273
+ })
274
+ .run();
275
+ tx.update(memberSessions)
276
+ .set({ revokedAt: claimedAt })
277
+ .where(and(eq(memberSessions.memberId, member.id), isNull(memberSessions.revokedAt)))
278
+ .run();
279
+ if (input.kind === 'enrollment') {
280
+ tx.update(members).set({ status: 'active' }).where(eq(members.id, member.id)).run();
281
+ }
282
+ });
283
+ member = getMember(db, member.id);
284
+ return { member, session: issueSession(db, member.id, input.deviceName) };
285
+ }
286
+ export function enrollMember(db, input) {
287
+ return consumeMemberAuthToken(db, { ...input, kind: 'enrollment' });
288
+ }
289
+ export function resetPassword(db, input) {
290
+ return consumeMemberAuthToken(db, { ...input, kind: 'password_reset' });
291
+ }
292
+ export function issueSession(db, memberId, deviceName) {
293
+ const member = getMember(db, memberId);
294
+ if (member.status !== 'active')
295
+ throw new EmailError('permission_denied', 'This member is not active.');
296
+ const now = Date.now();
297
+ const id = `session_${randomBytes(8).toString('hex')}`;
298
+ const token = `fms_${randomBytes(32).toString('hex')}`;
299
+ const info = {
300
+ id,
301
+ memberId,
302
+ deviceName: deviceName.trim() || 'Unknown device',
303
+ createdAt: now,
304
+ expiresAt: now + SESSION_TTL_MS,
305
+ lastUsedAt: now,
306
+ current: true,
307
+ };
308
+ db.insert(memberSessions)
309
+ .values({
310
+ id: info.id,
311
+ memberId: info.memberId,
312
+ deviceName: info.deviceName,
313
+ createdAt: info.createdAt,
314
+ expiresAt: info.expiresAt,
315
+ lastUsedAt: info.lastUsedAt,
316
+ tokenHash: secretHash(token),
317
+ revokedAt: null,
318
+ })
319
+ .run();
320
+ return { token, info };
321
+ }
322
+ export async function loginWithPassword(db, input) {
323
+ if (!isBootstrapComplete(db))
324
+ throw new EmailError('permission_denied', 'This instance has not finished setup.');
325
+ const email = normalizedEmail(input.email);
326
+ const now = Date.now();
327
+ const emailKey = rateKey('email', email);
328
+ const ipKey = rateKey('ip', input.ipAddress || 'unknown');
329
+ const reservation = reserveLoginAttempt(db, emailKey, ipKey, now);
330
+ if (!reservation) {
331
+ throw new EmailError('rate_limited', 'Too many login attempts. Try again later.');
332
+ }
333
+ const memberRow = db
334
+ .select()
335
+ .from(members)
336
+ .where(sql `lower(${members.email}) = ${email}`)
337
+ .get();
338
+ const credential = memberRow
339
+ ? db.select().from(memberCredentials).where(eq(memberCredentials.memberId, memberRow.id)).get()
340
+ : undefined;
341
+ const matches = await passwordMatches(credential?.passwordHash ?? (await dummyPasswordHash), input.password);
342
+ if (!memberRow || !credential || !matches || memberRow.status !== 'active') {
343
+ throw new EmailError('permission_denied', 'Email or password is incorrect.');
344
+ }
345
+ db.delete(authRateLimits).where(eq(authRateLimits.key, emailKey)).run();
346
+ releaseLoginAttempt(db, ipKey, reservation.ipWindowStartedAt);
347
+ const member = getMember(db, memberRow.id);
348
+ return { member, session: issueSession(db, member.id, input.deviceName) };
349
+ }
350
+ export function authenticateBearer(db, token) {
351
+ if (token.startsWith('fmk_')) {
352
+ const auth = authenticateApiKey(db, token);
353
+ if (!auth)
354
+ return null;
355
+ return {
356
+ kind: 'api_key',
357
+ principalId: auth.keyId,
358
+ keyId: auth.keyId,
359
+ memberId: auth.memberId,
360
+ role: auth.role,
361
+ permissions: auth.permissions,
362
+ accountIds: auth.accountIds,
363
+ };
364
+ }
365
+ if (!token.startsWith('fms_'))
366
+ return null;
367
+ const now = Date.now();
368
+ const row = db
369
+ .select()
370
+ .from(memberSessions)
371
+ .where(eq(memberSessions.tokenHash, secretHash(token)))
372
+ .get();
373
+ if (!row || row.revokedAt !== null || row.expiresAt <= now)
374
+ return null;
375
+ const member = getMember(db, row.memberId);
376
+ if (member.status !== 'active')
377
+ return null;
378
+ if (now - row.lastUsedAt >= SESSION_TOUCH_INTERVAL_MS) {
379
+ db.update(memberSessions).set({ lastUsedAt: now }).where(eq(memberSessions.id, row.id)).run();
380
+ }
381
+ return {
382
+ kind: 'session',
383
+ principalId: row.id,
384
+ sessionId: row.id,
385
+ memberId: member.id,
386
+ role: member.role,
387
+ permissions: FULL_PERMISSION_POLICY,
388
+ accountIds: null,
389
+ };
390
+ }
391
+ export function listMemberSessions(db, memberId, currentSessionId) {
392
+ const now = Date.now();
393
+ return db
394
+ .select()
395
+ .from(memberSessions)
396
+ .where(eq(memberSessions.memberId, memberId))
397
+ .all()
398
+ .filter((row) => row.revokedAt === null && row.expiresAt > now)
399
+ .map((row) => ({
400
+ id: row.id,
401
+ memberId: row.memberId,
402
+ deviceName: row.deviceName,
403
+ createdAt: row.createdAt,
404
+ expiresAt: row.expiresAt,
405
+ lastUsedAt: row.lastUsedAt,
406
+ current: row.id === currentSessionId,
407
+ }));
408
+ }
409
+ export function revokeSession(db, memberId, sessionId) {
410
+ return (db
411
+ .update(memberSessions)
412
+ .set({ revokedAt: Date.now() })
413
+ .where(and(eq(memberSessions.id, sessionId), eq(memberSessions.memberId, memberId), isNull(memberSessions.revokedAt)))
414
+ .run().changes > 0);
415
+ }
416
+ export async function changePassword(db, input) {
417
+ const member = getMember(db, input.memberId);
418
+ const credential = db.select().from(memberCredentials).where(eq(memberCredentials.memberId, member.id)).get();
419
+ if (!credential || !(await passwordMatches(credential.passwordHash, input.currentPassword))) {
420
+ throw new EmailError('permission_denied', 'Current password is incorrect.');
421
+ }
422
+ await replacePassword(db, member, input.newPassword);
423
+ db.update(memberSessions)
424
+ .set({ revokedAt: Date.now() })
425
+ .where(and(eq(memberSessions.memberId, member.id), sql `${memberSessions.id} != ${input.keepSessionId}`, isNull(memberSessions.revokedAt)))
426
+ .run();
427
+ }
428
+ export async function recoverAdminPassword(db, ref, password) {
429
+ if (!isBootstrapComplete(db)) {
430
+ throw new EmailError('invalid_request', 'Finish instance setup before using administrator recovery.');
431
+ }
432
+ const member = findMember(db, ref);
433
+ if (member.role !== 'admin')
434
+ throw new EmailError('permission_denied', 'Break-glass recovery is limited to administrators.');
435
+ if (!member.email) {
436
+ throw new EmailError('invalid_request', 'Claim this administrator with setup before using break-glass recovery.');
437
+ }
438
+ const passwordHash = await hashPassword(password, member);
439
+ storePasswordHash(db, member.id, passwordHash);
440
+ if (member.status !== 'active')
441
+ db.update(members).set({ status: 'active' }).where(eq(members.id, member.id)).run();
442
+ db.update(memberSessions)
443
+ .set({ revokedAt: Date.now() })
444
+ .where(and(eq(memberSessions.memberId, member.id), isNull(memberSessions.revokedAt)))
445
+ .run();
446
+ markBootstrapComplete(db);
447
+ return getMember(db, member.id);
448
+ }
449
+ export function deleteAllApiKeys(db) {
450
+ return db.delete(apiKeys).run().changes;
451
+ }
452
+ //# sourceMappingURL=auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.js","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ import type { Account } from '@fluxmail/core';
2
+ import type { Principal } from './auth.js';
3
+ import { type AdminCapability, type Capability } from './permissions.js';
4
+ export declare function canAccessAccount(principal: Principal, account: Account): boolean;
5
+ export declare function canSeeAccountMetadata(principal: Principal, account: Account): boolean;
6
+ export declare function allowsCapability(principal: Principal, capability: Capability): boolean;
7
+ export declare function canAdminister(principal: Principal, capability: AdminCapability): boolean;
8
+ export declare function canManageOwnedAccount(principal: Principal, account: Account): boolean;
9
+ //# sourceMappingURL=authorization.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"authorization.d.ts","sourceRoot":"","sources":["../src/authorization.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAC3C,OAAO,EAAiB,KAAK,eAAe,EAAE,KAAK,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAExF,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,SAAS,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAMhF;AAED,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,SAAS,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAMrF;AAED,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,SAAS,EAAE,UAAU,EAAE,UAAU,GAAG,OAAO,CAEtF;AAED,wBAAgB,aAAa,CAAC,SAAS,EAAE,SAAS,EAAE,UAAU,EAAE,eAAe,GAAG,OAAO,CAIxF;AAED,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,SAAS,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAErF"}
@@ -0,0 +1,23 @@
1
+ import { hasCapability } from './permissions.js';
2
+ export function canAccessAccount(principal, account) {
3
+ const granted = account.ownerMemberId === principal.memberId ||
4
+ account.sharedWithAll ||
5
+ account.grantedMemberIds.includes(principal.memberId);
6
+ return granted && (principal.accountIds === null || principal.accountIds.includes(account.id));
7
+ }
8
+ export function canSeeAccountMetadata(principal, account) {
9
+ if (canAccessAccount(principal, account))
10
+ return true;
11
+ return (canAdminister(principal, 'admin.accounts') &&
12
+ (principal.accountIds === null || principal.accountIds.includes(account.id)));
13
+ }
14
+ export function allowsCapability(principal, capability) {
15
+ return principal.kind === 'session' || hasCapability(principal.permissions, capability);
16
+ }
17
+ export function canAdminister(principal, capability) {
18
+ return (principal.role === 'admin' && (principal.kind === 'session' || hasCapability(principal.permissions, capability)));
19
+ }
20
+ export function canManageOwnedAccount(principal, account) {
21
+ return principal.role === 'admin' || account.ownerMemberId === principal.memberId;
22
+ }
23
+ //# sourceMappingURL=authorization.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"authorization.js","sourceRoot":"","sources":["../src/authorization.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,aAAa,EAAyC,MAAM,kBAAkB,CAAC;AAExF,MAAM,UAAU,gBAAgB,CAAC,SAAoB,EAAE,OAAgB;IACrE,MAAM,OAAO,GACX,OAAO,CAAC,aAAa,KAAK,SAAS,CAAC,QAAQ;QAC5C,OAAO,CAAC,aAAa;QACrB,OAAO,CAAC,gBAAgB,CAAC,QAAQ,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;IACxD,OAAO,OAAO,IAAI,CAAC,SAAS,CAAC,UAAU,KAAK,IAAI,IAAI,SAAS,CAAC,UAAU,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC;AACjG,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,SAAoB,EAAE,OAAgB;IAC1E,IAAI,gBAAgB,CAAC,SAAS,EAAE,OAAO,CAAC;QAAE,OAAO,IAAI,CAAC;IACtD,OAAO,CACL,aAAa,CAAC,SAAS,EAAE,gBAAgB,CAAC;QAC1C,CAAC,SAAS,CAAC,UAAU,KAAK,IAAI,IAAI,SAAS,CAAC,UAAU,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAC7E,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,SAAoB,EAAE,UAAsB;IAC3E,OAAO,SAAS,CAAC,IAAI,KAAK,SAAS,IAAI,aAAa,CAAC,SAAS,CAAC,WAAW,EAAE,UAAU,CAAC,CAAC;AAC1F,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,SAAoB,EAAE,UAA2B;IAC7E,OAAO,CACL,SAAS,CAAC,IAAI,KAAK,OAAO,IAAI,CAAC,SAAS,CAAC,IAAI,KAAK,SAAS,IAAI,aAAa,CAAC,SAAS,CAAC,WAAW,EAAE,UAAU,CAAC,CAAC,CACjH,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,SAAoB,EAAE,OAAgB;IAC1E,OAAO,SAAS,CAAC,IAAI,KAAK,OAAO,IAAI,OAAO,CAAC,aAAa,KAAK,SAAS,CAAC,QAAQ,CAAC;AACpF,CAAC"}
package/dist/cli.d.ts CHANGED
@@ -1,7 +1,9 @@
1
1
  #!/usr/bin/env node
2
2
  import { Command } from 'commander';
3
+ import { serve } from '@hono/node-server';
3
4
  import { type ApiKeyInfo } from './storage/apiKeys.js';
4
5
  import { type PermissionPolicy } from './permissions.js';
6
+ import { type Telemetry } from './telemetry.js';
5
7
  interface PermissionOptions {
6
8
  profile?: string;
7
9
  allow: string[];
@@ -9,8 +11,12 @@ interface PermissionOptions {
9
11
  }
10
12
  export declare function permissionPolicyFromOptions(opts: PermissionOptions, requireSelection?: boolean): PermissionPolicy;
11
13
  export declare function permissionPolicyForUpdate(opts: PermissionOptions, existing: Pick<ApiKeyInfo, 'permissionProfile'>): PermissionPolicy;
14
+ export interface CliProgramOptions {
15
+ telemetry?: Telemetry;
16
+ }
17
+ export declare function waitForServerListening(server: ReturnType<typeof serve>): Promise<void>;
12
18
  /** Build the command tree without parsing arguments or running command actions. */
13
- export declare function createCliProgram(): Command;
19
+ export declare function createCliProgram(options?: CliProgramOptions): Command;
14
20
  export declare function runCli(argv?: readonly string[]): Promise<void>;
15
21
  export {};
16
22
  //# sourceMappingURL=cli.d.ts.map
package/dist/cli.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAKA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAuBpC,OAAO,EAML,KAAK,UAAU,EAChB,MAAM,sBAAsB,CAAC;AAgB9B,OAAO,EAQL,KAAK,gBAAgB,EACtB,MAAM,kBAAkB,CAAC;AAqC1B,UAAU,iBAAiB;IACzB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;CAClB;AAqBD,wBAAgB,2BAA2B,CAAC,IAAI,EAAE,iBAAiB,EAAE,gBAAgB,UAAQ,GAAG,gBAAgB,CAoB/G;AAED,wBAAgB,yBAAyB,CACvC,IAAI,EAAE,iBAAiB,EACvB,QAAQ,EAAE,IAAI,CAAC,UAAU,EAAE,mBAAmB,CAAC,GAC9C,gBAAgB,CAQlB;AAyED,mFAAmF;AACnF,wBAAgB,gBAAgB,IAAI,OAAO,CA06B1C;AAED,wBAAsB,MAAM,CAAC,IAAI,GAAE,SAAS,MAAM,EAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CAQlF"}
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAOA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAsB1C,OAAO,EAAe,KAAK,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAOpE,OAAO,EAQL,KAAK,gBAAgB,EACtB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAOL,KAAK,SAAS,EACf,MAAM,gBAAgB,CAAC;AAwCxB,UAAU,iBAAiB;IACzB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;CAClB;AAcD,wBAAgB,2BAA2B,CAAC,IAAI,EAAE,iBAAiB,EAAE,gBAAgB,UAAQ,GAAG,gBAAgB,CAoB/G;AAED,wBAAgB,yBAAyB,CACvC,IAAI,EAAE,iBAAiB,EACvB,QAAQ,EAAE,IAAI,CAAC,UAAU,EAAE,mBAAmB,CAAC,GAC9C,gBAAgB,CAQlB;AAuFD,MAAM,WAAW,iBAAiB;IAChC,SAAS,CAAC,EAAE,SAAS,CAAC;CACvB;AAwBD,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,UAAU,CAAC,OAAO,KAAK,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAatF;AAED,mFAAmF;AACnF,wBAAgB,gBAAgB,CAAC,OAAO,GAAE,iBAAsB,GAAG,OAAO,CAy0CzE;AAED,wBAAsB,MAAM,CAAC,IAAI,GAAE,SAAS,MAAM,EAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CAUlF"}