@striae-org/striae 6.1.7 → 7.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.
- package/.env.example +0 -26
- package/README.md +1 -2
- package/app/components/actions/image-manage.ts +17 -67
- package/functions/api/audit/[[path]].ts +9 -24
- package/functions/api/data/[[path]].ts +9 -24
- package/functions/api/image/[[path]].ts +14 -30
- package/functions/api/pdf/[[path]].ts +9 -24
- package/functions/api/user/[[path]].ts +20 -36
- package/package.json +143 -137
- package/scripts/deploy-all.sh +29 -10
- package/scripts/deploy-config/modules/env-utils.sh +0 -68
- package/scripts/deploy-config/modules/prompt.sh +4 -110
- package/scripts/deploy-config/modules/scaffolding.sh +5 -68
- package/scripts/deploy-config/modules/validation.sh +1 -30
- package/scripts/deploy-pages-secrets.sh +0 -9
- package/scripts/deploy-worker-secrets.sh +2 -8
- package/tsconfig.json +1 -1
- package/workers/audit-worker/package.json +2 -2
- package/workers/audit-worker/src/{audit-worker.example.ts → audit-worker.ts} +1 -17
- package/workers/audit-worker/src/config.ts +1 -6
- package/workers/audit-worker/src/types.ts +0 -1
- package/workers/audit-worker/wrangler.jsonc.example +2 -6
- package/workers/data-worker/package.json +3 -2
- package/workers/data-worker/src/config.ts +1 -6
- package/workers/data-worker/src/{data-worker.example.ts → data-worker.ts} +2 -18
- package/workers/data-worker/src/types.ts +0 -1
- package/workers/data-worker/wrangler.jsonc.example +2 -4
- package/workers/image-worker/package.json +2 -2
- package/workers/image-worker/src/handlers/delete-image.ts +0 -5
- package/workers/image-worker/src/handlers/mint-signed-url.ts +0 -5
- package/workers/image-worker/src/handlers/serve-image.ts +2 -5
- package/workers/image-worker/src/handlers/upload-image.ts +0 -5
- package/workers/image-worker/src/{image-worker.example.ts → image-worker.ts} +2 -15
- package/workers/image-worker/src/router.ts +2 -3
- package/workers/image-worker/src/security/signed-url.ts +2 -2
- package/workers/image-worker/src/types.ts +0 -1
- package/workers/image-worker/wrangler.jsonc.example +2 -1
- package/workers/pdf-worker/package.json +2 -2
- package/workers/pdf-worker/src/{pdf-worker.example.ts → pdf-worker.ts} +1 -23
- package/workers/pdf-worker/wrangler.jsonc.example +2 -1
- package/workers/user-worker/package.json +2 -2
- package/workers/user-worker/src/auth.ts +0 -7
- package/workers/user-worker/src/handlers/user-routes.ts +25 -39
- package/workers/user-worker/src/types.ts +0 -2
- package/workers/user-worker/src/{user-worker.example.ts → user-worker.ts} +15 -30
- package/workers/user-worker/wrangler.jsonc.example +2 -1
- package/wrangler.toml.example +22 -2
- package/worker-configuration.d.ts +0 -7509
- package/workers/image-worker/src/auth.ts +0 -7
|
@@ -109,44 +109,6 @@ copy_example_configs() {
|
|
|
109
109
|
# Return to project root
|
|
110
110
|
cd ../..
|
|
111
111
|
|
|
112
|
-
# Copy worker source template files
|
|
113
|
-
echo -e "${YELLOW} Copying worker source template files...${NC}"
|
|
114
|
-
|
|
115
|
-
if [ -f "workers/user-worker/src/user-worker.example.ts" ] && { [ "$update_env" = "true" ] || [ ! -f "workers/user-worker/src/user-worker.ts" ]; }; then
|
|
116
|
-
cp workers/user-worker/src/user-worker.example.ts workers/user-worker/src/user-worker.ts
|
|
117
|
-
echo -e "${GREEN} ✅ user-worker: user-worker.ts created from example${NC}"
|
|
118
|
-
elif [ -f "workers/user-worker/src/user-worker.ts" ]; then
|
|
119
|
-
echo -e "${YELLOW} ⚠️ user-worker: user-worker.ts already exists, skipping copy${NC}"
|
|
120
|
-
fi
|
|
121
|
-
|
|
122
|
-
if [ -f "workers/data-worker/src/data-worker.example.ts" ] && { [ "$update_env" = "true" ] || [ ! -f "workers/data-worker/src/data-worker.ts" ]; }; then
|
|
123
|
-
cp workers/data-worker/src/data-worker.example.ts workers/data-worker/src/data-worker.ts
|
|
124
|
-
echo -e "${GREEN} ✅ data-worker: data-worker.ts created from example${NC}"
|
|
125
|
-
elif [ -f "workers/data-worker/src/data-worker.ts" ]; then
|
|
126
|
-
echo -e "${YELLOW} ⚠️ data-worker: data-worker.ts already exists, skipping copy${NC}"
|
|
127
|
-
fi
|
|
128
|
-
|
|
129
|
-
if [ -f "workers/audit-worker/src/audit-worker.example.ts" ] && { [ "$update_env" = "true" ] || [ ! -f "workers/audit-worker/src/audit-worker.ts" ]; }; then
|
|
130
|
-
cp workers/audit-worker/src/audit-worker.example.ts workers/audit-worker/src/audit-worker.ts
|
|
131
|
-
echo -e "${GREEN} ✅ audit-worker: audit-worker.ts created from example${NC}"
|
|
132
|
-
elif [ -f "workers/audit-worker/src/audit-worker.ts" ]; then
|
|
133
|
-
echo -e "${YELLOW} ⚠️ audit-worker: audit-worker.ts already exists, skipping copy${NC}"
|
|
134
|
-
fi
|
|
135
|
-
|
|
136
|
-
if [ -f "workers/image-worker/src/image-worker.example.ts" ] && { [ "$update_env" = "true" ] || [ ! -f "workers/image-worker/src/image-worker.ts" ]; }; then
|
|
137
|
-
cp workers/image-worker/src/image-worker.example.ts workers/image-worker/src/image-worker.ts
|
|
138
|
-
echo -e "${GREEN} ✅ image-worker: image-worker.ts created from example${NC}"
|
|
139
|
-
elif [ -f "workers/image-worker/src/image-worker.ts" ]; then
|
|
140
|
-
echo -e "${YELLOW} ⚠️ image-worker: image-worker.ts already exists, skipping copy${NC}"
|
|
141
|
-
fi
|
|
142
|
-
|
|
143
|
-
if [ -f "workers/pdf-worker/src/pdf-worker.example.ts" ] && { [ "$update_env" = "true" ] || [ ! -f "workers/pdf-worker/src/pdf-worker.ts" ]; }; then
|
|
144
|
-
cp workers/pdf-worker/src/pdf-worker.example.ts workers/pdf-worker/src/pdf-worker.ts
|
|
145
|
-
echo -e "${GREEN} ✅ pdf-worker: pdf-worker.ts created from example${NC}"
|
|
146
|
-
elif [ -f "workers/pdf-worker/src/pdf-worker.ts" ]; then
|
|
147
|
-
echo -e "${YELLOW} ⚠️ pdf-worker: pdf-worker.ts already exists, skipping copy${NC}"
|
|
148
|
-
fi
|
|
149
|
-
|
|
150
112
|
# Copy main wrangler.toml from example
|
|
151
113
|
if [ -f "wrangler.toml.example" ] && { [ "$update_env" = "true" ] || [ ! -f "wrangler.toml" ]; }; then
|
|
152
114
|
cp wrangler.toml.example wrangler.toml
|
|
@@ -187,12 +149,6 @@ update_wrangler_configs() {
|
|
|
187
149
|
echo -e "${GREEN} ✅ audit-worker configuration updated${NC}"
|
|
188
150
|
fi
|
|
189
151
|
|
|
190
|
-
if [ -f "workers/audit-worker/src/audit-worker.ts" ]; then
|
|
191
|
-
echo -e "${YELLOW} Updating audit-worker source placeholders...${NC}"
|
|
192
|
-
sed -i "s|'Access-Control-Allow-Origin': '[^']*'|'Access-Control-Allow-Origin': 'https://$escaped_pages_custom_domain'|g" workers/audit-worker/src/audit-worker.ts
|
|
193
|
-
echo -e "${GREEN} ✅ audit-worker source placeholders updated${NC}"
|
|
194
|
-
fi
|
|
195
|
-
|
|
196
152
|
if [ -f "workers/data-worker/wrangler.jsonc" ]; then
|
|
197
153
|
echo -e "${YELLOW} Updating data-worker/wrangler.jsonc...${NC}"
|
|
198
154
|
sed -i "s/\"DATA_WORKER_NAME\"/\"$DATA_WORKER_NAME\"/g" workers/data-worker/wrangler.jsonc
|
|
@@ -201,12 +157,6 @@ update_wrangler_configs() {
|
|
|
201
157
|
echo -e "${GREEN} ✅ data-worker configuration updated${NC}"
|
|
202
158
|
fi
|
|
203
159
|
|
|
204
|
-
if [ -f "workers/data-worker/src/data-worker.ts" ]; then
|
|
205
|
-
echo -e "${YELLOW} Updating data-worker source placeholders...${NC}"
|
|
206
|
-
sed -i "s|'Access-Control-Allow-Origin': '[^']*'|'Access-Control-Allow-Origin': 'https://$escaped_pages_custom_domain'|g" workers/data-worker/src/data-worker.ts
|
|
207
|
-
echo -e "${GREEN} ✅ data-worker source placeholders updated${NC}"
|
|
208
|
-
fi
|
|
209
|
-
|
|
210
160
|
if [ -f "workers/image-worker/wrangler.jsonc" ]; then
|
|
211
161
|
echo -e "${YELLOW} Updating image-worker/wrangler.jsonc...${NC}"
|
|
212
162
|
sed -i "s/\"IMAGES_WORKER_NAME\"/\"$IMAGES_WORKER_NAME\"/g" workers/image-worker/wrangler.jsonc
|
|
@@ -215,12 +165,6 @@ update_wrangler_configs() {
|
|
|
215
165
|
echo -e "${GREEN} ✅ image-worker configuration updated${NC}"
|
|
216
166
|
fi
|
|
217
167
|
|
|
218
|
-
if [ -f "workers/image-worker/src/image-worker.ts" ]; then
|
|
219
|
-
echo -e "${YELLOW} Updating image-worker source placeholders...${NC}"
|
|
220
|
-
sed -i "s|'Access-Control-Allow-Origin': '[^']*'|'Access-Control-Allow-Origin': 'https://$escaped_pages_custom_domain'|g" workers/image-worker/src/image-worker.ts
|
|
221
|
-
echo -e "${GREEN} ✅ image-worker source placeholders updated${NC}"
|
|
222
|
-
fi
|
|
223
|
-
|
|
224
168
|
if [ -f "workers/pdf-worker/wrangler.jsonc" ]; then
|
|
225
169
|
echo -e "${YELLOW} Updating pdf-worker/wrangler.jsonc...${NC}"
|
|
226
170
|
sed -i "s/\"PDF_WORKER_NAME\"/\"$PDF_WORKER_NAME\"/g" workers/pdf-worker/wrangler.jsonc
|
|
@@ -228,12 +172,6 @@ update_wrangler_configs() {
|
|
|
228
172
|
echo -e "${GREEN} ✅ pdf-worker configuration updated${NC}"
|
|
229
173
|
fi
|
|
230
174
|
|
|
231
|
-
if [ -f "workers/pdf-worker/src/pdf-worker.ts" ]; then
|
|
232
|
-
echo -e "${YELLOW} Updating pdf-worker source placeholders...${NC}"
|
|
233
|
-
sed -i "s|'Access-Control-Allow-Origin': '[^']*'|'Access-Control-Allow-Origin': 'https://$escaped_pages_custom_domain'|g" workers/pdf-worker/src/pdf-worker.ts
|
|
234
|
-
echo -e "${GREEN} ✅ pdf-worker source placeholders updated${NC}"
|
|
235
|
-
fi
|
|
236
|
-
|
|
237
175
|
if [ -f "workers/user-worker/wrangler.jsonc" ]; then
|
|
238
176
|
echo -e "${YELLOW} Updating user-worker/wrangler.jsonc...${NC}"
|
|
239
177
|
sed -i "s/\"USER_WORKER_NAME\"/\"$USER_WORKER_NAME\"/g" workers/user-worker/wrangler.jsonc
|
|
@@ -244,15 +182,14 @@ update_wrangler_configs() {
|
|
|
244
182
|
echo -e "${GREEN} ✅ user-worker configuration updated${NC}"
|
|
245
183
|
fi
|
|
246
184
|
|
|
247
|
-
if [ -f "workers/user-worker/src/user-worker.ts" ]; then
|
|
248
|
-
echo -e "${YELLOW} Updating user-worker source placeholders...${NC}"
|
|
249
|
-
sed -i "s|'Access-Control-Allow-Origin': '[^']*'|'Access-Control-Allow-Origin': 'https://$escaped_pages_custom_domain'|g" workers/user-worker/src/user-worker.ts
|
|
250
|
-
echo -e "${GREEN} ✅ user-worker source placeholders updated${NC}"
|
|
251
|
-
fi
|
|
252
|
-
|
|
253
185
|
if [ -f "wrangler.toml" ]; then
|
|
254
186
|
echo -e "${YELLOW} Updating wrangler.toml...${NC}"
|
|
255
187
|
sed -i "s/\"PAGES_PROJECT_NAME\"/\"$PAGES_PROJECT_NAME\"/g" wrangler.toml
|
|
188
|
+
sed -i "s/USER_WORKER_NAME/$USER_WORKER_NAME/g" wrangler.toml
|
|
189
|
+
sed -i "s/DATA_WORKER_NAME/$DATA_WORKER_NAME/g" wrangler.toml
|
|
190
|
+
sed -i "s/AUDIT_WORKER_NAME/$AUDIT_WORKER_NAME/g" wrangler.toml
|
|
191
|
+
sed -i "s/IMAGES_WORKER_NAME/$IMAGES_WORKER_NAME/g" wrangler.toml
|
|
192
|
+
sed -i "s/PDF_WORKER_NAME/$PDF_WORKER_NAME/g" wrangler.toml
|
|
256
193
|
echo -e "${GREEN} ✅ main wrangler.toml configuration updated${NC}"
|
|
257
194
|
fi
|
|
258
195
|
|
|
@@ -75,11 +75,6 @@ required_vars=(
|
|
|
75
75
|
# Core Cloudflare Configuration
|
|
76
76
|
"ACCOUNT_ID"
|
|
77
77
|
|
|
78
|
-
# Shared Authentication & Storage
|
|
79
|
-
"USER_DB_AUTH"
|
|
80
|
-
"R2_KEY_SECRET"
|
|
81
|
-
"IMAGES_API_TOKEN"
|
|
82
|
-
|
|
83
78
|
# Firebase Auth Configuration
|
|
84
79
|
"API_KEY"
|
|
85
80
|
"AUTH_DOMAIN"
|
|
@@ -102,13 +97,6 @@ required_vars=(
|
|
|
102
97
|
"IMAGES_WORKER_NAME"
|
|
103
98
|
"PDF_WORKER_NAME"
|
|
104
99
|
|
|
105
|
-
# Worker Domains (required for proxy/env secrets and worker fallbacks)
|
|
106
|
-
"USER_WORKER_DOMAIN"
|
|
107
|
-
"DATA_WORKER_DOMAIN"
|
|
108
|
-
"AUDIT_WORKER_DOMAIN"
|
|
109
|
-
"IMAGES_WORKER_DOMAIN"
|
|
110
|
-
"PDF_WORKER_DOMAIN"
|
|
111
|
-
|
|
112
100
|
# Storage Configuration (required for config replacement)
|
|
113
101
|
"DATA_BUCKET_NAME"
|
|
114
102
|
"AUDIT_BUCKET_NAME"
|
|
@@ -116,7 +104,6 @@ required_vars=(
|
|
|
116
104
|
"KV_STORE_ID"
|
|
117
105
|
|
|
118
106
|
# Worker-Specific Secrets (required for deployment)
|
|
119
|
-
"PDF_WORKER_AUTH"
|
|
120
107
|
"IMAGE_SIGNED_URL_SECRET"
|
|
121
108
|
"BROWSER_API_TOKEN"
|
|
122
109
|
"MANIFEST_SIGNING_PRIVATE_KEY"
|
|
@@ -212,11 +199,6 @@ validate_env_value_formats() {
|
|
|
212
199
|
echo -e "${YELLOW}🔍 Validating environment value formats...${NC}"
|
|
213
200
|
|
|
214
201
|
validate_domain_var "PAGES_CUSTOM_DOMAIN"
|
|
215
|
-
validate_domain_var "USER_WORKER_DOMAIN"
|
|
216
|
-
validate_domain_var "DATA_WORKER_DOMAIN"
|
|
217
|
-
validate_domain_var "AUDIT_WORKER_DOMAIN"
|
|
218
|
-
validate_domain_var "IMAGES_WORKER_DOMAIN"
|
|
219
|
-
validate_domain_var "PDF_WORKER_DOMAIN"
|
|
220
202
|
|
|
221
203
|
if ! [[ "$KV_STORE_ID" =~ ^([0-9a-fA-F]{32}|[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$ ]]; then
|
|
222
204
|
echo -e "${RED}❌ Error: KV_STORE_ID must be a 32-character hex namespace ID (or UUID format)${NC}"
|
|
@@ -312,14 +294,8 @@ validate_generated_configs() {
|
|
|
312
294
|
assert_contains_literal "app/config/firebase.ts" "$APP_ID" "APP_ID missing in app/config/firebase.ts"
|
|
313
295
|
assert_contains_literal "app/config/firebase.ts" "$MEASUREMENT_ID" "MEASUREMENT_ID missing in app/config/firebase.ts"
|
|
314
296
|
|
|
315
|
-
assert_contains_literal "workers/audit-worker/src/audit-worker.ts" "https://$PAGES_CUSTOM_DOMAIN" "PAGES_CUSTOM_DOMAIN missing in audit-worker source"
|
|
316
|
-
assert_contains_literal "workers/data-worker/src/data-worker.ts" "https://$PAGES_CUSTOM_DOMAIN" "PAGES_CUSTOM_DOMAIN missing in data-worker source"
|
|
317
|
-
assert_contains_literal "workers/image-worker/src/image-worker.ts" "https://$PAGES_CUSTOM_DOMAIN" "PAGES_CUSTOM_DOMAIN missing in image-worker source"
|
|
318
|
-
assert_contains_literal "workers/pdf-worker/src/pdf-worker.ts" "https://$PAGES_CUSTOM_DOMAIN" "PAGES_CUSTOM_DOMAIN missing in pdf-worker source"
|
|
319
|
-
assert_contains_literal "workers/user-worker/src/user-worker.ts" "https://$PAGES_CUSTOM_DOMAIN" "PAGES_CUSTOM_DOMAIN missing in user-worker source"
|
|
320
|
-
|
|
321
297
|
local placeholder_pattern
|
|
322
|
-
placeholder_pattern="(\"(ACCOUNT_ID|PAGES_PROJECT_NAME|PAGES_CUSTOM_DOMAIN|USER_WORKER_NAME|DATA_WORKER_NAME|AUDIT_WORKER_NAME|IMAGES_WORKER_NAME|PDF_WORKER_NAME|
|
|
298
|
+
placeholder_pattern="(\"(ACCOUNT_ID|PAGES_PROJECT_NAME|PAGES_CUSTOM_DOMAIN|USER_WORKER_NAME|DATA_WORKER_NAME|AUDIT_WORKER_NAME|IMAGES_WORKER_NAME|PDF_WORKER_NAME|DATA_BUCKET_NAME|AUDIT_BUCKET_NAME|FILES_BUCKET_NAME|KV_STORE_ID|MANIFEST_SIGNING_KEY_ID|MANIFEST_SIGNING_PUBLIC_KEY|EXPORT_ENCRYPTION_KEY_ID|EXPORT_ENCRYPTION_PUBLIC_KEY|YOUR_FIREBASE_API_KEY|YOUR_FIREBASE_AUTH_DOMAIN|YOUR_FIREBASE_PROJECT_ID|YOUR_FIREBASE_STORAGE_BUCKET|YOUR_FIREBASE_MESSAGING_SENDER_ID|YOUR_FIREBASE_APP_ID|YOUR_FIREBASE_MEASUREMENT_ID)\")"
|
|
323
299
|
|
|
324
300
|
local files_to_scan=(
|
|
325
301
|
"wrangler.toml"
|
|
@@ -328,11 +304,6 @@ validate_generated_configs() {
|
|
|
328
304
|
"workers/image-worker/wrangler.jsonc"
|
|
329
305
|
"workers/pdf-worker/wrangler.jsonc"
|
|
330
306
|
"workers/user-worker/wrangler.jsonc"
|
|
331
|
-
"workers/audit-worker/src/audit-worker.ts"
|
|
332
|
-
"workers/data-worker/src/data-worker.ts"
|
|
333
|
-
"workers/image-worker/src/image-worker.ts"
|
|
334
|
-
"workers/pdf-worker/src/pdf-worker.ts"
|
|
335
|
-
"workers/user-worker/src/user-worker.ts"
|
|
336
307
|
"app/config/config.json"
|
|
337
308
|
"app/config/firebase.ts"
|
|
338
309
|
)
|
|
@@ -151,16 +151,7 @@ if [ -z "$PAGES_PROJECT_NAME" ] || is_placeholder "$PAGES_PROJECT_NAME"; then
|
|
|
151
151
|
fi
|
|
152
152
|
|
|
153
153
|
required_pages_secrets=(
|
|
154
|
-
"AUDIT_WORKER_DOMAIN"
|
|
155
|
-
"DATA_WORKER_DOMAIN"
|
|
156
|
-
"IMAGES_API_TOKEN"
|
|
157
|
-
"IMAGES_WORKER_DOMAIN"
|
|
158
|
-
"PDF_WORKER_AUTH"
|
|
159
|
-
"PDF_WORKER_DOMAIN"
|
|
160
154
|
"PROJECT_ID"
|
|
161
|
-
"R2_KEY_SECRET"
|
|
162
|
-
"USER_DB_AUTH"
|
|
163
|
-
"USER_WORKER_DOMAIN"
|
|
164
155
|
)
|
|
165
156
|
|
|
166
157
|
echo -e "${YELLOW}🔍 Validating required Pages secret values...${NC}"
|
|
@@ -97,8 +97,6 @@ load_required_admin_service_credentials
|
|
|
97
97
|
|
|
98
98
|
build_user_worker_secret_list() {
|
|
99
99
|
local secrets=(
|
|
100
|
-
"USER_DB_AUTH"
|
|
101
|
-
"R2_KEY_SECRET"
|
|
102
100
|
"PROJECT_ID"
|
|
103
101
|
"FIREBASE_SERVICE_ACCOUNT_EMAIL"
|
|
104
102
|
"FIREBASE_SERVICE_ACCOUNT_PRIVATE_KEY"
|
|
@@ -149,9 +147,7 @@ build_user_worker_secret_list() {
|
|
|
149
147
|
}
|
|
150
148
|
|
|
151
149
|
build_audit_worker_secret_list() {
|
|
152
|
-
local secrets=(
|
|
153
|
-
"R2_KEY_SECRET"
|
|
154
|
-
)
|
|
150
|
+
local secrets=()
|
|
155
151
|
|
|
156
152
|
if [ -n "${DATA_AT_REST_ENCRYPTION_ENABLED:-}" ]; then
|
|
157
153
|
secrets+=("DATA_AT_REST_ENCRYPTION_ENABLED")
|
|
@@ -230,7 +226,6 @@ set_worker_secrets() {
|
|
|
230
226
|
|
|
231
227
|
build_data_worker_secret_list() {
|
|
232
228
|
local secrets=(
|
|
233
|
-
"R2_KEY_SECRET"
|
|
234
229
|
"MANIFEST_SIGNING_PRIVATE_KEY"
|
|
235
230
|
"MANIFEST_SIGNING_KEY_ID"
|
|
236
231
|
"EXPORT_ENCRYPTION_PRIVATE_KEY"
|
|
@@ -274,7 +269,6 @@ build_data_worker_secret_list() {
|
|
|
274
269
|
|
|
275
270
|
build_images_worker_secret_list() {
|
|
276
271
|
local secrets=(
|
|
277
|
-
"IMAGES_API_TOKEN"
|
|
278
272
|
"DATA_AT_REST_ENCRYPTION_PUBLIC_KEY"
|
|
279
273
|
"DATA_AT_REST_ENCRYPTION_KEY_ID"
|
|
280
274
|
"IMAGE_SIGNED_URL_SECRET"
|
|
@@ -365,7 +359,7 @@ fi
|
|
|
365
359
|
|
|
366
360
|
# PDF Worker
|
|
367
361
|
if ! set_worker_secrets "PDF Worker" "workers/pdf-worker" \
|
|
368
|
-
"
|
|
362
|
+
"ACCOUNT_ID" "BROWSER_API_TOKEN"; then
|
|
369
363
|
echo -e "${YELLOW}⚠️ Skipping PDF Worker (not configured)${NC}"
|
|
370
364
|
fi
|
|
371
365
|
|
package/tsconfig.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "audit-worker",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "7.0.0",
|
|
4
4
|
"private": true,
|
|
5
5
|
"scripts": {
|
|
6
6
|
"deploy": "wrangler deploy",
|
|
@@ -8,6 +8,6 @@
|
|
|
8
8
|
"start": "wrangler dev"
|
|
9
9
|
},
|
|
10
10
|
"devDependencies": {
|
|
11
|
-
"wrangler": "^4.84.
|
|
11
|
+
"wrangler": "^4.84.1"
|
|
12
12
|
}
|
|
13
13
|
}
|
|
@@ -1,29 +1,13 @@
|
|
|
1
|
-
import { hasValidHeader } from './config';
|
|
2
1
|
import { handleAuditRequest } from './handlers/audit-routes';
|
|
3
2
|
import type { CreateResponse, Env } from './types';
|
|
4
3
|
|
|
5
|
-
const corsHeaders: Record<string, string> = {
|
|
6
|
-
'Access-Control-Allow-Origin': 'PAGES_CUSTOM_DOMAIN',
|
|
7
|
-
'Access-Control-Allow-Methods': 'GET, POST, OPTIONS',
|
|
8
|
-
'Access-Control-Allow-Headers': 'Content-Type, X-Custom-Auth-Key',
|
|
9
|
-
'Content-Type': 'application/json'
|
|
10
|
-
};
|
|
11
|
-
|
|
12
4
|
const createWorkerResponse: CreateResponse = (data, status: number = 200): Response => new Response(
|
|
13
5
|
JSON.stringify(data),
|
|
14
|
-
{ status, headers:
|
|
6
|
+
{ status, headers: { 'Content-Type': 'application/json' } }
|
|
15
7
|
);
|
|
16
8
|
|
|
17
9
|
export default {
|
|
18
10
|
async fetch(request: Request, env: Env): Promise<Response> {
|
|
19
|
-
if (request.method === 'OPTIONS') {
|
|
20
|
-
return new Response(null, { headers: corsHeaders });
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
if (!hasValidHeader(request, env)) {
|
|
24
|
-
return createWorkerResponse({ error: 'Forbidden' }, 403);
|
|
25
|
-
}
|
|
26
|
-
|
|
27
11
|
try {
|
|
28
12
|
const url = new URL(request.url);
|
|
29
13
|
const pathname = url.pathname;
|
|
@@ -1,7 +1,2 @@
|
|
|
1
|
-
import type { Env } from './types';
|
|
2
|
-
|
|
3
1
|
export const DATA_AT_REST_ENCRYPTION_ALGORITHM = 'RSA-OAEP-AES-256-GCM';
|
|
4
|
-
export const DATA_AT_REST_ENCRYPTION_VERSION = '1.0';
|
|
5
|
-
|
|
6
|
-
export const hasValidHeader = (request: Request, env: Env): boolean =>
|
|
7
|
-
request.headers.get('X-Custom-Auth-Key') === env.R2_KEY_SECRET;
|
|
2
|
+
export const DATA_AT_REST_ENCRYPTION_VERSION = '1.0';
|
|
@@ -1,13 +1,9 @@
|
|
|
1
1
|
{
|
|
2
|
-
// Required secrets: R2_KEY_SECRET
|
|
3
|
-
// Optional data-at-rest secrets/vars:
|
|
4
|
-
// - DATA_AT_REST_ENCRYPTION_ENABLED=true
|
|
5
|
-
// - DATA_AT_REST_ENCRYPTION_PRIVATE_KEY (required for decrypting encrypted records)
|
|
6
|
-
// - DATA_AT_REST_ENCRYPTION_PUBLIC_KEY and DATA_AT_REST_ENCRYPTION_KEY_ID (required when encrypt-on-write is enabled)
|
|
7
2
|
"name": "AUDIT_WORKER_NAME",
|
|
8
3
|
"account_id": "ACCOUNT_ID",
|
|
9
4
|
"main": "src/audit-worker.ts",
|
|
10
|
-
"
|
|
5
|
+
"workers_dev": false,
|
|
6
|
+
"compatibility_date": "2026-04-21",
|
|
11
7
|
"compatibility_flags": [
|
|
12
8
|
"nodejs_compat"
|
|
13
9
|
],
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "data-worker",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "7.0.0",
|
|
4
4
|
"private": true,
|
|
5
5
|
"scripts": {
|
|
6
6
|
"deploy": "wrangler deploy",
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
"start": "wrangler dev"
|
|
9
9
|
},
|
|
10
10
|
"devDependencies": {
|
|
11
|
-
"
|
|
11
|
+
"@cloudflare/vitest-pool-workers": "^0.14.9",
|
|
12
|
+
"wrangler": "^4.84.1"
|
|
12
13
|
}
|
|
13
14
|
}
|
|
@@ -1,11 +1,6 @@
|
|
|
1
|
-
import type { Env } from './types';
|
|
2
|
-
|
|
3
1
|
export const SIGN_MANIFEST_PATH = '/api/forensic/sign-manifest';
|
|
4
2
|
export const SIGN_CONFIRMATION_PATH = '/api/forensic/sign-confirmation';
|
|
5
3
|
export const SIGN_AUDIT_EXPORT_PATH = '/api/forensic/sign-audit-export';
|
|
6
4
|
export const DECRYPT_EXPORT_PATH = '/api/forensic/decrypt-export';
|
|
7
5
|
export const DATA_AT_REST_ENCRYPTION_ALGORITHM = 'RSA-OAEP-AES-256-GCM';
|
|
8
|
-
export const DATA_AT_REST_ENCRYPTION_VERSION = '1.0';
|
|
9
|
-
|
|
10
|
-
export const hasValidHeader = (request: Request, env: Env): boolean =>
|
|
11
|
-
request.headers.get('X-Custom-Auth-Key') === env.R2_KEY_SECRET;
|
|
6
|
+
export const DATA_AT_REST_ENCRYPTION_VERSION = '1.0';
|
|
@@ -2,8 +2,7 @@ import {
|
|
|
2
2
|
DECRYPT_EXPORT_PATH,
|
|
3
3
|
SIGN_AUDIT_EXPORT_PATH,
|
|
4
4
|
SIGN_CONFIRMATION_PATH,
|
|
5
|
-
SIGN_MANIFEST_PATH
|
|
6
|
-
hasValidHeader
|
|
5
|
+
SIGN_MANIFEST_PATH
|
|
7
6
|
} from './config';
|
|
8
7
|
import { handleDecryptExport } from './handlers/decrypt-export';
|
|
9
8
|
import {
|
|
@@ -14,28 +13,13 @@ import {
|
|
|
14
13
|
import { handleStorageRequest } from './handlers/storage-routes';
|
|
15
14
|
import type { CreateResponse, Env } from './types';
|
|
16
15
|
|
|
17
|
-
const corsHeaders: Record<string, string> = {
|
|
18
|
-
'Access-Control-Allow-Origin': 'PAGES_CUSTOM_DOMAIN',
|
|
19
|
-
'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',
|
|
20
|
-
'Access-Control-Allow-Headers': 'Content-Type, X-Custom-Auth-Key',
|
|
21
|
-
'Content-Type': 'application/json'
|
|
22
|
-
};
|
|
23
|
-
|
|
24
16
|
const createWorkerResponse: CreateResponse = (data, status: number = 200): Response => new Response(
|
|
25
17
|
JSON.stringify(data),
|
|
26
|
-
{ status, headers:
|
|
18
|
+
{ status, headers: { 'Content-Type': 'application/json' } }
|
|
27
19
|
);
|
|
28
20
|
|
|
29
21
|
export default {
|
|
30
22
|
async fetch(request: Request, env: Env): Promise<Response> {
|
|
31
|
-
if (request.method === 'OPTIONS') {
|
|
32
|
-
return new Response(null, { headers: corsHeaders });
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
if (!hasValidHeader(request, env)) {
|
|
36
|
-
return createWorkerResponse({ error: 'Forbidden' }, 403);
|
|
37
|
-
}
|
|
38
|
-
|
|
39
23
|
try {
|
|
40
24
|
const url = new URL(request.url);
|
|
41
25
|
const pathname = url.pathname;
|
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
{
|
|
2
|
-
// Required secrets: R2_KEY_SECRET, MANIFEST_SIGNING_PRIVATE_KEY, MANIFEST_SIGNING_KEY_ID, EXPORT_ENCRYPTION_PRIVATE_KEY, EXPORT_ENCRYPTION_KEY_ID
|
|
3
|
-
// - DATA_AT_REST_ENCRYPTION_PRIVATE_KEY (required for decrypting encrypted records)
|
|
4
|
-
// - DATA_AT_REST_ENCRYPTION_PUBLIC_KEY and DATA_AT_REST_ENCRYPTION_KEY_ID (required when encrypt-on-write is enabled)
|
|
5
2
|
"name": "DATA_WORKER_NAME",
|
|
6
3
|
"account_id": "ACCOUNT_ID",
|
|
7
4
|
"main": "src/data-worker.ts",
|
|
8
|
-
"
|
|
5
|
+
"workers_dev": false,
|
|
6
|
+
"compatibility_date": "2026-04-21",
|
|
9
7
|
"compatibility_flags": [
|
|
10
8
|
"nodejs_compat"
|
|
11
9
|
],
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "image-worker",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "7.0.0",
|
|
4
4
|
"private": true,
|
|
5
5
|
"scripts": {
|
|
6
6
|
"deploy": "wrangler deploy",
|
|
@@ -8,6 +8,6 @@
|
|
|
8
8
|
"start": "wrangler dev"
|
|
9
9
|
},
|
|
10
10
|
"devDependencies": {
|
|
11
|
-
"wrangler": "^4.84.
|
|
11
|
+
"wrangler": "^4.84.1"
|
|
12
12
|
}
|
|
13
13
|
}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { hasValidToken } from '../auth';
|
|
2
1
|
import type { CreateImageWorkerResponse, Env } from '../types';
|
|
3
2
|
import { parseFileId } from '../utils/path-utils';
|
|
4
3
|
|
|
@@ -7,10 +6,6 @@ export async function handleImageDelete(
|
|
|
7
6
|
env: Env,
|
|
8
7
|
createJsonResponse: CreateImageWorkerResponse
|
|
9
8
|
): Promise<Response> {
|
|
10
|
-
if (!hasValidToken(request, env)) {
|
|
11
|
-
return createJsonResponse({ error: 'Unauthorized' }, 403);
|
|
12
|
-
}
|
|
13
|
-
|
|
14
9
|
const fileId = parseFileId(new URL(request.url).pathname);
|
|
15
10
|
if (!fileId) {
|
|
16
11
|
return createJsonResponse({ error: 'Image ID is required' }, 400);
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { hasValidToken } from '../auth';
|
|
2
1
|
import {
|
|
3
2
|
normalizeSignedUrlTtlSeconds,
|
|
4
3
|
parseSignedUrlBaseUrl,
|
|
@@ -21,10 +20,6 @@ export async function handleSignedUrlMinting(
|
|
|
21
20
|
fileId: string,
|
|
22
21
|
createJsonResponse: CreateImageWorkerResponse
|
|
23
22
|
): Promise<Response> {
|
|
24
|
-
if (!hasValidToken(request, env)) {
|
|
25
|
-
return createJsonResponse({ error: 'Unauthorized' }, 403);
|
|
26
|
-
}
|
|
27
|
-
|
|
28
23
|
requireSignedUrlConfig(env);
|
|
29
24
|
|
|
30
25
|
const existing = await env.STRIAE_FILES.head(fileId);
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { hasValidToken } from '../auth';
|
|
2
1
|
import {
|
|
3
2
|
decryptBinaryWithRegistry,
|
|
4
3
|
requireEncryptionRetrievalConfig
|
|
@@ -12,8 +11,7 @@ export async function handleImageServing(
|
|
|
12
11
|
request: Request,
|
|
13
12
|
env: Env,
|
|
14
13
|
fileId: string,
|
|
15
|
-
createJsonResponse: CreateImageWorkerResponse
|
|
16
|
-
corsHeaders: Record<string, string>
|
|
14
|
+
createJsonResponse: CreateImageWorkerResponse
|
|
17
15
|
): Promise<Response> {
|
|
18
16
|
const requestUrl = new URL(request.url);
|
|
19
17
|
const hasSignedToken = requestUrl.searchParams.has('st');
|
|
@@ -30,7 +28,7 @@ export async function handleImageServing(
|
|
|
30
28
|
if (!tokenValid) {
|
|
31
29
|
return createJsonResponse({ error: 'Invalid or expired signed URL token' }, 403);
|
|
32
30
|
}
|
|
33
|
-
} else
|
|
31
|
+
} else {
|
|
34
32
|
return createJsonResponse({ error: 'Unauthorized' }, 403);
|
|
35
33
|
}
|
|
36
34
|
|
|
@@ -56,7 +54,6 @@ export async function handleImageServing(
|
|
|
56
54
|
return new Response(plaintext, {
|
|
57
55
|
status: 200,
|
|
58
56
|
headers: {
|
|
59
|
-
...corsHeaders,
|
|
60
57
|
'Cache-Control': 'no-store',
|
|
61
58
|
'Content-Type': contentType,
|
|
62
59
|
'Content-Disposition': contentDisposition
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { hasValidToken } from '../auth';
|
|
2
1
|
import { encryptBinaryForStorage } from '../encryption-utils';
|
|
3
2
|
import { requireEncryptionUploadConfig } from '../security/key-registry';
|
|
4
3
|
import type { CreateImageWorkerResponse, Env } from '../types';
|
|
@@ -9,10 +8,6 @@ export async function handleImageUpload(
|
|
|
9
8
|
env: Env,
|
|
10
9
|
createJsonResponse: CreateImageWorkerResponse
|
|
11
10
|
): Promise<Response> {
|
|
12
|
-
if (!hasValidToken(request, env)) {
|
|
13
|
-
return createJsonResponse({ error: 'Unauthorized' }, 403);
|
|
14
|
-
}
|
|
15
|
-
|
|
16
11
|
requireEncryptionUploadConfig(env);
|
|
17
12
|
|
|
18
13
|
const formData = await request.formData();
|
|
@@ -1,31 +1,18 @@
|
|
|
1
1
|
import { routeImageWorkerRequest } from './router';
|
|
2
2
|
import type { APIResponse, Env } from './types';
|
|
3
3
|
|
|
4
|
-
const corsHeaders: Record<string, string> = {
|
|
5
|
-
'Access-Control-Allow-Origin': 'PAGES_CUSTOM_DOMAIN',
|
|
6
|
-
'Access-Control-Allow-Methods': 'GET, POST, DELETE, OPTIONS',
|
|
7
|
-
'Access-Control-Allow-Headers': 'Content-Type, Authorization, X-Custom-Auth-Key'
|
|
8
|
-
};
|
|
9
|
-
|
|
10
4
|
const createJsonResponse = (data: APIResponse, status: number = 200): Response => new Response(
|
|
11
5
|
JSON.stringify(data),
|
|
12
6
|
{
|
|
13
7
|
status,
|
|
14
|
-
headers: {
|
|
15
|
-
...corsHeaders,
|
|
16
|
-
'Content-Type': 'application/json'
|
|
17
|
-
}
|
|
8
|
+
headers: { 'Content-Type': 'application/json' }
|
|
18
9
|
}
|
|
19
10
|
);
|
|
20
11
|
|
|
21
12
|
export default {
|
|
22
13
|
async fetch(request: Request, env: Env): Promise<Response> {
|
|
23
|
-
if (request.method === 'OPTIONS') {
|
|
24
|
-
return new Response(null, { headers: corsHeaders });
|
|
25
|
-
}
|
|
26
|
-
|
|
27
14
|
try {
|
|
28
|
-
return await routeImageWorkerRequest(request, env, createJsonResponse
|
|
15
|
+
return await routeImageWorkerRequest(request, env, createJsonResponse);
|
|
29
16
|
} catch (error) {
|
|
30
17
|
const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred';
|
|
31
18
|
return createJsonResponse({ error: errorMessage }, 500);
|
|
@@ -8,8 +8,7 @@ import { parsePathSegments } from './utils/path-utils';
|
|
|
8
8
|
export async function routeImageWorkerRequest(
|
|
9
9
|
request: Request,
|
|
10
10
|
env: Env,
|
|
11
|
-
createJsonResponse: CreateImageWorkerResponse
|
|
12
|
-
corsHeaders: Record<string, string>
|
|
11
|
+
createJsonResponse: CreateImageWorkerResponse
|
|
13
12
|
): Promise<Response> {
|
|
14
13
|
const requestUrl = new URL(request.url);
|
|
15
14
|
const pathSegments = parsePathSegments(requestUrl.pathname);
|
|
@@ -36,7 +35,7 @@ export async function routeImageWorkerRequest(
|
|
|
36
35
|
return createJsonResponse({ error: 'Image ID is required' }, 400);
|
|
37
36
|
}
|
|
38
37
|
|
|
39
|
-
return handleImageServing(request, env, fileId, createJsonResponse
|
|
38
|
+
return handleImageServing(request, env, fileId, createJsonResponse);
|
|
40
39
|
}
|
|
41
40
|
|
|
42
41
|
case 'DELETE': {
|
|
@@ -51,7 +51,7 @@ export function normalizeSignedUrlTtlSeconds(requestedTtlSeconds: unknown, env:
|
|
|
51
51
|
}
|
|
52
52
|
|
|
53
53
|
export function requireSignedUrlConfig(env: Env): void {
|
|
54
|
-
const resolvedSecret = (env.IMAGE_SIGNED_URL_SECRET ||
|
|
54
|
+
const resolvedSecret = (env.IMAGE_SIGNED_URL_SECRET || '').trim();
|
|
55
55
|
if (resolvedSecret.length === 0) {
|
|
56
56
|
throw new Error('Signed URL configuration is missing');
|
|
57
57
|
}
|
|
@@ -77,7 +77,7 @@ export function parseSignedUrlBaseUrl(raw: string): string {
|
|
|
77
77
|
}
|
|
78
78
|
|
|
79
79
|
async function getSignedUrlHmacKey(env: Env): Promise<CryptoKey> {
|
|
80
|
-
const resolvedSecret = (env.IMAGE_SIGNED_URL_SECRET ||
|
|
80
|
+
const resolvedSecret = (env.IMAGE_SIGNED_URL_SECRET || '').trim();
|
|
81
81
|
const keyBytes = new TextEncoder().encode(resolvedSecret);
|
|
82
82
|
|
|
83
83
|
return crypto.subtle.importKey(
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pdf-worker",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "7.0.0",
|
|
4
4
|
"private": true,
|
|
5
5
|
"scripts": {
|
|
6
6
|
"generate:assets": "node scripts/generate-assets.js",
|
|
@@ -9,6 +9,6 @@
|
|
|
9
9
|
"start": "wrangler dev"
|
|
10
10
|
},
|
|
11
11
|
"devDependencies": {
|
|
12
|
-
"wrangler": "^4.84.
|
|
12
|
+
"wrangler": "^4.84.1"
|
|
13
13
|
}
|
|
14
14
|
}
|