@striae-org/striae 3.2.2 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (82) hide show
  1. package/.env.example +1 -1
  2. package/app/components/actions/case-export/core-export.ts +5 -2
  3. package/app/components/actions/case-export/download-handlers.ts +51 -3
  4. package/app/components/actions/case-import/confirmation-import.ts +65 -40
  5. package/app/components/actions/case-import/confirmation-package.ts +86 -0
  6. package/app/components/actions/case-import/image-operations.ts +20 -49
  7. package/app/components/actions/case-import/index.ts +1 -0
  8. package/app/components/actions/case-import/orchestrator.ts +13 -3
  9. package/app/components/actions/case-import/storage-operations.ts +54 -89
  10. package/app/components/actions/case-import/validation.ts +7 -111
  11. package/app/components/actions/case-import/zip-processing.ts +44 -2
  12. package/app/components/actions/case-manage.ts +15 -27
  13. package/app/components/actions/confirm-export.ts +44 -13
  14. package/app/components/actions/generate-pdf.ts +3 -7
  15. package/app/components/actions/image-manage.ts +63 -129
  16. package/app/components/button/button.module.css +12 -8
  17. package/app/components/form/form-button.tsx +1 -1
  18. package/app/components/form/form.module.css +9 -0
  19. package/app/components/public-signing-key-modal/public-signing-key-modal.module.css +163 -49
  20. package/app/components/public-signing-key-modal/public-signing-key-modal.tsx +365 -88
  21. package/app/components/sidebar/case-export/case-export.tsx +13 -60
  22. package/app/components/sidebar/case-import/case-import.tsx +18 -6
  23. package/app/components/sidebar/case-import/hooks/useFilePreview.ts +6 -4
  24. package/app/components/sidebar/case-import/utils/file-validation.ts +57 -2
  25. package/app/components/sidebar/cases/case-sidebar.tsx +122 -52
  26. package/app/components/sidebar/cases/cases.module.css +101 -18
  27. package/app/components/sidebar/notes/notes.module.css +33 -13
  28. package/app/components/sidebar/sidebar.module.css +0 -2
  29. package/app/components/user/delete-account.tsx +7 -7
  30. package/app/components/user/manage-profile.tsx +1 -1
  31. package/app/components/user/mfa-phone-update.tsx +15 -12
  32. package/app/config-example/config.json +2 -8
  33. package/app/hooks/useInactivityTimeout.ts +2 -5
  34. package/app/root.tsx +96 -65
  35. package/app/routes/auth/login.tsx +132 -11
  36. package/app/routes/auth/route.ts +4 -3
  37. package/app/routes/striae/striae.tsx +4 -8
  38. package/app/services/audit/audit-api-client.ts +40 -0
  39. package/app/services/audit/audit-worker-client.ts +14 -17
  40. package/app/styles/root.module.css +13 -101
  41. package/app/tailwind.css +9 -2
  42. package/app/utils/SHA256.ts +5 -1
  43. package/app/utils/auth.ts +5 -32
  44. package/app/utils/confirmation-signature.ts +5 -1
  45. package/app/utils/data-api-client.ts +43 -0
  46. package/app/utils/data-operations.ts +59 -75
  47. package/app/utils/export-verification.ts +353 -0
  48. package/app/utils/image-api-client.ts +130 -0
  49. package/app/utils/pdf-api-client.ts +43 -0
  50. package/app/utils/permissions.ts +10 -23
  51. package/app/utils/signature-utils.ts +74 -4
  52. package/app/utils/user-api-client.ts +90 -0
  53. package/functions/api/_shared/firebase-auth.ts +255 -0
  54. package/functions/api/audit/[[path]].ts +150 -0
  55. package/functions/api/data/[[path]].ts +141 -0
  56. package/functions/api/image/[[path]].ts +127 -0
  57. package/functions/api/pdf/[[path]].ts +110 -0
  58. package/functions/api/user/[[path]].ts +196 -0
  59. package/package.json +8 -4
  60. package/public/favicon.ico +0 -0
  61. package/public/icon-256.png +0 -0
  62. package/public/icon-512.png +0 -0
  63. package/public/manifest.json +39 -0
  64. package/public/shortcut.png +0 -0
  65. package/public/social-image.png +0 -0
  66. package/react-router.config.ts +5 -0
  67. package/scripts/deploy-all.sh +22 -8
  68. package/scripts/deploy-config.sh +143 -148
  69. package/scripts/deploy-pages-secrets.sh +231 -0
  70. package/scripts/deploy-worker-secrets.sh +1 -1
  71. package/workers/audit-worker/wrangler.jsonc.example +1 -8
  72. package/workers/data-worker/wrangler.jsonc.example +1 -8
  73. package/workers/image-worker/wrangler.jsonc.example +1 -8
  74. package/workers/keys-worker/wrangler.jsonc.example +2 -9
  75. package/workers/pdf-worker/scripts/generate-assets.js +94 -0
  76. package/workers/pdf-worker/src/assets/icon-256.png +0 -0
  77. package/workers/pdf-worker/wrangler.jsonc.example +1 -8
  78. package/workers/user-worker/src/user-worker.example.ts +121 -41
  79. package/workers/user-worker/wrangler.jsonc.example +1 -8
  80. package/wrangler.toml.example +1 -1
  81. package/app/styles/legal-pages.module.css +0 -113
  82. package/public/favicon.svg +0 -9
