@chatcops/server 0.5.0 → 0.6.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 (71) hide show
  1. package/README.md +4 -4
  2. package/dist/adapters/ai-sdk.d.ts +12 -0
  3. package/dist/adapters/ai-sdk.d.ts.map +1 -0
  4. package/dist/adapters/ai-sdk.js +27 -0
  5. package/dist/adapters/ai-sdk.js.map +1 -0
  6. package/dist/adapters/cloudflare.d.ts.map +1 -1
  7. package/dist/adapters/cloudflare.js +9 -83
  8. package/dist/adapters/cloudflare.js.map +1 -1
  9. package/dist/adapters/express.d.ts +6 -2
  10. package/dist/adapters/express.d.ts.map +1 -1
  11. package/dist/adapters/express.js +101 -30
  12. package/dist/adapters/express.js.map +1 -1
  13. package/dist/adapters/index.d.ts +1 -0
  14. package/dist/adapters/index.d.ts.map +1 -1
  15. package/dist/adapters/index.js +1 -0
  16. package/dist/adapters/index.js.map +1 -1
  17. package/dist/adapters/vercel.d.ts.map +1 -1
  18. package/dist/adapters/vercel.js +7 -74
  19. package/dist/adapters/vercel.js.map +1 -1
  20. package/dist/client-ip.d.ts +36 -0
  21. package/dist/client-ip.d.ts.map +1 -0
  22. package/dist/client-ip.js +62 -0
  23. package/dist/client-ip.js.map +1 -0
  24. package/dist/config.d.ts +110 -8
  25. package/dist/config.d.ts.map +1 -1
  26. package/dist/config.js +5 -1
  27. package/dist/config.js.map +1 -1
  28. package/dist/handler.d.ts +50 -1
  29. package/dist/handler.d.ts.map +1 -1
  30. package/dist/handler.js +384 -130
  31. package/dist/handler.js.map +1 -1
  32. package/dist/http.d.ts +66 -0
  33. package/dist/http.d.ts.map +1 -0
  34. package/dist/http.js +262 -0
  35. package/dist/http.js.map +1 -0
  36. package/dist/index.d.ts +3 -0
  37. package/dist/index.d.ts.map +1 -1
  38. package/dist/index.js +1 -0
  39. package/dist/index.js.map +1 -1
  40. package/dist/rate-limit.d.ts +5 -0
  41. package/dist/rate-limit.d.ts.map +1 -1
  42. package/dist/rate-limit.js +5 -0
  43. package/dist/rate-limit.js.map +1 -1
  44. package/dist/security/origin-policy.d.ts +19 -0
  45. package/dist/security/origin-policy.d.ts.map +1 -0
  46. package/dist/security/origin-policy.js +58 -0
  47. package/dist/security/origin-policy.js.map +1 -0
  48. package/dist/security/origin.d.ts +5 -0
  49. package/dist/security/origin.d.ts.map +1 -0
  50. package/dist/security/origin.js +47 -0
  51. package/dist/security/origin.js.map +1 -0
  52. package/dist/security/session-token.d.ts +65 -0
  53. package/dist/security/session-token.d.ts.map +1 -0
  54. package/dist/security/session-token.js +338 -0
  55. package/dist/security/session-token.js.map +1 -0
  56. package/dist/security/sessions.d.ts +49 -0
  57. package/dist/security/sessions.d.ts.map +1 -0
  58. package/dist/security/sessions.js +159 -0
  59. package/dist/security/sessions.js.map +1 -0
  60. package/dist/security/startup-checks.d.ts +44 -0
  61. package/dist/security/startup-checks.d.ts.map +1 -0
  62. package/dist/security/startup-checks.js +134 -0
  63. package/dist/security/startup-checks.js.map +1 -0
  64. package/dist/security/turnstile.d.ts +24 -0
  65. package/dist/security/turnstile.d.ts.map +1 -0
  66. package/dist/security/turnstile.js +93 -0
  67. package/dist/security/turnstile.js.map +1 -0
  68. package/dist/visitor-context.d.ts.map +1 -1
  69. package/dist/visitor-context.js +1 -0
  70. package/dist/visitor-context.js.map +1 -1
  71. package/package.json +22 -5
