@tumbaland/backend-core 1.37.0 → 1.39.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 (92) hide show
  1. package/dist/apiKeys/ApiKey.d.ts +23 -3
  2. package/dist/apiKeys/ApiKey.d.ts.map +1 -1
  3. package/dist/apiKeys/ApiKey.js +19 -2
  4. package/dist/apiKeys/ApiKey.js.map +1 -1
  5. package/dist/apiKeys/index.d.ts +2 -2
  6. package/dist/apiKeys/index.d.ts.map +1 -1
  7. package/dist/apiKeys/index.js +5 -1
  8. package/dist/apiKeys/index.js.map +1 -1
  9. package/dist/apiKeys/middleware.d.ts +17 -3
  10. package/dist/apiKeys/middleware.d.ts.map +1 -1
  11. package/dist/apiKeys/middleware.js +71 -34
  12. package/dist/apiKeys/middleware.js.map +1 -1
  13. package/dist/apiKeys/service.d.ts +5 -3
  14. package/dist/apiKeys/service.d.ts.map +1 -1
  15. package/dist/apiKeys/service.js +11 -3
  16. package/dist/apiKeys/service.js.map +1 -1
  17. package/dist/apiKeys/types.d.ts +43 -8
  18. package/dist/apiKeys/types.d.ts.map +1 -1
  19. package/dist/apiKeys/types.js +35 -1
  20. package/dist/apiKeys/types.js.map +1 -1
  21. package/dist/audit/AuditEvent.d.ts +51 -0
  22. package/dist/audit/AuditEvent.d.ts.map +1 -0
  23. package/dist/audit/AuditEvent.js +69 -0
  24. package/dist/audit/AuditEvent.js.map +1 -0
  25. package/dist/audit/actor.d.ts +41 -0
  26. package/dist/audit/actor.d.ts.map +1 -0
  27. package/dist/audit/actor.js +39 -0
  28. package/dist/audit/actor.js.map +1 -0
  29. package/dist/audit/context.d.ts +40 -0
  30. package/dist/audit/context.d.ts.map +1 -0
  31. package/dist/audit/context.js +60 -0
  32. package/dist/audit/context.js.map +1 -0
  33. package/dist/audit/index.d.ts +12 -0
  34. package/dist/audit/index.d.ts.map +1 -0
  35. package/dist/audit/index.js +22 -0
  36. package/dist/audit/index.js.map +1 -0
  37. package/dist/audit/plugin.d.ts +23 -0
  38. package/dist/audit/plugin.d.ts.map +1 -0
  39. package/dist/audit/plugin.js +226 -0
  40. package/dist/audit/plugin.js.map +1 -0
  41. package/dist/audit/reads.d.ts +47 -0
  42. package/dist/audit/reads.d.ts.map +1 -0
  43. package/dist/audit/reads.js +94 -0
  44. package/dist/audit/reads.js.map +1 -0
  45. package/dist/audit/service.d.ts +49 -0
  46. package/dist/audit/service.d.ts.map +1 -0
  47. package/dist/audit/service.js +65 -0
  48. package/dist/audit/service.js.map +1 -0
  49. package/dist/index.d.ts +1 -0
  50. package/dist/index.d.ts.map +1 -1
  51. package/dist/index.js +1 -0
  52. package/dist/index.js.map +1 -1
  53. package/dist/oauth/models.d.ts +13 -2
  54. package/dist/oauth/models.d.ts.map +1 -1
  55. package/dist/oauth/models.js +19 -0
  56. package/dist/oauth/models.js.map +1 -1
  57. package/dist/oauth/service.d.ts +15 -8
  58. package/dist/oauth/service.d.ts.map +1 -1
  59. package/dist/oauth/service.js +10 -3
  60. package/dist/oauth/service.js.map +1 -1
  61. package/dist/oauth/tokens.d.ts +37 -5
  62. package/dist/oauth/tokens.d.ts.map +1 -1
  63. package/dist/oauth/tokens.js +9 -2
  64. package/dist/oauth/tokens.js.map +1 -1
  65. package/package.json +1 -1
  66. package/src/apiKeys/ApiKey.test.ts +25 -1
  67. package/src/apiKeys/ApiKey.ts +31 -4
  68. package/src/apiKeys/index.ts +16 -2
  69. package/src/apiKeys/middleware.test.ts +126 -20
  70. package/src/apiKeys/middleware.ts +99 -39
  71. package/src/apiKeys/service.test.ts +58 -9
  72. package/src/apiKeys/service.ts +25 -6
  73. package/src/apiKeys/types.ts +63 -8
  74. package/src/audit/AuditEvent.ts +79 -0
  75. package/src/audit/actor.test.ts +95 -0
  76. package/src/audit/actor.ts +68 -0
  77. package/src/audit/context.test.ts +91 -0
  78. package/src/audit/context.ts +83 -0
  79. package/src/audit/index.ts +11 -0
  80. package/src/audit/plugin.test.ts +258 -0
  81. package/src/audit/plugin.ts +254 -0
  82. package/src/audit/reads.test.ts +164 -0
  83. package/src/audit/reads.ts +88 -0
  84. package/src/audit/service.test.ts +115 -0
  85. package/src/audit/service.ts +92 -0
  86. package/src/index.ts +1 -0
  87. package/src/middleware/authMiddleware.test.ts +6 -1
  88. package/src/oauth/models.ts +32 -2
  89. package/src/oauth/service.test.ts +58 -6
  90. package/src/oauth/service.ts +25 -7
  91. package/src/oauth/tokens.test.ts +22 -5
  92. package/src/oauth/tokens.ts +52 -7
@@ -1,5 +1,5 @@
1
1
  import mongoose, { Document } from 'mongoose';
2
- import type { ApiKeyScope } from './types';
2
+ import { type ApiKeyScope, type Tenant } from './types';
3
3
  /**
4
4
  * One API key. Lives in backend-core rather than auth-service because both
5
5
  * halves need it: auth-service issues and revokes keys, and every other service
@@ -30,8 +30,17 @@ export interface IApiKey extends Document {
30
30
  sealedIv: string;
31
31
  sealedTag: string;
32
32
  scopes: ApiKeyScope[];
33
- /** the tenant this key acts in; null means the user's own non-group data */
34
- groupId: string | null;
33
+ /** every tenant this key may act in; see `Tenant` */
34
+ tenants: Tenant[];
35
+ /** the one it acts in when a request names none; always a member of `tenants` */
36
+ defaultTenant: Tenant;
37
+ /**
38
+ * The single tenant this key was pinned to, before tenants were a set.
39
+ *
40
+ * Kept so keys issued under the old model keep working; `readTenants` falls
41
+ * back to it. Nothing writes it any more.
42
+ */
43
+ groupId?: string | null;
35
44
  lastUsedAt?: Date;