@@ -208,44 +208,10 @@ read_env_var_from_file() {
208
208
  ' "$env_file"
209
209
  }
210
210
 
211
- worker_domain_wrangler_path() {
212
- case "$1" in
213
- KEYS_WORKER_DOMAIN)
214
- printf '%s' "workers/keys-worker/wrangler.jsonc"
215
- ;;
216
- USER_WORKER_DOMAIN)
217
- printf '%s' "workers/user-worker/wrangler.jsonc"
218
- ;;
219
- DATA_WORKER_DOMAIN)
220
- printf '%s' "workers/data-worker/wrangler.jsonc"
221
- ;;
222
- AUDIT_WORKER_DOMAIN)
223
- printf '%s' "workers/audit-worker/wrangler.jsonc"
224
- ;;
225
- IMAGES_WORKER_DOMAIN)
226
- printf '%s' "workers/image-worker/wrangler.jsonc"
227
- ;;
228
- PDF_WORKER_DOMAIN)
229
- printf '%s' "workers/pdf-worker/wrangler.jsonc"
230
- ;;
231
- esac
232
- }
233
-
234
- read_worker_domain_from_wrangler() {
235
- local wrangler_file=$1
236
-
237
- if [ ! -f "$wrangler_file" ]; then
238
- return 0
239
- fi
240
-
241
- sed -n 's/.*"pattern"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' "$wrangler_file" | head -n 1
242
- }
243
-
244
211
  resolve_existing_domain_value() {
245
212
  local var_name=$1
246
213
  local current_value=$2
247
214
  local preserved_value=""
248
- local wrangler_file=""
249
215
 
250
216
  current_value=$(normalize_domain_value "$current_value")
251
217
 
@@ -272,24 +238,6 @@ resolve_existing_domain_value() {
272
238
  fi
273
239
  fi
274
240
 
275
- if [[ "$var_name" == *_WORKER_DOMAIN ]]; then
276
- wrangler_file=$(worker_domain_wrangler_path "$var_name")
277
-
278
- if [ -n "$wrangler_file" ] && [ -f "$wrangler_file" ]; then
279
- preserved_value=$(read_worker_domain_from_wrangler "$wrangler_file")
280
- preserved_value=$(normalize_domain_value "$preserved_value")
281
-
282
- if [ "$preserved_value" = "$var_name" ]; then
283
- preserved_value=""
284
- fi
285
-
286
- if [ -n "$preserved_value" ] && ! is_placeholder "$preserved_value"; then
287
- printf '%s' "$preserved_value"
288
- return 0
289
- fi
290
- fi
291
- fi
292
-
293
241
  printf '%s' "$current_value"
294
242
  }
295
243
 
@@ -297,25 +245,52 @@ generate_worker_subdomain_label() {
297
245
  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
298
246
  }
299
247
 
300
- generate_worker_subdomain() {
301
- local pages_domain=$1
302
- local subdomain_label=""
248
+ worker_name_var_for_domain_var() {
249
+ case "$1" in
250
+ KEYS_WORKER_DOMAIN)
251
+ printf '%s' "KEYS_WORKER_NAME"
252
+ ;;
253
+ USER_WORKER_DOMAIN)
254
+ printf '%s' "USER_WORKER_NAME"
255
+ ;;
256
+ DATA_WORKER_DOMAIN)
257
+ printf '%s' "DATA_WORKER_NAME"
258
+ ;;
259
+ AUDIT_WORKER_DOMAIN)
260
+ printf '%s' "AUDIT_WORKER_NAME"
261
+ ;;
262
+ IMAGES_WORKER_DOMAIN)
263
+ printf '%s' "IMAGES_WORKER_NAME"
264
+ ;;
265
+ PDF_WORKER_DOMAIN)
266
+ printf '%s' "PDF_WORKER_NAME"
267
+ ;;
268
+ *)
269
+ printf '%s' ""
270
+ ;;
271
+ esac
272
+ }
303
273
 
