@striae-org/striae 5.1.1 → 5.2.1

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 (30) hide show
  1. package/.env.example +41 -11
  2. package/app/utils/data/permissions.ts +4 -2
  3. package/package.json +5 -5
  4. package/scripts/deploy-config/modules/env-utils.sh +322 -0
  5. package/scripts/deploy-config/modules/keys.sh +404 -0
  6. package/scripts/deploy-config/modules/prompt.sh +372 -0
  7. package/scripts/deploy-config/modules/scaffolding.sh +344 -0
  8. package/scripts/deploy-config/modules/validation.sh +365 -0
  9. package/scripts/deploy-config.sh +47 -1572
  10. package/scripts/deploy-worker-secrets.sh +100 -5
  11. package/worker-configuration.d.ts +6 -3
  12. package/workers/audit-worker/package.json +1 -1
  13. package/workers/audit-worker/src/audit-worker.example.ts +188 -6
  14. package/workers/audit-worker/wrangler.jsonc.example +1 -1
  15. package/workers/data-worker/package.json +1 -1
  16. package/workers/data-worker/src/data-worker.example.ts +344 -32
  17. package/workers/data-worker/wrangler.jsonc.example +1 -1
  18. package/workers/image-worker/package.json +1 -1
  19. package/workers/image-worker/src/image-worker.example.ts +190 -5
  20. package/workers/image-worker/wrangler.jsonc.example +1 -1
  21. package/workers/keys-worker/package.json +1 -1
  22. package/workers/keys-worker/wrangler.jsonc.example +1 -1
  23. package/workers/pdf-worker/package.json +1 -1
  24. package/workers/pdf-worker/src/pdf-worker.example.ts +0 -1
  25. package/workers/pdf-worker/wrangler.jsonc.example +1 -5
  26. package/workers/user-worker/package.json +17 -17
  27. package/workers/user-worker/src/encryption-utils.ts +244 -0
  28. package/workers/user-worker/src/user-worker.example.ts +333 -31
  29. package/workers/user-worker/wrangler.jsonc.example +1 -1
  30. package/wrangler.toml.example +1 -1
@@ -28,6 +28,7 @@ trap 'echo -e "\n${RED}❌ deploy-config.sh failed near line ${LINENO}${NC}"' ER
28
28
  update_env=false
29
29
  show_help=false
30
30
  validate_only=false
31
+ force_rotate_keys=false
31
32
  for arg in "$@"; do
32
33
  case "$arg" in
33
34
  -h|--help)
@@ -39,6 +40,9 @@ for arg in "$@"; do
39
40
  --validate-only)
40
41
  validate_only=true
41
42
  ;;
43
+ --force-rotate-keys)
44
+ force_rotate_keys=true
45
+ ;;
42
46
  *)
43
47
  echo -e "${RED}❌ Unknown option: $arg${NC}"
44
48
  echo "Use --help to see supported options."
@@ -52,18 +56,28 @@ if [ "$update_env" = "true" ] && [ "$validate_only" = "true" ]; then
52
56
  exit 1
53
57
  fi
54
58
 
59
+ if [ "$force_rotate_keys" = "true" ] && [ "$validate_only" = "true" ]; then
60
+ echo -e "${RED}❌ --force-rotate-keys and --validate-only cannot be used together${NC}"
61
+ exit 1
62
+ fi
63
+
55
64
  if [ "$show_help" = "true" ]; then
56
- echo "Usage: bash ./scripts/deploy-config.sh [--update-env] [--validate-only]"
65
+ echo "Usage: bash ./scripts/deploy-config.sh [--update-env] [--validate-only] [--force-rotate-keys]"
57
66
  echo ""
58
67
  echo "Options:"
59
68
  echo " --update-env Reset .env from .env.example and overwrite configs"
60
69
  echo " --validate-only Validate current .env and generated config files without modifying them"
70
+ echo " --force-rotate-keys Force regeneration of all encryption/signing key pairs without prompts"
61
71
  echo " -h, --help Show this help message"
62
72
  exit 0
63
73
  fi
64
74
 
65
75
  if [ "$update_env" = "true" ]; then
66
- echo -e "${YELLOW}⚠️ Update-env mode: overwriting configs and regenerating .env values${NC}"
76
+ echo -e "${YELLOW}⚠️ Update-env mode: overwriting configs and resetting .env values from template${NC}"
77
+ fi
78
+
79
+ if [ "$force_rotate_keys" = "true" ]; then
80
+ echo -e "${YELLOW}⚠️ Force-rotate-keys mode: all encryption/signing key pairs will be regenerated without prompts${NC}"
67
81
  fi
68
82
 
