@positronic/cloudflare 0.0.57 → 0.0.59
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.
- package/dist/src/api/auth-middleware.js +107 -227
- package/dist/src/api/index.js +20 -3
- package/dist/src/api/secrets.js +31 -1
- package/dist/src/sqlite-adapter.js +4 -0
- package/dist/types/api/auth-middleware.d.ts +1 -1
- package/dist/types/api/auth-middleware.d.ts.map +1 -1
- package/dist/types/api/index.d.ts.map +1 -1
- package/dist/types/api/secrets.d.ts.map +1 -1
- package/dist/types/sqlite-adapter.d.ts.map +1 -1
- package/package.json +5 -5
|
@@ -1,11 +1,3 @@
|
|
|
1
|
-
function _array_like_to_array(arr, len) {
|
|
2
|
-
if (len == null || len > arr.length) len = arr.length;
|
|
3
|
-
for(var i = 0, arr2 = new Array(len); i < len; i++)arr2[i] = arr[i];
|
|
4
|
-
return arr2;
|
|
5
|
-
}
|
|
6
|
-
function _array_with_holes(arr) {
|
|
7
|
-
if (Array.isArray(arr)) return arr;
|
|
8
|
-
}
|
|
9
1
|
function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
|
|
10
2
|
try {
|
|
11
3
|
var info = gen[key](arg);
|
|
@@ -42,44 +34,6 @@ function _instanceof(left, right) {
|
|
|
42
34
|
return left instanceof right;
|
|
43
35
|
}
|
|
44
36
|
}
|
|
45
|
-
function _iterable_to_array_limit(arr, i) {
|
|
46
|
-
var _i = arr == null ? null : typeof Symbol !== "undefined" && arr[Symbol.iterator] || arr["@@iterator"];
|
|
47
|
-
if (_i == null) return;
|
|
48
|
-
var _arr = [];
|
|
49
|
-
var _n = true;
|
|
50
|
-
var _d = false;
|
|
51
|
-
var _s, _e;
|
|
52
|
-
try {
|
|
53
|
-
for(_i = _i.call(arr); !(_n = (_s = _i.next()).done); _n = true){
|
|
54
|
-
_arr.push(_s.value);
|
|
55
|
-
if (i && _arr.length === i) break;
|
|
56
|
-
}
|
|
57
|
-
} catch (err) {
|
|
58
|
-
_d = true;
|
|
59
|
-
_e = err;
|
|
60
|
-
} finally{
|
|
61
|
-
try {
|
|
62
|
-
if (!_n && _i["return"] != null) _i["return"]();
|
|
63
|
-
} finally{
|
|
64
|
-
if (_d) throw _e;
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
return _arr;
|
|
68
|
-
}
|
|
69
|
-
function _non_iterable_rest() {
|
|
70
|
-
throw new TypeError("Invalid attempt to destructure non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
|
|
71
|
-
}
|
|
72
|
-
function _sliced_to_array(arr, i) {
|
|
73
|
-
return _array_with_holes(arr) || _iterable_to_array_limit(arr, i) || _unsupported_iterable_to_array(arr, i) || _non_iterable_rest();
|
|
74
|
-
}
|
|
75
|
-
function _unsupported_iterable_to_array(o, minLen) {
|
|
76
|
-
if (!o) return;
|
|
77
|
-
if (typeof o === "string") return _array_like_to_array(o, minLen);
|
|
78
|
-
var n = Object.prototype.toString.call(o).slice(8, -1);
|
|
79
|
-
if (n === "Object" && o.constructor) n = o.constructor.name;
|
|
80
|
-
if (n === "Map" || n === "Set") return Array.from(n);
|
|
81
|
-
if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array(o, minLen);
|
|
82
|
-
}
|
|
83
37
|
function _ts_generator(thisArg, body) {
|
|
84
38
|
var f, y, t, _ = {
|
|
85
39
|
label: 0,
|
|
@@ -171,114 +125,34 @@ function _ts_generator(thisArg, body) {
|
|
|
171
125
|
};
|
|
172
126
|
}
|
|
173
127
|
}
|
|
174
|
-
import {
|
|
128
|
+
import { jwtVerify, decodeJwt, importJWK } from 'jose';
|
|
175
129
|
/**
|
|
176
|
-
* Get the algorithm
|
|
130
|
+
* Get the JWT algorithm based on JWK key type
|
|
177
131
|
*/ function getAlgorithmForJwk(jwk) {
|
|
178
132
|
if (jwk.kty === 'RSA') {
|
|
179
|
-
return
|
|
180
|
-
name: 'RSASSA-PKCS1-v1_5',
|
|
181
|
-
hash: 'SHA-256'
|
|
182
|
-
};
|
|
183
|
-
} else if (jwk.kty === 'EC') {
|
|
184
|
-
return {
|
|
185
|
-
name: 'ECDSA',
|
|
186
|
-
namedCurve: jwk.crv || 'P-256'
|
|
187
|
-
};
|
|
188
|
-
} else if (jwk.kty === 'OKP' && jwk.crv === 'Ed25519') {
|
|
189
|
-
return {
|
|
190
|
-
name: 'Ed25519'
|
|
191
|
-
};
|
|
192
|
-
}
|
|
193
|
-
throw new Error("Unsupported key type: ".concat(jwk.kty));
|
|
194
|
-
}
|
|
195
|
-
/**
|
|
196
|
-
* Get the algorithm parameters for signature verification
|
|
197
|
-
*/ function getVerifyAlgorithm(jwk) {
|
|
198
|
-
if (jwk.kty === 'RSA') {
|
|
199
|
-
return {
|
|
200
|
-
name: 'RSASSA-PKCS1-v1_5',
|
|
201
|
-
hash: 'SHA-256'
|
|
202
|
-
};
|
|
133
|
+
return 'RS256';
|
|
203
134
|
} else if (jwk.kty === 'EC') {
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
135
|
+
if (jwk.crv === 'P-256') {
|
|
136
|
+
return 'ES256';
|
|
137
|
+
} else if (jwk.crv === 'P-384') {
|
|
138
|
+
return 'ES384';
|
|
139
|
+
} else if (jwk.crv === 'P-521') {
|
|
140
|
+
return 'ES512';
|
|
141
|
+
}
|
|
142
|
+
// Default to ES256 for unknown curves
|
|
143
|
+
return 'ES256';
|
|
208
144
|
} else if (jwk.kty === 'OKP' && jwk.crv === 'Ed25519') {
|
|
209
|
-
return
|
|
210
|
-
name: 'Ed25519'
|
|
211
|
-
};
|
|
145
|
+
return 'EdDSA';
|
|
212
146
|
}
|
|
213
147
|
throw new Error("Unsupported key type: ".concat(jwk.kty));
|
|
214
148
|
}
|
|
215
|
-
/**
|
|
216
|
-
* Convert a JWK to a CryptoKey for signature verification
|
|
217
|
-
*/ function jwkToCryptoKey(jwkString) {
|
|
218
|
-
return _async_to_generator(function() {
|
|
219
|
-
var jwk, algorithm;
|
|
220
|
-
return _ts_generator(this, function(_state) {
|
|
221
|
-
jwk = JSON.parse(jwkString);
|
|
222
|
-
algorithm = getAlgorithmForJwk(jwk);
|
|
223
|
-
return [
|
|
224
|
-
2,
|
|
225
|
-
crypto.subtle.importKey('jwk', jwk, algorithm, true, [
|
|
226
|
-
'verify'
|
|
227
|
-
])
|
|
228
|
-
];
|
|
229
|
-
});
|
|
230
|
-
})();
|
|
231
|
-
}
|
|
232
|
-
/**
|
|
233
|
-
* Verify a signature using Web Crypto API
|
|
234
|
-
*/ function verifySignatureWithKey(signatureBase, signatureB64, cryptoKey, jwk) {
|
|
235
|
-
return _async_to_generator(function() {
|
|
236
|
-
var encoder, data, signatureBytes, algorithm;
|
|
237
|
-
return _ts_generator(this, function(_state) {
|
|
238
|
-
encoder = new TextEncoder();
|
|
239
|
-
data = encoder.encode(signatureBase);
|
|
240
|
-
signatureBytes = Uint8Array.from(atob(signatureB64), function(c) {
|
|
241
|
-
return c.charCodeAt(0);
|
|
242
|
-
});
|
|
243
|
-
algorithm = getVerifyAlgorithm(jwk);
|
|
244
|
-
return [
|
|
245
|
-
2,
|
|
246
|
-
crypto.subtle.verify(algorithm, cryptoKey, signatureBytes, data)
|
|
247
|
-
];
|
|
248
|
-
});
|
|
249
|
-
})();
|
|
250
|
-
}
|
|
251
|
-
/**
|
|
252
|
-
* Extract keyId and signature info from parsed signature
|
|
253
|
-
* Handles both draft and RFC9421 formats
|
|
254
|
-
*/ function extractSignatureInfo(parsed) {
|
|
255
|
-
if (parsed.version === 'draft') {
|
|
256
|
-
return {
|
|
257
|
-
keyId: parsed.value.keyId,
|
|
258
|
-
signature: parsed.value.params.signature,
|
|
259
|
-
base: parsed.value.signingString
|
|
260
|
-
};
|
|
261
|
-
} else if (parsed.version === 'rfc9421') {
|
|
262
|
-
// RFC9421 returns an array of [label, value] tuples
|
|
263
|
-
var signatures = parsed.value;
|
|
264
|
-
if (signatures.length === 0) return null;
|
|
265
|
-
// Use the first signature (usually 'sig1')
|
|
266
|
-
var _signatures_ = _sliced_to_array(signatures[0], 2), sigValue = _signatures_[1];
|
|
267
|
-
return {
|
|
268
|
-
keyId: sigValue.keyid,
|
|
269
|
-
signature: sigValue.signature,
|
|
270
|
-
base: sigValue.base
|
|
271
|
-
};
|
|
272
|
-
}
|
|
273
|
-
return null;
|
|
274
|
-
}
|
|
275
149
|
/**
|
|
276
150
|
* Authentication middleware for the Positronic API
|
|
277
|
-
* Verifies
|
|
151
|
+
* Verifies JWT Bearer tokens
|
|
278
152
|
*/ export function authMiddleware() {
|
|
279
153
|
return function(c, next) {
|
|
280
154
|
return _async_to_generator(function() {
|
|
281
|
-
var
|
|
155
|
+
var authHeader, token, fingerprint, decoded, userKey, authDoId, authDo, jwk, algorithm, publicKey, error, errorMessage, jwk1, algorithm1, publicKey1, error1, errorMessage1;
|
|
282
156
|
return _ts_generator(this, function(_state) {
|
|
283
157
|
switch(_state.label){
|
|
284
158
|
case 0:
|
|
@@ -293,11 +167,10 @@ import { parseRequestSignature } from '@misskey-dev/node-http-message-signatures
|
|
|
293
167
|
next()
|
|
294
168
|
];
|
|
295
169
|
}
|
|
296
|
-
// Get
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
if (!signatureHeader || !signatureInputHeader) {
|
|
170
|
+
// Get Authorization header
|
|
171
|
+
authHeader = c.req.header('Authorization');
|
|
172
|
+
// If no Authorization header, return 401
|
|
173
|
+
if (!authHeader) {
|
|
301
174
|
return [
|
|
302
175
|
2,
|
|
303
176
|
c.json({
|
|
@@ -305,84 +178,82 @@ import { parseRequestSignature } from '@misskey-dev/node-http-message-signatures
|
|
|
305
178
|
}, 401)
|
|
306
179
|
];
|
|
307
180
|
}
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
requestForParsing = {
|
|
311
|
-
method: c.req.method,
|
|
312
|
-
url: c.req.url,
|
|
313
|
-
headers: Object.fromEntries(c.req.raw.headers.entries())
|
|
314
|
-
};
|
|
315
|
-
parsedSignature = parseRequestSignature(requestForParsing, {
|
|
316
|
-
clockSkew: {
|
|
317
|
-
now: new Date(),
|
|
318
|
-
forward: 300000,
|
|
319
|
-
delay: 300000
|
|
320
|
-
}
|
|
321
|
-
});
|
|
322
|
-
} catch (error) {
|
|
323
|
-
// Log error type only - avoid logging request details that could contain sensitive data
|
|
324
|
-
errorMessage = _instanceof(error, Error) ? error.message : 'Unknown error';
|
|
325
|
-
console.error('Failed to parse signature:', errorMessage);
|
|
181
|
+
// Check for Bearer token format
|
|
182
|
+
if (!authHeader.startsWith('Bearer ')) {
|
|
326
183
|
return [
|
|
327
184
|
2,
|
|
328
185
|
c.json({
|
|
329
|
-
error: '
|
|
186
|
+
error: 'Authentication required'
|
|
330
187
|
}, 401)
|
|
331
188
|
];
|
|
332
189
|
}
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
190
|
+
token = authHeader.slice(7); // Remove 'Bearer ' prefix
|
|
191
|
+
try {
|
|
192
|
+
decoded = decodeJwt(token);
|
|
193
|
+
if (!decoded.sub) {
|
|
194
|
+
return [
|
|
195
|
+
2,
|
|
196
|
+
c.json({
|
|
197
|
+
error: 'Invalid or expired token'
|
|
198
|
+
}, 401)
|
|
199
|
+
];
|
|
200
|
+
}
|
|
201
|
+
fingerprint = decoded.sub;
|
|
202
|
+
} catch (e) {
|
|
336
203
|
return [
|
|
337
204
|
2,
|
|
338
205
|
c.json({
|
|
339
|
-
error: '
|
|
206
|
+
error: 'Invalid or expired token'
|
|
340
207
|
}, 401)
|
|
341
208
|
];
|
|
342
209
|
}
|
|
343
|
-
keyId = sigInfo.keyId, signature = sigInfo.signature, base = sigInfo.base;
|
|
344
210
|
// Try to find the key in the auth database
|
|
211
|
+
userKey = null;
|
|
212
|
+
if (!c.env.AUTH_DO) return [
|
|
213
|
+
3,
|
|
214
|
+
2
|
|
215
|
+
];
|
|
345
216
|
authDoId = c.env.AUTH_DO.idFromName('auth');
|
|
346
217
|
authDo = c.env.AUTH_DO.get(authDoId);
|
|
347
218
|
return [
|
|
348
219
|
4,
|
|
349
|
-
authDo.getKeyByFingerprint(
|
|
220
|
+
authDo.getKeyByFingerprint(fingerprint)
|
|
350
221
|
];
|
|
351
222
|
case 1:
|
|
352
223
|
userKey = _state.sent();
|
|
224
|
+
_state.label = 2;
|
|
225
|
+
case 2:
|
|
353
226
|
if (!userKey) return [
|
|
354
227
|
3,
|
|
355
|
-
|
|
228
|
+
7
|
|
356
229
|
];
|
|
357
|
-
_state.label =
|
|
358
|
-
case
|
|
230
|
+
_state.label = 3;
|
|
231
|
+
case 3:
|
|
359
232
|
_state.trys.push([
|
|
360
|
-
|
|
361
|
-
|
|
233
|
+
3,
|
|
234
|
+
6,
|
|
362
235
|
,
|
|
363
|
-
|
|
236
|
+
7
|
|
364
237
|
]);
|
|
365
238
|
jwk = JSON.parse(userKey.jwk);
|
|
239
|
+
algorithm = getAlgorithmForJwk(jwk);
|
|
366
240
|
return [
|
|
367
241
|
4,
|
|
368
|
-
|
|
242
|
+
importJWK(jwk, algorithm)
|
|
369
243
|
];
|
|
370
|
-
case
|
|
371
|
-
|
|
244
|
+
case 4:
|
|
245
|
+
publicKey = _state.sent();
|
|
246
|
+
// Verify the JWT - this checks both signature and expiry
|
|
372
247
|
return [
|
|
373
248
|
4,
|
|
374
|
-
|
|
249
|
+
jwtVerify(token, publicKey, {
|
|
250
|
+
algorithms: [
|
|
251
|
+
algorithm
|
|
252
|
+
]
|
|
253
|
+
})
|
|
375
254
|
];
|
|
376
|
-
case
|
|
377
|
-
|
|
378
|
-
if (!isValid) {
|
|
379
|
-
return [
|
|
380
|
-
2,
|
|
381
|
-
c.json({
|
|
382
|
-
error: 'Invalid signature'
|
|
383
|
-
}, 401)
|
|
384
|
-
];
|
|
385
|
-
}
|
|
255
|
+
case 5:
|
|
256
|
+
_state.sent();
|
|
386
257
|
c.set('auth', {
|
|
387
258
|
userId: userKey.userId,
|
|
388
259
|
isRoot: false
|
|
@@ -391,72 +262,81 @@ import { parseRequestSignature } from '@misskey-dev/node-http-message-signatures
|
|
|
391
262
|
2,
|
|
392
263
|
next()
|
|
393
264
|
];
|
|
394
|
-
case
|
|
265
|
+
case 6:
|
|
395
266
|
error = _state.sent();
|
|
396
|
-
// Log error type only - avoid logging key material or
|
|
397
|
-
|
|
398
|
-
console.error('
|
|
267
|
+
// Log error type only - avoid logging key material or token data
|
|
268
|
+
errorMessage = _instanceof(error, Error) ? error.message : 'Unknown error';
|
|
269
|
+
console.error('JWT verification failed:', errorMessage);
|
|
399
270
|
return [
|
|
400
271
|
2,
|
|
401
272
|
c.json({
|
|
402
|
-
error: '
|
|
273
|
+
error: 'Invalid or expired token'
|
|
403
274
|
}, 401)
|
|
404
275
|
];
|
|
405
|
-
case
|
|
276
|
+
case 7:
|
|
406
277
|
if (!c.env.ROOT_PUBLIC_KEY) return [
|
|
407
278
|
3,
|
|
408
|
-
|
|
279
|
+
12
|
|
409
280
|
];
|
|
410
|
-
_state.label =
|
|
411
|
-
case
|
|
281
|
+
_state.label = 8;
|
|
282
|
+
case 8:
|
|
412
283
|
_state.trys.push([
|
|
413
|
-
|
|
414
|
-
|
|
284
|
+
8,
|
|
285
|
+
11,
|
|
415
286
|
,
|
|
416
|
-
|
|
287
|
+
12
|
|
417
288
|
]);
|
|
418
289
|
jwk1 = JSON.parse(c.env.ROOT_PUBLIC_KEY);
|
|
290
|
+
algorithm1 = getAlgorithmForJwk(jwk1);
|
|
419
291
|
return [
|
|
420
292
|
4,
|
|
421
|
-
|
|
293
|
+
importJWK(jwk1, algorithm1)
|
|
422
294
|
];
|
|
423
|
-
case
|
|
424
|
-
|
|
295
|
+
case 9:
|
|
296
|
+
publicKey1 = _state.sent();
|
|
297
|
+
// Verify the JWT - this checks both signature and expiry
|
|
425
298
|
return [
|
|
426
299
|
4,
|
|
427
|
-
|
|
300
|
+
jwtVerify(token, publicKey1, {
|
|
301
|
+
algorithms: [
|
|
302
|
+
algorithm1
|
|
303
|
+
]
|
|
304
|
+
})
|
|
428
305
|
];
|
|
429
|
-
case
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
});
|
|
436
|
-
return [
|
|
437
|
-
2,
|
|
438
|
-
next()
|
|
439
|
-
];
|
|
440
|
-
}
|
|
306
|
+
case 10:
|
|
307
|
+
_state.sent();
|
|
308
|
+
c.set('auth', {
|
|
309
|
+
userId: null,
|
|
310
|
+
isRoot: true
|
|
311
|
+
});
|
|
441
312
|
return [
|
|
442
|
-
|
|
443
|
-
|
|
313
|
+
2,
|
|
314
|
+
next()
|
|
444
315
|
];
|
|
445
|
-
case
|
|
316
|
+
case 11:
|
|
446
317
|
error1 = _state.sent();
|
|
447
318
|
// Log error type only - avoid logging key material
|
|
448
|
-
|
|
449
|
-
console.error('Root key verification failed:',
|
|
319
|
+
errorMessage1 = _instanceof(error1, Error) ? error1.message : 'Unknown error';
|
|
320
|
+
console.error('Root key JWT verification failed:', errorMessage1);
|
|
450
321
|
return [
|
|
451
322
|
3,
|
|
452
|
-
|
|
323
|
+
12
|
|
453
324
|
];
|
|
454
|
-
case
|
|
325
|
+
case 12:
|
|
455
326
|
// No matching key found
|
|
327
|
+
// Check if ROOT_PUBLIC_KEY is configured - if not, return specific error
|
|
328
|
+
if (!c.env.ROOT_PUBLIC_KEY) {
|
|
329
|
+
return [
|
|
330
|
+
2,
|
|
331
|
+
c.json({
|
|
332
|
+
error: 'ROOT_KEY_NOT_CONFIGURED'
|
|
333
|
+
}, 401)
|
|
334
|
+
];
|
|
335
|
+
}
|
|
456
336
|
return [
|
|
457
337
|
2,
|
|
458
338
|
c.json({
|
|
459
|
-
error: '
|
|
339
|
+
error: 'Invalid or expired token'
|
|
460
340
|
}, 401)
|
|
461
341
|
];
|
|
462
342
|
}
|
package/dist/src/api/index.js
CHANGED
|
@@ -141,12 +141,29 @@ app.get('/status', function(context) {
|
|
|
141
141
|
});
|
|
142
142
|
})();
|
|
143
143
|
});
|
|
144
|
-
//
|
|
144
|
+
// Auth setup endpoint (no auth required) - returns setup instructions
|
|
145
|
+
app.get('/auth/setup', function(context) {
|
|
146
|
+
return _async_to_generator(function() {
|
|
147
|
+
var rootKeyConfigured;
|
|
148
|
+
return _ts_generator(this, function(_state) {
|
|
149
|
+
rootKeyConfigured = !!context.env.ROOT_PUBLIC_KEY;
|
|
150
|
+
return [
|
|
151
|
+
2,
|
|
152
|
+
context.json({
|
|
153
|
+
backend: 'cloudflare',
|
|
154
|
+
rootKeyConfigured: rootKeyConfigured,
|
|
155
|
+
instructions: "To configure root authentication:\n1. Run: px auth format-jwk-key\n2. In Cloudflare dashboard, go to Workers & Pages > Your project > Settings > Variables and Secrets\n3. Add a new secret named ROOT_PUBLIC_KEY\n4. Paste the JWK value from step 1"
|
|
156
|
+
})
|
|
157
|
+
];
|
|
158
|
+
});
|
|
159
|
+
})();
|
|
160
|
+
});
|
|
161
|
+
// Apply auth middleware to all routes except /status and /auth/setup
|
|
145
162
|
app.use('*', function(c, next) {
|
|
146
163
|
return _async_to_generator(function() {
|
|
147
164
|
return _ts_generator(this, function(_state) {
|
|
148
|
-
// Skip auth for
|
|
149
|
-
if (c.req.path === '/status') {
|
|
165
|
+
// Skip auth for unauthenticated endpoints
|
|
166
|
+
if (c.req.path === '/status' || c.req.path === '/auth/setup') {
|
|
150
167
|
return [
|
|
151
168
|
2,
|
|
152
169
|
next()
|
package/dist/src/api/secrets.js
CHANGED
|
@@ -214,6 +214,8 @@ import { Hono } from 'hono';
|
|
|
214
214
|
}).apply(this, arguments);
|
|
215
215
|
}
|
|
216
216
|
var secrets = new Hono();
|
|
217
|
+
// Protected secret name that cannot be managed via the API
|
|
218
|
+
var PROTECTED_SECRET = 'ROOT_PUBLIC_KEY';
|
|
217
219
|
// List all secrets (names only, not values)
|
|
218
220
|
secrets.get('/', function(context) {
|
|
219
221
|
return _async_to_generator(function() {
|
|
@@ -262,8 +264,11 @@ secrets.get('/', function(context) {
|
|
|
262
264
|
}
|
|
263
265
|
// Transform to match spec format - Cloudflare API doesn't return timestamps
|
|
264
266
|
// so we use placeholder values
|
|
267
|
+
// Filter out ROOT_PUBLIC_KEY from the list for security
|
|
265
268
|
now = new Date().toISOString();
|
|
266
|
-
secretList = data.result.
|
|
269
|
+
secretList = data.result.filter(function(secret) {
|
|
270
|
+
return secret.name !== PROTECTED_SECRET;
|
|
271
|
+
}).map(function(secret) {
|
|
267
272
|
return {
|
|
268
273
|
name: secret.name,
|
|
269
274
|
createdAt: now,
|
|
@@ -341,6 +346,15 @@ secrets.post('/', function(context) {
|
|
|
341
346
|
}, 400)
|
|
342
347
|
];
|
|
343
348
|
}
|
|
349
|
+
// Block setting ROOT_PUBLIC_KEY via API - must be set in Cloudflare dashboard
|
|
350
|
+
if (name === PROTECTED_SECRET) {
|
|
351
|
+
return [
|
|
352
|
+
2,
|
|
353
|
+
context.json({
|
|
354
|
+
error: "Cannot set ".concat(PROTECTED_SECRET, " via API. This secret must be configured directly in the Cloudflare dashboard under Workers & Pages > Settings > Variables and Secrets.")
|
|
355
|
+
}, 403)
|
|
356
|
+
];
|
|
357
|
+
}
|
|
344
358
|
return [
|
|
345
359
|
4,
|
|
346
360
|
cloudflareSecretsApi(config, '', {
|
|
@@ -413,6 +427,15 @@ secrets.delete('/:name', function(context) {
|
|
|
413
427
|
];
|
|
414
428
|
}
|
|
415
429
|
name = decodeURIComponent(context.req.param('name'));
|
|
430
|
+
// Block deleting ROOT_PUBLIC_KEY via API - must be managed in Cloudflare dashboard
|
|
431
|
+
if (name === PROTECTED_SECRET) {
|
|
432
|
+
return [
|
|
433
|
+
2,
|
|
434
|
+
context.json({
|
|
435
|
+
error: "Cannot delete ".concat(PROTECTED_SECRET, " via API. This secret must be managed directly in the Cloudflare dashboard under Workers & Pages > Settings > Variables and Secrets.")
|
|
436
|
+
}, 403)
|
|
437
|
+
];
|
|
438
|
+
}
|
|
416
439
|
_state.label = 1;
|
|
417
440
|
case 1:
|
|
418
441
|
_state.trys.push([
|
|
@@ -620,6 +643,13 @@ secrets.post('/bulk', function(context) {
|
|
|
620
643
|
9
|
|
621
644
|
]; // Skip invalid entries
|
|
622
645
|
}
|
|
646
|
+
// Skip ROOT_PUBLIC_KEY - it cannot be set via API
|
|
647
|
+
if (secret.name === PROTECTED_SECRET) {
|
|
648
|
+
return [
|
|
649
|
+
3,
|
|
650
|
+
9
|
|
651
|
+
];
|
|
652
|
+
}
|
|
623
653
|
return [
|
|
624
654
|
4,
|
|
625
655
|
cloudflareSecretsApi(config, '', {
|
|
@@ -150,6 +150,10 @@ function _ts_generator(thisArg, body) {
|
|
|
150
150
|
};
|
|
151
151
|
}
|
|
152
152
|
}
|
|
153
|
+
// R2 overflow stores large events (>1MB) in R2 instead of SQLite.
|
|
154
|
+
// This feature is manually tested because vitest-pool-workers has limitations
|
|
155
|
+
// with large data and isolated storage cleanup.
|
|
156
|
+
// See: https://developers.cloudflare.com/workers/testing/vitest-integration/known-issues/#isolated-storage
|
|
153
157
|
// Size threshold for R2 overflow (1MB)
|
|
154
158
|
export var R2_OVERFLOW_THRESHOLD = 1024 * 1024;
|
|
155
159
|
// Define the schema with r2_key column for overflow support
|
|
@@ -11,7 +11,7 @@ declare module 'hono' {
|
|
|
11
11
|
}
|
|
12
12
|
/**
|
|
13
13
|
* Authentication middleware for the Positronic API
|
|
14
|
-
* Verifies
|
|
14
|
+
* Verifies JWT Bearer tokens
|
|
15
15
|
*/
|
|
16
16
|
export declare function authMiddleware(): MiddlewareHandler<{
|
|
17
17
|
Bindings: Bindings;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth-middleware.d.ts","sourceRoot":"","sources":["../../../src/api/auth-middleware.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAW,iBAAiB,EAAE,MAAM,MAAM,CAAC;AACvD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"auth-middleware.d.ts","sourceRoot":"","sources":["../../../src/api/auth-middleware.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAW,iBAAiB,EAAE,MAAM,MAAM,CAAC;AACvD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAI3C,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,MAAM,EAAE,OAAO,CAAC;CACjB;AAGD,OAAO,QAAQ,MAAM,CAAC;IACpB,UAAU,kBAAkB;QAC1B,IAAI,EAAE,WAAW,CAAC;KACnB;CACF;AAwBD;;;GAGG;AACH,wBAAgB,cAAc,IAAI,iBAAiB,CAAC;IAAE,QAAQ,EAAE,QAAQ,CAAA;CAAE,CAAC,CA4F1E"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/api/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAgB,MAAM,MAAM,CAAC;AAC1C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAU3C,QAAA,MAAM,GAAG;cAAwB,QAAQ;yCAAK,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/api/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAgB,MAAM,MAAM,CAAC;AAC1C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAU3C,QAAA,MAAM,GAAG;cAAwB,QAAQ;yCAAK,CAAC;AAwC/C,eAAe,GAAG,CAAC;AAGnB,YAAY,EAAE,QAAQ,EAAE,OAAO,EAAE,qBAAqB,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"secrets.d.ts","sourceRoot":"","sources":["../../../src/api/secrets.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAgB,MAAM,MAAM,CAAC;AAC1C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAiD3C,QAAA,MAAM,OAAO;cAAwB,QAAQ;yCAAK,CAAC;
|
|
1
|
+
{"version":3,"file":"secrets.d.ts","sourceRoot":"","sources":["../../../src/api/secrets.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAgB,MAAM,MAAM,CAAC;AAC1C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAiD3C,QAAA,MAAM,OAAO;cAAwB,QAAQ;yCAAK,CAAC;AA0SnD,eAAe,OAAO,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sqlite-adapter.d.ts","sourceRoot":"","sources":["../../src/sqlite-adapter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC5D,OAAO,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAC;
|
|
1
|
+
{"version":3,"file":"sqlite-adapter.d.ts","sourceRoot":"","sources":["../../src/sqlite-adapter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC5D,OAAO,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAC;AAQtE,eAAO,MAAM,qBAAqB,QAAc,CAAC;AAajD,qBAAa,qBAAsB,YAAW,OAAO;IACnD,OAAO,CAAC,GAAG,CAAa;IACxB,OAAO,CAAC,MAAM,CAAW;IACzB,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,iBAAiB,CAAS;gBAEtB,GAAG,EAAE,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM;IAMjE,OAAO,CAAC,gBAAgB;IAOX,QAAQ,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;CA+DxD"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@positronic/cloudflare",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.59",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
@@ -31,16 +31,16 @@
|
|
|
31
31
|
"clean": "rm -rf tsconfig.tsbuildinfo dist"
|
|
32
32
|
},
|
|
33
33
|
"dependencies": {
|
|
34
|
-
"@
|
|
35
|
-
"@positronic/
|
|
36
|
-
"@positronic/
|
|
37
|
-
"@positronic/template-new-project": "^0.0.57",
|
|
34
|
+
"@positronic/core": "^0.0.59",
|
|
35
|
+
"@positronic/spec": "^0.0.59",
|
|
36
|
+
"@positronic/template-new-project": "^0.0.59",
|
|
38
37
|
"aws4fetch": "^1.0.18",
|
|
39
38
|
"caz": "^2.0.0",
|
|
40
39
|
"cron-schedule": "^5.0.4",
|
|
41
40
|
"dotenv": "^16.0.3",
|
|
42
41
|
"fuse.js": "^7.1.0",
|
|
43
42
|
"hono": "^4.2.3",
|
|
43
|
+
"jose": "^5.2.0",
|
|
44
44
|
"uuid": "^9.0.1"
|
|
45
45
|
},
|
|
46
46
|
"devDependencies": {
|