304
- pages_domain=$(normalize_domain_value "$pages_domain")
274
+ compose_worker_domain() {
275
+ local worker_name=$1
276
+ local worker_subdomain=$2
305
277
 
306
- if [ -z "$pages_domain" ] || is_placeholder "$pages_domain"; then
307
- return 1
308
- fi
278
+ worker_name=$(normalize_domain_value "$worker_name")
279
+ worker_subdomain=$(normalize_domain_value "$worker_subdomain")
280
+ worker_name="${worker_name#.}"
281
+ worker_name="${worker_name%.}"
282
+ worker_subdomain="${worker_subdomain#.}"
283
+ worker_subdomain="${worker_subdomain%.}"
309
284
 
310
- if ! subdomain_label=$(generate_worker_subdomain_label); then
285
+ if [ -z "$worker_name" ] || [ -z "$worker_subdomain" ]; then
311
286
  return 1
312
287
  fi
313
288
 
314
- if [ ${#subdomain_label} -ne 10 ]; then
289
+ if [[ "$worker_name" == *.* ]] || [[ "$worker_name" == */* ]] || [[ "$worker_subdomain" == */* ]]; then
315
290
  return 1
316
291
  fi
317
292
 
318
- printf '%s.%s' "$subdomain_label" "$pages_domain"
293
+ printf '%s.%s' "$worker_name" "$worker_subdomain"
319
294
  }
320
295
 
321
296
  write_env_var() {
@@ -482,11 +457,17 @@ configure_manifest_signing_credentials() {
482
457
  echo -e "${GREEN}✅ Keeping current manifest signing key pair${NC}"
483
458
  fi
484
459
 
485
- if [ -z "$MANIFEST_SIGNING_KEY_ID" ] || is_placeholder "$MANIFEST_SIGNING_KEY_ID"; then
486
- MANIFEST_SIGNING_KEY_ID="forensic-signing-key-v1"
460
+ if [ -z "$MANIFEST_SIGNING_KEY_ID" ] || is_placeholder "$MANIFEST_SIGNING_KEY_ID" || [ "$should_generate" = "true" ]; then
461
+ local generated_key_id
462
+ generated_key_id=$(generate_worker_subdomain_label)
463
+ if [ -z "$generated_key_id" ] || [ ${#generated_key_id} -ne 10 ]; then
464
+ echo -e "${RED}❌ Error: Failed to generate MANIFEST_SIGNING_KEY_ID${NC}"
465
+ exit 1
466
+ fi
467
+ MANIFEST_SIGNING_KEY_ID="$generated_key_id"
487
468
  export MANIFEST_SIGNING_KEY_ID
488
469
  write_env_var "MANIFEST_SIGNING_KEY_ID" "$MANIFEST_SIGNING_KEY_ID"
489
- echo -e "${GREEN}✅ MANIFEST_SIGNING_KEY_ID set to default: $MANIFEST_SIGNING_KEY_ID${NC}"
470
+ echo -e "${GREEN}✅ MANIFEST_SIGNING_KEY_ID generated: $MANIFEST_SIGNING_KEY_ID${NC}"
490
471
  else
491
472
  echo -e "${GREEN}✅ MANIFEST_SIGNING_KEY_ID: $MANIFEST_SIGNING_KEY_ID${NC}"
492
473
  fi
@@ -527,7 +508,7 @@ required_vars=(
527
508
  "IMAGES_WORKER_NAME"
528
509
  "PDF_WORKER_NAME"
529
510
 
530
- # Worker Domains (required for config replacement)
511
+ # Worker Domains (required for proxy/env secrets and worker fallbacks)
531
512
  "KEYS_WORKER_DOMAIN"
532
513
  "USER_WORKER_DOMAIN"
533
514
  "DATA_WORKER_DOMAIN"
@@ -720,25 +701,12 @@ validate_generated_configs() {
720
701
  assert_contains_literal "workers/image-worker/wrangler.jsonc" "$ACCOUNT_ID" "ACCOUNT_ID missing in image worker config"
721
702
  assert_contains_literal "workers/pdf-worker/wrangler.jsonc" "$ACCOUNT_ID" "ACCOUNT_ID missing in pdf worker config"
722
703
 
723
- assert_contains_literal "workers/keys-worker/wrangler.jsonc" "$KEYS_WORKER_DOMAIN" "KEYS_WORKER_DOMAIN missing in keys worker config"
724
- assert_contains_literal "workers/user-worker/wrangler.jsonc" "$USER_WORKER_DOMAIN" "USER_WORKER_DOMAIN missing in user worker config"
725
- assert_contains_literal "workers/data-worker/wrangler.jsonc" "$DATA_WORKER_DOMAIN" "DATA_WORKER_DOMAIN missing in data worker config"
726
- assert_contains_literal "workers/audit-worker/wrangler.jsonc" "$AUDIT_WORKER_DOMAIN" "AUDIT_WORKER_DOMAIN missing in audit worker config"
727
- assert_contains_literal "workers/image-worker/wrangler.jsonc" "$IMAGES_WORKER_DOMAIN" "IMAGES_WORKER_DOMAIN missing in image worker config"
728
- assert_contains_literal "workers/pdf-worker/wrangler.jsonc" "$PDF_WORKER_DOMAIN" "PDF_WORKER_DOMAIN missing in pdf worker config"
729
-
730
704
  assert_contains_literal "workers/data-worker/wrangler.jsonc" "$DATA_BUCKET_NAME" "DATA_BUCKET_NAME missing in data worker config"
731
705
  assert_contains_literal "workers/audit-worker/wrangler.jsonc" "$AUDIT_BUCKET_NAME" "AUDIT_BUCKET_NAME missing in audit worker config"
732
706
  assert_contains_literal "workers/user-worker/wrangler.jsonc" "$KV_STORE_ID" "KV_STORE_ID missing in user worker config"
733
707
 
734
708
  assert_contains_literal "app/config/config.json" "https://$PAGES_CUSTOM_DOMAIN" "PAGES_CUSTOM_DOMAIN missing in app/config/config.json"
735
- assert_contains_literal "app/config/config.json" "https://$DATA_WORKER_DOMAIN" "DATA_WORKER_DOMAIN missing in app/config/config.json"
736
- assert_contains_literal "app/config/config.json" "https://$AUDIT_WORKER_DOMAIN" "AUDIT_WORKER_DOMAIN missing in app/config/config.json"
737
- assert_contains_literal "app/config/config.json" "https://$KEYS_WORKER_DOMAIN" "KEYS_WORKER_DOMAIN missing in app/config/config.json"
738
- assert_contains_literal "app/config/config.json" "https://$IMAGES_WORKER_DOMAIN" "IMAGES_WORKER_DOMAIN missing in app/config/config.json"
739
- assert_contains_literal "app/config/config.json" "https://$USER_WORKER_DOMAIN" "USER_WORKER_DOMAIN missing in app/config/config.json"
740
- assert_contains_literal "app/config/config.json" "https://$PDF_WORKER_DOMAIN" "PDF_WORKER_DOMAIN missing in app/config/config.json"
741
- assert_contains_literal "app/config/config.json" "$KEYS_AUTH" "KEYS_AUTH missing in app/config/config.json"
709
+ assert_contains_literal "app/config/config.json" "$ACCOUNT_HASH" "ACCOUNT_HASH missing in app/config/config.json"
742
710
 
743
711
  assert_contains_literal "app/config/firebase.ts" "$API_KEY" "API_KEY missing in app/config/firebase.ts"
744
712
  assert_contains_literal "app/config/firebase.ts" "$AUTH_DOMAIN" "AUTH_DOMAIN missing in app/config/firebase.ts"
@@ -754,11 +722,9 @@ validate_generated_configs() {
754
722
  assert_contains_literal "workers/keys-worker/src/keys.ts" "https://$PAGES_CUSTOM_DOMAIN" "PAGES_CUSTOM_DOMAIN missing in keys-worker source"
755
723
  assert_contains_literal "workers/pdf-worker/src/pdf-worker.ts" "https://$PAGES_CUSTOM_DOMAIN" "PAGES_CUSTOM_DOMAIN missing in pdf-worker source"
756
724
  assert_contains_literal "workers/user-worker/src/user-worker.ts" "https://$PAGES_CUSTOM_DOMAIN" "PAGES_CUSTOM_DOMAIN missing in user-worker source"
757
- assert_contains_literal "workers/user-worker/src/user-worker.ts" "https://$DATA_WORKER_DOMAIN" "DATA_WORKER_DOMAIN missing in user-worker source"
758
- assert_contains_literal "workers/user-worker/src/user-worker.ts" "https://$IMAGES_WORKER_DOMAIN" "IMAGES_WORKER_DOMAIN missing in user-worker source"
759
725
 
760
726
  local placeholder_pattern
761
- 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|KV_STORE_ID|DATA_WORKER_CUSTOM_DOMAIN|AUDIT_WORKER_CUSTOM_DOMAIN|KEYS_WORKER_CUSTOM_DOMAIN|IMAGE_WORKER_CUSTOM_DOMAIN|USER_WORKER_CUSTOM_DOMAIN|PDF_WORKER_CUSTOM_DOMAIN|YOUR_KEYS_AUTH_TOKEN|MANIFEST_SIGNING_KEY_ID|MANIFEST_SIGNING_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)')"
727
+ 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|KV_STORE_ID|ACCOUNT_HASH|MANIFEST_SIGNING_KEY_ID|MANIFEST_SIGNING_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)')"
762
728
 
763
729
  local files_to_scan=(
764
730
  "wrangler.toml"
@@ -1074,67 +1040,106 @@ prompt_for_secrets() {
1074
1040
  fi
1075
1041
  fi
1076
1042
  elif [[ "$var_name" == *_WORKER_DOMAIN ]]; then
1077
- local pages_domain
1043
+ local worker_name_var
1044
+ local worker_name_current=""
1045
+ local worker_name_input=""
1046
+ local worker_subdomain_input=""
1047
+ local inferred_subdomain=""
1078
1048
  local domain_choice=""
1049
+ local composed_domain=""
1079
1050
 
1080
- pages_domain=$(resolve_existing_domain_value "PAGES_CUSTOM_DOMAIN" "$PAGES_CUSTOM_DOMAIN")
1051
+ worker_name_var=$(worker_name_var_for_domain_var "$var_name")
1052
+ worker_name_current=$(strip_carriage_returns "${!worker_name_var}")
1053
+
1054
+ if [ -n "$worker_name_current" ] && ! is_placeholder "$worker_name_current" && [ -n "$current_value" ] && ! is_placeholder "$current_value"; then
1055
+ case "$current_value" in
1056
+ "$worker_name_current".*)
1057
+ inferred_subdomain="${current_value#${worker_name_current}.}"
1058
+ ;;
1059
+ esac
1060
+ fi
1081
1061
 
1082
1062
  echo -e "${BLUE}$var_name${NC}"
1083
1063
  echo -e "${YELLOW}$description${NC}"
1084
1064
 
1085
- if [ -n "$current_value" ] && ! is_placeholder "$current_value"; then
1086
- echo -e "${GREEN}Current value: $current_value${NC}"
1087
- else
1088
- while true; do
1089
- if [ -n "$pages_domain" ] && ! is_placeholder "$pages_domain"; then
1090
- echo -e "${YELLOW}Choose how to configure this worker domain:${NC}"
1091
- echo " A) Auto-generate a 10-character subdomain of $pages_domain"
1092
- echo " M) Manually enter the worker domain"
1093
- read -p "Selection (A/M): " domain_choice
1094
- domain_choice=$(strip_carriage_returns "$domain_choice")
1095
- domain_choice=$(printf '%s' "$domain_choice" | tr '[:upper:]' '[:lower:]')
1096
-
1097
- if [ -z "$domain_choice" ] || [ "$domain_choice" = "a" ]; then
1098
- new_value=$(generate_worker_subdomain "$pages_domain" || echo "")
1099
-
1100
- if [ -n "$new_value" ]; then
1101
- echo -e "${GREEN}✅ Generated worker domain: $new_value${NC}"
1102
- break
1103
- fi
1104
-
1105
- echo -e "${RED}❌ Failed to auto-generate a worker subdomain. Please try manual entry.${NC}"
1106
- continue
1107
- fi
1065
+ while true; do
1066
+ if [ "$update_env" != "true" ] && [ -n "$current_value" ] && ! is_placeholder "$current_value"; then
1067
+ echo -e "${GREEN}Current value: $current_value${NC}"
1068
+ read -p "Press Enter to keep current, or type 'y' to rebuild from worker-name and worker-subdomain: " domain_choice
1069
+ domain_choice=$(strip_carriage_returns "$domain_choice")
1108
1070
 
1109
- if [ "$domain_choice" = "m" ]; then
1110
- read -p "Enter value: " new_value
1111
- new_value=$(strip_carriage_returns "$new_value")
1112
- else
1113
- echo -e "${RED}❌ Please choose 'A' for automatic or 'M' for manual.${NC}"
1114
- continue
1115
- fi
1116
- else
1117
- echo -e "${YELLOW}PAGES_CUSTOM_DOMAIN is required for auto-generated worker subdomains.${NC}"
1118
- read -p "Enter value: " new_value
1119
- new_value=$(strip_carriage_returns "$new_value")
1071
+ if [ -z "$domain_choice" ]; then
1072
+ new_value=""
1073
+ break
1120
1074
  fi
1121
1075
 
1122
- if [ -z "$new_value" ]; then
1123
- echo -e "${RED}❌ A value is required.${NC}"
1076
+ if [ "$domain_choice" != "y" ] && [ "$domain_choice" != "Y" ]; then
1077
+ echo -e "${RED}❌ Please press Enter to keep current or type 'y' to rebuild.${NC}"
1124
1078
  continue
1125
1079
  fi
1080
+ fi
1126
1081
 
1127
- new_value=$(normalize_domain_value "$new_value")
1082
+ if [ -n "$worker_name_current" ] && ! is_placeholder "$worker_name_current"; then
1083
+ read -p "Prompt: worker-name [$worker_name_current]: " worker_name_input
1084
+ worker_name_input=$(strip_carriage_returns "$worker_name_input")
1085
+ if [ -z "$worker_name_input" ]; then
1086
+ worker_name_input="$worker_name_current"
1087
+ fi
1088
+ else
1089
+ read -p "Prompt: worker-name: " worker_name_input
1090
+ worker_name_input=$(strip_carriage_returns "$worker_name_input")
1091
+ fi
1128
1092
 
1129
- if is_placeholder "$new_value"; then
1130
- echo -e "${RED}❌ Placeholder values are not allowed.${NC}"
1131
- new_value=""
1132
- continue
1093
+ if [ -z "$worker_name_input" ] || is_placeholder "$worker_name_input"; then
1094
+ echo -e "${RED}❌ worker-name is required and cannot be a placeholder.${NC}"
1095
+ continue
1096
+ fi
1097
+
1098
+ worker_name_input=$(normalize_domain_value "$worker_name_input")
1099
+ worker_name_input="${worker_name_input#.}"
1100
+ worker_name_input="${worker_name_input%.}"
1101
+
1102
+ if [[ "$worker_name_input" == *.* ]] || [[ "$worker_name_input" == */* ]]; then
1103
+ echo -e "${RED}❌ worker-name must be a single hostname label (for example: striae-dev-data).${NC}"
1104
+ continue
1105
+ fi
1106
+
1107
+ if [ -n "$inferred_subdomain" ]; then
1108
+ read -p "Prompt: worker-subdomain [$inferred_subdomain]: " worker_subdomain_input
1109
+ worker_subdomain_input=$(strip_carriage_returns "$worker_subdomain_input")
1110
+ if [ -z "$worker_subdomain_input" ]; then
1111
+ worker_subdomain_input="$inferred_subdomain"
1133
1112
  fi
1113
+ else
1114
+ read -p "Prompt: worker-subdomain: " worker_subdomain_input
1115
+ worker_subdomain_input=$(strip_carriage_returns "$worker_subdomain_input")
1116
+ fi
1134
1117
 
1135
- break
1136
- done
1137
- fi
1118
+ if [ -z "$worker_subdomain_input" ] || is_placeholder "$worker_subdomain_input"; then
1119
+ echo -e "${RED}❌ worker-subdomain is required and cannot be a placeholder.${NC}"
1120
+ continue
1121
+ fi
1122
+
1123
+ worker_subdomain_input=$(normalize_domain_value "$worker_subdomain_input")
1124
+ worker_subdomain_input="${worker_subdomain_input#.}"
1125
+ worker_subdomain_input="${worker_subdomain_input%.}"
1126
+
1127
+ composed_domain=$(compose_worker_domain "$worker_name_input" "$worker_subdomain_input" || echo "")
1128
+ if [ -z "$composed_domain" ]; then
1129
+ echo -e "${RED}❌ Invalid worker-name/worker-subdomain combination.${NC}"
1130
+ continue
1131
+ fi
1132
+
1133
+ if [ -n "$worker_name_var" ]; then
1134
+ write_env_var "$worker_name_var" "$worker_name_input"
1135
+ export "$worker_name_var=$worker_name_input"
1136
+ worker_name_current="$worker_name_input"
1137
+ fi
1138
+
1139
+ new_value="$composed_domain"
1140
+ echo -e "${GREEN}Resulting worker domain: $new_value${NC}"
1141
+ break
1142
+ done
1138
1143
  else
1139
1144
  # Normal prompt for other variables
1140
1145
  echo -e "${BLUE}$var_name${NC}"
@@ -1221,17 +1226,17 @@ prompt_for_secrets() {
1221
1226
  echo -e "${BLUE}🔑 WORKER NAMES & DOMAINS${NC}"
1222
1227
  echo "========================="
1223
1228
  prompt_for_var "KEYS_WORKER_NAME" "Keys worker name"
1224
- prompt_for_var "KEYS_WORKER_DOMAIN" "Keys worker domain (e.g., keys.striae.org) - DO NOT include https://"
1229
+ prompt_for_var "KEYS_WORKER_DOMAIN" "Keys worker domain (format: {worker-name}.{worker-subdomain})"
1225
1230
  prompt_for_var "USER_WORKER_NAME" "User worker name"
1226
- prompt_for_var "USER_WORKER_DOMAIN" "User worker domain (e.g., users.striae.org) - DO NOT include https://"
1231
+ prompt_for_var "USER_WORKER_DOMAIN" "User worker domain (format: {worker-name}.{worker-subdomain})"
1227
1232
  prompt_for_var "DATA_WORKER_NAME" "Data worker name"
1228
- prompt_for_var "DATA_WORKER_DOMAIN" "Data worker domain (e.g., data.striae.org) - DO NOT include https://"
1233
+ prompt_for_var "DATA_WORKER_DOMAIN" "Data worker domain (format: {worker-name}.{worker-subdomain})"
1229
1234
  prompt_for_var "AUDIT_WORKER_NAME" "Audit worker name"
1230
- prompt_for_var "AUDIT_WORKER_DOMAIN" "Audit worker domain (e.g., audit.striae.org) - DO NOT include https://"
1235
+ prompt_for_var "AUDIT_WORKER_DOMAIN" "Audit worker domain (format: {worker-name}.{worker-subdomain})"
1231
1236
  prompt_for_var "IMAGES_WORKER_NAME" "Images worker name"
1232
- prompt_for_var "IMAGES_WORKER_DOMAIN" "Images worker domain (e.g., images.striae.org) - DO NOT include https://"
1237
+ prompt_for_var "IMAGES_WORKER_DOMAIN" "Images worker domain (format: {worker-name}.{worker-subdomain})"
1233
1238
  prompt_for_var "PDF_WORKER_NAME" "PDF worker name"
1234
- prompt_for_var "PDF_WORKER_DOMAIN" "PDF worker domain (e.g., pdf.striae.org) - DO NOT include https://"
1239
+ prompt_for_var "PDF_WORKER_DOMAIN" "PDF worker domain (format: {worker-name}.{worker-subdomain})"
1235
1240
 
1236
1241
  echo -e "${BLUE}🗄️ STORAGE CONFIGURATION${NC}"
1237
1242
  echo "========================="
@@ -1280,7 +1285,6 @@ update_wrangler_configs() {
1280
1285
  echo -e "${YELLOW} Updating audit-worker/wrangler.jsonc...${NC}"
1281
1286
  sed -i "s/\"AUDIT_WORKER_NAME\"/\"$AUDIT_WORKER_NAME\"/g" workers/audit-worker/wrangler.jsonc
1282
1287
  sed -i "s/\"ACCOUNT_ID\"/\"$ACCOUNT_ID\"/g" workers/audit-worker/wrangler.jsonc
1283
- sed -i "s/\"AUDIT_WORKER_DOMAIN\"/\"$AUDIT_WORKER_DOMAIN\"/g" workers/audit-worker/wrangler.jsonc
1284
1288
  sed -i "s/\"AUDIT_BUCKET_NAME\"/\"$AUDIT_BUCKET_NAME\"/g" workers/audit-worker/wrangler.jsonc
1285
1289
  echo -e "${GREEN} ✅ audit-worker configuration updated${NC}"
1286
1290
  fi
@@ -1297,7 +1301,6 @@ update_wrangler_configs() {
1297
1301
  echo -e "${YELLOW} Updating data-worker/wrangler.jsonc...${NC}"
1298
1302
  sed -i "s/\"DATA_WORKER_NAME\"/\"$DATA_WORKER_NAME\"/g" workers/data-worker/wrangler.jsonc
1299
1303
  sed -i "s/\"ACCOUNT_ID\"/\"$ACCOUNT_ID\"/g" workers/data-worker/wrangler.jsonc
1300
- sed -i "s/\"DATA_WORKER_DOMAIN\"/\"$DATA_WORKER_DOMAIN\"/g" workers/data-worker/wrangler.jsonc
1301
1304
  sed -i "s/\"DATA_BUCKET_NAME\"/\"$DATA_BUCKET_NAME\"/g" workers/data-worker/wrangler.jsonc
1302
1305
  echo -e "${GREEN} ✅ data-worker configuration updated${NC}"
1303
1306
  fi
@@ -1314,7 +1317,6 @@ update_wrangler_configs() {
1314
1317
  echo -e "${YELLOW} Updating image-worker/wrangler.jsonc...${NC}"
1315
1318
  sed -i "s/\"IMAGES_WORKER_NAME\"/\"$IMAGES_WORKER_NAME\"/g" workers/image-worker/wrangler.jsonc
1316
1319
  sed -i "s/\"ACCOUNT_ID\"/\"$ACCOUNT_ID\"/g" workers/image-worker/wrangler.jsonc
1317
- sed -i "s/\"IMAGES_WORKER_DOMAIN\"/\"$IMAGES_WORKER_DOMAIN\"/g" workers/image-worker/wrangler.jsonc
1318
1320
  echo -e "${GREEN} ✅ image-worker configuration updated${NC}"
1319
1321
  fi
1320
1322
 
@@ -1330,7 +1332,6 @@ update_wrangler_configs() {
1330
1332
  echo -e "${YELLOW} Updating keys-worker/wrangler.jsonc...${NC}"
1331
1333
  sed -i "s/\"KEYS_WORKER_NAME\"/\"$KEYS_WORKER_NAME\"/g" workers/keys-worker/wrangler.jsonc
1332
1334
  sed -i "s/\"ACCOUNT_ID\"/\"$ACCOUNT_ID\"/g" workers/keys-worker/wrangler.jsonc
1333
- sed -i "s/\"KEYS_WORKER_DOMAIN\"/\"$KEYS_WORKER_DOMAIN\"/g" workers/keys-worker/wrangler.jsonc
1334
1335
  echo -e "${GREEN} ✅ keys-worker configuration updated${NC}"
1335
1336
  fi
1336
1337
 
@@ -1346,7 +1347,6 @@ update_wrangler_configs() {
1346
1347
  echo -e "${YELLOW} Updating pdf-worker/wrangler.jsonc...${NC}"
1347
1348
  sed -i "s/\"PDF_WORKER_NAME\"/\"$PDF_WORKER_NAME\"/g" workers/pdf-worker/wrangler.jsonc
1348
1349
  sed -i "s/\"ACCOUNT_ID\"/\"$ACCOUNT_ID\"/g" workers/pdf-worker/wrangler.jsonc
1349
- sed -i "s/\"PDF_WORKER_DOMAIN\"/\"$PDF_WORKER_DOMAIN\"/g" workers/pdf-worker/wrangler.jsonc
1350
1350
  echo -e "${GREEN} ✅ pdf-worker configuration updated${NC}"
1351
1351
  fi
1352
1352
 
@@ -1362,7 +1362,6 @@ update_wrangler_configs() {
1362
1362
  echo -e "${YELLOW} Updating user-worker/wrangler.jsonc...${NC}"
1363
1363
  sed -i "s/\"USER_WORKER_NAME\"/\"$USER_WORKER_NAME\"/g" workers/user-worker/wrangler.jsonc
1364
1364
  sed -i "s/\"ACCOUNT_ID\"/\"$ACCOUNT_ID\"/g" workers/user-worker/wrangler.jsonc
1365
- sed -i "s/\"USER_WORKER_DOMAIN\"/\"$USER_WORKER_DOMAIN\"/g" workers/user-worker/wrangler.jsonc
1366
1365
  sed -i "s/\"KV_STORE_ID\"/\"$KV_STORE_ID\"/g" workers/user-worker/wrangler.jsonc
1367
1366
  echo -e "${GREEN} ✅ user-worker configuration updated${NC}"
1368
1367
  fi
@@ -1391,17 +1390,13 @@ update_wrangler_configs() {
1391
1390
  echo -e "${YELLOW} Updating app/config/config.json...${NC}"
1392
1391
  local escaped_manifest_signing_key_id
1393
1392
  local escaped_manifest_signing_public_key
1393
+ local escaped_account_hash
1394
1394
  escaped_manifest_signing_key_id=$(escape_for_sed_replacement "$MANIFEST_SIGNING_KEY_ID")
1395
1395
  escaped_manifest_signing_public_key=$(escape_for_sed_replacement "$MANIFEST_SIGNING_PUBLIC_KEY")
1396
+ escaped_account_hash=$(escape_for_sed_replacement "$ACCOUNT_HASH")
1396
1397
 
1397
1398
  sed -i "s|\"url\": \"[^\"]*\"|\"url\": \"https://$escaped_pages_custom_domain\"|g" app/config/config.json
1398
- sed -i "s|\"DATA_WORKER_CUSTOM_DOMAIN\"|\"https://$DATA_WORKER_DOMAIN\"|g" app/config/config.json
1399
- sed -i "s|\"AUDIT_WORKER_CUSTOM_DOMAIN\"|\"https://$AUDIT_WORKER_DOMAIN\"|g" app/config/config.json
1400
- sed -i "s|\"KEYS_WORKER_CUSTOM_DOMAIN\"|\"https://$KEYS_WORKER_DOMAIN\"|g" app/config/config.json
1401
- sed -i "s|\"IMAGE_WORKER_CUSTOM_DOMAIN\"|\"https://$IMAGES_WORKER_DOMAIN\"|g" app/config/config.json
1402
- sed -i "s|\"USER_WORKER_CUSTOM_DOMAIN\"|\"https://$USER_WORKER_DOMAIN\"|g" app/config/config.json
1403
- sed -i "s|\"PDF_WORKER_CUSTOM_DOMAIN\"|\"https://$PDF_WORKER_DOMAIN\"|g" app/config/config.json
1404
- sed -i "s|\"YOUR_KEYS_AUTH_TOKEN\"|\"$KEYS_AUTH\"|g" app/config/config.json
1399
+ sed -i "s|\"account_hash\": \"[^\"]*\"|\"account_hash\": \"$escaped_account_hash\"|g" app/config/config.json
1405
1400
  sed -i "s|\"MANIFEST_SIGNING_KEY_ID\"|\"$escaped_manifest_signing_key_id\"|g" app/config/config.json
1406
1401
  sed -i "s|\"MANIFEST_SIGNING_PUBLIC_KEY\"|\"$escaped_manifest_signing_public_key\"|g" app/config/config.json
1407
1402
  echo -e "${GREEN} ✅ app config.json updated${NC}"