@nacre.work/api 0.0.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 (46) hide show
  1. package/README.md +3 -0
  2. package/dist/__tests__/admin-surface.test.d.ts +2 -0
  3. package/dist/__tests__/admin-surface.test.d.ts.map +1 -0
  4. package/dist/__tests__/admin-surface.test.js +431 -0
  5. package/dist/__tests__/admin-surface.test.js.map +1 -0
  6. package/dist/__tests__/init.test.d.ts +2 -0
  7. package/dist/__tests__/init.test.d.ts.map +1 -0
  8. package/dist/__tests__/init.test.js +125 -0
  9. package/dist/__tests__/init.test.js.map +1 -0
  10. package/dist/__tests__/service-keys.test.d.ts +2 -0
  11. package/dist/__tests__/service-keys.test.d.ts.map +1 -0
  12. package/dist/__tests__/service-keys.test.js +204 -0
  13. package/dist/__tests__/service-keys.test.js.map +1 -0
  14. package/dist/adapters.d.ts +197 -0
  15. package/dist/adapters.d.ts.map +1 -0
  16. package/dist/adapters.js +672 -0
  17. package/dist/adapters.js.map +1 -0
  18. package/dist/auth.d.ts +42 -0
  19. package/dist/auth.d.ts.map +1 -0
  20. package/dist/auth.js +106 -0
  21. package/dist/auth.js.map +1 -0
  22. package/dist/errors.d.ts +43 -0
  23. package/dist/errors.d.ts.map +1 -0
  24. package/dist/errors.js +101 -0
  25. package/dist/errors.js.map +1 -0
  26. package/dist/index.d.ts +10 -0
  27. package/dist/index.d.ts.map +1 -0
  28. package/dist/index.js +6 -0
  29. package/dist/index.js.map +1 -0
  30. package/dist/init.d.ts +49 -0
  31. package/dist/init.d.ts.map +1 -0
  32. package/dist/init.js +201 -0
  33. package/dist/init.js.map +1 -0
  34. package/dist/main.d.ts +2 -0
  35. package/dist/main.d.ts.map +1 -0
  36. package/dist/main.js +113 -0
  37. package/dist/main.js.map +1 -0
  38. package/dist/server.d.ts +239 -0
  39. package/dist/server.d.ts.map +1 -0
  40. package/dist/server.js +543 -0
  41. package/dist/server.js.map +1 -0
  42. package/dist/service-keys.d.ts +82 -0
  43. package/dist/service-keys.d.ts.map +1 -0
  44. package/dist/service-keys.js +158 -0
  45. package/dist/service-keys.js.map +1 -0
  46. package/package.json +40 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"service-keys.d.ts","sourceRoot":"","sources":["../src/service-keys.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,IAAI,CAAA;AAE9B,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,WAAW,CAAA;AAE5C;;;;;;;;;;;;;;;GAeG;AAEH,8EAA8E;AAC9E,eAAO,MAAM,UAAU,cAAc,CAAA;AAErC;;;;;;;;GAQG;AACH,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAE5C;AAED,wBAAgB,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAE1C;AAED,oEAAoE;AACpE,wBAAgB,WAAW,IAAI,MAAM,CAEpC;AAED,eAAO,MAAM,mBAAmB,GAAI,OAAO,MAAM,KAAG,OAAuC,CAAA;AAE3F,MAAM,WAAW,kBAAkB;IACjC,8EAA8E;IAC9E,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,SAAS,CAAC,CAAA;CACvD;AAED;;;;;;GAMG;AACH,qBAAa,mBAAoB,YAAW,kBAAkB;IAE1D,OAAO,CAAC,QAAQ,CAAC,IAAI;IACrB,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC;gBADL,IAAI,EAAE,IAAI,EACV,IAAI,CAAC,EAAE,MAAM,YAAA;IAG1B,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,SAAS,CAAC;CAiD7D;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;IACnB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;IAClC,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;CAClC;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,CAAC,IAAI,EAAE,WAAW,GAAG,OAAO,CAAC,SAAS,cAAc,EAAE,CAAC,CAAA;IAC3D,6DAA6D;IAC7D,MAAM,CAAC,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,OAAO,EAAE,cAAc,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IAC1F,gFAAgF;IAChF,MAAM,CAAC,IAAI,EAAE,WAAW,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;CACxD;AAED,qBAAa,uBAAwB,YAAW,eAAe;IAE3D,OAAO,CAAC,QAAQ,CAAC,IAAI;IACrB,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC;gBADL,IAAI,EAAE,IAAI,EACV,IAAI,CAAC,EAAE,MAAM,YAAA;IAGhC,OAAO,KAAK,KAAK,GAEhB;IAEK,IAAI,CAAC,IAAI,EAAE,WAAW,GAAG,OAAO,CAAC,SAAS,cAAc,EAAE,CAAC;IAkC3D,MAAM,CAAC,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,OAAO,EAAE,cAAc,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC;IAgC1F,MAAM,CAAC,IAAI,EAAE,WAAW,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;CAoB9D"}
