@tumbaland/backend-core 1.36.0 → 1.38.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 (56) hide show
  1. package/dist/apiKeys/ApiKey.d.ts +12 -3
  2. package/dist/apiKeys/ApiKey.d.ts.map +1 -1
  3. package/dist/apiKeys/ApiKey.js +5 -1
  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 +9 -5
  10. package/dist/apiKeys/middleware.d.ts.map +1 -1
  11. package/dist/apiKeys/middleware.js +125 -59
  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 +10 -3
  16. package/dist/apiKeys/service.js.map +1 -1
  17. package/dist/apiKeys/types.d.ts +41 -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/middleware/authMiddleware.d.ts +7 -0
  22. package/dist/middleware/authMiddleware.d.ts.map +1 -1
  23. package/dist/middleware/authMiddleware.js +25 -4
  24. package/dist/middleware/authMiddleware.js.map +1 -1
  25. package/dist/oauth/index.d.ts +1 -1
  26. package/dist/oauth/index.d.ts.map +1 -1
  27. package/dist/oauth/index.js +3 -1
  28. package/dist/oauth/index.js.map +1 -1
  29. package/dist/oauth/models.d.ts +13 -2
  30. package/dist/oauth/models.d.ts.map +1 -1
  31. package/dist/oauth/models.js +9 -0
  32. package/dist/oauth/models.js.map +1 -1
  33. package/dist/oauth/service.d.ts +15 -8
  34. package/dist/oauth/service.d.ts.map +1 -1
  35. package/dist/oauth/service.js +10 -3
  36. package/dist/oauth/service.js.map +1 -1
  37. package/dist/oauth/tokens.d.ts +34 -8
  38. package/dist/oauth/tokens.d.ts.map +1 -1
  39. package/dist/oauth/tokens.js +22 -6
  40. package/dist/oauth/tokens.js.map +1 -1
  41. package/package.json +1 -1
  42. package/src/apiKeys/ApiKey.ts +16 -4
  43. package/src/apiKeys/index.ts +16 -2
  44. package/src/apiKeys/middleware.test.ts +207 -16
  45. package/src/apiKeys/middleware.ts +159 -66
  46. package/src/apiKeys/service.test.ts +56 -9
  47. package/src/apiKeys/service.ts +24 -6
  48. package/src/apiKeys/types.ts +61 -8
  49. package/src/middleware/authMiddleware.test.ts +52 -0
  50. package/src/middleware/authMiddleware.ts +26 -4
  51. package/src/oauth/index.ts +7 -1
  52. package/src/oauth/models.ts +21 -2
  53. package/src/oauth/service.test.ts +58 -6
  54. package/src/oauth/service.ts +25 -7
  55. package/src/oauth/tokens.test.ts +20 -5
  56. package/src/oauth/tokens.ts +51 -11