69
83
  require_command() {
@@ -146,863 +160,45 @@ fi
146
160
  echo -e "${YELLOW}📖 Loading environment variables from .env...${NC}"
147
161
  source .env
148
162
 
149
- escape_for_sed_pattern() {
150
- printf '%s' "$1" | sed -e 's/[][\\.^$*+?{}|()]/\\&/g'
151
- }
152
-
153
- dedupe_env_var_entries() {
154
- local var_name=$1
155
- local expected_count=1
156
- local escaped_var_name
157
-
158
- escaped_var_name=$(escape_for_sed_pattern "$var_name")
159
-
160
- if [ -f ".env.example" ]; then
161
- expected_count=$(grep -c "^$escaped_var_name=" .env.example || true)
162
-
163
- if [ "$expected_count" -lt 1 ]; then
164
- expected_count=1
165
- fi
166
- fi
167
-
168
- awk -v key="$var_name" -v keep="$expected_count" '
169
- BEGIN { seen = 0 }
170
- {
171
- if (index($0, key "=") == 1) {
172
- seen++
173
-
174
- if (seen > keep) {
175
- next
176
- }
177
- }
178
- print
179
- }
180
- ' .env > .env.tmp && mv .env.tmp .env
181
- }
182
-
183
- normalize_domain_value() {
184
- local domain="$1"
185
-
186
- domain=$(printf '%s' "$domain" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')
187
- domain="${domain#http://}"
188
- domain="${domain#https://}"
189
- domain="${domain%/}"
190
-
191
- printf '%s' "$domain"
192
- }
193
-
194
- normalize_worker_label_value() {
195
- local label="$1"
196
-
197
- label=$(normalize_domain_value "$label")
198
- label="${label#.}"
199
- label="${label%.}"
200
- label=$(printf '%s' "$label" | tr '[:upper:]' '[:lower:]')
201
-
202
- printf '%s' "$label"
203
- }
204
-
205
- normalize_worker_subdomain_value() {
206
- local subdomain="$1"
207
-
208
- subdomain=$(normalize_domain_value "$subdomain")
209
- subdomain="${subdomain#.}"
210
- subdomain="${subdomain%.}"
211
- subdomain=$(printf '%s' "$subdomain" | tr '[:upper:]' '[:lower:]')
212
-
213
- printf '%s' "$subdomain"
214
- }
215
-
216
- is_valid_worker_label() {
217
- local label="$1"
218
-
219
- [[ "$label" =~ ^[a-z0-9-]+$ ]]
220
- }
221
-
222
- is_valid_worker_subdomain() {
223
- local subdomain="$1"
224
-
225
- [[ "$subdomain" =~ ^[a-z0-9]([a-z0-9-]*[a-z0-9])?(\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)+$ ]]
226
- }
227
-
228
- strip_carriage_returns() {
229
- printf '%s' "$1" | tr -d '\r'
230
- }
231
-
232
- read_env_var_from_file() {
233
- local env_file=$1
234
- local var_name=$2
235
-
236
- if [ ! -f "$env_file" ]; then
237
- return 0
238
- fi
239
-
240
- awk -v key="$var_name" '
241
- index($0, key "=") == 1 {
242
- value = substr($0, length(key) + 2)
243
- }
244
- END {
245
- if (value != "") {
246
- gsub(/\r/, "", value)
247
- gsub(/^"/, "", value)
248
- gsub(/"$/, "", value)
249
- print value
250
- }
251
- }
252
- ' "$env_file"
253
- }
254
-
255
- resolve_existing_domain_value() {
256
- local var_name=$1
257
- local current_value=$2
258
- local preserved_value=""
259
-
260
- current_value=$(normalize_domain_value "$current_value")
261
-
262
- if [ "$current_value" = "$var_name" ]; then
263
- current_value=""
264
- fi
265
-
266
- if [ -n "$current_value" ] && ! is_placeholder "$current_value"; then
267
- printf '%s' "$current_value"
268
- return 0
269
- fi
270
-
271
- if [ -n "$preserved_domain_env_file" ] && [ -f "$preserved_domain_env_file" ]; then
272
- preserved_value=$(read_env_var_from_file "$preserved_domain_env_file" "$var_name")
273
- preserved_value=$(normalize_domain_value "$preserved_value")
274
-
275
- if [ "$preserved_value" = "$var_name" ]; then
276
- preserved_value=""
277
- fi
278
-
279
- if [ -n "$preserved_value" ] && ! is_placeholder "$preserved_value"; then
280
- printf '%s' "$preserved_value"
281
- return 0
282
- fi
283
- fi
284
-
285
- printf '%s' "$current_value"
286
- }
287
-
288
- generate_worker_subdomain_label() {
289
- node -e "const { randomInt } = require('crypto'); const alphabet = 'abcdefghijklmnopqrstuvwxyz0123456789'; let value = ''; for (let index = 0; index < 10; index += 1) { value += alphabet[randomInt(alphabet.length)]; } process.stdout.write(value);" 2>/dev/null
290
- }
291
-
292
- compose_worker_domain() {
293
- local worker_name=$1
294
- local worker_subdomain=$2
295
-
296
- worker_name=$(normalize_worker_label_value "$worker_name")
297
- worker_subdomain=$(normalize_worker_subdomain_value "$worker_subdomain")
298
-
299
- if [ -z "$worker_name" ] || [ -z "$worker_subdomain" ]; then
300
- return 1
301
- fi
302
-
303
- if ! is_valid_worker_label "$worker_name" || ! is_valid_worker_subdomain "$worker_subdomain"; then
304
- return 1
305
- fi
306
-
307
- printf '%s.%s' "$worker_name" "$worker_subdomain"
308
- }
309
-
310
- infer_worker_subdomain_from_domain() {
311
- local worker_name=$1
312
- local worker_domain=$2
313
- local worker_subdomain=""
314
-
315
- worker_name=$(normalize_worker_label_value "$worker_name")
316
- worker_domain=$(normalize_domain_value "$worker_domain")
317
- worker_domain=$(printf '%s' "$worker_domain" | tr '[:upper:]' '[:lower:]')
318
-
319
- if [ -z "$worker_name" ] || [ -z "$worker_domain" ] || is_placeholder "$worker_name" || is_placeholder "$worker_domain"; then
320
- printf '%s' ""
321
- return 0
322
- fi
323
-
324
- case "$worker_domain" in
325
- "$worker_name".*)
326
- worker_subdomain="${worker_domain#${worker_name}.}"
327
- worker_subdomain=$(normalize_worker_subdomain_value "$worker_subdomain")
328
-
329
- if is_valid_worker_subdomain "$worker_subdomain"; then
330
- printf '%s' "$worker_subdomain"
331
- return 0
332
- fi
333
- ;;
334
- esac
335
-
336
- printf '%s' ""
337
- }
338
-
339
- write_env_var() {
340
- local var_name=$1
341
- local var_value=$2
342
- local env_file_value="$var_value"
343
-
344
- var_value=$(strip_carriage_returns "$var_value")
345
- env_file_value="$var_value"
346
-
347
- if [ "$var_name" = "FIREBASE_SERVICE_ACCOUNT_PRIVATE_KEY" ] || [ "$var_name" = "MANIFEST_SIGNING_PRIVATE_KEY" ] || [ "$var_name" = "MANIFEST_SIGNING_PUBLIC_KEY" ] || [ "$var_name" = "EXPORT_ENCRYPTION_PRIVATE_KEY" ] || [ "$var_name" = "EXPORT_ENCRYPTION_PUBLIC_KEY" ] || [ "$var_name" = "DATA_AT_REST_ENCRYPTION_PRIVATE_KEY" ] || [ "$var_name" = "DATA_AT_REST_ENCRYPTION_PUBLIC_KEY" ]; then
348
- # Store as a quoted string so sourced .env preserves escaped newline markers (\n)
349
- env_file_value=${env_file_value//\"/\\\"}
350
- env_file_value="\"$env_file_value\""
351
- fi
352
-
353
- local escaped_var_name
354
- local replacement_line
355
- escaped_var_name=$(escape_for_sed_pattern "$var_name")
356
- replacement_line=$(escape_for_sed_replacement "$var_name=$env_file_value")
357
-
358
- if grep -q "^$escaped_var_name=" .env; then
359
- # Replace all occurrences so intentional duplicates in .env.example stay in sync.
360
- sed -i "s|^$escaped_var_name=.*|$replacement_line|g" .env
361
- dedupe_env_var_entries "$var_name"
362
- else
363
- echo "$var_name=$env_file_value" >> .env
364
- fi
365
- }
366
-
367
- escape_for_sed_replacement() {
368
- printf '%s' "$1" | sed -e 's/[&|\\]/\\&/g'
369
- }
370
-
371
- is_admin_service_placeholder() {
372
- local value="$1"
373
- local normalized=$(echo "$value" | tr '[:upper:]' '[:lower:]')
374
-
375
- [[ -z "$normalized" || "$normalized" == your-* || "$normalized" == *"your_private_key"* ]]
376
- }
377
-
378
- load_admin_service_credentials() {
379
- local admin_service_path="app/config/admin-service.json"
380
-
381
- if [ ! -f "$admin_service_path" ]; then
382
- echo -e "${RED}❌ Error: Required Firebase admin service file not found: $admin_service_path${NC}"
383
- echo -e "${YELLOW} Create app/config/admin-service.json with service account credentials.${NC}"
384
- exit 1
385
- fi
386
-
387
- local service_project_id
388
- local service_client_email
389
- local service_private_key
390
-
391
- if ! service_project_id=$(node -e "const fs=require('fs'); const data=JSON.parse(fs.readFileSync(process.argv[1], 'utf8')); process.stdout.write(data.project_id || '');" "$admin_service_path"); then
392
- echo -e "${RED}❌ Error: Could not parse project_id from $admin_service_path${NC}"
393
- exit 1
394
- fi
395
-
396
- if ! service_client_email=$(node -e "const fs=require('fs'); const data=JSON.parse(fs.readFileSync(process.argv[1], 'utf8')); process.stdout.write(data.client_email || '');" "$admin_service_path"); then
397
- echo -e "${RED}❌ Error: Could not parse client_email from $admin_service_path${NC}"
398
- exit 1
399
- fi
400
-
401
- if ! service_private_key=$(node -e "const fs=require('fs'); const data=JSON.parse(fs.readFileSync(process.argv[1], 'utf8')); process.stdout.write(data.private_key || '');" "$admin_service_path"); then
402
- echo -e "${RED}❌ Error: Could not parse private_key from $admin_service_path${NC}"
403
- exit 1
404
- fi
405
-
406
- local normalized_private_key="${service_private_key//$'\r'/}"
407
- normalized_private_key="${normalized_private_key//$'\n'/\\n}"
408
-
409
- if is_admin_service_placeholder "$service_project_id"; then
410
- echo -e "${RED}❌ Error: project_id in $admin_service_path is missing or placeholder${NC}"
411
- exit 1
412
- fi
413
-
414
- if is_admin_service_placeholder "$service_client_email" || [[ "$service_client_email" != *".gserviceaccount.com"* ]]; then
415
- echo -e "${RED}❌ Error: client_email in $admin_service_path is invalid${NC}"
416
- exit 1
417
- fi
418
-
419
- if is_admin_service_placeholder "$normalized_private_key" || [[ "$normalized_private_key" != *"-----BEGIN PRIVATE KEY-----"* ]] || [[ "$normalized_private_key" != *"-----END PRIVATE KEY-----"* ]]; then
420
- echo -e "${RED}❌ Error: private_key in $admin_service_path is invalid${NC}"
421
- exit 1
422
- fi
423
-
424
- PROJECT_ID="$service_project_id"
425
- export PROJECT_ID
426
- write_env_var "PROJECT_ID" "$PROJECT_ID"
427
-
428
- FIREBASE_SERVICE_ACCOUNT_EMAIL="$service_client_email"
429
- export FIREBASE_SERVICE_ACCOUNT_EMAIL
430
- write_env_var "FIREBASE_SERVICE_ACCOUNT_EMAIL" "$FIREBASE_SERVICE_ACCOUNT_EMAIL"
431
-
432
- FIREBASE_SERVICE_ACCOUNT_PRIVATE_KEY="$normalized_private_key"
433
- export FIREBASE_SERVICE_ACCOUNT_PRIVATE_KEY
434
- write_env_var "FIREBASE_SERVICE_ACCOUNT_PRIVATE_KEY" "$FIREBASE_SERVICE_ACCOUNT_PRIVATE_KEY"
435
-
436
- echo -e "${GREEN}✅ Imported Firebase service account credentials from $admin_service_path${NC}"
437
- }
438
-
439
- generate_manifest_signing_key_pair() {
440
- local private_key_file
441
- local public_key_file
442
- private_key_file=$(mktemp)
443
- public_key_file=$(mktemp)
444
-
445
- if ! node -e "const { generateKeyPairSync } = require('crypto'); const fs = require('fs'); const pair = generateKeyPairSync('rsa', { modulusLength: 2048, publicKeyEncoding: { type: 'spki', format: 'pem' }, privateKeyEncoding: { type: 'pkcs8', format: 'pem' } }); fs.writeFileSync(process.argv[1], pair.privateKey, 'utf8'); fs.writeFileSync(process.argv[2], pair.publicKey, 'utf8');" "$private_key_file" "$public_key_file"; then
446
- rm -f "$private_key_file" "$public_key_file"
447
- return 1
448
- fi
449
-
450
- local private_key_pem
451
- local public_key_pem
452
- private_key_pem=$(cat "$private_key_file")
453
- public_key_pem=$(cat "$public_key_file")
454
- rm -f "$private_key_file" "$public_key_file"
455
-
456
- private_key_pem="${private_key_pem//$'\r'/}"
457
- public_key_pem="${public_key_pem//$'\r'/}"
458
-
459
- MANIFEST_SIGNING_PRIVATE_KEY="${private_key_pem//$'\n'/\\n}"
460
- MANIFEST_SIGNING_PUBLIC_KEY="${public_key_pem//$'\n'/\\n}"
461
-
462
- export MANIFEST_SIGNING_PRIVATE_KEY
463
- export MANIFEST_SIGNING_PUBLIC_KEY
464
-
465
- write_env_var "MANIFEST_SIGNING_PRIVATE_KEY" "$MANIFEST_SIGNING_PRIVATE_KEY"
466
- write_env_var "MANIFEST_SIGNING_PUBLIC_KEY" "$MANIFEST_SIGNING_PUBLIC_KEY"
467
-
468
- return 0
469
- }
470
-
471
- configure_manifest_signing_credentials() {
472
- echo -e "${BLUE}🛡️ MANIFEST SIGNING CONFIGURATION${NC}"
473
- echo "================================="
474
-
475
- local should_generate="false"
476
- local regenerate_choice=""
477
-
478
- if [ "$update_env" = "true" ]; then
479
- should_generate="true"
480
- elif [ -z "$MANIFEST_SIGNING_PRIVATE_KEY" ] || is_placeholder "$MANIFEST_SIGNING_PRIVATE_KEY" || [ -z "$MANIFEST_SIGNING_PUBLIC_KEY" ] || is_placeholder "$MANIFEST_SIGNING_PUBLIC_KEY"; then
481
- should_generate="true"
482
- else
483
- echo -e "${GREEN}Current manifest signing key pair: [HIDDEN]${NC}"
484
- read -p "Generate new manifest signing key pair? (press Enter to keep current, or type 'y' to regenerate): " regenerate_choice
485
- regenerate_choice=$(strip_carriage_returns "$regenerate_choice")
486
- if [ "$regenerate_choice" = "y" ] || [ "$regenerate_choice" = "Y" ]; then
487
- should_generate="true"
488
- fi
489
- fi
490
-
491
- if [ "$should_generate" = "true" ]; then
492
- echo -e "${YELLOW}Generating manifest signing RSA key pair...${NC}"
493
- if generate_manifest_signing_key_pair; then
494
- echo -e "${GREEN}✅ Manifest signing key pair generated${NC}"
495
- else
496
- echo -e "${RED}❌ Error: Failed to generate manifest signing key pair${NC}"
497
- exit 1
498
- fi
499
- else
500
- echo -e "${GREEN}✅ Keeping current manifest signing key pair${NC}"
501
- fi
502
-
503
- if [ -z "$MANIFEST_SIGNING_KEY_ID" ] || is_placeholder "$MANIFEST_SIGNING_KEY_ID" || [ "$should_generate" = "true" ]; then
504
- local generated_key_id
505
- generated_key_id=$(generate_worker_subdomain_label)
506
- if [ -z "$generated_key_id" ] || [ ${#generated_key_id} -ne 10 ]; then
507
- echo -e "${RED}❌ Error: Failed to generate MANIFEST_SIGNING_KEY_ID${NC}"
508
- exit 1
509
- fi
510
- MANIFEST_SIGNING_KEY_ID="$generated_key_id"
511
- export MANIFEST_SIGNING_KEY_ID
512
- write_env_var "MANIFEST_SIGNING_KEY_ID" "$MANIFEST_SIGNING_KEY_ID"
513
- echo -e "${GREEN}✅ MANIFEST_SIGNING_KEY_ID generated: $MANIFEST_SIGNING_KEY_ID${NC}"
514
- else
515
- echo -e "${GREEN}✅ MANIFEST_SIGNING_KEY_ID: $MANIFEST_SIGNING_KEY_ID${NC}"
516
- fi
517
-
518
- echo ""
519
- }
520
-
521
- generate_export_encryption_key_pair() {
522
- local private_key_file
523
- local public_key_file
524
- private_key_file=$(mktemp)
525
- public_key_file=$(mktemp)
526
-
527
- if ! node -e "const { generateKeyPairSync } = require('crypto'); const fs = require('fs'); const pair = generateKeyPairSync('rsa', { modulusLength: 2048, publicKeyEncoding: { type: 'spki', format: 'pem' }, privateKeyEncoding: { type: 'pkcs8', format: 'pem' } }); fs.writeFileSync(process.argv[1], pair.privateKey, 'utf8'); fs.writeFileSync(process.argv[2], pair.publicKey, 'utf8');" "$private_key_file" "$public_key_file"; then
528
- rm -f "$private_key_file" "$public_key_file"
529
- return 1
530
- fi
531
-
532
- local private_key_pem
533
- local public_key_pem
534
- private_key_pem=$(cat "$private_key_file")
535
- public_key_pem=$(cat "$public_key_file")
536
- rm -f "$private_key_file" "$public_key_file"
537
-
538
- private_key_pem="${private_key_pem//$'\r'/}"
539
- public_key_pem="${public_key_pem//$'\r'/}"
540
-
541
- EXPORT_ENCRYPTION_PRIVATE_KEY="${private_key_pem//$'\n'/\\n}"
542
- EXPORT_ENCRYPTION_PUBLIC_KEY="${public_key_pem//$'\n'/\\n}"
543
-
544
- export EXPORT_ENCRYPTION_PRIVATE_KEY
545
- export EXPORT_ENCRYPTION_PUBLIC_KEY
546
-
547
- write_env_var "EXPORT_ENCRYPTION_PRIVATE_KEY" "$EXPORT_ENCRYPTION_PRIVATE_KEY"
548
- write_env_var "EXPORT_ENCRYPTION_PUBLIC_KEY" "$EXPORT_ENCRYPTION_PUBLIC_KEY"
549
-
550
- return 0
551
- }
552
-
553
- configure_export_encryption_credentials() {
554
- echo -e "${BLUE}🔐 EXPORT ENCRYPTION CONFIGURATION${NC}"
555
- echo "================================="
556
-
557
- local should_generate="false"
558
- local regenerate_choice=""
559
-
560
- if [ "$update_env" = "true" ]; then
561
- should_generate="true"
562
- elif [ -z "$EXPORT_ENCRYPTION_PRIVATE_KEY" ] || is_placeholder "$EXPORT_ENCRYPTION_PRIVATE_KEY" || [ -z "$EXPORT_ENCRYPTION_PUBLIC_KEY" ] || is_placeholder "$EXPORT_ENCRYPTION_PUBLIC_KEY"; then
563
- should_generate="true"
564
- else
565
- echo -e "${GREEN}Current export encryption key pair: [HIDDEN]${NC}"
566
- read -p "Generate new export encryption key pair? (press Enter to keep current, or type 'y' to regenerate): " regenerate_choice
567
- regenerate_choice=$(strip_carriage_returns "$regenerate_choice")
568
- if [ "$regenerate_choice" = "y" ] || [ "$regenerate_choice" = "Y" ]; then
569
- should_generate="true"
570
- fi
571
- fi
572
-
573
- if [ "$should_generate" = "true" ]; then
574
- echo -e "${YELLOW}Generating export encryption RSA key pair...${NC}"
575
- if generate_export_encryption_key_pair; then
576
- echo -e "${GREEN}✅ Export encryption key pair generated${NC}"
577
- else
578
- echo -e "${RED}❌ Error: Failed to generate export encryption key pair${NC}"
579
- exit 1
580
- fi
581
- else
582
- echo -e "${GREEN}✅ Keeping current export encryption key pair${NC}"
583
- fi
584
-
585
- if [ -z "$EXPORT_ENCRYPTION_KEY_ID" ] || is_placeholder "$EXPORT_ENCRYPTION_KEY_ID" || [ "$should_generate" = "true" ]; then
586
- local generated_key_id
587
- generated_key_id=$(generate_worker_subdomain_label)
588
- if [ -z "$generated_key_id" ] || [ ${#generated_key_id} -ne 10 ]; then
589
- echo -e "${RED}❌ Error: Failed to generate EXPORT_ENCRYPTION_KEY_ID${NC}"
590
- exit 1
591
- fi
592
- EXPORT_ENCRYPTION_KEY_ID="$generated_key_id"
593
- export EXPORT_ENCRYPTION_KEY_ID
594
- write_env_var "EXPORT_ENCRYPTION_KEY_ID" "$EXPORT_ENCRYPTION_KEY_ID"
595
- echo -e "${GREEN}✅ EXPORT_ENCRYPTION_KEY_ID generated: $EXPORT_ENCRYPTION_KEY_ID${NC}"
596
- else
597
- echo -e "${GREEN}✅ EXPORT_ENCRYPTION_KEY_ID: $EXPORT_ENCRYPTION_KEY_ID${NC}"
598
- fi
599
-
600
- echo ""
601
- }
602
-
603
- generate_data_at_rest_encryption_key_pair() {
604
- local private_key_file
605
- local public_key_file
606
- private_key_file=$(mktemp)
607
- public_key_file=$(mktemp)
608
-
609
- if ! node -e "const { generateKeyPairSync } = require('crypto'); const fs = require('fs'); const pair = generateKeyPairSync('rsa', { modulusLength: 2048, publicKeyEncoding: { type: 'spki', format: 'pem' }, privateKeyEncoding: { type: 'pkcs8', format: 'pem' } }); fs.writeFileSync(process.argv[1], pair.privateKey, 'utf8'); fs.writeFileSync(process.argv[2], pair.publicKey, 'utf8');" "$private_key_file" "$public_key_file"; then
610
- rm -f "$private_key_file" "$public_key_file"
611
- return 1
612
- fi
613
-
614
- local private_key_pem
615
- local public_key_pem
616
- private_key_pem=$(cat "$private_key_file")
617
- public_key_pem=$(cat "$public_key_file")
618
- rm -f "$private_key_file" "$public_key_file"
619
-
620
- private_key_pem="${private_key_pem//$'\r'/}"
621
- public_key_pem="${public_key_pem//$'\r'/}"
622
-
623
- DATA_AT_REST_ENCRYPTION_PRIVATE_KEY="${private_key_pem//$'\n'/\\n}"
624
- DATA_AT_REST_ENCRYPTION_PUBLIC_KEY="${public_key_pem//$'\n'/\\n}"
625
-
626
- export DATA_AT_REST_ENCRYPTION_PRIVATE_KEY
627
- export DATA_AT_REST_ENCRYPTION_PUBLIC_KEY
628
-
629
- write_env_var "DATA_AT_REST_ENCRYPTION_PRIVATE_KEY" "$DATA_AT_REST_ENCRYPTION_PRIVATE_KEY"
630
- write_env_var "DATA_AT_REST_ENCRYPTION_PUBLIC_KEY" "$DATA_AT_REST_ENCRYPTION_PUBLIC_KEY"
631
-
632
- return 0
633
- }
634
-
635
- configure_data_at_rest_encryption_credentials() {
636
- echo -e "${BLUE}🗃️ DATA-AT-REST ENCRYPTION CONFIGURATION${NC}"
637
- echo "========================================"
638
-
639
- # Data-at-rest encryption is mandatory for all environments.
640
- DATA_AT_REST_ENCRYPTION_ENABLED="true"
641
-
642
- export DATA_AT_REST_ENCRYPTION_ENABLED
643
- write_env_var "DATA_AT_REST_ENCRYPTION_ENABLED" "$DATA_AT_REST_ENCRYPTION_ENABLED"
644
- echo -e "${GREEN}✅ DATA_AT_REST_ENCRYPTION_ENABLED: $DATA_AT_REST_ENCRYPTION_ENABLED${NC}"
645
-
646
- local should_generate="false"
647
- local regenerate_choice=""
648
-
649
- if [ "$update_env" = "true" ]; then
650
- should_generate="true"
651
- elif [ -z "$DATA_AT_REST_ENCRYPTION_PRIVATE_KEY" ] || is_placeholder "$DATA_AT_REST_ENCRYPTION_PRIVATE_KEY" || [ -z "$DATA_AT_REST_ENCRYPTION_PUBLIC_KEY" ] || is_placeholder "$DATA_AT_REST_ENCRYPTION_PUBLIC_KEY"; then
652
- should_generate="true"
653
- else
654
- echo -e "${GREEN}Current data-at-rest encryption key pair: [HIDDEN]${NC}"
655
- read -p "Generate new data-at-rest encryption key pair? (press Enter to keep current, or type 'y' to regenerate): " regenerate_choice
656
- regenerate_choice=$(strip_carriage_returns "$regenerate_choice")
657
- if [ "$regenerate_choice" = "y" ] || [ "$regenerate_choice" = "Y" ]; then
658
- should_generate="true"
659
- fi
660
- fi
661
-
662
- if [ "$should_generate" = "true" ]; then
663
- echo -e "${YELLOW}Generating data-at-rest encryption RSA key pair...${NC}"
664
- if generate_data_at_rest_encryption_key_pair; then
665
- echo -e "${GREEN}✅ Data-at-rest encryption key pair generated${NC}"
666
- else
667
- echo -e "${RED}❌ Error: Failed to generate data-at-rest encryption key pair${NC}"
668
- exit 1
669
- fi
670
- else
671
- echo -e "${GREEN}✅ Keeping current data-at-rest encryption key pair${NC}"
672
- fi
673
-
674
- if [ -z "$DATA_AT_REST_ENCRYPTION_KEY_ID" ] || is_placeholder "$DATA_AT_REST_ENCRYPTION_KEY_ID" || [ "$should_generate" = "true" ]; then
675
- local generated_key_id
676
- generated_key_id=$(generate_worker_subdomain_label)
677
- if [ -z "$generated_key_id" ] || [ ${#generated_key_id} -ne 10 ]; then
678
- echo -e "${RED}❌ Error: Failed to generate DATA_AT_REST_ENCRYPTION_KEY_ID${NC}"
679
- exit 1
680
- fi
681
- DATA_AT_REST_ENCRYPTION_KEY_ID="$generated_key_id"
682
- export DATA_AT_REST_ENCRYPTION_KEY_ID
683
- write_env_var "DATA_AT_REST_ENCRYPTION_KEY_ID" "$DATA_AT_REST_ENCRYPTION_KEY_ID"
684
- echo -e "${GREEN}✅ DATA_AT_REST_ENCRYPTION_KEY_ID generated: $DATA_AT_REST_ENCRYPTION_KEY_ID${NC}"
685
- else
686
- echo -e "${GREEN}✅ DATA_AT_REST_ENCRYPTION_KEY_ID: $DATA_AT_REST_ENCRYPTION_KEY_ID${NC}"
687
- fi
688
-
689
- echo ""
690
- }
691
-
692
- validate_data_at_rest_encryption_settings() {
693
- local enabled_normalized
694
- enabled_normalized=$(printf '%s' "${DATA_AT_REST_ENCRYPTION_ENABLED:-false}" | tr '[:upper:]' '[:lower:]')
695
-
696
- if [ "$enabled_normalized" = "1" ] || [ "$enabled_normalized" = "true" ] || [ "$enabled_normalized" = "yes" ] || [ "$enabled_normalized" = "on" ]; then
697
- if [ -z "$DATA_AT_REST_ENCRYPTION_PRIVATE_KEY" ] || is_placeholder "$DATA_AT_REST_ENCRYPTION_PRIVATE_KEY"; then
698
- echo -e "${RED}❌ Error: DATA_AT_REST_ENCRYPTION_PRIVATE_KEY is required when DATA_AT_REST_ENCRYPTION_ENABLED is true${NC}"
699
- exit 1
700
- fi
701
-
702
- if [ -z "$DATA_AT_REST_ENCRYPTION_PUBLIC_KEY" ] || is_placeholder "$DATA_AT_REST_ENCRYPTION_PUBLIC_KEY"; then
703
- echo -e "${RED}❌ Error: DATA_AT_REST_ENCRYPTION_PUBLIC_KEY is required when DATA_AT_REST_ENCRYPTION_ENABLED is true${NC}"
704
- exit 1
705
- fi
706
-
707
- if [ -z "$DATA_AT_REST_ENCRYPTION_KEY_ID" ] || is_placeholder "$DATA_AT_REST_ENCRYPTION_KEY_ID"; then
708
- echo -e "${RED}❌ Error: DATA_AT_REST_ENCRYPTION_KEY_ID is required when DATA_AT_REST_ENCRYPTION_ENABLED is true${NC}"
709
- exit 1
710
- fi
711
- fi
712
- }
713
-
714
- # Validate required variables
715
- required_vars=(
716
- # Core Cloudflare Configuration
717
- "ACCOUNT_ID"
718
-
719
- # Shared Authentication & Storage
720
- "USER_DB_AUTH"
721
- "R2_KEY_SECRET"
722
- "IMAGES_API_TOKEN"
723
-
724
- # Firebase Auth Configuration
725
- "API_KEY"
726
- "AUTH_DOMAIN"
727
- "PROJECT_ID"
728
- "STORAGE_BUCKET"
729
- "MESSAGING_SENDER_ID"
730
- "APP_ID"
731
- "MEASUREMENT_ID"
732
- "FIREBASE_SERVICE_ACCOUNT_EMAIL"
733
- "FIREBASE_SERVICE_ACCOUNT_PRIVATE_KEY"
734
-
735
- # Pages Configuration
736
- "PAGES_PROJECT_NAME"
737
- "PAGES_CUSTOM_DOMAIN"
738
-
739
- # Worker Names (required for config replacement)
740
- "KEYS_WORKER_NAME"
741
- "USER_WORKER_NAME"
742
- "DATA_WORKER_NAME"
743
- "AUDIT_WORKER_NAME"
744
- "IMAGES_WORKER_NAME"
745
- "PDF_WORKER_NAME"
746
-
747
- # Worker Domains (required for proxy/env secrets and worker fallbacks)
748
- "KEYS_WORKER_DOMAIN"
749
- "USER_WORKER_DOMAIN"
750
- "DATA_WORKER_DOMAIN"
751
- "AUDIT_WORKER_DOMAIN"
752
- "IMAGES_WORKER_DOMAIN"
753
- "PDF_WORKER_DOMAIN"
754
-
755
- # Storage Configuration (required for config replacement)
756
- "DATA_BUCKET_NAME"
757
- "AUDIT_BUCKET_NAME"
758
- "FILES_BUCKET_NAME"
759
- "KV_STORE_ID"
760
-
761
- # Worker-Specific Secrets (required for deployment)
762
- "KEYS_AUTH"
763
- "PDF_WORKER_AUTH"
764
- "IMAGE_SIGNED_URL_SECRET"
765
- "BROWSER_API_TOKEN"
766
- "MANIFEST_SIGNING_PRIVATE_KEY"
767
- "MANIFEST_SIGNING_KEY_ID"
768
- "MANIFEST_SIGNING_PUBLIC_KEY"
769
- "EXPORT_ENCRYPTION_PRIVATE_KEY"
770
- "EXPORT_ENCRYPTION_KEY_ID"
771
- "EXPORT_ENCRYPTION_PUBLIC_KEY"
772
- )
773
-
774
- validate_required_vars() {
775
- echo -e "${YELLOW}🔍 Validating required environment variables...${NC}"
776
- for var in "${required_vars[@]}"; do
777
- if [ -z "${!var}" ] || is_placeholder "${!var}"; then
778
- echo -e "${RED}❌ Error: $var is not set in .env file or is a placeholder${NC}"
779
- exit 1
780
- fi
781
- done
782
- echo -e "${GREEN}✅ All required variables found${NC}"
783
- }
784
-
785
- assert_file_exists() {
786
- local file_path=$1
787
-
788
- if [ ! -f "$file_path" ]; then
789
- echo -e "${RED}❌ Error: required file is missing: $file_path${NC}"
790
- exit 1
791
- fi
792
- }
793
-
794
- assert_contains_literal() {
795
- local file_path=$1
796
- local literal=$2
797
- local description=$3
798
-
799
- if ! grep -Fq -- "$literal" "$file_path"; then
800
- echo -e "${RED}❌ Error: ${description}${NC}"
801
- echo -e "${YELLOW} Expected to find '$literal' in $file_path${NC}"
802
- exit 1
803
- fi
804
- }
805
-
806
- assert_no_match_in_file() {
807
- local file_path=$1
808
- local pattern=$2
809
- local description=$3
810
- local matches
811
-
812
- matches=$(grep -En "$pattern" "$file_path" | head -n 3 || true)
813
- if [ -n "$matches" ]; then
814
- echo -e "${RED}❌ Error: ${description}${NC}"
815
- echo -e "${YELLOW} First matching lines in $file_path:${NC}"
816
- echo "$matches"
817
- exit 1
818
- fi
819
- }
820
-
821
- validate_json_file() {
822
- local file_path=$1
823
-
824
- if ! node -e "const fs=require('fs'); JSON.parse(fs.readFileSync(process.argv[1], 'utf8'));" "$file_path" > /dev/null 2>&1; then
825
- echo -e "${RED}❌ Error: invalid JSON in $file_path${NC}"
826
- exit 1
827
- fi
828
- }
163
+ DEPLOY_CONFIG_MODULES_DIR="$SCRIPT_DIR/deploy-config/modules"
164
+ DEPLOY_CONFIG_ENV_UTILS_MODULE="$DEPLOY_CONFIG_MODULES_DIR/env-utils.sh"
829
165
 
830
- validate_domain_var() {
831
- local var_name=$1
832
- local value="${!var_name}"
833
- local normalized
834
-
835
- value=$(strip_carriage_returns "$value")
836
- normalized=$(normalize_domain_value "$value")
837
-
838
- if [ -z "$value" ] || is_placeholder "$value"; then
839
- echo -e "${RED}❌ Error: $var_name is missing or placeholder${NC}"
840
- exit 1
841
- fi
842
-
843
- if [ "$value" != "$normalized" ]; then
844
- echo -e "${RED}❌ Error: $var_name must not include protocol, trailing slash, or surrounding whitespace${NC}"
845
- echo -e "${YELLOW} Use '$normalized' instead${NC}"
846
- exit 1
847
- fi
848
-
849
- if [[ "$value" == */* ]]; then
850
- echo -e "${RED}❌ Error: $var_name must be a bare domain (no path segments)${NC}"
851
- exit 1
852
- fi
853
- }
854
-
855
- validate_env_value_formats() {
856
- echo -e "${YELLOW}🔍 Validating environment value formats...${NC}"
857
-
858
- validate_domain_var "PAGES_CUSTOM_DOMAIN"
859
- validate_domain_var "KEYS_WORKER_DOMAIN"
860
- validate_domain_var "USER_WORKER_DOMAIN"
861
- validate_domain_var "DATA_WORKER_DOMAIN"
862
- validate_domain_var "AUDIT_WORKER_DOMAIN"
863
- validate_domain_var "IMAGES_WORKER_DOMAIN"
864
- validate_domain_var "PDF_WORKER_DOMAIN"
865
-
866
- 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
867
- echo -e "${RED}❌ Error: KV_STORE_ID must be a 32-character hex namespace ID (or UUID format)${NC}"
868
- exit 1
869
- fi
870
-
871
- if [[ "$ACCOUNT_ID" =~ [[:space:]] ]]; then
872
- echo -e "${RED}❌ Error: ACCOUNT_ID must not contain whitespace${NC}"
873
- exit 1
874
- fi
875
-
876
- echo -e "${GREEN}✅ Environment value formats look valid${NC}"
877
- }
878
-
879
- validate_env_file_entries() {
880
- local var_name
881
- local escaped_var_name
882
- local count
883
-
884
- echo -e "${YELLOW}🔍 Verifying required .env entries...${NC}"
885
- for var_name in "${required_vars[@]}"; do
886
- escaped_var_name=$(escape_for_sed_pattern "$var_name")
887
- count=$(grep -c "^$escaped_var_name=" .env || true)
888
-
889
- if [ "$count" -lt 1 ]; then
890
- echo -e "${RED}❌ Error: missing .env entry for $var_name${NC}"
891
- exit 1
892
- fi
893
- done
894
- echo -e "${GREEN}✅ Required .env entries found${NC}"
895
- }
896
-
897
- validate_generated_configs() {
898
- echo -e "${YELLOW}🔍 Running generated configuration checkpoint validations...${NC}"
899
-
900
- local required_files=(
901
- "wrangler.toml"
902
- "app/config/config.json"
903
- "app/config/firebase.ts"
904
- "app/config/admin-service.json"
905
- "app/routes/auth/login.tsx"
906
- "app/routes/auth/login.module.css"
907
- "workers/audit-worker/wrangler.jsonc"
908
- "workers/data-worker/wrangler.jsonc"
909
- "workers/image-worker/wrangler.jsonc"
910
- "workers/keys-worker/wrangler.jsonc"
911
- "workers/pdf-worker/wrangler.jsonc"
912
- "workers/user-worker/wrangler.jsonc"
913
- "workers/audit-worker/src/audit-worker.ts"
914
- "workers/data-worker/src/data-worker.ts"
915
- "workers/image-worker/src/image-worker.ts"
916
- "workers/keys-worker/src/keys.ts"
917
- "workers/pdf-worker/src/pdf-worker.ts"
918
- "workers/user-worker/src/user-worker.ts"
919
- )
920
-
921
- local file_path
922
- for file_path in "${required_files[@]}"; do
923
- assert_file_exists "$file_path"
924
- done
925
-
926
- validate_json_file "app/config/config.json"
927
- validate_json_file "app/config/admin-service.json"
928
-
929
- assert_contains_literal "wrangler.toml" "\"$PAGES_PROJECT_NAME\"" "PAGES_PROJECT_NAME was not applied to wrangler.toml"
930
-
931
- assert_contains_literal "workers/keys-worker/wrangler.jsonc" "$KEYS_WORKER_NAME" "KEYS_WORKER_NAME was not applied"
932
- assert_contains_literal "workers/user-worker/wrangler.jsonc" "$USER_WORKER_NAME" "USER_WORKER_NAME was not applied"
933
- assert_contains_literal "workers/data-worker/wrangler.jsonc" "$DATA_WORKER_NAME" "DATA_WORKER_NAME was not applied"
934
- assert_contains_literal "workers/audit-worker/wrangler.jsonc" "$AUDIT_WORKER_NAME" "AUDIT_WORKER_NAME was not applied"
935
- assert_contains_literal "workers/image-worker/wrangler.jsonc" "$IMAGES_WORKER_NAME" "IMAGES_WORKER_NAME was not applied"
936
- assert_contains_literal "workers/pdf-worker/wrangler.jsonc" "$PDF_WORKER_NAME" "PDF_WORKER_NAME was not applied"
937
-
938
- assert_contains_literal "workers/keys-worker/wrangler.jsonc" "$ACCOUNT_ID" "ACCOUNT_ID missing in keys worker config"
939
- assert_contains_literal "workers/user-worker/wrangler.jsonc" "$ACCOUNT_ID" "ACCOUNT_ID missing in user worker config"
940
- assert_contains_literal "workers/data-worker/wrangler.jsonc" "$ACCOUNT_ID" "ACCOUNT_ID missing in data worker config"
941
- assert_contains_literal "workers/audit-worker/wrangler.jsonc" "$ACCOUNT_ID" "ACCOUNT_ID missing in audit worker config"
942
- assert_contains_literal "workers/image-worker/wrangler.jsonc" "$ACCOUNT_ID" "ACCOUNT_ID missing in image worker config"
943
- assert_contains_literal "workers/pdf-worker/wrangler.jsonc" "$ACCOUNT_ID" "ACCOUNT_ID missing in pdf worker config"
944
-
945
- assert_contains_literal "workers/data-worker/wrangler.jsonc" "$DATA_BUCKET_NAME" "DATA_BUCKET_NAME missing in data worker config"
946
- assert_contains_literal "workers/audit-worker/wrangler.jsonc" "$AUDIT_BUCKET_NAME" "AUDIT_BUCKET_NAME missing in audit worker config"
947
- assert_contains_literal "workers/image-worker/wrangler.jsonc" "$FILES_BUCKET_NAME" "FILES_BUCKET_NAME missing in image worker config"
948
- assert_contains_literal "workers/user-worker/wrangler.jsonc" "$KV_STORE_ID" "KV_STORE_ID missing in user worker config"
949
-
950
- assert_contains_literal "app/config/config.json" "https://$PAGES_CUSTOM_DOMAIN" "PAGES_CUSTOM_DOMAIN missing in app/config/config.json"
951
- assert_contains_literal "app/config/config.json" "$EXPORT_ENCRYPTION_KEY_ID" "EXPORT_ENCRYPTION_KEY_ID missing in app/config/config.json"
952
- assert_contains_literal "app/config/config.json" "\"export_encryption_public_key\":" "export_encryption_public_key missing in app/config/config.json"
953
- assert_contains_literal "app/routes/auth/login.tsx" "const APP_CANONICAL_ORIGIN = 'https://$PAGES_CUSTOM_DOMAIN';" "PAGES_CUSTOM_DOMAIN missing in app/routes/auth/login.tsx canonical origin"
166
+ if [ ! -f "$DEPLOY_CONFIG_ENV_UTILS_MODULE" ]; then
167
+ echo -e "${RED}❌ Error: Required deploy-config module not found: $DEPLOY_CONFIG_ENV_UTILS_MODULE${NC}"
168
+ exit 1
169
+ fi
954
170
 
955
- assert_contains_literal "app/config/firebase.ts" "$API_KEY" "API_KEY missing in app/config/firebase.ts"
956
- assert_contains_literal "app/config/firebase.ts" "$AUTH_DOMAIN" "AUTH_DOMAIN missing in app/config/firebase.ts"
957
- assert_contains_literal "app/config/firebase.ts" "$PROJECT_ID" "PROJECT_ID missing in app/config/firebase.ts"
958
- assert_contains_literal "app/config/firebase.ts" "$STORAGE_BUCKET" "STORAGE_BUCKET missing in app/config/firebase.ts"
959
- assert_contains_literal "app/config/firebase.ts" "$MESSAGING_SENDER_ID" "MESSAGING_SENDER_ID missing in app/config/firebase.ts"
960
- assert_contains_literal "app/config/firebase.ts" "$APP_ID" "APP_ID missing in app/config/firebase.ts"
961
- assert_contains_literal "app/config/firebase.ts" "$MEASUREMENT_ID" "MEASUREMENT_ID missing in app/config/firebase.ts"
171
+ source "$DEPLOY_CONFIG_ENV_UTILS_MODULE"
962
172
 
963
- assert_contains_literal "workers/audit-worker/src/audit-worker.ts" "https://$PAGES_CUSTOM_DOMAIN" "PAGES_CUSTOM_DOMAIN missing in audit-worker source"
964
- assert_contains_literal "workers/data-worker/src/data-worker.ts" "https://$PAGES_CUSTOM_DOMAIN" "PAGES_CUSTOM_DOMAIN missing in data-worker source"
965
- assert_contains_literal "workers/image-worker/src/image-worker.ts" "https://$PAGES_CUSTOM_DOMAIN" "PAGES_CUSTOM_DOMAIN missing in image-worker source"
966
- assert_contains_literal "workers/keys-worker/src/keys.ts" "https://$PAGES_CUSTOM_DOMAIN" "PAGES_CUSTOM_DOMAIN missing in keys-worker source"
967
- assert_contains_literal "workers/pdf-worker/src/pdf-worker.ts" "https://$PAGES_CUSTOM_DOMAIN" "PAGES_CUSTOM_DOMAIN missing in pdf-worker source"
968
- assert_contains_literal "workers/user-worker/src/user-worker.ts" "https://$PAGES_CUSTOM_DOMAIN" "PAGES_CUSTOM_DOMAIN missing in user-worker source"
173
+ DEPLOY_CONFIG_KEYS_MODULE="$DEPLOY_CONFIG_MODULES_DIR/keys.sh"
174
+ DEPLOY_CONFIG_VALIDATION_MODULE="$DEPLOY_CONFIG_MODULES_DIR/validation.sh"
175
+ DEPLOY_CONFIG_SCAFFOLDING_MODULE="$DEPLOY_CONFIG_MODULES_DIR/scaffolding.sh"
176
+ DEPLOY_CONFIG_PROMPT_MODULE="$DEPLOY_CONFIG_MODULES_DIR/prompt.sh"
969
177
 
970
- local placeholder_pattern
971
- placeholder_pattern="(\"(ACCOUNT_ID|PAGES_PROJECT_NAME|PAGES_CUSTOM_DOMAIN|KEYS_WORKER_NAME|USER_WORKER_NAME|DATA_WORKER_NAME|AUDIT_WORKER_NAME|IMAGES_WORKER_NAME|PDF_WORKER_NAME|KEYS_WORKER_DOMAIN|USER_WORKER_DOMAIN|DATA_WORKER_DOMAIN|AUDIT_WORKER_DOMAIN|IMAGES_WORKER_DOMAIN|PDF_WORKER_DOMAIN|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)\"|'(PAGES_CUSTOM_DOMAIN|DATA_WORKER_DOMAIN|IMAGES_WORKER_DOMAIN)')"
178
+ if [ ! -f "$DEPLOY_CONFIG_KEYS_MODULE" ]; then
179
+ echo -e "${RED}❌ Error: Required deploy-config module not found: $DEPLOY_CONFIG_KEYS_MODULE${NC}"
180
+ exit 1
181
+ fi
972
182
 
973
- local files_to_scan=(
974
- "wrangler.toml"
975
- "workers/audit-worker/wrangler.jsonc"
976
- "workers/data-worker/wrangler.jsonc"
977
- "workers/image-worker/wrangler.jsonc"
978
- "workers/keys-worker/wrangler.jsonc"
979
- "workers/pdf-worker/wrangler.jsonc"
980
- "workers/user-worker/wrangler.jsonc"
981
- "workers/audit-worker/src/audit-worker.ts"
982
- "workers/data-worker/src/data-worker.ts"
983
- "workers/image-worker/src/image-worker.ts"
984
- "workers/keys-worker/src/keys.ts"
985
- "workers/pdf-worker/src/pdf-worker.ts"
986
- "workers/user-worker/src/user-worker.ts"
987
- "app/config/config.json"
988
- "app/config/firebase.ts"
989
- "app/routes/auth/login.tsx"
990
- )
183
+ if [ ! -f "$DEPLOY_CONFIG_VALIDATION_MODULE" ]; then
184
+ echo -e "${RED}❌ Error: Required deploy-config module not found: $DEPLOY_CONFIG_VALIDATION_MODULE${NC}"
185
+ exit 1
186
+ fi
991
187
 
992
- for file_path in "${files_to_scan[@]}"; do
993
- assert_no_match_in_file "$file_path" "$placeholder_pattern" "Unresolved placeholder token found after config update"
994
- done
188
+ if [ ! -f "$DEPLOY_CONFIG_SCAFFOLDING_MODULE" ]; then
189
+ echo -e "${RED}❌ Error: Required deploy-config module not found: $DEPLOY_CONFIG_SCAFFOLDING_MODULE${NC}"
190
+ exit 1
191
+ fi
995
192
 
996
- echo -e "${GREEN}✅ Generated configuration checkpoint validation passed${NC}"
997
- }
193
+ if [ ! -f "$DEPLOY_CONFIG_PROMPT_MODULE" ]; then
194
+ echo -e "${RED}❌ Error: Required deploy-config module not found: $DEPLOY_CONFIG_PROMPT_MODULE${NC}"
195
+ exit 1
196
+ fi
998
197
 
999
- run_validation_checkpoint() {
1000
- validate_required_vars
1001
- validate_env_value_formats
1002
- validate_env_file_entries
1003
- validate_data_at_rest_encryption_settings
1004
- validate_generated_configs
1005
- }
198
+ source "$DEPLOY_CONFIG_KEYS_MODULE"
199
+ source "$DEPLOY_CONFIG_VALIDATION_MODULE"
200
+ source "$DEPLOY_CONFIG_SCAFFOLDING_MODULE"
201
+ source "$DEPLOY_CONFIG_PROMPT_MODULE"
1006
202
 
1007
203
  if [ "$validate_only" = "true" ]; then
1008
204
  echo -e "\n${BLUE}🧪 Validate-only mode enabled${NC}"
@@ -1011,196 +207,6 @@ if [ "$validate_only" = "true" ]; then
1011
207
  exit 0
1012
208
  fi
1013
209
 
1014
- # Function to copy example configuration files
1015
- copy_example_configs() {
1016
- echo -e "\n${BLUE}📋 Copying example configuration files...${NC}"
1017
-
1018
- # Copy app configuration files
1019
- echo -e "${YELLOW} Copying app configuration files...${NC}"
1020
-
1021
- # Copy app config-example directory to config (always sync non-admin files)
1022
- if [ -d "app/config-example" ]; then
1023
- local admin_service_backup=""
1024
- local copied_config_files=0
1025
- local skipped_existing_files=0
1026
-
1027
- if [ -f "app/config/admin-service.json" ]; then
1028
- admin_service_backup=$(mktemp)
1029
- cp "app/config/admin-service.json" "$admin_service_backup"
1030
- fi
1031
-
1032
- if [ "$update_env" = "true" ]; then
1033
- rm -rf app/config
1034
- fi
1035
-
1036
- mkdir -p app/config
1037
-
1038
- while IFS= read -r source_file; do
1039
- local relative_path
1040
- local destination_file
1041
- relative_path="${source_file#app/config-example/}"
1042
- destination_file="app/config/$relative_path"
1043
-
1044
- mkdir -p "$(dirname "$destination_file")"
1045
-
1046
- if [ "$update_env" = "true" ] || [ ! -f "$destination_file" ]; then
1047
- cp "$source_file" "$destination_file"
1048
- copied_config_files=$((copied_config_files + 1))
1049
- else
1050
- skipped_existing_files=$((skipped_existing_files + 1))
1051
- fi
1052
- done < <(find app/config-example -type f ! -name "admin-service.json")
1053
-
1054
- # Ensure example credentials are never copied from config-example.
1055
- rm -f app/config/admin-service.json
1056
-
1057
- if [ -n "$admin_service_backup" ] && [ -f "$admin_service_backup" ]; then
1058
- cp "$admin_service_backup" "app/config/admin-service.json"
1059
- rm -f "$admin_service_backup"
1060
- echo -e "${GREEN} ✅ app: preserved existing admin-service.json${NC}"
1061
- else
1062
- echo -e "${YELLOW} ⚠️ app: skipped copying admin-service.json (provide your own credentials file)${NC}"
1063
- fi
1064
-
1065
- if [ "$update_env" = "true" ]; then
1066
- echo -e "${GREEN} ✅ app: config directory reset from config-example (excluding admin-service.json)${NC}"
1067
- else
1068
- echo -e "${GREEN} ✅ app: synced missing files from config-example (excluding admin-service.json)${NC}"
1069
- fi
1070
-
1071
- if [ "$skipped_existing_files" -gt 0 ]; then
1072
- echo -e "${YELLOW} ℹ️ app: kept $skipped_existing_files existing config file(s)${NC}"
1073
- fi
1074
-
1075
- echo -e "${GREEN} ✅ app: copied $copied_config_files config file(s) from config-example${NC}"
1076
- fi
1077
-
1078
- # Copy auth route template files
1079
- echo -e "${YELLOW} Copying auth route template files...${NC}"
1080
-
1081
- if [ -f "app/routes/auth/login.example.tsx" ] && { [ "$update_env" = "true" ] || [ ! -f "app/routes/auth/login.tsx" ]; }; then
1082
- cp app/routes/auth/login.example.tsx app/routes/auth/login.tsx
1083
- echo -e "${GREEN} ✅ auth: login.tsx created from example${NC}"
1084
- elif [ -f "app/routes/auth/login.tsx" ]; then
1085
- echo -e "${YELLOW} ⚠️ auth: login.tsx already exists, skipping copy${NC}"
1086
- fi
1087
-
1088
- if [ -f "app/routes/auth/login.module.example.css" ] && { [ "$update_env" = "true" ] || [ ! -f "app/routes/auth/login.module.css" ]; }; then
1089
- cp app/routes/auth/login.module.example.css app/routes/auth/login.module.css
1090
- echo -e "${GREEN} ✅ auth: login.module.css created from example${NC}"
1091
- elif [ -f "app/routes/auth/login.module.css" ]; then
1092
- echo -e "${YELLOW} ⚠️ auth: login.module.css already exists, skipping copy${NC}"
1093
- fi
1094
-
1095
- # Navigate to each worker directory and copy the example file
1096
- echo -e "${YELLOW} Copying worker configuration files...${NC}"
1097
-
1098
- cd workers/keys-worker
1099
- if [ -f "wrangler.jsonc.example" ] && { [ "$update_env" = "true" ] || [ ! -f "wrangler.jsonc" ]; }; then
1100
- cp wrangler.jsonc.example wrangler.jsonc
1101
- echo -e "${GREEN} ✅ keys-worker: wrangler.jsonc created from example${NC}"
1102
- elif [ -f "wrangler.jsonc" ]; then
1103
- echo -e "${YELLOW} ⚠️ keys-worker: wrangler.jsonc already exists, skipping copy${NC}"
1104
- fi
1105
-
1106
- cd ../user-worker
1107
- if [ -f "wrangler.jsonc.example" ] && { [ "$update_env" = "true" ] || [ ! -f "wrangler.jsonc" ]; }; then
1108
- cp wrangler.jsonc.example wrangler.jsonc
1109
- echo -e "${GREEN} ✅ user-worker: wrangler.jsonc created from example${NC}"
1110
- elif [ -f "wrangler.jsonc" ]; then
1111
- echo -e "${YELLOW} ⚠️ user-worker: wrangler.jsonc already exists, skipping copy${NC}"
1112
- fi
1113
-
1114
- cd ../data-worker
1115
- if [ -f "wrangler.jsonc.example" ] && { [ "$update_env" = "true" ] || [ ! -f "wrangler.jsonc" ]; }; then
1116
- cp wrangler.jsonc.example wrangler.jsonc
1117
- echo -e "${GREEN} ✅ data-worker: wrangler.jsonc created from example${NC}"
1118
- elif [ -f "wrangler.jsonc" ]; then
1119
- echo -e "${YELLOW} ⚠️ data-worker: wrangler.jsonc already exists, skipping copy${NC}"
1120
- fi
1121
-
1122
- cd ../audit-worker
1123
- if [ -f "wrangler.jsonc.example" ] && { [ "$update_env" = "true" ] || [ ! -f "wrangler.jsonc" ]; }; then
1124
- cp wrangler.jsonc.example wrangler.jsonc
1125
- echo -e "${GREEN} ✅ audit-worker: wrangler.jsonc created from example${NC}"
1126
- elif [ -f "wrangler.jsonc" ]; then
1127
- echo -e "${YELLOW} ⚠️ audit-worker: wrangler.jsonc already exists, skipping copy${NC}"
1128
- fi
1129
-
1130
- cd ../image-worker
1131
- if [ -f "wrangler.jsonc.example" ] && { [ "$update_env" = "true" ] || [ ! -f "wrangler.jsonc" ]; }; then
1132
- cp wrangler.jsonc.example wrangler.jsonc
1133
- echo -e "${GREEN} ✅ image-worker: wrangler.jsonc created from example${NC}"
1134
- elif [ -f "wrangler.jsonc" ]; then
1135
- echo -e "${YELLOW} ⚠️ image-worker: wrangler.jsonc already exists, skipping copy${NC}"
1136
- fi
1137
-
1138
- cd ../pdf-worker
1139
- if [ -f "wrangler.jsonc.example" ] && { [ "$update_env" = "true" ] || [ ! -f "wrangler.jsonc" ]; }; then
1140
- cp wrangler.jsonc.example wrangler.jsonc
1141
- echo -e "${GREEN} ✅ pdf-worker: wrangler.jsonc created from example${NC}"
1142
- elif [ -f "wrangler.jsonc" ]; then
1143
- echo -e "${YELLOW} ⚠️ pdf-worker: wrangler.jsonc already exists, skipping copy${NC}"
1144
- fi
1145
-
1146
- # Return to project root
1147
- cd ../..
1148
-
1149
- # Copy worker source template files
1150
- echo -e "${YELLOW} Copying worker source template files...${NC}"
1151
-
1152
- if [ -f "workers/keys-worker/src/keys.example.ts" ] && { [ "$update_env" = "true" ] || [ ! -f "workers/keys-worker/src/keys.ts" ]; }; then
1153
- cp workers/keys-worker/src/keys.example.ts workers/keys-worker/src/keys.ts
1154
- echo -e "${GREEN} ✅ keys-worker: keys.ts created from example${NC}"
1155
- elif [ -f "workers/keys-worker/src/keys.ts" ]; then
1156
- echo -e "${YELLOW} ⚠️ keys-worker: keys.ts already exists, skipping copy${NC}"
1157
- fi
1158
-
1159
- if [ -f "workers/user-worker/src/user-worker.example.ts" ] && { [ "$update_env" = "true" ] || [ ! -f "workers/user-worker/src/user-worker.ts" ]; }; then
1160
- cp workers/user-worker/src/user-worker.example.ts workers/user-worker/src/user-worker.ts
1161
- echo -e "${GREEN} ✅ user-worker: user-worker.ts created from example${NC}"
1162
- elif [ -f "workers/user-worker/src/user-worker.ts" ]; then
1163
- echo -e "${YELLOW} ⚠️ user-worker: user-worker.ts already exists, skipping copy${NC}"
1164
- fi
1165
-
1166
- if [ -f "workers/data-worker/src/data-worker.example.ts" ] && { [ "$update_env" = "true" ] || [ ! -f "workers/data-worker/src/data-worker.ts" ]; }; then
1167
- cp workers/data-worker/src/data-worker.example.ts workers/data-worker/src/data-worker.ts
1168
- echo -e "${GREEN} ✅ data-worker: data-worker.ts created from example${NC}"
1169
- elif [ -f "workers/data-worker/src/data-worker.ts" ]; then
1170
- echo -e "${YELLOW} ⚠️ data-worker: data-worker.ts already exists, skipping copy${NC}"
1171
- fi
1172
-
1173
- if [ -f "workers/audit-worker/src/audit-worker.example.ts" ] && { [ "$update_env" = "true" ] || [ ! -f "workers/audit-worker/src/audit-worker.ts" ]; }; then
1174
- cp workers/audit-worker/src/audit-worker.example.ts workers/audit-worker/src/audit-worker.ts
1175
- echo -e "${GREEN} ✅ audit-worker: audit-worker.ts created from example${NC}"
1176
- elif [ -f "workers/audit-worker/src/audit-worker.ts" ]; then
1177
- echo -e "${YELLOW} ⚠️ audit-worker: audit-worker.ts already exists, skipping copy${NC}"
1178
- fi
1179
-
1180
- if [ -f "workers/image-worker/src/image-worker.example.ts" ] && { [ "$update_env" = "true" ] || [ ! -f "workers/image-worker/src/image-worker.ts" ]; }; then
1181
- cp workers/image-worker/src/image-worker.example.ts workers/image-worker/src/image-worker.ts
1182
- echo -e "${GREEN} ✅ image-worker: image-worker.ts created from example${NC}"
1183
- elif [ -f "workers/image-worker/src/image-worker.ts" ]; then
1184
- echo -e "${YELLOW} ⚠️ image-worker: image-worker.ts already exists, skipping copy${NC}"
1185
- fi
1186
-
1187
- if [ -f "workers/pdf-worker/src/pdf-worker.example.ts" ] && { [ "$update_env" = "true" ] || [ ! -f "workers/pdf-worker/src/pdf-worker.ts" ]; }; then
1188
- cp workers/pdf-worker/src/pdf-worker.example.ts workers/pdf-worker/src/pdf-worker.ts
1189
- echo -e "${GREEN} ✅ pdf-worker: pdf-worker.ts created from example${NC}"
1190
- elif [ -f "workers/pdf-worker/src/pdf-worker.ts" ]; then
1191
- echo -e "${YELLOW} ⚠️ pdf-worker: pdf-worker.ts already exists, skipping copy${NC}"
1192
- fi
1193
-
1194
- # Copy main wrangler.toml from example
1195
- if [ -f "wrangler.toml.example" ] && { [ "$update_env" = "true" ] || [ ! -f "wrangler.toml" ]; }; then
1196
- cp wrangler.toml.example wrangler.toml
1197
- echo -e "${GREEN} ✅ root: wrangler.toml created from example${NC}"
1198
- elif [ -f "wrangler.toml" ]; then
1199
- echo -e "${YELLOW} ⚠️ root: wrangler.toml already exists, skipping copy${NC}"
1200
- fi
1201
-
1202
- echo -e "${GREEN}✅ Configuration file copying completed${NC}"
1203
- }
1204
210
 
1205
211
  # Copy example configuration files
1206
212
  copy_example_configs
@@ -1208,543 +214,12 @@ copy_example_configs
1208
214
  # Load required Firebase admin service credentials from app/config/admin-service.json
1209
215
  load_admin_service_credentials
1210
216
 
1211
- # Function to prompt for environment variables and update .env file
1212
- prompt_for_secrets() {
1213
- echo -e "\n${BLUE}🔐 Environment Variables Setup${NC}"
1214
- echo "=============================="
1215
- echo -e "${YELLOW}Please provide values for the following environment variables.${NC}"
1216
- echo -e "${YELLOW}Press Enter to keep existing values (if any).${NC}"
1217
- echo ""
1218
-
1219
- # Create or backup existing .env
1220
- if [ -f ".env" ] && [ "$update_env" != "true" ]; then
1221
- cp .env .env.backup
1222
- echo -e "${GREEN}📄 Existing .env backed up to .env.backup${NC}"
1223
- fi
1224
-
1225
- # Copy .env.example to .env if it doesn't exist
1226
- if [ ! -f ".env" ]; then
1227
- cp .env.example .env
1228
- echo -e "${GREEN}📄 Created .env from .env.example${NC}"
1229
- fi
1230
-
1231
- # Function to prompt for a variable
1232
- is_auto_generated_secret_var() {
1233
- local var_name=$1
1234
- case "$var_name" in
1235
- USER_DB_AUTH|R2_KEY_SECRET|KEYS_AUTH|PDF_WORKER_AUTH|IMAGES_API_TOKEN|IMAGE_SIGNED_URL_SECRET)
1236
- return 0
1237
- ;;
1238
- *)
1239
- return 1
1240
- ;;
1241
- esac
1242
- }
1243
-
1244
- is_secret_placeholder_value() {
1245
- local var_name=$1
1246
- local value=$2
1247
- case "$var_name" in
1248
- USER_DB_AUTH)
1249
- [ "$value" = "your_custom_user_db_auth_token_here" ]
1250
- ;;
1251
- R2_KEY_SECRET)
1252
- [ "$value" = "your_custom_r2_secret_here" ]
1253
- ;;
1254
- KEYS_AUTH)
1255
- [ "$value" = "your_custom_keys_auth_token_here" ]
1256
- ;;
1257
- PDF_WORKER_AUTH)
1258
- [ "$value" = "your_custom_pdf_worker_auth_token_here" ]
1259
- ;;
1260
- IMAGES_API_TOKEN)
1261
- [ "$value" = "your_cloudflare_images_api_token_here" ]
1262
- ;;
1263
- IMAGE_SIGNED_URL_SECRET)
1264
- [ "$value" = "your_image_signed_url_secret_here" ]
1265
- ;;
1266
- *)
1267
- return 1
1268
- ;;
1269
- esac
1270
- }
1271
-
1272
- generate_secret_value() {
1273
- local var_name=$1
1274
- case "$var_name" in
1275
- IMAGE_SIGNED_URL_SECRET)
1276
- openssl rand -base64 48 2>/dev/null | tr '+/' '-_' | tr -d '='
1277
- ;;
1278
- *)
1279
- openssl rand -hex 32 2>/dev/null
1280
- ;;
1281
- esac
1282
- }
1283
-
1284
- prompt_for_var() {
1285
- local var_name=$1
1286
- local description=$2
1287
- local current_value="${!var_name}"
1288
- local new_value=""
1289
- local allow_keep="false"
1290
-
1291
- current_value=$(strip_carriage_returns "$current_value")
1292
-
1293
- if [ "$var_name" = "PAGES_CUSTOM_DOMAIN" ]; then
1294
- current_value=$(resolve_existing_domain_value "$var_name" "$current_value")
1295
- fi
1296
-
1297
- # Auto-generate selected secrets - but allow keeping current.
1298
- if is_auto_generated_secret_var "$var_name"; then
1299
- echo -e "${BLUE}$var_name${NC}"
1300
- echo -e "${YELLOW}$description${NC}"
1301
-
1302
- if [ "$update_env" != "true" ] && [ -n "$current_value" ] && ! is_placeholder "$current_value" && ! is_secret_placeholder_value "$var_name" "$current_value"; then
1303
- # Current value exists and is not a placeholder
1304
- echo -e "${GREEN}Current value: [HIDDEN]${NC}"
1305
- read -p "Generate new secret? (press Enter to keep current, or type 'y' to generate): " gen_choice
1306
- gen_choice=$(strip_carriage_returns "$gen_choice")
1307
-
1308
- if [ "$gen_choice" = "y" ] || [ "$gen_choice" = "Y" ]; then
1309
- new_value=$(generate_secret_value "$var_name" || echo "")
1310
- if [ -n "$new_value" ]; then
1311
- echo -e "${GREEN}✅ $var_name auto-generated${NC}"
1312
- else
1313
- while true; do
1314
- echo -e "${RED}❌ Failed to auto-generate, please enter manually:${NC}"
1315
- read -p "Enter value: " new_value
1316
- new_value=$(strip_carriage_returns "$new_value")
1317
- if [ -z "$new_value" ]; then
1318
- echo -e "${RED}❌ A value is required.${NC}"
1319
- continue
1320
- fi
1321
- if is_placeholder "$new_value"; then
1322
- echo -e "${RED}❌ Placeholder values are not allowed.${NC}"
1323
- new_value=""
1324
- continue
1325
- fi
1326
- break
1327
- done
1328
- fi
1329
- else
1330
- # User wants to keep current value
1331
- new_value=""
1332
- fi
1333
- else
1334
- # No current value or placeholder value - auto-generate
1335
- echo -e "${YELLOW}Auto-generating secret...${NC}"
1336
- new_value=$(generate_secret_value "$var_name" || echo "")
1337
- if [ -n "$new_value" ]; then
1338
- echo -e "${GREEN}✅ $var_name auto-generated${NC}"
1339
- else
1340
- while true; do
1341
- echo -e "${RED}❌ Failed to auto-generate, please enter manually:${NC}"
1342
- read -p "Enter value: " new_value
1343
- new_value=$(strip_carriage_returns "$new_value")
1344
- if [ -z "$new_value" ]; then
1345
- echo -e "${RED}❌ A value is required.${NC}"
1346
- continue
1347
- fi
1348
- if is_placeholder "$new_value"; then
1349
- echo -e "${RED}❌ Placeholder values are not allowed.${NC}"
1350
- new_value=""
1351
- continue
1352
- fi
1353
- break
1354
- done
1355
- fi
1356
- fi
1357
- else
1358
- # Normal prompt for other variables
1359
- echo -e "${BLUE}$var_name${NC}"
1360
- echo -e "${YELLOW}$description${NC}"
1361
- if [ "$update_env" != "true" ] && [ -n "$current_value" ] && ! is_placeholder "$current_value"; then
1362
- allow_keep="true"
1363
- if [ "$var_name" = "FIREBASE_SERVICE_ACCOUNT_PRIVATE_KEY" ]; then
1364
- echo -e "${GREEN}Current value: [HIDDEN]${NC}"
1365
- else
1366
- echo -e "${GREEN}Current value: $current_value${NC}"
1367
- fi
1368
- fi
1369
-
1370
- while true; do
1371
- if [ "$allow_keep" = "true" ]; then
1372
- read -p "New value (or press Enter to keep current): " new_value
1373
- new_value=$(strip_carriage_returns "$new_value")
1374
- if [ -z "$new_value" ]; then
1375
- break
1376
- fi
1377
- else
1378
- read -p "Enter value: " new_value
1379
- new_value=$(strip_carriage_returns "$new_value")
1380
- if [ -z "$new_value" ]; then
1381
- echo -e "${RED}❌ A value is required.${NC}"
1382
- continue
1383
- fi
1384
- fi
1385
-
1386
- if is_placeholder "$new_value"; then
1387
- echo -e "${RED}❌ Placeholder values are not allowed.${NC}"
1388
- new_value=""
1389
- continue
1390
- fi
1391
-
1392
- if [[ "$var_name" == *_WORKER_NAME ]]; then
1393
- new_value=$(normalize_worker_label_value "$new_value")
1394
-
1395
- if [ -z "$new_value" ] || ! is_valid_worker_label "$new_value"; then
1396
- echo -e "${RED}❌ $var_name must use only lowercase letters, numbers, and dashes.${NC}"
1397
- new_value=""
1398
- continue
1399
- fi
1400
- fi
1401
-
1402
- break
1403
- done
1404
- fi
1405
-
1406
- if [ -n "$new_value" ]; then
1407
- if [ "$var_name" = "PAGES_CUSTOM_DOMAIN" ]; then
1408
- new_value=$(normalize_domain_value "$new_value")
1409
- fi
1410
-
1411
- # Update the .env file
1412
- write_env_var "$var_name" "$new_value"
1413
-
1414
- export "$var_name=$new_value"
1415
- echo -e "${GREEN}✅ $var_name updated${NC}"
1416
- elif [ -n "$current_value" ]; then
1417
- if [[ "$var_name" == *_WORKER_NAME ]]; then
1418
- current_value=$(normalize_worker_label_value "$current_value")
1419
- fi
1420
-
1421
- # Keep values aligned with .env.example ordering and remove stale duplicates.
1422
- write_env_var "$var_name" "$current_value"
1423
- export "$var_name=$current_value"
1424
- echo -e "${GREEN}✅ Keeping current value for $var_name${NC}"
1425
- fi
1426
- echo ""
1427
- }
1428
-
1429
- set_worker_domain_from_shared_subdomain() {
1430
- local worker_name_var=$1
1431
- local worker_domain_var=$2
1432
- local worker_name_value="${!worker_name_var}"
1433
- local composed_domain=""
1434
-
1435
- worker_name_value=$(normalize_worker_label_value "$worker_name_value")
1436
-
1437
- if [ -z "$worker_name_value" ] || ! is_valid_worker_label "$worker_name_value"; then
1438
- echo -e "${RED}❌ $worker_name_var must use only lowercase letters, numbers, and dashes.${NC}"
1439
- exit 1
1440
- fi
1441
-
1442
- composed_domain=$(compose_worker_domain "$worker_name_value" "$shared_worker_subdomain" || echo "")
1443
-
1444
- if [ -z "$composed_domain" ]; then
1445
- echo -e "${RED}❌ Could not build $worker_domain_var from $worker_name_var and shared worker-subdomain.${NC}"
1446
- exit 1
1447
- fi
1448
-
1449
- write_env_var "$worker_domain_var" "$composed_domain"
1450
- export "$worker_domain_var=$composed_domain"
1451
- echo -e "${GREEN}✅ $worker_domain_var set to $composed_domain${NC}"
1452
- }
1453
-
1454
- echo -e "${BLUE}📊 CLOUDFLARE CORE CONFIGURATION${NC}"
1455
- echo "=================================="
1456
- prompt_for_var "ACCOUNT_ID" "Your Cloudflare Account ID"
1457
-
1458
- echo -e "${BLUE}🔐 SHARED AUTHENTICATION & STORAGE${NC}"
1459
- echo "==================================="
1460
- prompt_for_var "USER_DB_AUTH" "Custom user database authentication token (generate with: openssl rand -hex 16)"
1461
- prompt_for_var "R2_KEY_SECRET" "Custom R2 storage authentication token (generate with: openssl rand -hex 16)"
1462
- prompt_for_var "IMAGES_API_TOKEN" "Image worker API token (shared between workers)"
1463
-
1464
- echo -e "${BLUE}🔥 FIREBASE AUTH CONFIGURATION${NC}"
1465
- echo "==============================="
1466
- prompt_for_var "API_KEY" "Firebase API key"
1467
- prompt_for_var "AUTH_DOMAIN" "Firebase auth domain (project-id.firebaseapp.com)"
1468
- prompt_for_var "STORAGE_BUCKET" "Firebase storage bucket"
1469
- prompt_for_var "MESSAGING_SENDER_ID" "Firebase messaging sender ID"
1470
- prompt_for_var "APP_ID" "Firebase app ID"
1471
- prompt_for_var "MEASUREMENT_ID" "Firebase measurement ID (optional)"
1472
- echo -e "${GREEN}Using PROJECT_ID and service account values from app/config/admin-service.json${NC}"
1473
-
1474
- echo -e "${BLUE}📄 PAGES CONFIGURATION${NC}"
1475
- echo "======================"
1476
- prompt_for_var "PAGES_PROJECT_NAME" "Your Cloudflare Pages project name"
1477
- prompt_for_var "PAGES_CUSTOM_DOMAIN" "Your custom domain (e.g., striae.org) - DO NOT include https://"
1478
-
1479
- echo -e "${BLUE}🔑 WORKER NAMES & DOMAINS${NC}"
1480
- echo "========================="
1481
- echo -e "${YELLOW}Worker names are lowercased automatically and must use only letters, numbers, and dashes.${NC}"
1482
- echo -e "${YELLOW}Enter one shared worker-subdomain as a hostname (for example: team-name.workers.dev).${NC}"
1483
- echo -e "${YELLOW}Each worker domain is generated as {worker-name}.{worker-subdomain}.${NC}"
1484
-
1485
- local shared_worker_subdomain=""
1486
- local shared_worker_subdomain_default=""
1487
- local shared_worker_subdomain_input=""
1488
-
1489
- shared_worker_subdomain_default=$(infer_worker_subdomain_from_domain "$KEYS_WORKER_NAME" "$KEYS_WORKER_DOMAIN")
1490
- if [ -z "$shared_worker_subdomain_default" ]; then
1491
- shared_worker_subdomain_default=$(infer_worker_subdomain_from_domain "$USER_WORKER_NAME" "$USER_WORKER_DOMAIN")
1492
- fi
1493
- if [ -z "$shared_worker_subdomain_default" ]; then
1494
- shared_worker_subdomain_default=$(infer_worker_subdomain_from_domain "$DATA_WORKER_NAME" "$DATA_WORKER_DOMAIN")
1495
- fi
1496
- if [ -z "$shared_worker_subdomain_default" ]; then
1497
- shared_worker_subdomain_default=$(infer_worker_subdomain_from_domain "$AUDIT_WORKER_NAME" "$AUDIT_WORKER_DOMAIN")
1498
- fi
1499
- if [ -z "$shared_worker_subdomain_default" ]; then
1500
- shared_worker_subdomain_default=$(infer_worker_subdomain_from_domain "$IMAGES_WORKER_NAME" "$IMAGES_WORKER_DOMAIN")
1501
- fi
1502
- if [ -z "$shared_worker_subdomain_default" ]; then
1503
- shared_worker_subdomain_default=$(infer_worker_subdomain_from_domain "$PDF_WORKER_NAME" "$PDF_WORKER_DOMAIN")
1504
- fi
1505
-
1506
- while true; do
1507
- echo -e "${BLUE}WORKER_SUBDOMAIN${NC}"
1508
-
1509
- if [ "$update_env" != "true" ] && [ -n "$shared_worker_subdomain_default" ] && ! is_placeholder "$shared_worker_subdomain_default"; then
1510
- echo -e "${GREEN}Current value: $shared_worker_subdomain_default${NC}"
1511
- read -p "New value (or press Enter to keep current): " shared_worker_subdomain_input
1512
- shared_worker_subdomain_input=$(strip_carriage_returns "$shared_worker_subdomain_input")
1513
-
1514
- if [ -z "$shared_worker_subdomain_input" ]; then
1515
- shared_worker_subdomain="$shared_worker_subdomain_default"
1516
- else
1517
- shared_worker_subdomain="$shared_worker_subdomain_input"
1518
- fi
1519
- else
1520
- read -p "Enter shared worker-subdomain (e.g., team-name.workers.dev): " shared_worker_subdomain_input
1521
- shared_worker_subdomain_input=$(strip_carriage_returns "$shared_worker_subdomain_input")
1522
- shared_worker_subdomain="$shared_worker_subdomain_input"
1523
- fi
1524
-
1525
- if [ -z "$shared_worker_subdomain" ] || is_placeholder "$shared_worker_subdomain"; then
1526
- echo -e "${RED}❌ shared worker-subdomain is required and cannot be a placeholder.${NC}"
1527
- continue
1528
- fi
1529
-
1530
- shared_worker_subdomain=$(normalize_worker_subdomain_value "$shared_worker_subdomain")
1531
-
1532
- if [ -z "$shared_worker_subdomain" ] || ! is_valid_worker_subdomain "$shared_worker_subdomain"; then
1533
- echo -e "${RED}❌ shared worker-subdomain must be a valid hostname like team-name.workers.dev (letters, numbers, dashes, and dots).${NC}"
1534
- continue
1535
- fi
1536
-
1537
- echo -e "${GREEN}✅ Shared worker-subdomain set to: $shared_worker_subdomain${NC}"
1538
- echo ""
1539
- break
1540
- done
1541
-
1542
- prompt_for_var "KEYS_WORKER_NAME" "Keys worker name"
1543
- prompt_for_var "USER_WORKER_NAME" "User worker name"
1544
- prompt_for_var "DATA_WORKER_NAME" "Data worker name"
1545
- prompt_for_var "AUDIT_WORKER_NAME" "Audit worker name"
1546
- prompt_for_var "IMAGES_WORKER_NAME" "Images worker name"
1547
- prompt_for_var "PDF_WORKER_NAME" "PDF worker name"
1548
-
1549
- set_worker_domain_from_shared_subdomain "KEYS_WORKER_NAME" "KEYS_WORKER_DOMAIN"
1550
- set_worker_domain_from_shared_subdomain "USER_WORKER_NAME" "USER_WORKER_DOMAIN"
1551
- set_worker_domain_from_shared_subdomain "DATA_WORKER_NAME" "DATA_WORKER_DOMAIN"
1552
- set_worker_domain_from_shared_subdomain "AUDIT_WORKER_NAME" "AUDIT_WORKER_DOMAIN"
1553
- set_worker_domain_from_shared_subdomain "IMAGES_WORKER_NAME" "IMAGES_WORKER_DOMAIN"
1554
- set_worker_domain_from_shared_subdomain "PDF_WORKER_NAME" "PDF_WORKER_DOMAIN"
1555
- echo ""
1556
-
1557
- echo -e "${BLUE}🗄️ STORAGE CONFIGURATION${NC}"
1558
- echo "========================="
1559
- prompt_for_var "DATA_BUCKET_NAME" "Your R2 bucket name for case data storage"
1560
- prompt_for_var "AUDIT_BUCKET_NAME" "Your R2 bucket name for audit logs (separate from data bucket)"
1561
- prompt_for_var "FILES_BUCKET_NAME" "Your R2 bucket name for encrypted files storage"
1562
- prompt_for_var "KV_STORE_ID" "Your KV namespace ID (UUID format)"
1563
-
1564
- echo -e "${BLUE}🔐 SERVICE-SPECIFIC SECRETS${NC}"
1565
- echo "============================"
1566
- prompt_for_var "KEYS_AUTH" "Keys worker authentication token (generate with: openssl rand -hex 16)"
1567
- prompt_for_var "PDF_WORKER_AUTH" "PDF worker authentication token (generate with: openssl rand -hex 16)"
1568
- prompt_for_var "IMAGE_SIGNED_URL_SECRET" "Image signed URL secret (generate with: openssl rand -base64 48 | tr '+/' '-_' | tr -d '=')"
1569
- prompt_for_var "BROWSER_API_TOKEN" "Cloudflare Browser Rendering API token (for PDF Worker)"
1570
-
1571
- configure_manifest_signing_credentials
1572
- configure_export_encryption_credentials
1573
- configure_data_at_rest_encryption_credentials
1574
-
1575
- # Reload the updated .env file
1576
- source .env
1577
-
1578
- echo -e "${GREEN}🎉 Environment variables setup completed!${NC}"
1579
- echo -e "${BLUE}📄 All values saved to .env file${NC}"
1580
- }
1581
-
1582
217
  # Always prompt for secrets to ensure configuration
1583
218
  prompt_for_secrets
1584
219
 
1585
220
  # Validate after secrets have been configured
1586
221
  validate_required_vars
1587
222
 
1588
- # Function to replace variables in wrangler configuration files
1589
- update_wrangler_configs() {
1590
- echo -e "\n${BLUE}🔧 Updating wrangler configuration files...${NC}"
1591
-
1592
- local normalized_pages_custom_domain
1593
- local escaped_pages_custom_domain
1594
-
1595
- normalized_pages_custom_domain=$(normalize_domain_value "$PAGES_CUSTOM_DOMAIN")
1596
- PAGES_CUSTOM_DOMAIN="$normalized_pages_custom_domain"
1597
- export PAGES_CUSTOM_DOMAIN
1598
- write_env_var "PAGES_CUSTOM_DOMAIN" "$PAGES_CUSTOM_DOMAIN"
1599
- escaped_pages_custom_domain=$(escape_for_sed_replacement "$PAGES_CUSTOM_DOMAIN")
1600
-
1601
- # Audit Worker
1602
- if [ -f "workers/audit-worker/wrangler.jsonc" ]; then
1603
- echo -e "${YELLOW} Updating audit-worker/wrangler.jsonc...${NC}"
1604
- sed -i "s/\"AUDIT_WORKER_NAME\"/\"$AUDIT_WORKER_NAME\"/g" workers/audit-worker/wrangler.jsonc
1605
- sed -i "s/\"ACCOUNT_ID\"/\"$ACCOUNT_ID\"/g" workers/audit-worker/wrangler.jsonc
1606
- sed -i "s/\"AUDIT_BUCKET_NAME\"/\"$AUDIT_BUCKET_NAME\"/g" workers/audit-worker/wrangler.jsonc
1607
- echo -e "${GREEN} ✅ audit-worker configuration updated${NC}"
1608
- fi
1609
-
1610
- # Update audit-worker source file domain placeholders
1611
- if [ -f "workers/audit-worker/src/audit-worker.ts" ]; then
1612
- echo -e "${YELLOW} Updating audit-worker source placeholders...${NC}"
1613
- sed -i "s|'Access-Control-Allow-Origin': '[^']*'|'Access-Control-Allow-Origin': 'https://$escaped_pages_custom_domain'|g" workers/audit-worker/src/audit-worker.ts
1614
- echo -e "${GREEN} ✅ audit-worker source placeholders updated${NC}"
1615
- fi
1616
-
1617
- # Data Worker
1618
- if [ -f "workers/data-worker/wrangler.jsonc" ]; then
1619
- echo -e "${YELLOW} Updating data-worker/wrangler.jsonc...${NC}"
1620
- sed -i "s/\"DATA_WORKER_NAME\"/\"$DATA_WORKER_NAME\"/g" workers/data-worker/wrangler.jsonc
1621
- sed -i "s/\"ACCOUNT_ID\"/\"$ACCOUNT_ID\"/g" workers/data-worker/wrangler.jsonc
1622
- sed -i "s/\"DATA_BUCKET_NAME\"/\"$DATA_BUCKET_NAME\"/g" workers/data-worker/wrangler.jsonc
1623
- echo -e "${GREEN} ✅ data-worker configuration updated${NC}"
1624
- fi
1625
-
1626
- # Update data-worker source file domain placeholders
1627
- if [ -f "workers/data-worker/src/data-worker.ts" ]; then
1628
- echo -e "${YELLOW} Updating data-worker source placeholders...${NC}"
1629
- sed -i "s|'Access-Control-Allow-Origin': '[^']*'|'Access-Control-Allow-Origin': 'https://$escaped_pages_custom_domain'|g" workers/data-worker/src/data-worker.ts
1630
- echo -e "${GREEN} ✅ data-worker source placeholders updated${NC}"
1631
- fi
1632
-
1633
- # Image Worker
1634
- if [ -f "workers/image-worker/wrangler.jsonc" ]; then
1635
- echo -e "${YELLOW} Updating image-worker/wrangler.jsonc...${NC}"
1636
- sed -i "s/\"IMAGES_WORKER_NAME\"/\"$IMAGES_WORKER_NAME\"/g" workers/image-worker/wrangler.jsonc
1637
- sed -i "s/\"ACCOUNT_ID\"/\"$ACCOUNT_ID\"/g" workers/image-worker/wrangler.jsonc
1638
- sed -i "s/\"FILES_BUCKET_NAME\"/\"$FILES_BUCKET_NAME\"/g" workers/image-worker/wrangler.jsonc
1639
- echo -e "${GREEN} ✅ image-worker configuration updated${NC}"
1640
- fi
1641
-
1642
- # Update image-worker source file domain placeholders
1643
- if [ -f "workers/image-worker/src/image-worker.ts" ]; then
1644
- echo -e "${YELLOW} Updating image-worker source placeholders...${NC}"
1645
- sed -i "s|'Access-Control-Allow-Origin': '[^']*'|'Access-Control-Allow-Origin': 'https://$escaped_pages_custom_domain'|g" workers/image-worker/src/image-worker.ts
1646
- echo -e "${GREEN} ✅ image-worker source placeholders updated${NC}"
1647
- fi
1648
-
1649
- # Keys Worker
1650
- if [ -f "workers/keys-worker/wrangler.jsonc" ]; then
1651
- echo -e "${YELLOW} Updating keys-worker/wrangler.jsonc...${NC}"
1652
- sed -i "s/\"KEYS_WORKER_NAME\"/\"$KEYS_WORKER_NAME\"/g" workers/keys-worker/wrangler.jsonc
1653
- sed -i "s/\"ACCOUNT_ID\"/\"$ACCOUNT_ID\"/g" workers/keys-worker/wrangler.jsonc
1654
- echo -e "${GREEN} ✅ keys-worker configuration updated${NC}"
1655
- fi
1656
-
1657
- # Update keys-worker source file domain placeholders
1658
- if [ -f "workers/keys-worker/src/keys.ts" ]; then
1659
- echo -e "${YELLOW} Updating keys-worker source placeholders...${NC}"
1660
- sed -i "s|'Access-Control-Allow-Origin': '[^']*'|'Access-Control-Allow-Origin': 'https://$escaped_pages_custom_domain'|g" workers/keys-worker/src/keys.ts
1661
- echo -e "${GREEN} ✅ keys-worker source placeholders updated${NC}"
1662
- fi
1663
-
1664
- # PDF Worker
1665
- if [ -f "workers/pdf-worker/wrangler.jsonc" ]; then
1666
- echo -e "${YELLOW} Updating pdf-worker/wrangler.jsonc...${NC}"
1667
- sed -i "s/\"PDF_WORKER_NAME\"/\"$PDF_WORKER_NAME\"/g" workers/pdf-worker/wrangler.jsonc
1668
- sed -i "s/\"ACCOUNT_ID\"/\"$ACCOUNT_ID\"/g" workers/pdf-worker/wrangler.jsonc
1669
- echo -e "${GREEN} ✅ pdf-worker configuration updated${NC}"
1670
- fi
1671
-
1672
- # Update pdf-worker source file domain placeholders
1673
- if [ -f "workers/pdf-worker/src/pdf-worker.ts" ]; then
1674
- echo -e "${YELLOW} Updating pdf-worker source placeholders...${NC}"
1675
- sed -i "s|'Access-Control-Allow-Origin': '[^']*'|'Access-Control-Allow-Origin': 'https://$escaped_pages_custom_domain'|g" workers/pdf-worker/src/pdf-worker.ts
1676
- echo -e "${GREEN} ✅ pdf-worker source placeholders updated${NC}"
1677
- fi
1678
-
1679
- # User Worker
1680
- if [ -f "workers/user-worker/wrangler.jsonc" ]; then
1681
- echo -e "${YELLOW} Updating user-worker/wrangler.jsonc...${NC}"
1682
- sed -i "s/\"USER_WORKER_NAME\"/\"$USER_WORKER_NAME\"/g" workers/user-worker/wrangler.jsonc
1683
- sed -i "s/\"ACCOUNT_ID\"/\"$ACCOUNT_ID\"/g" workers/user-worker/wrangler.jsonc
1684
- sed -i "s/\"KV_STORE_ID\"/\"$KV_STORE_ID\"/g" workers/user-worker/wrangler.jsonc
1685
- echo -e "${GREEN} ✅ user-worker configuration updated${NC}"
1686
- fi
1687
-
1688
- # Update user-worker source file domain placeholders
1689
- if [ -f "workers/user-worker/src/user-worker.ts" ]; then
1690
- echo -e "${YELLOW} Updating user-worker source placeholders...${NC}"
1691
- sed -i "s|'Access-Control-Allow-Origin': '[^']*'|'Access-Control-Allow-Origin': 'https://$escaped_pages_custom_domain'|g" workers/user-worker/src/user-worker.ts
1692
- sed -i "s|'DATA_WORKER_DOMAIN'|'https://$DATA_WORKER_DOMAIN'|g" workers/user-worker/src/user-worker.ts
1693
- sed -i "s|'IMAGES_WORKER_DOMAIN'|'https://$IMAGES_WORKER_DOMAIN'|g" workers/user-worker/src/user-worker.ts
1694
- echo -e "${GREEN} ✅ user-worker source placeholders updated${NC}"
1695
- fi
1696
-
1697
- # Main wrangler.toml
1698
- if [ -f "wrangler.toml" ]; then
1699
- echo -e "${YELLOW} Updating wrangler.toml...${NC}"
1700
- sed -i "s/\"PAGES_PROJECT_NAME\"/\"$PAGES_PROJECT_NAME\"/g" wrangler.toml
1701
- echo -e "${GREEN} ✅ main wrangler.toml configuration updated${NC}"
1702
- fi
1703
-
1704
- # Update app configuration files
1705
- echo -e "${YELLOW} Updating app configuration files...${NC}"
1706
-
1707
- # Update app/config/config.json
1708
- if [ -f "app/config/config.json" ]; then
1709
- echo -e "${YELLOW} Updating app/config/config.json...${NC}"
1710
- local escaped_manifest_signing_key_id
1711
- local escaped_manifest_signing_public_key
1712
- local escaped_export_encryption_key_id
1713
- local escaped_export_encryption_public_key
1714
- escaped_manifest_signing_key_id=$(escape_for_sed_replacement "$MANIFEST_SIGNING_KEY_ID")
1715
- escaped_manifest_signing_public_key=$(escape_for_sed_replacement "$MANIFEST_SIGNING_PUBLIC_KEY")
1716
- escaped_export_encryption_key_id=$(escape_for_sed_replacement "$EXPORT_ENCRYPTION_KEY_ID")
1717
- escaped_export_encryption_public_key=$(escape_for_sed_replacement "$EXPORT_ENCRYPTION_PUBLIC_KEY")
1718
-
1719
- sed -i "s|\"url\": \"[^\"]*\"|\"url\": \"https://$escaped_pages_custom_domain\"|g" app/config/config.json
1720
- sed -i "s|\"MANIFEST_SIGNING_KEY_ID\"|\"$escaped_manifest_signing_key_id\"|g" app/config/config.json
1721
- sed -i "s|\"MANIFEST_SIGNING_PUBLIC_KEY\"|\"$escaped_manifest_signing_public_key\"|g" app/config/config.json
1722
- sed -i "s|\"EXPORT_ENCRYPTION_KEY_ID\"|\"$escaped_export_encryption_key_id\"|g" app/config/config.json
1723
- sed -i "s|\"EXPORT_ENCRYPTION_PUBLIC_KEY\"|\"$escaped_export_encryption_public_key\"|g" app/config/config.json
1724
- echo -e "${GREEN} ✅ app config.json updated${NC}"
1725
- fi
1726
-
1727
- # Update app/config/firebase.ts
1728
- if [ -f "app/config/firebase.ts" ]; then
1729
- echo -e "${YELLOW} Updating app/config/firebase.ts...${NC}"
1730
- sed -i "s|\"YOUR_FIREBASE_API_KEY\"|\"$API_KEY\"|g" app/config/firebase.ts
1731
- sed -i "s|\"YOUR_FIREBASE_AUTH_DOMAIN\"|\"$AUTH_DOMAIN\"|g" app/config/firebase.ts
1732
- sed -i "s|\"YOUR_FIREBASE_PROJECT_ID\"|\"$PROJECT_ID\"|g" app/config/firebase.ts
1733
- sed -i "s|\"YOUR_FIREBASE_STORAGE_BUCKET\"|\"$STORAGE_BUCKET\"|g" app/config/firebase.ts
1734
- sed -i "s|\"YOUR_FIREBASE_MESSAGING_SENDER_ID\"|\"$MESSAGING_SENDER_ID\"|g" app/config/firebase.ts
1735
- sed -i "s|\"YOUR_FIREBASE_APP_ID\"|\"$APP_ID\"|g" app/config/firebase.ts
1736
- sed -i "s|\"YOUR_FIREBASE_MEASUREMENT_ID\"|\"$MEASUREMENT_ID\"|g" app/config/firebase.ts
1737
- echo -e "${GREEN} ✅ app firebase.ts updated${NC}"
1738
- fi
1739
-
1740
- if [ -f "app/routes/auth/login.tsx" ]; then
1741
- echo -e "${YELLOW} Updating app/routes/auth/login.tsx...${NC}"
1742
- sed -i "s|^const APP_CANONICAL_ORIGIN = .*;|const APP_CANONICAL_ORIGIN = 'https://$escaped_pages_custom_domain';|g" app/routes/auth/login.tsx
1743
- echo -e "${GREEN} ✅ app login.tsx canonical origin updated${NC}"
1744
- fi
1745
-
1746
- echo -e "${GREEN}✅ All configuration files updated${NC}"
1747
- }
1748
223
 
1749
224
  # Update wrangler configurations
1750
225
  update_wrangler_configs