36
45
  expiresAt?: Date;
37
46
  revokedAt?: Date;
@@ -41,6 +50,17 @@ export interface IApiKey extends Document {
41
50
  createdAt: Date;
42
51
  updatedAt: Date;
43
52
  }
53
+ /**
54
+ * Issuing and revoking a key is worth a record — arguably more than anything a
55
+ * key goes on to do, since a credential nobody remembers creating is the one
56
+ * that matters.
57
+ *
58
+ * Every secret-bearing field is redacted. The trail is readable by the account
59
+ * owner and kept for a year; a snapshot carrying `hash` or the sealed
60
+ * ciphertext would put credential material into a second collection with a
61
+ * different lifetime, which is precisely the thing the encryption is for.
62
+ */
63
+ export declare const API_KEY_SECRET_FIELDS: string[];
44
64
  export declare const ApiKey: mongoose.Model<IApiKey, {}, {}, {}, mongoose.Document<unknown, {}, IApiKey, {}, mongoose.DefaultSchemaOptions> & IApiKey & Required<{
45
65
  _id: mongoose.Types.ObjectId;
46
66
  }> & {
@@ -1 +1 @@
1
- {"version":3,"file":"ApiKey.d.ts","sourceRoot":"","sources":["../../src/apiKeys/ApiKey.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,EAAE,EAAE,QAAQ,EAAU,MAAM,UAAU,CAAC;AACtD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAE3C;;;;;GAKG;AACH,MAAM,WAAW,OAAQ,SAAQ,QAAQ;IACvC,MAAM,EAAE,MAAM,CAAC;IACf;;;;;;;;OAQG;IACH,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,gEAAgE;IAChE,IAAI,EAAE,MAAM,CAAC;IACb,qFAAqF;IACrF,KAAK,EAAE,MAAM,CAAC;IACd,+EAA+E;IAC/E,IAAI,EAAE,MAAM,CAAC;IACb,sEAAsE;IACtE,gBAAgB,EAAE,MAAM,CAAC;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,WAAW,EAAE,CAAC;IACtB,4EAA4E;IAC5E,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,UAAU,CAAC,EAAE,IAAI,CAAC;IAClB,SAAS,CAAC,EAAE,IAAI,CAAC;IACjB,SAAS,CAAC,EAAE,IAAI,CAAC;IACjB,uFAAuF;IACvF,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,CAAC,EAAE,IAAI,CAAC;IACtB,SAAS,EAAE,IAAI,CAAC;IAChB,SAAS,EAAE,IAAI,CAAC;CACjB;AA6BD,eAAO,MAAM,MAAM;;;;;;gBAEgC,CAAC"}
1
+ {"version":3,"file":"ApiKey.d.ts","sourceRoot":"","sources":["../../src/apiKeys/ApiKey.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,EAAE,EAAE,QAAQ,EAAU,MAAM,UAAU,CAAC;AAEtD,OAAO,EAAmB,KAAK,WAAW,EAAE,KAAK,MAAM,EAAE,MAAM,SAAS,CAAC;AAEzE;;;;;GAKG;AACH,MAAM,WAAW,OAAQ,SAAQ,QAAQ;IACvC,MAAM,EAAE,MAAM,CAAC;IACf;;;;;;;;OAQG;IACH,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,gEAAgE;IAChE,IAAI,EAAE,MAAM,CAAC;IACb,qFAAqF;IACrF,KAAK,EAAE,MAAM,CAAC;IACd,+EAA+E;IAC/E,IAAI,EAAE,MAAM,CAAC;IACb,sEAAsE;IACtE,gBAAgB,EAAE,MAAM,CAAC;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,WAAW,EAAE,CAAC;IACtB,qDAAqD;IACrD,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,iFAAiF;IACjF,aAAa,EAAE,MAAM,CAAC;IACtB;;;;;OAKG;IACH,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,UAAU,CAAC,EAAE,IAAI,CAAC;IAClB,SAAS,CAAC,EAAE,IAAI,CAAC;IACjB,SAAS,CAAC,EAAE,IAAI,CAAC;IACjB,uFAAuF;IACvF,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,CAAC,EAAE,IAAI,CAAC;IACtB,SAAS,EAAE,IAAI,CAAC;IAChB,SAAS,EAAE,IAAI,CAAC;CACjB;AAgCD;;;;;;;;;GASG;AACH,eAAO,MAAM,qBAAqB,UAAwD,CAAC;AAI3F,eAAO,MAAM,MAAM;;;;;;gBAEgC,CAAC"}
@@ -33,8 +33,10 @@ var __importStar = (this && this.__importStar) || (function () {
33
33
  };
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.ApiKey = void 0;
36
+ exports.ApiKey = exports.API_KEY_SECRET_FIELDS = void 0;
37
37
  const mongoose_1 = __importStar(require("mongoose"));
38
+ const plugin_1 = require("../audit/plugin");
39
+ const types_1 = require("./types");
38
40
  const ApiKeySchema = new mongoose_1.Schema({
39
41
  userId: { type: String, required: true, index: true },
40
42
  userEmail: { type: String, required: true },
@@ -46,8 +48,11 @@ const ApiKeySchema = new mongoose_1.Schema({
46
48
  sealedIv: { type: String, required: true },
47
49
  sealedTag: { type: String, required: true },
48
50
  scopes: { type: [String], default: [] },
49
- // Explicitly nullable rather than optional: "personal scope" is a decision the
51
+ // Defaulted rather than optional: which data a key reaches is a decision the
50
52
  // creator made, and it must not be indistinguishable from a field nobody set.
53
+ tenants: { type: [String], default: () => [types_1.PERSONAL_TENANT] },
54
+ defaultTenant: { type: String, default: types_1.PERSONAL_TENANT },
55
+ // Written by the single-tenant model this replaced; read-only now.
51
56
  groupId: { type: String, default: null },
52
57
  lastUsedAt: { type: Date },
53
58
  expiresAt: { type: Date },
@@ -57,6 +62,18 @@ const ApiKeySchema = new mongoose_1.Schema({
57
62
  }, { timestamps: true, collection: 'api_keys' });
58
63
  // Every listing is one user's keys, newest first.
59
64
  ApiKeySchema.index({ userId: 1, createdAt: -1 });
65
+ /**
66
+ * Issuing and revoking a key is worth a record — arguably more than anything a
67
+ * key goes on to do, since a credential nobody remembers creating is the one
68
+ * that matters.
69
+ *
70
+ * Every secret-bearing field is redacted. The trail is readable by the account
71
+ * owner and kept for a year; a snapshot carrying `hash` or the sealed
72
+ * ciphertext would put credential material into a second collection with a
73
+ * different lifetime, which is precisely the thing the encryption is for.
74
+ */
75
+ exports.API_KEY_SECRET_FIELDS = ['hash', 'sealedCiphertext', 'sealedIv', 'sealedTag'];
76
+ ApiKeySchema.plugin(plugin_1.auditPlugin, { resource: 'api_key', redact: exports.API_KEY_SECRET_FIELDS });
60
77
  exports.ApiKey = mongoose_1.default.models.ApiKey
61
78
  ? mongoose_1.default.models.ApiKey
62
79
  : mongoose_1.default.model('ApiKey', ApiKeySchema);
@@ -1 +1 @@
1
- {"version":3,"file":"ApiKey.js","sourceRoot":"","sources":["../../src/apiKeys/ApiKey.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,qDAAsD;AA6CtD,MAAM,YAAY,GAAG,IAAI,iBAAM,CAC7B;IACE,MAAM,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE;IACrD,SAAS,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE;IAC3C,QAAQ,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE;IACvD,IAAI,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,EAAE;IACjE,KAAK,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE;IAClE,IAAI,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE;IACtC,gBAAgB,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE;IAClD,QAAQ,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE;IAC1C,SAAS,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE;IAC3C,MAAM,EAAE,EAAE,IAAI,EAAE,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE;IACvC,+EAA+E;IAC/E,8EAA8E;IAC9E,OAAO,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE;IACxC,UAAU,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE;IAC1B,SAAS,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE;IACzB,SAAS,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE;IACzB,WAAW,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,EAAE;IACzC,cAAc,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE;CAC/B,EACD,EAAE,UAAU,EAAE,IAAI,EAAE,UAAU,EAAE,UAAU,EAAE,CAC7C,CAAC;AAEF,kDAAkD;AAClD,YAAY,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;AAEpC,QAAA,MAAM,GAAG,kBAAQ,CAAC,MAAM,CAAC,MAAM;IAC1C,CAAC,CAAE,kBAAQ,CAAC,MAAM,CAAC,MAAkC;IACrD,CAAC,CAAC,kBAAQ,CAAC,KAAK,CAAU,QAAQ,EAAE,YAAY,CAAC,CAAC"}
1
+ {"version":3,"file":"ApiKey.js","sourceRoot":"","sources":["../../src/apiKeys/ApiKey.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,qDAAsD;AACtD,4CAA8C;AAC9C,mCAAyE;AAqDzE,MAAM,YAAY,GAAG,IAAI,iBAAM,CAC7B;IACE,MAAM,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE;IACrD,SAAS,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE;IAC3C,QAAQ,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE;IACvD,IAAI,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,EAAE;IACjE,KAAK,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE;IAClE,IAAI,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE;IACtC,gBAAgB,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE;IAClD,QAAQ,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE;IAC1C,SAAS,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE;IAC3C,MAAM,EAAE,EAAE,IAAI,EAAE,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE;IACvC,6EAA6E;IAC7E,8EAA8E;IAC9E,OAAO,EAAE,EAAE,IAAI,EAAE,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,CAAC,uBAAe,CAAC,EAAE;IAC7D,aAAa,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,uBAAe,EAAE;IACzD,mEAAmE;IACnE,OAAO,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE;IACxC,UAAU,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE;IAC1B,SAAS,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE;IACzB,SAAS,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE;IACzB,WAAW,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,EAAE;IACzC,cAAc,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE;CAC/B,EACD,EAAE,UAAU,EAAE,IAAI,EAAE,UAAU,EAAE,UAAU,EAAE,CAC7C,CAAC;AAEF,kDAAkD;AAClD,YAAY,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;AAEjD;;;;;;;;;GASG;AACU,QAAA,qBAAqB,GAAG,CAAC,MAAM,EAAE,kBAAkB,EAAE,UAAU,EAAE,WAAW,CAAC,CAAC;AAE3F,YAAY,CAAC,MAAM,CAAC,oBAAW,EAAE,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,EAAE,6BAAqB,EAAE,CAAC,CAAC;AAE5E,QAAA,MAAM,GAAG,kBAAQ,CAAC,MAAM,CAAC,MAAM;IAC1C,CAAC,CAAE,kBAAQ,CAAC,MAAM,CAAC,MAAkC;IACrD,CAAC,CAAC,kBAAQ,CAAC,KAAK,CAAU,QAAQ,EAAE,YAAY,CAAC,CAAC"}
@@ -4,7 +4,7 @@ export { createApiKey, listApiKeys, revealApiKey, revokeApiKey, deleteApiKey, ve
4
4
  export type { CreateApiKeyInput, CreatedApiKey } from './service';
5
5
  export { authenticateAgent, requireScope, denyApiKeys } from './middleware';
6
6
  export type { ApiKeyContext } from './middleware';
7
- export { API_KEY_SCOPES, isApiKeyScope } from './types';
8
- export type { ApiKeyScope, ApiKeySummary, ApiKeyVerification, ApiKeyRejection } from './types';
7
+ export { API_KEY_SCOPES, isApiKeyScope, PERSONAL_TENANT, groupIdOf, groupIdsOf, readTenants } from './types';
8
+ export type { ApiKeyScope, ApiKeySummary, ApiKeyVerification, ApiKeyRejection, ApiKeyTenant, Tenant } from './types';
9
9
  export { looksLikeApiKey, displayPrefix, isEncryptionConfigured, resetEncryptionKeyCache } from './crypto';
10
10
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/apiKeys/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAClC,YAAY,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AACxC,OAAO,EACL,YAAY,EACZ,WAAW,EACX,YAAY,EACZ,YAAY,EACZ,YAAY,EACZ,YAAY,EACb,MAAM,WAAW,CAAC;AACnB,YAAY,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAClE,OAAO,EAAE,iBAAiB,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAC5E,YAAY,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAClD,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACxD,YAAY,EAAE,WAAW,EAAE,aAAa,EAAE,kBAAkB,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAC/F,OAAO,EACL,eAAe,EACf,aAAa,EACb,sBAAsB,EACtB,uBAAuB,EACxB,MAAM,UAAU,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/apiKeys/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAClC,YAAY,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AACxC,OAAO,EACL,YAAY,EACZ,WAAW,EACX,YAAY,EACZ,YAAY,EACZ,YAAY,EACZ,YAAY,EACb,MAAM,WAAW,CAAC;AACnB,YAAY,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAClE,OAAO,EAAE,iBAAiB,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAC5E,YAAY,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAClD,OAAO,EACL,cAAc,EACd,aAAa,EACb,eAAe,EACf,SAAS,EACT,UAAU,EACV,WAAW,EACZ,MAAM,SAAS,CAAC;AACjB,YAAY,EACV,WAAW,EACX,aAAa,EACb,kBAAkB,EAClB,eAAe,EACf,YAAY,EACZ,MAAM,EACP,MAAM,SAAS,CAAC;AACjB,OAAO,EACL,eAAe,EACf,aAAa,EACb,sBAAsB,EACtB,uBAAuB,EACxB,MAAM,UAAU,CAAC"}
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.resetEncryptionKeyCache = exports.isEncryptionConfigured = exports.displayPrefix = exports.looksLikeApiKey = exports.isApiKeyScope = exports.API_KEY_SCOPES = exports.denyApiKeys = exports.requireScope = exports.authenticateAgent = exports.verifyApiKey = exports.deleteApiKey = exports.revokeApiKey = exports.revealApiKey = exports.listApiKeys = exports.createApiKey = exports.ApiKey = void 0;
3
+ exports.resetEncryptionKeyCache = exports.isEncryptionConfigured = exports.displayPrefix = exports.looksLikeApiKey = exports.readTenants = exports.groupIdsOf = exports.groupIdOf = exports.PERSONAL_TENANT = exports.isApiKeyScope = exports.API_KEY_SCOPES = exports.denyApiKeys = exports.requireScope = exports.authenticateAgent = exports.verifyApiKey = exports.deleteApiKey = exports.revokeApiKey = exports.revealApiKey = exports.listApiKeys = exports.createApiKey = exports.ApiKey = void 0;
4
4
  var ApiKey_1 = require("./ApiKey");
5
5
  Object.defineProperty(exports, "ApiKey", { enumerable: true, get: function () { return ApiKey_1.ApiKey; } });
6
6
  var service_1 = require("./service");
@@ -17,6 +17,10 @@ Object.defineProperty(exports, "denyApiKeys", { enumerable: true, get: function
17
17
  var types_1 = require("./types");
18
18
  Object.defineProperty(exports, "API_KEY_SCOPES", { enumerable: true, get: function () { return types_1.API_KEY_SCOPES; } });
19
19
  Object.defineProperty(exports, "isApiKeyScope", { enumerable: true, get: function () { return types_1.isApiKeyScope; } });
20
+ Object.defineProperty(exports, "PERSONAL_TENANT", { enumerable: true, get: function () { return types_1.PERSONAL_TENANT; } });
21
+ Object.defineProperty(exports, "groupIdOf", { enumerable: true, get: function () { return types_1.groupIdOf; } });
22
+ Object.defineProperty(exports, "groupIdsOf", { enumerable: true, get: function () { return types_1.groupIdsOf; } });
23
+ Object.defineProperty(exports, "readTenants", { enumerable: true, get: function () { return types_1.readTenants; } });
20
24
  var crypto_1 = require("./crypto");
21
25
  Object.defineProperty(exports, "looksLikeApiKey", { enumerable: true, get: function () { return crypto_1.looksLikeApiKey; } });
22
26
  Object.defineProperty(exports, "displayPrefix", { enumerable: true, get: function () { return crypto_1.displayPrefix; } });
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/apiKeys/index.ts"],"names":[],"mappings":";;;AAAA,mCAAkC;AAAzB,gGAAA,MAAM,OAAA;AAEf,qCAOmB;AANjB,uGAAA,YAAY,OAAA;AACZ,sGAAA,WAAW,OAAA;AACX,uGAAA,YAAY,OAAA;AACZ,uGAAA,YAAY,OAAA;AACZ,uGAAA,YAAY,OAAA;AACZ,uGAAA,YAAY,OAAA;AAGd,2CAA4E;AAAnE,+GAAA,iBAAiB,OAAA;AAAE,0GAAA,YAAY,OAAA;AAAE,yGAAA,WAAW,OAAA;AAErD,iCAAwD;AAA/C,uGAAA,cAAc,OAAA;AAAE,sGAAA,aAAa,OAAA;AAEtC,mCAKkB;AAJhB,yGAAA,eAAe,OAAA;AACf,uGAAA,aAAa,OAAA;AACb,gHAAA,sBAAsB,OAAA;AACtB,iHAAA,uBAAuB,OAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/apiKeys/index.ts"],"names":[],"mappings":";;;AAAA,mCAAkC;AAAzB,gGAAA,MAAM,OAAA;AAEf,qCAOmB;AANjB,uGAAA,YAAY,OAAA;AACZ,sGAAA,WAAW,OAAA;AACX,uGAAA,YAAY,OAAA;AACZ,uGAAA,YAAY,OAAA;AACZ,uGAAA,YAAY,OAAA;AACZ,uGAAA,YAAY,OAAA;AAGd,2CAA4E;AAAnE,+GAAA,iBAAiB,OAAA;AAAE,0GAAA,YAAY,OAAA;AAAE,yGAAA,WAAW,OAAA;AAErD,iCAOiB;AANf,uGAAA,cAAc,OAAA;AACd,sGAAA,aAAa,OAAA;AACb,wGAAA,eAAe,OAAA;AACf,kGAAA,SAAS,OAAA;AACT,mGAAA,UAAU,OAAA;AACV,oGAAA,WAAW,OAAA;AAUb,mCAKkB;AAJhB,yGAAA,eAAe,OAAA;AACf,uGAAA,aAAa,OAAA;AACb,gHAAA,sBAAsB,OAAA;AACtB,iHAAA,uBAAuB,OAAA"}
@@ -1,5 +1,5 @@
1
1
  import { RequestHandler } from 'express';
2
- import { type ApiKeyScope } from './types';
2
+ import { type ApiKeyScope, type ApiKeyTenant, type Tenant } from './types';
3
3
  /**
4
4
  * Request-scoped facts about the key a request arrived on. Absent on ordinary
5
5
  * session requests, which is itself the signal a handler needs: `req.apiKey`
@@ -8,8 +8,22 @@ import { type ApiKeyScope } from './types';
8
8
  export interface ApiKeyContext {
9
9
  keyId: string;
10
10
  scopes: ApiKeyScope[];
11
- /** the tenant this key is pinned to; null means the owner's personal data */
12
- groupId: string | null;
11
+ /** every tenant this credential may act in, and the one it acts in by default */
12
+ tenants: ApiKeyTenant;
13
+ /** the tenant this particular request resolved to */
14
+ actingAs: Tenant;
15
+ /** which credential this is; they are revoked and audited differently */
16
+ kind: 'api_key' | 'oauth';
17
+ /** what the owner called it — a key's name, or the connected app's */
18
+ label: string;
19
+ /**
20
+ * The stable identity of the credential.
21
+ *
22
+ * A key's document id, or an OAuth client id — never the access token's
23
+ * `jti`, which rotates hourly and would make one connection look like a new
24
+ * actor every time it refreshed.
25
+ */
26
+ credentialId: string;
13
27
  }
14
28
  declare global {
15
29
  namespace Express {
@@ -1 +1 @@
1
- {"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../../src/apiKeys/middleware.ts"],"names":[],"mappings":"AAAA,OAAO,EAAyB,cAAc,EAAY,MAAM,SAAS,CAAC;AAQ1E,OAAO,EAAiB,KAAK,WAAW,EAAE,MAAM,SAAS,CAAC;AAE1D;;;;GAIG;AACH,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,WAAW,EAAE,CAAC;IACtB,6EAA6E;IAC7E,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CACxB;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,OAAO,CAAC;QAChB,UAAU,OAAO;YACf,MAAM,CAAC,EAAE,aAAa,CAAC;SACxB;KACF;CACF;AAgHD;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,iBAAiB,GAAI,GAAG,gBAAgB,WAAW,EAAE,KAAG,cA+DlE,CAAC;AAEJ;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,YAAY,GAAI,GAAG,gBAAgB,WAAW,EAAE,KAAG,cAiB7D,CAAC;AAEJ;;;;;;GAMG;AACH,eAAO,MAAM,WAAW,EAAE,cASzB,CAAC"}
1
+ {"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../../src/apiKeys/middleware.ts"],"names":[],"mappings":"AAAA,OAAO,EAAyB,cAAc,EAAY,MAAM,SAAS,CAAC;AAS1E,OAAO,EAKL,KAAK,WAAW,EAChB,KAAK,YAAY,EACjB,KAAK,MAAM,EACZ,MAAM,SAAS,CAAC;AAEjB;;;;GAIG;AACH,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,WAAW,EAAE,CAAC;IACtB,iFAAiF;IACjF,OAAO,EAAE,YAAY,CAAC;IACtB,qDAAqD;IACrD,QAAQ,EAAE,MAAM,CAAC;IACjB,yEAAyE;IACzE,IAAI,EAAE,SAAS,GAAG,OAAO,CAAC;IAC1B,sEAAsE;IACtE,KAAK,EAAE,MAAM,CAAC;IACd;;;;;;OAMG;IACH,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,OAAO,CAAC;QAChB,UAAU,OAAO;YACf,MAAM,CAAC,EAAE,aAAa,CAAC;SACxB;KACF;CACF;AAgJD;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,iBAAiB,GAAI,GAAG,gBAAgB,WAAW,EAAE,KAAG,cAoElE,CAAC;AAEJ;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,YAAY,GAAI,GAAG,gBAAgB,WAAW,EAAE,KAAG,cAiB7D,CAAC;AAEJ;;;;;;GAMG;AACH,eAAO,MAAM,WAAW,EAAE,cASzB,CAAC"}
@@ -7,6 +7,7 @@ exports.denyApiKeys = exports.requireScope = exports.authenticateAgent = void 0;
7
7
  const jsonwebtoken_1 = __importDefault(require("jsonwebtoken"));
8
8
  const env_1 = require("../config/env");
9
9
  const logger_1 = __importDefault(require("../logging/logger"));
10
+ const context_1 = require("../audit/context");
10
11
  const tokens_1 = require("../oauth/tokens");
11
12
  const crypto_1 = require("./crypto");
12
13
  const service_1 = require("./service");
@@ -20,10 +21,12 @@ const unauthorized = (res) => {
20
21
  * The tenant a request is asking to act in, wherever it named one.
21
22
  *
22
23
  * Handlers read `groupId` from either the query string or the body depending on
23
- * the verb, so both are checked — a pin that only covered one of them would be
24
- * no pin at all.
24
+ * the verb, so both are checked — a rule that only covered one of them would be
25
+ * no rule at all. A caller names the personal tenant with the literal
26
+ * `personal`, since "no group" is what the resolved default gets written into
27
+ * and would otherwise be indistinguishable from not having asked.
25
28
  */
26
- const requestedGroupId = (req) => {
29
+ const requestedTenant = (req) => {
27
30
  const fromQuery = req.query?.groupId;
28
31
  if (typeof fromQuery === 'string' && fromQuery.length > 0)
29
32
  return fromQuery;
@@ -32,33 +35,50 @@ const requestedGroupId = (req) => {
32
35
  return fromBody;
33
36
  return undefined;
34
37
  };
38
+ /** Express 5 makes `req.query` a getter, so it is redefined rather than assigned. */
39
+ const setQueryGroupId = (req, groupId) => {
40
+ const query = { ...req.query };
41
+ if (groupId === undefined)
42
+ delete query.groupId;
43
+ else
44
+ query.groupId = groupId;
45
+ Object.defineProperty(req, 'query', {
46
+ value: query,
47
+ writable: true,
48
+ configurable: true,
49
+ enumerable: true
50
+ });
51
+ };
35
52
  /**
36
- * Hold a key to the tenant it was issued for.
53
+ * Hold a credential to the tenants it was granted, and settle which one this
54
+ * request is acting in.
55
+ *
56
+ * A request naming a tenant outside the grant is refused outright — that
57
+ * boundary is the whole reason a credential is safe to hand to an agent, and it
58
+ * is unchanged by the grant being a set rather than one. What the set adds is a
59
+ * choice *inside* it, which is what lets one connection reach a shared journal
60
+ * and a private photo library without reconnecting.
37
61
  *
38
- * Two things happen here, and the second is the one that makes keys pleasant to
39
- * use. A request that names a *different* tenant is refused outright the pin
40
- * is the whole reason a key is safe to hand to an agent. A request that names
41
- * none has the pinned tenant written in for it, so the agent never has to know a
42
- * group id exists, and a handler's `if (groupId) ... else personal` branch lands
43
- * where the key's owner intended.
62
+ * A request that names nothing gets the default written in for it, so an agent
63
+ * granted a single tenant never has to know a group id exists and a handler's
64
+ * `if (groupId) else personal` branch lands where the owner intended.
44
65
  */
45
- const applyTenantPin = (req, groupId) => {
46
- const requested = requestedGroupId(req);
47
- if (requested !== undefined && requested !== groupId)
48
- return false;
49
- if (groupId !== null && requested === undefined) {
50
- // Express 5 makes req.query a getter, so it is redefined rather than assigned.
51
- Object.defineProperty(req, 'query', {
52
- value: { ...req.query, groupId },
53
- writable: true,
54
- configurable: true,
55
- enumerable: true
56
- });
57
- if (req.body && typeof req.body === 'object') {
66
+ const applyTenantGrant = (req, tenants) => {
67
+ const requested = requestedTenant(req) ?? tenants.default;
68
+ if (!tenants.allowed.includes(requested))
69
+ return null;
70
+ // Resolved either way, including when the caller asked for exactly what the
71
+ // default already was: handlers read the personal tenant as an absent
72
+ // `groupId`, so `personal` has to be erased rather than passed through.
73
+ const groupId = requested === types_1.PERSONAL_TENANT ? undefined : requested;
74
+ setQueryGroupId(req, groupId);
75
+ if (req.body && typeof req.body === 'object') {
76
+ if (groupId === undefined)
77
+ delete req.body.groupId;
78
+ else
58
79
  req.body.groupId = groupId;
59
- }
60
80
  }
61
- return true;
81
+ return requested;
62
82
  };
63
83
  /**
64
84
  * Admit software acting for a user, on the terms its credential carries.
@@ -78,7 +98,8 @@ function admitAgent(req, res, next, requiredScopes, credential) {
78
98
  });
79
99
  return;
80
100
  }
81
- if (!applyTenantPin(req, credential.groupId)) {
101
+ const actingAs = applyTenantGrant(req, credential.tenants);
102
+ if (actingAs === null) {
82
103
  res.status(403).json({
83
104
  success: false,
84
105
  message: 'Credential is not permitted to act in the requested group'
@@ -86,12 +107,23 @@ function admitAgent(req, res, next, requiredScopes, credential) {
86
107
  return;
87
108
  }
88
109
  req.user = { id: credential.userId, email: credential.email, name: credential.name };
89
- // Only the pinned group, never the owner's full membership: this is what
110
+ // Only the granted groups, never the owner's full membership: this is what
90
111
  // stops a credential reaching a group it was not issued for through any
91
112
  // handler that consults `userGroups` instead of the `groupId` parameter.
92
- req.userGroups = credential.groupId ? [credential.groupId] : [];
93
- req.apiKey = { keyId: credential.credentialId, scopes: credential.scopes, groupId: credential.groupId };
94
- next();
113
+ req.userGroups = (0, types_1.groupIdsOf)(credential.tenants.allowed);
114
+ req.apiKey = {
115
+ keyId: credential.credentialId,
116
+ scopes: credential.scopes,
117
+ tenants: credential.tenants,
118
+ actingAs,
119
+ kind: credential.kind,
120
+ label: credential.label,
121
+ credentialId: credential.credentialId
122
+ };
123
+ // Attribution comes from authentication, so it is established here rather
124
+ // than mounted separately — a router that authenticates per route would
125
+ // otherwise have no actor in scope when a router-level middleware ran.
126
+ (0, context_1.beginAudit)(req, res, next);
95
127
  }
96
128
  /**
97
129
  * Authenticate a request that software may legitimately be making.
@@ -124,7 +156,7 @@ const authenticateAgent = (...requiredScopes) => async function authenticateAgen
124
156
  const user = claims;
125
157
  req.user = user;
126
158
  req.userGroups = user.groups ?? [];
127
- next();
159
+ (0, context_1.beginAudit)(req, res, next);
128
160
  return;
129
161
  }
130
162
  // An OAuth access token: signed with the same secret as a session and
@@ -138,12 +170,15 @@ const authenticateAgent = (...requiredScopes) => async function authenticateAgen
138
170
  // whose scope collapsed to nothing fell through to "no user context" and
139
171
  // answered from the whole collection.
140
172
  admitAgent(req, res, next, requiredScopes, {
141
- credentialId: claims.jti,
173
+ // The client, not the token: `jti` is a new value every hour.
174
+ credentialId: claims.clientId ?? 'unknown-client',
175
+ kind: 'oauth',
176
+ label: claims.clientName || 'A connected app',
142
177
  userId: claims.sub,
143
178
  email: claims.email ?? '',
144
179
  name: claims.name ?? '',
145
180
  scopes: (claims.scope ?? '').split(' ').filter(types_1.isApiKeyScope),
146
- groupId: claims.groupId ?? null
181
+ tenants: (0, types_1.readTenants)(claims)
147
182
  });
148
183
  return;
149
184
  }
@@ -157,11 +192,13 @@ const authenticateAgent = (...requiredScopes) => async function authenticateAgen
157
192
  }
158
193
  admitAgent(req, res, next, requiredScopes, {
159
194
  credentialId: result.keyId,
195
+ kind: 'api_key',
196
+ label: result.label || 'An API key',
160
197
  userId: result.userId,
161
198
  email: result.userEmail ?? '',
162
199
  name: result.userName ?? '',
163
200
  scopes: result.scopes ?? [],
164
- groupId: result.groupId ?? null
201
+ tenants: result.tenants ?? (0, types_1.readTenants)({})
165
202
  });
166
203
  };
167
204
  exports.authenticateAgent = authenticateAgent;
@@ -1 +1 @@
1
- {"version":3,"file":"middleware.js","sourceRoot":"","sources":["../../src/apiKeys/middleware.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"middleware.js","sourceRoot":"","sources":["../../src/apiKeys/middleware.ts"],"names":[],"mappings":"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"}
@@ -1,12 +1,14 @@
1
- import type { ApiKeyScope, ApiKeySummary, ApiKeyVerification } from './types';
1
+ import { type ApiKeyScope, type ApiKeySummary, type ApiKeyVerification, type Tenant } from './types';
2
2
  export interface CreateApiKeyInput {
3
3
  userId: string;
4
4
  userEmail: string;
5
5
  userName: string;
6
6
  name: string;
7
7
  scopes: ApiKeyScope[];
8
- /** null pins the key to the user's own non-group data */
9
- groupId?: string | null;
8
+ /** every tenant the key may act in; defaults to the user's own data alone */
9
+ tenants?: Tenant[];
10
+ /** which of them it acts in when a request names none */
11
+ defaultTenant?: Tenant;
10
12
  expiresAt?: Date | null;
11
13
  }
12
14
  export interface CreatedApiKey {
@@ -1 +1 @@
1
- {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../src/apiKeys/service.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAE9E,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,WAAW,EAAE,CAAC;IACtB,yDAAyD;IACzD,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,SAAS,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;CACzB;AAED,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,aAAa,CAAC;IACvB,+EAA+E;IAC/E,KAAK,EAAE,MAAM,CAAC;CACf;AAcD,eAAO,MAAM,YAAY,GAAU,OAAO,iBAAiB,KAAG,OAAO,CAAC,aAAa,CAoBlF,CAAC;AAEF,eAAO,MAAM,WAAW,GAAU,QAAQ,MAAM,KAAG,OAAO,CAAC,aAAa,EAAE,CAGzE,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,YAAY,GAAU,QAAQ,MAAM,EAAE,IAAI,MAAM,KAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAepF,CAAC;AAEF,+EAA+E;AAC/E,eAAO,MAAM,YAAY,GAAU,QAAQ,MAAM,EAAE,IAAI,MAAM,KAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAU3F,CAAC;AAEF,eAAO,MAAM,YAAY,GAAU,QAAQ,MAAM,EAAE,IAAI,MAAM,KAAG,OAAO,CAAC,OAAO,CAG9E,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,YAAY,GAAU,OAAO,OAAO,KAAG,OAAO,CAAC,kBAAkB,CA2B7E,CAAC"}
1
+ {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../src/apiKeys/service.ts"],"names":[],"mappings":"AASA,OAAO,EAGL,KAAK,WAAW,EAChB,KAAK,aAAa,EAClB,KAAK,kBAAkB,EACvB,KAAK,MAAM,EACZ,MAAM,SAAS,CAAC;AAEjB,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,WAAW,EAAE,CAAC;IACtB,6EAA6E;IAC7E,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,yDAAyD;IACzD,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,SAAS,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;CACzB;AAED,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,aAAa,CAAC;IACvB,+EAA+E;IAC/E,KAAK,EAAE,MAAM,CAAC;CACf;AAgBD,eAAO,MAAM,YAAY,GAAU,OAAO,iBAAiB,KAAG,OAAO,CAAC,aAAa,CA2BlF,CAAC;AAEF,eAAO,MAAM,WAAW,GAAU,QAAQ,MAAM,KAAG,OAAO,CAAC,aAAa,EAAE,CAGzE,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,YAAY,GAAU,QAAQ,MAAM,EAAE,IAAI,MAAM,KAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAepF,CAAC;AAEF,+EAA+E;AAC/E,eAAO,MAAM,YAAY,GAAU,QAAQ,MAAM,EAAE,IAAI,MAAM,KAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAU3F,CAAC;AAEF,eAAO,MAAM,YAAY,GAAU,QAAQ,MAAM,EAAE,IAAI,MAAM,KAAG,OAAO,CAAC,OAAO,CAG9E,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,YAAY,GAAU,OAAO,OAAO,KAAG,OAAO,CAAC,kBAAkB,CA4B7E,CAAC"}
@@ -3,18 +3,22 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.verifyApiKey = exports.deleteApiKey = exports.revokeApiKey = exports.revealApiKey = exports.listApiKeys = exports.createApiKey = void 0;
4
4
  const ApiKey_1 = require("./ApiKey");
5
5
  const crypto_1 = require("./crypto");
6
+ const types_1 = require("./types");
6
7
  const toSummary = (key) => ({
7
8
  id: String(key._id),
8
9
  name: key.name,
9
10
  prefix: (0, crypto_1.displayPrefix)(key.keyId),
10
11
  scopes: key.scopes,
11
- groupId: key.groupId ?? null,
12
+ ...(({ allowed, default: fallback }) => ({ tenants: allowed, defaultTenant: fallback }))((0, types_1.readTenants)(key)),
12
13
  createdAt: key.createdAt.toISOString(),
13
14
  lastUsedAt: key.lastUsedAt?.toISOString() ?? null,
14
15
  expiresAt: key.expiresAt?.toISOString() ?? null,
15
16
  revokedAt: key.revokedAt?.toISOString() ?? null
16
17
  });
17
18
  const createApiKey = async (input) => {
19
+ // A key that reaches nowhere would authenticate and then fail every call, so
20
+ // an empty grant is read as the safest non-empty one rather than stored.
21
+ const tenants = input.tenants?.length ? input.tenants : [types_1.PERSONAL_TENANT];
18
22
  const { token, id, hash } = (0, crypto_1.generateKey)();
19
23
  const sealed = (0, crypto_1.encryptSecret)(token);
20
24
  const key = await ApiKey_1.ApiKey.create({
@@ -28,7 +32,10 @@ const createApiKey = async (input) => {
28
32
  sealedIv: sealed.iv,
29
33
  sealedTag: sealed.tag,
30
34
  scopes: input.scopes,
31
- groupId: input.groupId ?? null,
35
+ tenants,
36
+ defaultTenant: tenants.includes(input.defaultTenant ?? '')
37
+ ? input.defaultTenant
38
+ : tenants[0],
32
39
  expiresAt: input.expiresAt ?? undefined
33
40
  });
34
41
  return { summary: toSummary(key), token };
@@ -114,8 +121,9 @@ const verifyApiKey = async (token) => {
114
121
  userEmail: key.userEmail,
115
122
  userName: key.userName,
116
123
  keyId: String(key._id),
124
+ label: key.name,
117
125
  scopes: key.scopes,
118
- groupId: key.groupId ?? null
126
+ tenants: (0, types_1.readTenants)(key)
119
127
  };
120
128
  };
121
129
  exports.verifyApiKey = verifyApiKey;
@@ -1 +1 @@
1
- {"version":3,"file":"service.js","sourceRoot":"","sources":["../../src/apiKeys/service.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"service.js","sourceRoot":"","sources":["../../src/apiKeys/service.ts"],"names":[],"mappings":"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"}
@@ -12,16 +12,48 @@ export declare const API_KEY_SCOPES: readonly ["relationship:read", "relationshi
12
12
  export type ApiKeyScope = (typeof API_KEY_SCOPES)[number];
13
13
  export declare const isApiKeyScope: (value: unknown) => value is ApiKeyScope;
14
14
  /**
15
- * The tenant a key acts in, fixed when the key is created.
15
+ * A tenant a credential may act in: a group id, or the user's own data.
16
16
  *
17
- * The web app picks this per request from a tenant selector, but an agent has no
18
- * such UI and no way to know it guessed wrong so the choice is made once, by a
19
- * person, and the key cannot escape it. `groupId: null` means the user's own
20
- * non-group data.
17
+ * Personal is a named sentinel rather than `null` so that a tenant is always a
18
+ * plain string storable in an array, sendable in a JWT claim, comparable
19
+ * without a special case at every layer. It cannot collide with a real tenant:
20
+ * group ids are 24-character hex.
21
+ */
22
+ export declare const PERSONAL_TENANT = "personal";
23
+ export type Tenant = string;
24
+ /** The `groupId` a tenant corresponds to, as handlers have always read it. */
25
+ export declare const groupIdOf: (tenant: Tenant) => string | null;
26
+ /**
27
+ * Which tenants a credential may act in, and which one it acts in by default.
28
+ *
29
+ * The web app picks a tenant per request from a selector; an agent has no such
30
+ * UI. So the *set* is chosen once, by a person, and the credential cannot escape
31
+ * it — but within that set the caller may name one per request, which is what
32
+ * lets a single connection reach both a shared journal and a private photo
33
+ * library without reconnecting.
34
+ *
35
+ * `allowed` is never empty and always contains `default`. A credential granted
36
+ * exactly one tenant behaves precisely as a pinned one did: nothing to name,
37
+ * nothing to get wrong.
21
38
  */
22
39
  export interface ApiKeyTenant {
23
- groupId: string | null;
40
+ allowed: Tenant[];
41
+ default: Tenant;
24
42
  }
43
+ /** Just the groups, for the `req.userGroups` every handler already reads. */
44
+ export declare const groupIdsOf: (tenants: Tenant[]) => string[];
45
+ /**
46
+ * Read a stored tenant grant, tolerating one written before tenants were a set.
47
+ *
48
+ * Keys and grants issued under the old single-tenant model carry `groupId`
49
+ * alone. Falling back to it here means they keep working across the deploy
50
+ * rather than every connected assistant breaking at once.
51
+ */
52
+ export declare const readTenants: (stored: {
53
+ tenants?: Tenant[] | null;
54
+ defaultTenant?: Tenant | null;
55
+ groupId?: string | null;
56
+ }) => ApiKeyTenant;
25
57
  /** A key as the API hands it back — never including the secret. */
26
58
  export interface ApiKeySummary {
27
59
  id: string;
@@ -29,7 +61,8 @@ export interface ApiKeySummary {
29
61
  /** the public half, shown in listings so a key is identifiable at a glance */
30
62
  prefix: string;
31
63
  scopes: ApiKeyScope[];
32
- groupId: string | null;
64
+ tenants: Tenant[];
65
+ defaultTenant: Tenant;
33
66
  createdAt: string;
34
67
  lastUsedAt: string | null;
35
68
  expiresAt: string | null;
@@ -44,7 +77,9 @@ export interface ApiKeyVerification {
44
77
  userEmail?: string;
45
78
  userName?: string;
46
79
  keyId?: string;
80
+ /** what the owner called this key, for an audit trail a person can read */
81
+ label?: string;
47
82
  scopes?: ApiKeyScope[];
48
- groupId?: string | null;
83
+ tenants?: ApiKeyTenant;
49
84
  }
50
85
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/apiKeys/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,+EAA+E;AAC/E,eAAO,MAAM,cAAc,oHAOjB,CAAC;AAEX,MAAM,MAAM,WAAW,GAAG,CAAC,OAAO,cAAc,CAAC,CAAC,MAAM,CAAC,CAAC;AAE1D,eAAO,MAAM,aAAa,GAAI,OAAO,OAAO,KAAG,KAAK,IAAI,WAC4B,CAAC;AAErF;;;;;;;GAOG;AACH,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CACxB;AAED,mEAAmE;AACnE,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,8EAA8E;IAC9E,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,WAAW,EAAE,CAAC;IACtB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAED,2FAA2F;AAC3F,MAAM,MAAM,eAAe,GACvB,WAAW,GACX,SAAS,GACT,SAAS,GACT,SAAS,GACT,YAAY,CAAC;AAEjB,MAAM,WAAW,kBAAkB;IACjC,EAAE,EAAE,OAAO,CAAC;IACZ,SAAS,CAAC,EAAE,eAAe,CAAC;IAC5B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,WAAW,EAAE,CAAC;IACvB,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/apiKeys/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,+EAA+E;AAC/E,eAAO,MAAM,cAAc,oHAOjB,CAAC;AAEX,MAAM,MAAM,WAAW,GAAG,CAAC,OAAO,cAAc,CAAC,CAAC,MAAM,CAAC,CAAC;AAE1D,eAAO,MAAM,aAAa,GAAI,OAAO,OAAO,KAAG,KAAK,IAAI,WAC4B,CAAC;AAErF;;;;;;;GAOG;AACH,eAAO,MAAM,eAAe,aAAa,CAAC;AAE1C,MAAM,MAAM,MAAM,GAAG,MAAM,CAAC;AAE5B,8EAA8E;AAC9E,eAAO,MAAM,SAAS,GAAI,QAAQ,MAAM,KAAG,MAAM,GAAG,IACR,CAAC;AAE7C;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,6EAA6E;AAC7E,eAAO,MAAM,UAAU,GAAI,SAAS,MAAM,EAAE,KAAG,MAAM,EACG,CAAC;AAEzD;;;;;;GAMG;AACH,eAAO,MAAM,WAAW,GAAI,QAAQ;IAClC,OAAO,CAAC,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;IAC1B,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB,KAAG,YAaH,CAAC;AAEF,mEAAmE;AACnE,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,8EAA8E;IAC9E,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,WAAW,EAAE,CAAC;IACtB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAED,2FAA2F;AAC3F,MAAM,MAAM,eAAe,GACvB,WAAW,GACX,SAAS,GACT,SAAS,GACT,SAAS,GACT,YAAY,CAAC;AAEjB,MAAM,WAAW,kBAAkB;IACjC,EAAE,EAAE,OAAO,CAAC;IACZ,SAAS,CAAC,EAAE,eAAe,CAAC;IAC5B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,2EAA2E;IAC3E,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,WAAW,EAAE,CAAC;IACvB,OAAO,CAAC,EAAE,YAAY,CAAC;CACxB"}