@@ -0,0 +1,158 @@
1
+ import { createHash, randomBytes, timingSafeEqual } from 'node:crypto';
2
+ import { withOrg } from '@nacre.work/core';
3
+ /**
4
+ * Service account keys.
5
+ *
6
+ * The one credential in the system meant to outlive a session. `init` issues a
7
+ * token that expires in an hour, which is right for getting through the
8
+ * quickstart and useless for an agent that runs for a week — until this
9
+ * existed, `NACRE_SERVICE_KEY` had nothing to put in it.
10
+ *
11
+ * The shape is not invented here: migration 0001 gave `service_accounts` a
12
+ * `key_hash`, a `key_prefix`, and a `revoked_at`, which is an opaque key stored
13
+ * hashed and looked up by a non-secret prefix. This implements that.
14
+ *
15
+ * A key is shown once, at creation, and never again. Storing anything
16
+ * reversible would make a database backup a set of live credentials, and the
17
+ * whole point of `key_hash` is that a stolen dump is not one.
18
+ */
19
+ /** Identifies the credential type on sight, in a log or a pasted variable. */
20
+ export const KEY_PREFIX = 'nacre_sk_';
21
+ /**
22
+ * The lookup prefix: the marker plus the first 8 characters of the secret.
23
+ *
24
+ * Long enough that the indexed lookup returns one row in practice, short enough
25
+ * that it is not a meaningful head start — 8 base64url characters is 48 bits,
26
+ * against a 256-bit secret. It is stored in clear and shown in listings on
27
+ * purpose: an operator revoking a key needs to tell two apart, and the whole
28
+ * key is gone.
29
+ */
30
+ export function prefixOf(key) {
31
+ return key.slice(0, KEY_PREFIX.length + 8);
32
+ }
33
+ export function hashOf(key) {
34
+ return createHash('sha256').update(key, 'utf8').digest('hex');
35
+ }
36
+ /** 32 bytes from the CSPRNG. Not a UUID — those are not secrets. */
37
+ export function generateKey() {
38
+ return `${KEY_PREFIX}${randomBytes(32).toString('base64url')}`;
39
+ }
40
+ export const looksLikeServiceKey = (value) => value.startsWith(KEY_PREFIX);
41
+ /**
42
+ * Resolve a key against the database.
43
+ *
44
+ * Undefined for unknown, revoked, malformed and wrong alike — the caller turns
45
+ * all of them into the same 401 a bad JWT gets, so which one it was cannot be
46
+ * read off the response.
47
+ */
48
+ export class PostgresServiceKeys {
49
+ pool;
50
+ role;
51
+ constructor(pool, role) {
52
+ this.pool = pool;
53
+ this.role = role;
54
+ }
55
+ async resolve(key) {
56
+ if (!looksLikeServiceKey(key))
57
+ return undefined;
58
+ const client = await this.pool.connect();
59
+ try {
60
+ // Across organizations: the key is what says which one, so there is no
61
+ // org to scope to yet. This is why the lookup runs here rather than
62
+ // inside withOrg, and why every column it reads is on service_accounts
63
+ // rather than joined from tenant data.
64
+ const { rows } = await client.query(`SELECT id, org_id, key_hash FROM service_accounts
65
+ WHERE key_prefix = $1 AND revoked_at IS NULL`, [prefixOf(key)]);
66
+ const expected = Buffer.from(hashOf(key), 'utf8');
67
+ for (const row of rows) {
68
+ const stored = Buffer.from(row.key_hash, 'utf8');
69
+ // Constant-time, and length-checked first because timingSafeEqual
70
+ // throws on a mismatch rather than returning false.
71
+ if (stored.length !== expected.length)
72
+ continue;
73
+ if (!timingSafeEqual(stored, expected))
74
+ continue;
75
+ // Best-effort. A failure to record when a key was last used must not
76
+ // fail the request it authenticated — the column is for an operator
77
+ // pruning dead keys, not for the decision.
78
+ void client
79
+ .query('UPDATE service_accounts SET last_used_at = now() WHERE id = $1', [row.id])
80
+ .catch(() => undefined);
81
+ // 'member', always. A service account holds nothing by virtue of being
82
+ // one; every permission it has comes from a grant, which is what
83
+ // docs/mcp.md means by "permissions are exactly the service account's".
84
+ return {
85
+ orgId: row.org_id,
86
+ principal: { type: 'service_account', id: row.id },
87
+ role: 'member',
88
+ };
89
+ }
90
+ return undefined;
91
+ }
92
+ finally {
93
+ client.release();
94
+ }
95
+ }
96
+ }
97
+ export class PostgresServiceAccounts {
98
+ pool;
99
+ role;
100
+ constructor(pool, role) {
101
+ this.pool = pool;
102
+ this.role = role;
103
+ }
104
+ get scope() {
105
+ return this.role === undefined ? {} : { role: this.role };
106
+ }
107
+ async list(auth) {
108
+ return withOrg(this.pool, auth.orgId, async (client) => {
109
+ const { rows } = await client.query(`SELECT id, name, key_prefix, created_at, last_used_at, revoked_at
110
+ FROM service_accounts WHERE org_id = $1 ORDER BY created_at`, [auth.orgId]);
111
+ // Revoked ones are listed rather than hidden: "this key was revoked on
112
+ // Tuesday" is the answer to the question an operator is actually
113
+ // asking, and a key that vanishes looks like one that never existed.
114
+ return rows.map((r) => ({
115
+ id: r.id,
116
+ name: r.name,
117
+ keyPrefix: r.key_prefix,
118
+ createdAt: r.created_at.toISOString(),
119
+ lastUsedAt: r.last_used_at?.toISOString() ?? null,
120
+ revokedAt: r.revoked_at?.toISOString() ?? null,
121
+ }));
122
+ }, this.scope);
123
+ }
124
+ async create(auth, name) {
125
+ const key = generateKey();
126
+ return withOrg(this.pool, auth.orgId, async (client) => {
127
+ const { rows } = await client.query(`INSERT INTO service_accounts (org_id, name, key_hash, key_prefix)
128
+ VALUES ($1,$2,$3,$4) RETURNING id, created_at`, [auth.orgId, name, hashOf(key), prefixOf(key)]);
129
+ const row = rows[0];
130
+ if (row === undefined)
131
+ throw new Error('the service account insert returned no row');
132
+ return {
133
+ key,
134
+ account: {
135
+ id: row.id,
136
+ name,
137
+ keyPrefix: prefixOf(key),
138
+ createdAt: row.created_at.toISOString(),
139
+ lastUsedAt: null,
140
+ revokedAt: null,
141
+ },
142
+ };
143
+ }, this.scope);
144
+ }
145
+ async revoke(auth, id) {
146
+ if (!/^[0-9a-f-]{36}$/i.test(id))
147
+ return false;
148
+ return withOrg(this.pool, auth.orgId, async (client) => {
149
+ // Revoked, never deleted. The audit log refers to this id, and a row
150
+ // that disappears turns every past event into an unresolvable
151
+ // reference — which is the one thing an access log must not do.
152
+ const { rowCount } = await client.query(`UPDATE service_accounts SET revoked_at = now()
153
+ WHERE org_id = $1 AND id = $2 AND revoked_at IS NULL`, [auth.orgId, id]);
154
+ return (rowCount ?? 0) > 0;
155
+ }, this.scope);
156
+ }
157
+ }
158
+ //# sourceMappingURL=service-keys.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"service-keys.js","sourceRoot":"","sources":["../src/service-keys.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,40 @@
1
+ {
2
+ "name": "@nacre.work/api",
3
+ "version": "0.0.0",
4
+ "description": "REST API and authorization service",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "git+https://github.com/nacre-work/nacre.git",
8
+ "directory": "packages/api"
9
+ },
10
+ "homepage": "https://nacre.work",
11
+ "license": "Apache-2.0",
12
+ "type": "module",
13
+ "scripts": {
14
+ "build": "tsc -b",
15
+ "dev": "tsx watch src/index.ts"
16
+ },
17
+ "publishConfig": {
18
+ "access": "public"
19
+ },
20
+ "main": "./dist/index.js",
21
+ "types": "./dist/index.d.ts",
22
+ "exports": {
23
+ ".": {
24
+ "types": "./dist/index.d.ts",
25
+ "default": "./dist/index.js"
26
+ }
27
+ },
28
+ "files": [
29
+ "dist"
30
+ ],
31
+ "dependencies": {
32
+ "@nacre.work/core": "workspace:*",
33
+ "jose": "^6.2.7",
34
+ "pg": "^8.22.0"
35
+ },
36
+ "devDependencies": {
37
+ "@types/node": "^22.20.1",
38
+ "@types/pg": "^8.20.3"
39
+ }
40
+ }