@@ -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;
@@ -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;AACtD,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,eAAO,MAAM,MAAM;;;;;;gBAEgC,CAAC"}
@@ -35,6 +35,7 @@ var __importStar = (this && this.__importStar) || (function () {
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.ApiKey = void 0;
37
37
  const mongoose_1 = __importStar(require("mongoose"));
38
+ const types_1 = require("./types");
38
39
  const ApiKeySchema = new mongoose_1.Schema({
39
40
  userId: { type: String, required: true, index: true },
40
41
  userEmail: { type: String, required: true },
@@ -46,8 +47,11 @@ const ApiKeySchema = new mongoose_1.Schema({
46
47
  sealedIv: { type: String, required: true },
47
48
  sealedTag: { type: String, required: true },
48
49
  scopes: { type: [String], default: [] },
49
- // Explicitly nullable rather than optional: "personal scope" is a decision the
50
+ // Defaulted rather than optional: which data a key reaches is a decision the
50
51
  // creator made, and it must not be indistinguishable from a field nobody set.
52
+ tenants: { type: [String], default: () => [types_1.PERSONAL_TENANT] },
53
+ defaultTenant: { type: String, default: types_1.PERSONAL_TENANT },
54
+ // Written by the single-tenant model this replaced; read-only now.
51
55
  groupId: { type: String, default: null },
52
56
  lastUsedAt: { type: Date },
53
57
  expiresAt: { type: Date },
@@ -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,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;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"}
@@ -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,10 @@ 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;
13
15
  }
14
16
  declare global {
15
17
  namespace Express {
@@ -40,11 +42,13 @@ export declare const authenticateAgent: (...requiredScopes: ApiKeyScope[]) => Re
40
42
  * door for lacking a scope half the router never uses.
41
43
  *
42
44
  * A session passes unconditionally: scopes narrow what software may do on a
43
- * person's behalf, not what the person may do themselves.
45
+ * person's behalf, not what the person may do themselves. Everything that is
46
+ * not a session — an API key or an OAuth access token alike — arrives with
47
+ * `req.apiKey` set and is held to it.
44
48
  */
45
49
  export declare const requireScope: (...requiredScopes: ApiKeyScope[]) => RequestHandler;
46
50
  /**
47
- * Refuse API keys on a route that a session may still use.
51
+ * Refuse every non-session credential on a route that a session may still use.
48
52
  *
49
53
  * For the handful of operations that should stay a person's to perform — key
50
54
  * management itself, most obviously, since a key that can mint keys is a key
@@ -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;AAO1E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAE3C;;;;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;AA0DD;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,iBAAiB,GAAI,GAAG,gBAAgB,WAAW,EAAE,KAAG,cA4DlE,CAAC;AAEJ;;;;;;;;;;GAUG;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;AAQ1E,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;CAClB;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,OAAO,CAAC;QAChB,UAAU,OAAO;YACf,MAAM,CAAC,EAAE,aAAa,CAAC;SACxB;KACF;CACF;AAuID;;;;;;;;;;;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"}
@@ -7,8 +7,10 @@ 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 tokens_1 = require("../oauth/tokens");
10
11
  const crypto_1 = require("./crypto");
11
12
  const service_1 = require("./service");
13
+ const types_1 = require("./types");
12
14
  /** Both auth paths read the token from the same two places. */
13
15
  const extractToken = (req) => req.cookies?.access_token || req.headers.authorization?.replace('Bearer ', '');
14
16
  const unauthorized = (res) => {
@@ -18,10 +20,12 @@ const unauthorized = (res) => {
18
20
  * The tenant a request is asking to act in, wherever it named one.
19
21
  *
20
22
  * Handlers read `groupId` from either the query string or the body depending on
21
- * the verb, so both are checked — a pin that only covered one of them would be
22
- * no pin at all.
23
+ * the verb, so both are checked — a rule that only covered one of them would be
24
+ * no rule at all. A caller names the personal tenant with the literal
25
+ * `personal`, since "no group" is what the resolved default gets written into
26
+ * and would otherwise be indistinguishable from not having asked.
23
27
  */
24
- const requestedGroupId = (req) => {
28
+ const requestedTenant = (req) => {
25
29
  const fromQuery = req.query?.groupId;
26
30
  if (typeof fromQuery === 'string' && fromQuery.length > 0)
27
31
  return fromQuery;
@@ -30,34 +34,90 @@ const requestedGroupId = (req) => {
30
34
  return fromBody;
31
35
  return undefined;
32
36
  };
37
+ /** Express 5 makes `req.query` a getter, so it is redefined rather than assigned. */
38
+ const setQueryGroupId = (req, groupId) => {
39
+ const query = { ...req.query };
40
+ if (groupId === undefined)
41
+ delete query.groupId;
42
+ else
43
+ query.groupId = groupId;
44
+ Object.defineProperty(req, 'query', {
45
+ value: query,
46
+ writable: true,
47
+ configurable: true,
48
+ enumerable: true
49
+ });
50
+ };
33
51
  /**
34
- * Hold a key to the tenant it was issued for.
52
+ * Hold a credential to the tenants it was granted, and settle which one this
53
+ * request is acting in.
54
+ *
55
+ * A request naming a tenant outside the grant is refused outright — that
56
+ * boundary is the whole reason a credential is safe to hand to an agent, and it
57
+ * is unchanged by the grant being a set rather than one. What the set adds is a
58
+ * choice *inside* it, which is what lets one connection reach a shared journal
59
+ * and a private photo library without reconnecting.
35
60
  *
36
- * Two things happen here, and the second is the one that makes keys pleasant to
37
- * use. A request that names a *different* tenant is refused outright the pin
38
- * is the whole reason a key is safe to hand to an agent. A request that names
39
- * none has the pinned tenant written in for it, so the agent never has to know a
40
- * group id exists, and a handler's `if (groupId) ... else personal` branch lands
41
- * where the key's owner intended.
61
+ * A request that names nothing gets the default written in for it, so an agent
62
+ * granted a single tenant never has to know a group id exists and a handler's
63
+ * `if (groupId) else personal` branch lands where the owner intended.
42
64
  */
43
- const applyTenantPin = (req, groupId) => {
44
- const requested = requestedGroupId(req);
45
- if (requested !== undefined && requested !== groupId)
46
- return false;
47
- if (groupId !== null && requested === undefined) {
48
- // Express 5 makes req.query a getter, so it is redefined rather than assigned.
49
- Object.defineProperty(req, 'query', {
50
- value: { ...req.query, groupId },
51
- writable: true,
52
- configurable: true,
53
- enumerable: true
54
- });
55
- if (req.body && typeof req.body === 'object') {
65
+ const applyTenantGrant = (req, tenants) => {
66
+ const requested = requestedTenant(req) ?? tenants.default;
67
+ if (!tenants.allowed.includes(requested))
68
+ return null;
69
+ // Resolved either way, including when the caller asked for exactly what the
70
+ // default already was: handlers read the personal tenant as an absent
71
+ // `groupId`, so `personal` has to be erased rather than passed through.
72
+ const groupId = requested === types_1.PERSONAL_TENANT ? undefined : requested;
73
+ setQueryGroupId(req, groupId);
74
+ if (req.body && typeof req.body === 'object') {
75
+ if (groupId === undefined)
76
+ delete req.body.groupId;
77
+ else
56
78
  req.body.groupId = groupId;
57
- }
58
79
  }
59
- return true;
80
+ return requested;
60
81
  };
82
+ /**
83
+ * Admit software acting for a user, on the terms its credential carries.
84
+ *
85
+ * Shared by both non-session credentials on purpose. An API key and an OAuth
86
+ * access token differ entirely in how they are issued and verified, and not at
87
+ * all in what they mean once they are: a user, a set of scopes, and one tenant.
88
+ * Settling that in one place is what keeps the two from drifting into subtly
89
+ * different amounts of access.
90
+ */
91
+ function admitAgent(req, res, next, requiredScopes, credential) {
92
+ const missing = requiredScopes.filter((scope) => !credential.scopes.includes(scope));
93
+ if (missing.length > 0) {
94
+ res.status(403).json({
95
+ success: false,
96
+ message: `Credential is missing required scope: ${missing.join(', ')}`
97
+ });
98
+ return;
99
+ }
100
+ const actingAs = applyTenantGrant(req, credential.tenants);
101
+ if (actingAs === null) {
102
+ res.status(403).json({
103
+ success: false,
104
+ message: 'Credential is not permitted to act in the requested group'
105
+ });
106
+ return;
107
+ }
108
+ req.user = { id: credential.userId, email: credential.email, name: credential.name };
109
+ // Only the granted groups, never the owner's full membership: this is what
110
+ // stops a credential reaching a group it was not issued for through any
111
+ // handler that consults `userGroups` instead of the `groupId` parameter.
112
+ req.userGroups = (0, types_1.groupIdsOf)(credential.tenants.allowed);
113
+ req.apiKey = {
114
+ keyId: credential.credentialId,
115
+ scopes: credential.scopes,
116
+ tenants: credential.tenants,
117
+ actingAs
118
+ };
119
+ next();
120
+ }
61
121
  /**
62
122
  * Authenticate a request that software may legitimately be making.
63
123
  *
@@ -77,15 +137,39 @@ const authenticateAgent = (...requiredScopes) => async function authenticateAgen
77
137
  return;
78
138
  }
79
139
  if (!(0, crypto_1.looksLikeApiKey)(token)) {
140
+ let claims;
80
141
  try {
81
- const user = jsonwebtoken_1.default.verify(token, (0, env_1.requireEnv)('JWT_SECRET'));
82
- req.user = user;
83
- req.userGroups = user.groups ?? [];
84
- next();
142
+ claims = jsonwebtoken_1.default.verify(token, (0, env_1.requireEnv)('JWT_SECRET'));
85
143
  }
86
144
  catch {
87
145
  unauthorized(res);
146
+ return;
147
+ }
148
+ if (!(0, tokens_1.isAccessTokenClaims)(claims)) {
149
+ const user = claims;
150
+ req.user = user;
151
+ req.userGroups = user.groups ?? [];
152
+ next();
153
+ return;
88
154
  }
155
+ // An OAuth access token: signed with the same secret as a session and
156
+ // arriving in the same header, but nothing like one. It names its user in
157
+ // `sub`, carries scopes, and is pinned to a tenant — so it is admitted
158
+ // the way a key is, not the way a person is.
159
+ //
160
+ // Reading it as a session was the original bug and it failed quietly: the
161
+ // claims have no `id` and no `groups`, so `req.user.id` arrived as
162
+ // `undefined`, scoped writes were refused as inaccessible, and a read
163
+ // whose scope collapsed to nothing fell through to "no user context" and
164
+ // answered from the whole collection.
165
+ admitAgent(req, res, next, requiredScopes, {
166
+ credentialId: claims.jti,
167
+ userId: claims.sub,
168
+ email: claims.email ?? '',
169
+ name: claims.name ?? '',
170
+ scopes: (claims.scope ?? '').split(' ').filter(types_1.isApiKeyScope),
171
+ tenants: (0, types_1.readTenants)(claims)
172
+ });
89
173
  return;
90
174
  }
91
175
  const result = await (0, service_1.verifyApiKey)(token);
@@ -96,34 +180,14 @@ const authenticateAgent = (...requiredScopes) => async function authenticateAgen
96
180
  unauthorized(res);
97
181
  return;
98
182
  }
99
- const scopes = result.scopes ?? [];
100
- const missing = requiredScopes.filter((scope) => !scopes.includes(scope));
101
- if (missing.length > 0) {
102
- res.status(403).json({
103
- success: false,
104
- message: `API key is missing required scope: ${missing.join(', ')}`
105
- });
106
- return;
107
- }
108
- const groupId = result.groupId ?? null;
109
- if (!applyTenantPin(req, groupId)) {
110
- res.status(403).json({
111
- success: false,
112
- message: 'API key is not permitted to act in the requested group'
113
- });
114
- return;
115
- }
116
- req.user = {
117
- id: result.userId,
183
+ admitAgent(req, res, next, requiredScopes, {
184
+ credentialId: result.keyId,
185
+ userId: result.userId,
118
186
  email: result.userEmail ?? '',
119
- name: result.userName ?? ''
120
- };
121
- // Only the pinned group, never the owner's full membership: this is what
122
- // stops a key reaching a group it was not issued for through any handler
123
- // that consults `userGroups` instead of the `groupId` parameter.
124
- req.userGroups = groupId ? [groupId] : [];
125
- req.apiKey = { keyId: result.keyId, scopes, groupId };
126
- next();
187
+ name: result.userName ?? '',
188
+ scopes: result.scopes ?? [],
189
+ tenants: result.tenants ?? (0, types_1.readTenants)({})
190
+ });
127
191
  };
128
192
  exports.authenticateAgent = authenticateAgent;
129
193
  /**
@@ -135,7 +199,9 @@ exports.authenticateAgent = authenticateAgent;
135
199
  * door for lacking a scope half the router never uses.
136
200
  *
137
201
  * A session passes unconditionally: scopes narrow what software may do on a
138
- * person's behalf, not what the person may do themselves.
202
+ * person's behalf, not what the person may do themselves. Everything that is
203
+ * not a session — an API key or an OAuth access token alike — arrives with
204
+ * `req.apiKey` set and is held to it.
139
205
  */
140
206
  const requireScope = (...requiredScopes) => function requireScopeHandler(req, res, next) {
141
207
  if (!req.apiKey) {
@@ -146,7 +212,7 @@ const requireScope = (...requiredScopes) => function requireScopeHandler(req, re
146
212
  if (missing.length > 0) {
147
213
  res.status(403).json({
148
214
  success: false,
149
- message: `API key is missing required scope: ${missing.join(', ')}`
215
+ message: `Credential is missing required scope: ${missing.join(', ')}`
150
216
  });
151
217
  return;
152
218
  }
@@ -154,7 +220,7 @@ const requireScope = (...requiredScopes) => function requireScopeHandler(req, re
154
220
  };
155
221
  exports.requireScope = requireScope;
156
222
  /**
157
- * Refuse API keys on a route that a session may still use.
223
+ * Refuse every non-session credential on a route that a session may still use.
158
224
  *
159
225
  * For the handful of operations that should stay a person's to perform — key
160
226
  * management itself, most obviously, since a key that can mint keys is a key
@@ -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,CA2B7E,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 };
@@ -115,7 +122,7 @@ const verifyApiKey = async (token) => {
115
122
  userName: key.userName,
116
123
  keyId: String(key._id),
117
124
  scopes: key.scopes,
118
- groupId: key.groupId ?? null
125
+ tenants: (0, types_1.readTenants)(key)
119
126
  };
120
127
  };
121
128
  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;
@@ -45,6 +78,6 @@ export interface ApiKeyVerification {
45
78
  userName?: string;
46
79
  keyId?: string;
47
80
  scopes?: ApiKeyScope[];
48
- groupId?: string | null;
81
+ tenants?: ApiKeyTenant;
49
82
  }
50
83
  //# sourceMappingURL=types.d.ts.map