@@ -0,0 +1,65 @@
1
+ /**
2
+ * Session token signing and verification using compact JWS with HS256 and Web Crypto (crypto.subtle).
3
+ */
4
+ export interface SessionClaims {
5
+ v: 1;
6
+ sid: string;
7
+ cid: string;
8
+ org: string;
9
+ iat: number;
10
+ exp: number;
11
+ uid?: string;
12
+ tier?: string;
13
+ }
14
+ export type VerifySessionResult = {
15
+ ok: true;
16
+ claims: SessionClaims;
17
+ } | {
18
+ ok: false;
19
+ code: 'malformed' | 'bad_signature' | 'expired' | 'origin_mismatch' | 'conversation_mismatch';
20
+ };
21
+ export interface VerifySessionOptions {
22
+ origin: string | null;
23
+ conversationId: string;
24
+ now?: number;
25
+ clockSkewSec?: number;
26
+ }
27
+ /**
28
+ * Strict, unpadded base64url encoding.
29
+ */
30
+ export declare function base64UrlEncode(bytes: Uint8Array): string;
31
+ /**
32
+ * Strict, unpadded base64url decoding. Rejects padding ('='), non-base64url characters,
33
+ * invalid lengths (len % 4 === 1), and non-canonical trailing bits.
34
+ */
35
+ export declare function base64UrlDecode(str: string): Uint8Array;
36
+ /**
37
+ * Imports an HMAC-SHA256 key for signing and verifying session tokens.
38
+ * Rejects secrets shorter than 32 UTF-8 bytes with a clear error.
39
+ * Does not access crypto.subtle at module load time.
40
+ */
41
+ export declare function importSessionKey(secret: string | Uint8Array): Promise<CryptoKey>;
42
+ /**
43
+ * Signs session claims using the first key in keys and sets kid to '0'.
44
+ */
45
+ export declare function signSession(claims: SessionClaims | (Omit<SessionClaims, 'v'> & {
46
+ v?: 1;
47
+ }), keys: CryptoKey[]): Promise<string>;
48
+ /**
49
+ * Verifies a compact JWS signature over `header.payload` using HS256 and the provided key(s).
50
+ * Does not validate SessionClaims.
51
+ */
52
+ export declare function verifySessionSignature(token: string, keys: CryptoKey[]): Promise<boolean>;
53
+ /**
54
+ * Verifies a session token.
55
+ * 1. Checks compact JWS format (header.payload.signature) and base64url decoding.
56
+ * 2. Verifies header alg is HS256 (rejects none and any other algorithm).
57
+ * 3. Verifies signature over the exact original header.payload bytes via verifySessionSignature.
58
+ * 4. Only after signature verification succeeds, validates session claims:
59
+ * v must be 1; sid, cid, org must be strings; uid and tier (if present) must be strings;
60
+ * iat and exp must be valid numeric seconds.
61
+ * 5. Constructs returned claims exclusively from validated fields (never spreads untrusted payload).
62
+ * 6. Enforces expiration with clock skew (default 60s), exact origin matching, and exact conversation ID matching.
63
+ */
64
+ export declare function verifySession(token: string, keys: CryptoKey[], options: VerifySessionOptions): Promise<VerifySessionResult>;
65
+ //# sourceMappingURL=session-token.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-token.d.ts","sourceRoot":"","sources":["../../src/security/session-token.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,WAAW,aAAa;IAC5B,CAAC,EAAE,CAAC,CAAC;IACL,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,MAAM,mBAAmB,GAC3B;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,aAAa,CAAA;CAAE,GACnC;IACE,EAAE,EAAE,KAAK,CAAC;IACV,IAAI,EACA,WAAW,GACX,eAAe,GACf,SAAS,GACT,iBAAiB,GACjB,uBAAuB,CAAC;CAC7B,CAAC;AAEN,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,cAAc,EAAE,MAAM,CAAC;IACvB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AASD;;GAEG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAgCzD;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU,CAuEvD;AAED;;;;GAIG;AACH,wBAAsB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,UAAU,GAAG,OAAO,CAAC,SAAS,CAAC,CAYtF;AAED;;GAEG;AACH,wBAAsB,WAAW,CAC/B,MAAM,EAAE,aAAa,GAAG,CAAC,IAAI,CAAC,aAAa,EAAE,GAAG,CAAC,GAAG;IAAE,CAAC,CAAC,EAAE,CAAC,CAAA;CAAE,CAAC,EAC9D,IAAI,EAAE,SAAS,EAAE,GAChB,OAAO,CAAC,MAAM,CAAC,CA2BjB;AAED;;;GAGG;AACH,wBAAsB,sBAAsB,CAC1C,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,SAAS,EAAE,GAChB,OAAO,CAAC,OAAO,CAAC,CA2DlB;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,aAAa,CACjC,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,SAAS,EAAE,EACjB,OAAO,EAAE,oBAAoB,GAC5B,OAAO,CAAC,mBAAmB,CAAC,CA+H9B"}
@@ -0,0 +1,338 @@
1
+ /**
2
+ * Session token signing and verification using compact JWS with HS256 and Web Crypto (crypto.subtle).
3
+ */
4
+ const B64URL_CHARS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_';
5
+ const B64URL_LOOKUP = new Int8Array(256).fill(-1);
6
+ for (let i = 0; i < B64URL_CHARS.length; i++) {
7
+ B64URL_LOOKUP[B64URL_CHARS.charCodeAt(i)] = i;
8
+ }
9
+ /**
10
+ * Strict, unpadded base64url encoding.
11
+ */
12
+ export function base64UrlEncode(bytes) {
13
+ let result = '';
14
+ const len = bytes.length;
15
+ let i = 0;
16
+ for (; i + 2 < len; i += 3) {
17
+ const b0 = bytes[i];
18
+ const b1 = bytes[i + 1];
19
+ const b2 = bytes[i + 2];
20
+ result +=
21
+ B64URL_CHARS[b0 >> 2] +
22
+ B64URL_CHARS[((b0 & 3) << 4) | (b1 >> 4)] +
23
+ B64URL_CHARS[((b1 & 15) << 2) | (b2 >> 6)] +
24
+ B64URL_CHARS[b2 & 63];
25
+ }
26
+ if (i < len) {
27
+ const b0 = bytes[i];
28
+ if (i + 1 < len) {
29
+ const b1 = bytes[i + 1];
30
+ result +=
31
+ B64URL_CHARS[b0 >> 2] +
32
+ B64URL_CHARS[((b0 & 3) << 4) | (b1 >> 4)] +
33
+ B64URL_CHARS[(b1 & 15) << 2];
34
+ }
35
+ else {
36
+ result +=
37
+ B64URL_CHARS[b0 >> 2] +
38
+ B64URL_CHARS[(b0 & 3) << 4];
39
+ }
40
+ }
41
+ return result;
42
+ }
43
+ /**
44
+ * Strict, unpadded base64url decoding. Rejects padding ('='), non-base64url characters,
45
+ * invalid lengths (len % 4 === 1), and non-canonical trailing bits.
46
+ */
47
+ export function base64UrlDecode(str) {
48
+ if (typeof str !== 'string' || str.length === 0) {
49
+ throw new Error('Invalid base64url string: empty');
50
+ }
51
+ const len = str.length;
52
+ const rem = len % 4;
53
+ if (rem === 1) {
54
+ throw new Error('Invalid base64url string: length % 4 cannot be 1');
55
+ }
56
+ const byteLen = Math.floor(len / 4) * 3 + (rem === 2 ? 1 : rem === 3 ? 2 : 0);
57
+ const out = new Uint8Array(byteLen);
58
+ let inIdx = 0;
59
+ let outIdx = 0;
60
+ const fullChunks = Math.floor(len / 4);
61
+ for (let i = 0; i < fullChunks; i++) {
62
+ const code0 = str.charCodeAt(inIdx++);
63
+ const code1 = str.charCodeAt(inIdx++);
64
+ const code2 = str.charCodeAt(inIdx++);
65
+ const code3 = str.charCodeAt(inIdx++);
66
+ if (code0 >= 256 || code1 >= 256 || code2 >= 256 || code3 >= 256) {
67
+ throw new Error('Invalid base64url character');
68
+ }
69
+ const c0 = B64URL_LOOKUP[code0];
70
+ const c1 = B64URL_LOOKUP[code1];
71
+ const c2 = B64URL_LOOKUP[code2];
72
+ const c3 = B64URL_LOOKUP[code3];
73
+ if (c0 === -1 || c1 === -1 || c2 === -1 || c3 === -1) {
74
+ throw new Error('Invalid base64url character');
75
+ }
76
+ out[outIdx++] = (c0 << 2) | (c1 >> 4);
77
+ out[outIdx++] = ((c1 & 15) << 4) | (c2 >> 2);
78
+ out[outIdx++] = ((c2 & 3) << 6) | c3;
79
+ }
80
+ if (rem === 2) {
81
+ const code0 = str.charCodeAt(inIdx++);
82
+ const code1 = str.charCodeAt(inIdx++);
83
+ if (code0 >= 256 || code1 >= 256) {
84
+ throw new Error('Invalid base64url character');
85
+ }
86
+ const c0 = B64URL_LOOKUP[code0];
87
+ const c1 = B64URL_LOOKUP[code1];
88
+ if (c0 === -1 || c1 === -1 || (c1 & 15) !== 0) {
89
+ throw new Error('Invalid base64url character or non-canonical trailing bits');
90
+ }
91
+ out[outIdx++] = (c0 << 2) | (c1 >> 4);
92
+ }
93
+ else if (rem === 3) {
94
+ const code0 = str.charCodeAt(inIdx++);
95
+ const code1 = str.charCodeAt(inIdx++);
96
+ const code2 = str.charCodeAt(inIdx++);
97
+ if (code0 >= 256 || code1 >= 256 || code2 >= 256) {
98
+ throw new Error('Invalid base64url character');
99
+ }
100
+ const c0 = B64URL_LOOKUP[code0];
101
+ const c1 = B64URL_LOOKUP[code1];
102
+ const c2 = B64URL_LOOKUP[code2];
103
+ if (c0 === -1 || c1 === -1 || c2 === -1 || (c2 & 3) !== 0) {
104
+ throw new Error('Invalid base64url character or non-canonical trailing bits');
105
+ }
106
+ out[outIdx++] = (c0 << 2) | (c1 >> 4);
107
+ out[outIdx++] = ((c1 & 15) << 4) | (c2 >> 2);
108
+ }
109
+ return out;
110
+ }
111
+ /**
112
+ * Imports an HMAC-SHA256 key for signing and verifying session tokens.
113
+ * Rejects secrets shorter than 32 UTF-8 bytes with a clear error.
114
+ * Does not access crypto.subtle at module load time.
115
+ */
116
+ export async function importSessionKey(secret) {
117
+ const bytes = typeof secret === 'string' ? new TextEncoder().encode(secret) : new Uint8Array(secret);
118
+ if (bytes.byteLength < 32) {
119
+ throw new Error(`Session secret must be at least 32 bytes (got ${bytes.byteLength})`);
120
+ }
121
+ return await crypto.subtle.importKey('raw', bytes, { name: 'HMAC', hash: 'SHA-256' }, false, ['sign', 'verify']);
122
+ }
123
+ /**
124
+ * Signs session claims using the first key in keys and sets kid to '0'.
125
+ */
126
+ export async function signSession(claims, keys) {
127
+ if (keys.length === 0) {
128
+ throw new Error('At least one key is required to sign');
129
+ }
130
+ const signingKey = keys[0];
131
+ const fullClaims = {
132
+ ...claims,
133
+ v: (claims.v ?? 1),
134
+ };
135
+ const header = {
136
+ alg: 'HS256',
137
+ typ: 'JWT',
138
+ kid: '0',
139
+ };
140
+ const headerB64 = base64UrlEncode(new TextEncoder().encode(JSON.stringify(header)));
141
+ const payloadB64 = base64UrlEncode(new TextEncoder().encode(JSON.stringify(fullClaims)));
142
+ const signingInput = `${headerB64}.${payloadB64}`;
143
+ const signingInputBytes = new TextEncoder().encode(signingInput);
144
+ const signatureBuffer = await crypto.subtle.sign('HMAC', signingKey, signingInputBytes);
145
+ const signatureB64 = base64UrlEncode(new Uint8Array(signatureBuffer));
146
+ return `${signingInput}.${signatureB64}`;
147
+ }
148
+ /**
149
+ * Verifies a compact JWS signature over `header.payload` using HS256 and the provided key(s).
150
+ * Does not validate SessionClaims.
151
+ */
152
+ export async function verifySessionSignature(token, keys) {
153
+ if (typeof token !== 'string')
154
+ return false;
155
+ const parts = token.split('.');
156
+ if (parts.length !== 3)
157
+ return false;
158
+ const [headerPart, payloadPart, signaturePart] = parts;
159
+ if (!headerPart || !payloadPart || !signaturePart)
160
+ return false;
161
+ let headerBytes;
162
+ let signatureBytes;
163
+ try {
164
+ headerBytes = base64UrlDecode(headerPart);
165
+ signatureBytes = base64UrlDecode(signaturePart);
166
+ }
167
+ catch {
168
+ return false;
169
+ }
170
+ let header;
171
+ try {
172
+ header = JSON.parse(new TextDecoder().decode(headerBytes));
173
+ }
174
+ catch {
175
+ return false;
176
+ }
177
+ if (typeof header !== 'object' || header === null || Array.isArray(header))
178
+ return false;
179
+ const headerObj = header;
180
+ if (headerObj.alg !== 'HS256')
181
+ return false;
182
+ if (keys.length === 0)
183
+ return false;
184
+ const signingInputBytes = new TextEncoder().encode(`${headerPart}.${payloadPart}`);
185
+ const kidRaw = headerObj.kid;
186
+ const indexedIdx = typeof kidRaw === 'number'
187
+ ? kidRaw
188
+ : typeof kidRaw === 'string' && /^\d+$/.test(kidRaw)
189
+ ? parseInt(kidRaw, 10)
190
+ : undefined;
191
+ if (indexedIdx !== undefined && indexedIdx >= 0 && indexedIdx < keys.length) {
192
+ try {
193
+ if (await crypto.subtle.verify('HMAC', keys[indexedIdx], signatureBytes, signingInputBytes)) {
194
+ return true;
195
+ }
196
+ }
197
+ catch {
198
+ // ignore
199
+ }
200
+ }
201
+ for (let i = 0; i < keys.length; i++) {
202
+ if (i === indexedIdx)
203
+ continue;
204
+ try {
205
+ if (await crypto.subtle.verify('HMAC', keys[i], signatureBytes, signingInputBytes)) {
206
+ return true;
207
+ }
208
+ }
209
+ catch {
210
+ // ignore
211
+ }
212
+ }
213
+ return false;
214
+ }
215
+ /**
216
+ * Verifies a session token.
217
+ * 1. Checks compact JWS format (header.payload.signature) and base64url decoding.
218
+ * 2. Verifies header alg is HS256 (rejects none and any other algorithm).
219
+ * 3. Verifies signature over the exact original header.payload bytes via verifySessionSignature.
220
+ * 4. Only after signature verification succeeds, validates session claims:
221
+ * v must be 1; sid, cid, org must be strings; uid and tier (if present) must be strings;
222
+ * iat and exp must be valid numeric seconds.
223
+ * 5. Constructs returned claims exclusively from validated fields (never spreads untrusted payload).
224
+ * 6. Enforces expiration with clock skew (default 60s), exact origin matching, and exact conversation ID matching.
225
+ */
226
+ export async function verifySession(token, keys, options) {
227
+ if (typeof token !== 'string') {
228
+ return { ok: false, code: 'malformed' };
229
+ }
230
+ const parts = token.split('.');
231
+ if (parts.length !== 3) {
232
+ return { ok: false, code: 'malformed' };
233
+ }
234
+ const [headerPart, payloadPart, signaturePart] = parts;
235
+ if (!headerPart || !payloadPart) {
236
+ return { ok: false, code: 'malformed' };
237
+ }
238
+ let headerBytes;
239
+ try {
240
+ headerBytes = base64UrlDecode(headerPart);
241
+ }
242
+ catch {
243
+ return { ok: false, code: 'malformed' };
244
+ }
245
+ let header;
246
+ try {
247
+ header = JSON.parse(new TextDecoder().decode(headerBytes));
248
+ }
249
+ catch {
250
+ return { ok: false, code: 'malformed' };
251
+ }
252
+ if (typeof header !== 'object' || header === null || Array.isArray(header)) {
253
+ return { ok: false, code: 'malformed' };
254
+ }
255
+ const headerObj = header;
256
+ // Reject algorithms other than HS256, including 'none'
257
+ if (headerObj.alg !== 'HS256') {
258
+ return { ok: false, code: 'bad_signature' };
259
+ }
260
+ if (!signaturePart) {
261
+ return { ok: false, code: 'bad_signature' };
262
+ }
263
+ let payloadBytes;
264
+ try {
265
+ payloadBytes = base64UrlDecode(payloadPart);
266
+ base64UrlDecode(signaturePart);
267
+ }
268
+ catch {
269
+ return { ok: false, code: 'malformed' };
270
+ }
271
+ const verified = await verifySessionSignature(token, keys);
272
+ if (!verified) {
273
+ return { ok: false, code: 'bad_signature' };
274
+ }
275
+ // Validate all claims only after signature verification
276
+ let payload;
277
+ try {
278
+ payload = JSON.parse(new TextDecoder().decode(payloadBytes));
279
+ }
280
+ catch {
281
+ return { ok: false, code: 'malformed' };
282
+ }
283
+ if (typeof payload !== 'object' || payload === null || Array.isArray(payload)) {
284
+ return { ok: false, code: 'malformed' };
285
+ }
286
+ const p = payload;
287
+ if (p.v !== 1) {
288
+ return { ok: false, code: 'malformed' };
289
+ }
290
+ if (typeof p.sid !== 'string') {
291
+ return { ok: false, code: 'malformed' };
292
+ }
293
+ if (typeof p.cid !== 'string') {
294
+ return { ok: false, code: 'malformed' };
295
+ }
296
+ if (typeof p.org !== 'string') {
297
+ return { ok: false, code: 'malformed' };
298
+ }
299
+ if (p.uid !== undefined && typeof p.uid !== 'string') {
300
+ return { ok: false, code: 'malformed' };
301
+ }
302
+ if (p.tier !== undefined && typeof p.tier !== 'string') {
303
+ return { ok: false, code: 'malformed' };
304
+ }
305
+ if (typeof p.iat !== 'number' || !Number.isFinite(p.iat)) {
306
+ return { ok: false, code: 'malformed' };
307
+ }
308
+ if (typeof p.exp !== 'number' || !Number.isFinite(p.exp)) {
309
+ return { ok: false, code: 'malformed' };
310
+ }
311
+ // Construct returned claims exclusively from validated fields
312
+ const claims = {
313
+ v: 1,
314
+ sid: p.sid,
315
+ cid: p.cid,
316
+ org: p.org,
317
+ iat: p.iat,
318
+ exp: p.exp,
319
+ ...(typeof p.uid === 'string' ? { uid: p.uid } : {}),
320
+ ...(typeof p.tier === 'string' ? { tier: p.tier } : {}),
321
+ };
322
+ // Expiration check with clock skew (default 60 seconds), strictly in seconds
323
+ const clockSkewSec = options.clockSkewSec ?? 60;
324
+ const nowSec = options.now ?? Math.floor(Date.now() / 1000);
325
+ if (nowSec - clockSkewSec > claims.exp) {
326
+ return { ok: false, code: 'expired' };
327
+ }
328
+ // Exact origin matching (origin: null directly compares claims.org !== null)
329
+ if (claims.org !== options.origin) {
330
+ return { ok: false, code: 'origin_mismatch' };
331
+ }
332
+ // Exact conversation ID matching
333
+ if (claims.cid !== options.conversationId) {
334
+ return { ok: false, code: 'conversation_mismatch' };
335
+ }
336
+ return { ok: true, claims };
337
+ }
338
+ //# sourceMappingURL=session-token.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-token.js","sourceRoot":"","sources":["../../src/security/session-token.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,49 @@
1
+ import { type WireErrorBody, type WireErrorCode } from '@chatcops/core';
2
+ import { type SessionClaims } from './session-token.js';
3
+ import { type TurnstileConfig } from './turnstile.js';
4
+ /**
5
+ * Session tokens for the chat endpoint. `POST /session` gives the widget a
6
+ * short-lived token bound to its origin and one conversation id, and chat
7
+ * requests send it as `Authorization: Bearer <token>`. A visitor who guesses
8
+ * another conversation's id can't get a token for it, so the id alone no
9
+ * longer reads or writes someone else's conversation.
10
+ */
11
+ export declare const DEFAULT_SESSION_TTL_SEC = 900;
12
+ /** An expired token still resumes its conversation for this long after it expires. */
13
+ export declare const SESSION_RESUME_GRACE_SEC: number;
14
+ export interface SessionConfig {
15
+ sessionSecrets?: string[];
16
+ sessionTtlSec?: number;
17
+ requireSession?: boolean;
18
+ turnstile?: TurnstileConfig;
19
+ }
20
+ export type SessionCheck = {
21
+ ok: true;
22
+ claims?: SessionClaims;
23
+ } | {
24
+ ok: false;
25
+ code: WireErrorCode;
26
+ message: string;
27
+ };
28
+ export interface SessionReply {
29
+ status: number;
30
+ body: {
31
+ token: string;
32
+ expiresAt: number;
33
+ conversationId: string;
34
+ } | WireErrorBody;
35
+ }
36
+ export interface Sessions {
37
+ /** Whether chat requests without a token are refused. */
38
+ required: boolean;
39
+ /** Answers `POST /session`. */
40
+ mint(body: unknown, origin: string | null, clientIp?: string): Promise<SessionReply>;
41
+ /** Checks the `Authorization` header of a chat request for this conversation. */
42
+ check(authorization: string | null | undefined, origin: string | null, conversationId: string): Promise<SessionCheck>;
43
+ }
44
+ /**
45
+ * `undefined` when `sessionSecrets` isn't set. Throws at startup on a bad
46
+ * config. `isUnused` says whether a conversation has nothing stored yet.
47
+ */
48
+ export declare function createSessions(config: SessionConfig, isUnused?: (conversationId: string) => Promise<boolean>, now?: () => number): Sessions | undefined;
49
+ //# sourceMappingURL=sessions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sessions.d.ts","sourceRoot":"","sources":["../../src/security/sessions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,KAAK,aAAa,EAAE,KAAK,aAAa,EAAE,MAAM,gBAAgB,CAAC;AACnF,OAAO,EAAgD,KAAK,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACtG,OAAO,EAAmB,KAAK,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAEvE;;;;;;GAMG;AAEH,eAAO,MAAM,uBAAuB,MAAM,CAAC;AAC3C,sFAAsF;AACtF,eAAO,MAAM,wBAAwB,QAAoB,CAAC;AAI1D,MAAM,WAAW,aAAa;IAC5B,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,SAAS,CAAC,EAAE,eAAe,CAAC;CAC7B;AAED,MAAM,MAAM,YAAY,GACpB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,MAAM,CAAC,EAAE,aAAa,CAAA;CAAE,GACpC;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,IAAI,EAAE,aAAa,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAExD,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,cAAc,EAAE,MAAM,CAAA;KAAE,GAAG,aAAa,CAAC;CACpF;AAED,MAAM,WAAW,QAAQ;IACvB,yDAAyD;IACzD,QAAQ,EAAE,OAAO,CAAC;IAClB,+BAA+B;IAC/B,IAAI,CAAC,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;IACrF,iFAAiF;IACjF,KAAK,CAAC,aAAa,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,EAAE,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;CACvH;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAC5B,MAAM,EAAE,aAAa,EACrB,QAAQ,GAAE,CAAC,cAAc,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAqB,EAC1E,GAAG,GAAE,MAAM,MAAiB,GAC3B,QAAQ,GAAG,SAAS,CAoGtB"}
@@ -0,0 +1,159 @@
1
+ import { errorBody } from '@chatcops/core';
2
+ import { importSessionKey, signSession, verifySession } from './session-token.js';
3
+ import { verifyTurnstile } from './turnstile.js';
4
+ /**
5
+ * Session tokens for the chat endpoint. `POST /session` gives the widget a
6
+ * short-lived token bound to its origin and one conversation id, and chat
7
+ * requests send it as `Authorization: Bearer <token>`. A visitor who guesses
8
+ * another conversation's id can't get a token for it, so the id alone no
9
+ * longer reads or writes someone else's conversation.
10
+ */
11
+ export const DEFAULT_SESSION_TTL_SEC = 900;
12
+ /** An expired token still resumes its conversation for this long after it expires. */
13
+ export const SESSION_RESUME_GRACE_SEC = 30 * 24 * 60 * 60;
14
+ const MIN_SECRET_BYTES = 32;
15
+ const MAX_ID_LENGTH = 128;
16
+ /**
17
+ * `undefined` when `sessionSecrets` isn't set. Throws at startup on a bad
18
+ * config. `isUnused` says whether a conversation has nothing stored yet.
19
+ */
20
+ export function createSessions(config, isUnused = async () => false, now = Date.now) {
21
+ const secrets = config.sessionSecrets;
22
+ if (secrets === undefined) {
23
+ if (config.requireSession)
24
+ throw new Error('`requireSession` needs `sessionSecrets` to sign tokens with.');
25
+ if (config.turnstile)
26
+ throw new Error('`turnstile` is checked when a session token is issued, so it needs `sessionSecrets`.');
27
+ return undefined;
28
+ }
29
+ const turnstile = config.turnstile;
30
+ if (turnstile && !turnstile.secretKey)
31
+ throw new Error('`turnstile` needs its `secretKey`.');
32
+ if (!Array.isArray(secrets) || secrets.length === 0)
33
+ throw new Error('`sessionSecrets` needs at least one secret.');
34
+ secrets.forEach((secret, i) => {
35
+ const bytes = typeof secret === 'string' ? new TextEncoder().encode(secret).byteLength : 0;
36
+ if (bytes < MIN_SECRET_BYTES) {
37
+ throw new Error(`sessionSecrets[${i}] is ${bytes} bytes; it needs at least ${MIN_SECRET_BYTES}. Generate one with \`openssl rand -base64 32\`.`);
38
+ }
39
+ });
40
+ const ttlSec = config.sessionTtlSec ?? DEFAULT_SESSION_TTL_SEC;
41
+ if (!(Number.isInteger(ttlSec) && ttlSec > 0))
42
+ throw new Error('`sessionTtlSec` must be a whole number of seconds above 0.');
43
+ // Imported on first use: Workers don't allow crypto.subtle at global scope.
44
+ let keys;
45
+ const getKeys = () => (keys ??= Promise.all(secrets.map((secret) => importSessionKey(secret))));
46
+ const nowSec = () => Math.floor(now() / 1000);
47
+ const required = config.requireSession ?? true;
48
+ return {
49
+ required,
50
+ async mint(body, origin, clientIp) {
51
+ const request = readMintRequest(body);
52
+ if (!request)
53
+ return { status: 400, body: errorBody('invalid_request', { message: 'Invalid session request' }) };
54
+ const org = origin ?? '';
55
+ const time = nowSec();
56
+ // Resuming a conversation needs a token that was issued for it, from
57
+ // this origin. Expired is fine within the grace window. An id with
58
+ // nothing stored yet (the widget makes its own) is given out as is,
59
+ // since there's nothing in it to read. Anything else gets a new
60
+ // conversation, so a guessed or leaked id is useless.
61
+ let resumed;
62
+ let cid;
63
+ if (request.conversationId && request.previousToken) {
64
+ const result = await verifySession(request.previousToken, await getKeys(), {
65
+ origin: org,
66
+ conversationId: request.conversationId,
67
+ now: time,
68
+ clockSkewSec: SESSION_RESUME_GRACE_SEC,
69
+ });
70
+ if (result.ok)
71
+ resumed = result.claims;
72
+ }
73
+ // A refresh was checked when its first token was issued; a new session
74
+ // has to pass Turnstile first.
75
+ if (turnstile && !resumed) {
76
+ const result = await verifyTurnstile(request.turnstileToken, turnstile, {
77
+ remoteIp: clientIp,
78
+ idempotencyKey: request.idempotencyKey,
79
+ });
80
+ if (!result.ok) {
81
+ if (result.code === 'unavailable') {
82
+ console.warn('[chatcops] Turnstile could not be reached, so no session token was issued.');
83
+ return { status: 503, body: errorBody('turnstile_failed', { message: 'Turnstile could not be reached. Try again.' }) };
84
+ }
85
+ return { status: 401, body: errorBody('turnstile_failed', { message: 'The Turnstile check failed.' }) };
86
+ }
87
+ }
88
+ if (resumed)
89
+ cid = resumed.cid;
90
+ else if (request.conversationId && (await isUnused(request.conversationId)))
91
+ cid = request.conversationId;
92
+ const claims = {
93
+ v: 1,
94
+ sid: resumed?.sid ?? crypto.randomUUID(),
95
+ cid: cid ?? crypto.randomUUID(),
96
+ org,
97
+ iat: time,
98
+ exp: time + ttlSec,
99
+ };
100
+ const token = await signSession(claims, await getKeys());
101
+ return { status: 200, body: { token, expiresAt: claims.exp * 1000, conversationId: claims.cid } };
102
+ },
103
+ async check(authorization, origin, conversationId) {
104
+ const token = bearer(authorization);
105
+ if (!token) {
106
+ return required
107
+ ? { ok: false, code: 'session_required', message: 'This chat needs a session token. Get one from POST /session.' }
108
+ : { ok: true };
109
+ }
110
+ const result = await verifySession(token, await getKeys(), { origin: origin ?? '', conversationId, now: nowSec() });
111
+ if (result.ok)
112
+ return { ok: true, claims: result.claims };
113
+ switch (result.code) {
114
+ case 'expired':
115
+ return { ok: false, code: 'token_expired', message: 'The session token has expired. Get a new one from POST /session.' };
116
+ case 'conversation_mismatch':
117
+ return { ok: false, code: 'conversation_mismatch', message: 'The session token is for a different conversation.' };
118
+ default:
119
+ return { ok: false, code: 'session_required', message: 'The session token is invalid. Get a new one from POST /session.' };
120
+ }
121
+ },
122
+ };
123
+ }
124
+ function bearer(header) {
125
+ if (typeof header !== 'string')
126
+ return undefined;
127
+ const match = /^Bearer\s+(\S+)\s*$/i.exec(header);
128
+ return match?.[1];
129
+ }
130
+ function readMintRequest(body) {
131
+ if (body === undefined || body === null)
132
+ return {};
133
+ if (typeof body !== 'object' || Array.isArray(body))
134
+ return undefined;
135
+ const { conversationId, previousToken, turnstileToken, idempotencyKey } = body;
136
+ const request = {};
137
+ if (turnstileToken !== undefined) {
138
+ if (typeof turnstileToken !== 'string' || turnstileToken.length > 4096)
139
+ return undefined;
140
+ request.turnstileToken = turnstileToken;
141
+ }
142
+ if (idempotencyKey !== undefined) {
143
+ if (typeof idempotencyKey !== 'string' || idempotencyKey.length > 128)
144
+ return undefined;
145
+ request.idempotencyKey = idempotencyKey;
146
+ }
147
+ if (conversationId !== undefined) {
148
+ if (typeof conversationId !== 'string' || conversationId.length === 0 || conversationId.length > MAX_ID_LENGTH)
149
+ return undefined;
150
+ request.conversationId = conversationId;
151
+ }
152
+ if (previousToken !== undefined) {
153
+ if (typeof previousToken !== 'string' || previousToken.length > 4096)
154
+ return undefined;
155
+ request.previousToken = previousToken;
156
+ }
157
+ return request;
158
+ }
159
+ //# sourceMappingURL=sessions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sessions.js","sourceRoot":"","sources":["../../src/security/sessions.ts"],"names":[],"mappings":"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"}