@striae-org/striae 5.2.1 → 5.3.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 (117) hide show
  1. package/.env.example +2 -10
  2. package/README.md +5 -46
  3. package/app/components/actions/case-export/core-export.ts +5 -174
  4. package/app/components/actions/case-export/download-handlers.ts +84 -751
  5. package/app/components/actions/case-export/index.ts +6 -30
  6. package/app/components/actions/case-export/metadata-helpers.ts +0 -78
  7. package/app/components/actions/case-export/types-constants.ts +0 -43
  8. package/app/components/actions/case-import/confirmation-import.ts +75 -36
  9. package/app/components/actions/case-import/confirmation-package.ts +68 -1
  10. package/app/components/actions/case-import/index.ts +1 -1
  11. package/app/components/actions/case-import/orchestrator.ts +78 -53
  12. package/app/components/actions/case-import/zip-processing.ts +160 -330
  13. package/app/components/actions/generate-pdf.ts +3 -2
  14. package/app/components/audit/user-audit-viewer.tsx +0 -19
  15. package/app/components/audit/viewer/audit-viewer-header.tsx +0 -33
  16. package/app/components/navbar/case-modals/archive-case-modal.tsx +1 -1
  17. package/app/components/navbar/case-modals/export-case-modal.module.css +27 -0
  18. package/app/components/navbar/case-modals/export-case-modal.tsx +132 -0
  19. package/app/components/navbar/case-modals/export-confirmations-modal.module.css +24 -0
  20. package/app/components/navbar/case-modals/export-confirmations-modal.tsx +108 -0
  21. package/app/components/navbar/navbar.tsx +1 -1
  22. package/app/components/sidebar/case-import/case-import.module.css +35 -0
  23. package/app/components/sidebar/case-import/components/CasePreviewSection.tsx +51 -3
  24. package/app/components/sidebar/case-import/components/ConfirmationDialog.tsx +2 -4
  25. package/app/components/sidebar/case-import/components/ConfirmationPreviewSection.tsx +36 -5
  26. package/app/components/sidebar/case-import/hooks/useFilePreview.ts +5 -9
  27. package/app/components/sidebar/case-import/index.ts +1 -4
  28. package/app/components/sidebar/notes/class-details-shared.ts +2 -2
  29. package/app/components/toast/toast.module.css +36 -0
  30. package/app/components/toast/toast.tsx +6 -2
  31. package/app/components/user/manage-profile.tsx +4 -3
  32. package/app/config-example/config.json +1 -2
  33. package/app/root.tsx +0 -7
  34. package/app/routes/_index.tsx +1 -1
  35. package/app/routes/auth/login.example.tsx +22 -103
  36. package/app/routes/auth/login.tsx +22 -103
  37. package/app/routes/auth/route.ts +1 -1
  38. package/app/routes/striae/striae.tsx +117 -59
  39. package/app/services/firebase/index.ts +0 -3
  40. package/app/types/case.ts +1 -0
  41. package/app/types/export.ts +2 -2
  42. package/app/types/import.ts +10 -0
  43. package/app/utils/auth/index.ts +0 -1
  44. package/app/utils/data/permissions.ts +3 -2
  45. package/package.json +9 -16
  46. package/public/_headers +0 -4
  47. package/public/_routes.json +0 -1
  48. package/worker-configuration.d.ts +20 -17
  49. package/workers/audit-worker/src/audit-worker.example.ts +9 -806
  50. package/workers/audit-worker/src/config.ts +7 -0
  51. package/workers/audit-worker/src/crypto/data-at-rest.ts +410 -0
  52. package/workers/audit-worker/src/handlers/audit-routes.ts +125 -0
  53. package/workers/audit-worker/src/storage/audit-storage.ts +99 -0
  54. package/workers/audit-worker/src/types.ts +56 -0
  55. package/workers/audit-worker/worker-configuration.d.ts +1 -1
  56. package/workers/audit-worker/wrangler.jsonc.example +1 -1
  57. package/workers/data-worker/src/config.ts +11 -0
  58. package/workers/data-worker/src/data-worker.example.ts +21 -942
  59. package/workers/data-worker/src/handlers/decrypt-export.ts +118 -0
  60. package/workers/data-worker/src/handlers/signing.ts +174 -0
  61. package/workers/data-worker/src/handlers/storage-routes.ts +129 -0
  62. package/workers/data-worker/src/registry/key-registry.ts +368 -0
  63. package/workers/data-worker/src/types.ts +46 -0
  64. package/workers/data-worker/worker-configuration.d.ts +1 -1
  65. package/workers/data-worker/wrangler.jsonc.example +1 -1
  66. package/workers/image-worker/worker-configuration.d.ts +1 -1
  67. package/workers/image-worker/wrangler.jsonc.example +1 -1
  68. package/workers/pdf-worker/worker-configuration.d.ts +2 -3
  69. package/workers/pdf-worker/wrangler.jsonc.example +1 -1
  70. package/workers/user-worker/src/auth.ts +30 -0
  71. package/workers/user-worker/src/cleanup/account-deletion.ts +337 -0
  72. package/workers/user-worker/src/config.ts +4 -0
  73. package/workers/user-worker/src/encryption-utils.ts +25 -0
  74. package/workers/user-worker/src/firebase/admin.ts +152 -0
  75. package/workers/user-worker/src/handlers/user-routes.ts +242 -0
  76. package/workers/user-worker/src/registry/user-kv.ts +172 -0
  77. package/workers/user-worker/src/storage/user-records.ts +34 -0
  78. package/workers/user-worker/src/types.ts +106 -0
  79. package/workers/user-worker/src/user-worker.example.ts +18 -964
  80. package/workers/user-worker/worker-configuration.d.ts +4 -2
  81. package/workers/user-worker/wrangler.jsonc.example +12 -1
  82. package/wrangler.toml.example +1 -1
  83. package/app/components/actions/case-export/data-processing.ts +0 -223
  84. package/app/components/sidebar/case-export/case-export.module.css +0 -418
  85. package/app/components/sidebar/case-export/case-export.tsx +0 -310
  86. package/app/types/exceljs-bare.d.ts +0 -9
  87. package/app/utils/auth/auth.ts +0 -11
  88. package/public/.well-known/security.txt +0 -6
  89. package/public/favicon.ico +0 -0
  90. package/public/icon-256.png +0 -0
  91. package/public/icon-512.png +0 -0
  92. package/public/manifest.json +0 -39
  93. package/public/shortcut.png +0 -0
  94. package/public/social-image.png +0 -0
  95. package/public/vendor/exceljs.LICENSE +0 -22
  96. package/public/vendor/exceljs.bare.min.js +0 -45
  97. package/scripts/deploy-all.sh +0 -166
  98. package/scripts/deploy-config/modules/env-utils.sh +0 -322
  99. package/scripts/deploy-config/modules/keys.sh +0 -404
  100. package/scripts/deploy-config/modules/prompt.sh +0 -372
  101. package/scripts/deploy-config/modules/scaffolding.sh +0 -344
  102. package/scripts/deploy-config/modules/validation.sh +0 -365
  103. package/scripts/deploy-config.sh +0 -236
  104. package/scripts/deploy-pages-secrets.sh +0 -231
  105. package/scripts/deploy-pages.sh +0 -34
  106. package/scripts/deploy-primershear-emails.sh +0 -167
  107. package/scripts/deploy-worker-secrets.sh +0 -374
  108. package/scripts/dev.cjs +0 -23
  109. package/scripts/install-workers.sh +0 -88
  110. package/scripts/run-eslint.cjs +0 -43
  111. package/scripts/update-compatibility-dates.cjs +0 -124
  112. package/scripts/update-markdown-versions.cjs +0 -43
  113. package/workers/keys-worker/package.json +0 -18
  114. package/workers/keys-worker/src/keys.example.ts +0 -67
  115. package/workers/keys-worker/src/keys.ts +0 -67
  116. package/workers/keys-worker/worker-configuration.d.ts +0 -7447
  117. package/workers/keys-worker/wrangler.jsonc.example +0 -15
@@ -1,166 +0,0 @@
1
- #!/bin/bash
2
-
3
- # ======================================
4
- # STRIAE COMPLETE DEPLOYMENT SCRIPT
5
- # ======================================
6
- # This script deploys the entire Striae application:
7
- # 1. Configuration setup (copy configs, replace placeholders)
8
- # 2. Worker dependencies installation
9
- # 3. Workers (all 7 workers)
10
- # 4. Worker secrets/environment variables
11
- # 5. Pages secrets/environment variables
12
- # 6. Pages (frontend)
13
-
14
- set -e
15
- set -o pipefail
16
-
17
- # Colors for output
18
- RED='\033[0;31m'
19
- GREEN='\033[0;32m'
20
- YELLOW='\033[1;33m'
21
- BLUE='\033[0;34m'
22
- PURPLE='\033[0;35m'
23
- NC='\033[0m' # No Color
24
-
25
- echo -e "${BLUE}🚀 Striae Complete Deployment Script${NC}"
26
- echo "======================================"
27
- echo ""
28
-
29
- # Get the script directory
30
- SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
31
- PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
32
- cd "$PROJECT_ROOT"
33
-
34
- trap 'echo -e "\n${RED}❌ deploy-all.sh failed near line ${LINENO}${NC}"' ERR
35
-
36
- require_command() {
37
- local cmd=$1
38
- if ! command -v "$cmd" > /dev/null 2>&1; then
39
- echo -e "${RED}❌ Error: required command '$cmd' is not installed or not in PATH${NC}"
40
- exit 1
41
- fi
42
- }
43
-
44
- assert_file_exists() {
45
- local file_path=$1
46
- if [ ! -f "$file_path" ]; then
47
- echo -e "${RED}❌ Error: required file is missing: $file_path${NC}"
48
- exit 1
49
- fi
50
- }
51
-
52
- run_config_checkpoint() {
53
- echo -e "${YELLOW}🧪 Running configuration checkpoint validation...${NC}"
54
- if ! bash "$SCRIPT_DIR/deploy-config.sh" --validate-only; then
55
- echo -e "${RED}❌ Configuration checkpoint validation failed!${NC}"
56
- exit 1
57
- fi
58
- echo -e "${GREEN}✅ Configuration checkpoint validation passed${NC}"
59
- }
60
-
61
- echo -e "${BLUE}🔍 Running deployment preflight checks...${NC}"
62
- require_command bash
63
- require_command node
64
- require_command npm
65
- require_command wrangler
66
-
67
- assert_file_exists "$SCRIPT_DIR/deploy-config.sh"
68
- assert_file_exists "$SCRIPT_DIR/install-workers.sh"
69
- assert_file_exists "$SCRIPT_DIR/deploy-worker-secrets.sh"
70
- assert_file_exists "$SCRIPT_DIR/deploy-pages-secrets.sh"
71
- assert_file_exists "package.json"
72
-
73
- if [ ! -f ".env" ] && [ ! -f ".env.example" ]; then
74
- echo -e "${RED}❌ Error: neither .env nor .env.example was found in project root${NC}"
75
- exit 1
76
- fi
77
-
78
- echo -e "${GREEN}✅ Preflight checks passed${NC}"
79
- echo ""
80
-
81
- # Step 1: Configuration Setup
82
- echo -e "${PURPLE}Step 1/6: Configuration Setup${NC}"
83
- echo "------------------------------"
84
- echo -e "${YELLOW}⚙️ Setting up configuration files and replacing placeholders...${NC}"
85
- if ! bash "$SCRIPT_DIR/deploy-config.sh"; then
86
- echo -e "${RED}❌ Configuration setup failed!${NC}"
87
- echo -e "${YELLOW}Please check your .env file and configuration before proceeding.${NC}"
88
- exit 1
89
- fi
90
- echo -e "${GREEN}✅ Configuration setup completed successfully${NC}"
91
- run_config_checkpoint
92
- echo ""
93
-
94
- # Step 2: Install Worker Dependencies
95
- echo -e "${PURPLE}Step 2/6: Installing Worker Dependencies${NC}"
96
- echo "----------------------------------------"
97
- echo -e "${YELLOW}📦 Installing npm dependencies for all workers...${NC}"
98
- if ! bash "$SCRIPT_DIR/install-workers.sh"; then
99
- echo -e "${RED}❌ Worker dependencies installation failed!${NC}"
100
- exit 1
101
- fi
102
- echo -e "${GREEN}✅ All worker dependencies installed successfully${NC}"
103
- echo ""
104
-
105
- # Step 3: Deploy Workers
106
- echo -e "${PURPLE}Step 3/6: Deploying Workers${NC}"
107
- echo "----------------------------"
108
- echo -e "${YELLOW}🔧 Deploying all 7 Cloudflare Workers...${NC}"
109
- if ! npm run deploy-workers; then
110
- echo -e "${RED}❌ Worker deployment failed!${NC}"
111
- exit 1
112
- fi
113
- echo -e "${GREEN}✅ All workers deployed successfully${NC}"
114
- echo ""
115
-
116
- # Step 4: Deploy Worker Secrets
117
- echo -e "${PURPLE}Step 4/6: Deploying Worker Secrets${NC}"
118
- echo "-----------------------------------"
119
- echo -e "${YELLOW}🔐 Deploying worker environment variables...${NC}"
120
- if ! bash "$SCRIPT_DIR/deploy-worker-secrets.sh"; then
121
- echo -e "${RED}❌ Worker secrets deployment failed!${NC}"
122
- exit 1
123
- fi
124
- echo -e "${GREEN}✅ Worker secrets deployed successfully${NC}"
125
- echo ""
126
-
127
- # Step 5: Deploy Pages Secrets
128
- echo -e "${PURPLE}Step 5/6: Deploying Pages Secrets${NC}"
129
- echo "----------------------------------"
130
- echo -e "${YELLOW}🔐 Deploying Pages environment variables...${NC}"
131
- if ! bash "$SCRIPT_DIR/deploy-pages-secrets.sh"; then
132
- echo -e "${RED}❌ Pages secrets deployment failed!${NC}"
133
- exit 1
134
- fi
135
- echo -e "${GREEN}✅ Pages secrets deployed successfully${NC}"
136
- echo ""
137
-
138
- # Step 6: Deploy Pages
139
- echo -e "${PURPLE}Step 6/6: Deploying Pages${NC}"
140
- echo "--------------------------"
141
- echo -e "${YELLOW}🌐 Building and deploying Pages...${NC}"
142
- if ! npm run deploy-pages; then
143
- echo -e "${RED}❌ Pages deployment failed!${NC}"
144
- exit 1
145
- fi
146
- echo -e "${GREEN}✅ Pages deployed successfully${NC}"
147
- echo ""
148
-
149
- # Success summary
150
- echo "=========================================="
151
- echo -e "${GREEN}🎉 COMPLETE DEPLOYMENT SUCCESSFUL! 🎉${NC}"
152
- echo "=========================================="
153
- echo ""
154
- echo -e "${BLUE}Deployed Components:${NC}"
155
- echo " ✅ Worker dependencies (npm install)"
156
- echo " ✅ 7 Cloudflare Workers"
157
- echo " ✅ Worker environment variables"
158
- echo " ✅ Pages environment variables"
159
- echo " ✅ Cloudflare Pages frontend"
160
- echo ""
161
- echo -e "${BLUE}Next Steps:${NC}"
162
- echo " 1. Test your application endpoints"
163
- echo " 2. Verify all services are working"
164
- echo " 3. Verify worker and Pages secrets are set as expected"
165
- echo ""
166
- echo -e "${GREEN}✨ Your Striae application is now fully deployed!${NC}"
@@ -1,322 +0,0 @@
1
- #!/bin/bash
2
-
3
- escape_for_sed_pattern() {
4
- printf '%s' "$1" | sed -e 's/[][\\.^$*+?{}|()]/\\&/g'
5
- }
6
-
7
- dedupe_env_var_entries() {
8
- local var_name=$1
9
- local expected_count=1
10
- local escaped_var_name
11
-
12
- escaped_var_name=$(escape_for_sed_pattern "$var_name")
13
-
14
- if [ -f ".env.example" ]; then
15
- expected_count=$(grep -c "^$escaped_var_name=" .env.example || true)
16
-
17
- if [ "$expected_count" -lt 1 ]; then
18
- expected_count=1
19
- fi
20
- fi
21
-
22
- awk -v key="$var_name" -v keep="$expected_count" '
23
- BEGIN { seen = 0 }
24
- {
25
- if (index($0, key "=") == 1) {
26
- seen++
27
-
28
- if (seen > keep) {
29
- next
30
- }
31
- }
32
- print
33
- }
34
- ' .env > .env.tmp && mv .env.tmp .env
35
- }
36
-
37
- normalize_domain_value() {
38
- local domain="$1"
39
-
40
- domain=$(printf '%s' "$domain" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')
41
- domain="${domain#http://}"
42
- domain="${domain#https://}"
43
- domain="${domain%/}"
44
-
45
- printf '%s' "$domain"
46
- }
47
-
48
- normalize_worker_label_value() {
49
- local label="$1"
50
-
51
- label=$(normalize_domain_value "$label")
52
- label="${label#.}"
53
- label="${label%.}"
54
- label=$(printf '%s' "$label" | tr '[:upper:]' '[:lower:]')
55
-
56
- printf '%s' "$label"
57
- }
58
-
59
- normalize_worker_subdomain_value() {
60
- local subdomain="$1"
61
-
62
- subdomain=$(normalize_domain_value "$subdomain")
63
- subdomain="${subdomain#.}"
64
- subdomain="${subdomain%.}"
65
- subdomain=$(printf '%s' "$subdomain" | tr '[:upper:]' '[:lower:]')
66
-
67
- printf '%s' "$subdomain"
68
- }
69
-
70
- is_valid_worker_label() {
71
- local label="$1"
72
-
73
- [[ "$label" =~ ^[a-z0-9-]+$ ]]
74
- }
75
-
76
- is_valid_worker_subdomain() {
77
- local subdomain="$1"
78
-
79
- [[ "$subdomain" =~ ^[a-z0-9]([a-z0-9-]*[a-z0-9])?(\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)+$ ]]
80
- }
81
-
82
- strip_carriage_returns() {
83
- printf '%s' "$1" | tr -d '\r'
84
- }
85
-
86
- read_env_var_from_file() {
87
- local env_file=$1
88
- local var_name=$2
89
-
90
- if [ ! -f "$env_file" ]; then
91
- return 0
92
- fi
93
-
94
- awk -v key="$var_name" '
95
- index($0, key "=") == 1 {
96
- value = substr($0, length(key) + 2)
97
- }
98
- END {
99
- if (value != "") {
100
- gsub(/\r/, "", value)
101
- gsub(/^"/, "", value)
102
- gsub(/"$/, "", value)
103
- print value
104
- }
105
- }
106
- ' "$env_file"
107
- }
108
-
109
- resolve_existing_domain_value() {
110
- local var_name=$1
111
- local current_value=$2
112
- local preserved_value=""
113
-
114
- current_value=$(normalize_domain_value "$current_value")
115
-
116
- if [ "$current_value" = "$var_name" ]; then
117
- current_value=""
118
- fi
119
-
120
- if [ -n "$current_value" ] && ! is_placeholder "$current_value"; then
121
- printf '%s' "$current_value"
122
- return 0
123
- fi
124
-
125
- if [ -n "$preserved_domain_env_file" ] && [ -f "$preserved_domain_env_file" ]; then
126
- preserved_value=$(read_env_var_from_file "$preserved_domain_env_file" "$var_name")
127
- preserved_value=$(normalize_domain_value "$preserved_value")
128
-
129
- if [ "$preserved_value" = "$var_name" ]; then
130
- preserved_value=""
131
- fi
132
-
133
- if [ -n "$preserved_value" ] && ! is_placeholder "$preserved_value"; then
134
- printf '%s' "$preserved_value"
135
- return 0
136
- fi
137
- fi
138
-
139
- printf '%s' "$current_value"
140
- }
141
-
142
- restore_env_var_from_backup_if_missing() {
143
- local var_name=$1
144
- local current_value="${!var_name}"
145
- local preserved_value=""
146
-
147
- if [ "$update_env" != "true" ]; then
148
- return 0
149
- fi
150
-
151
- if [ -z "$preserved_domain_env_file" ] || [ ! -f "$preserved_domain_env_file" ]; then
152
- return 0
153
- fi
154
-
155
- current_value=$(strip_carriage_returns "$current_value")
156
-
157
- if [ -n "$current_value" ] && ! is_placeholder "$current_value"; then
158
- return 0
159
- fi
160
-
161
- preserved_value=$(read_env_var_from_file "$preserved_domain_env_file" "$var_name")
162
- preserved_value=$(strip_carriage_returns "$preserved_value")
163
-
164
- if [ -z "$preserved_value" ] || is_placeholder "$preserved_value"; then
165
- return 0
166
- fi
167
-
168
- printf -v "$var_name" '%s' "$preserved_value"
169
- export "$var_name"
170
- write_env_var "$var_name" "$preserved_value"
171
- }
172
-
173
- confirm_key_pair_regeneration() {
174
- local key_pair_label=$1
175
- local impact_warning=$2
176
- local regenerate_choice=""
177
-
178
- if [ "$force_rotate_keys" = "true" ]; then
179
- echo -e "${YELLOW}⚠️ Auto-confirmed regeneration for $key_pair_label key pair (--force-rotate-keys).${NC}"
180
- return 0
181
- fi
182
-
183
- echo -e "${GREEN}Current $key_pair_label key pair: [HIDDEN]${NC}"
184
-
185
- if [ -n "$impact_warning" ]; then
186
- echo -e "${YELLOW}⚠️ $impact_warning${NC}"
187
- fi
188
-
189
- read -p "Regenerate $key_pair_label key pair? (press Enter to keep current, or type 'y' to regenerate): " regenerate_choice
190
- regenerate_choice=$(strip_carriage_returns "$regenerate_choice")
191
-
192
- if [ "$regenerate_choice" = "y" ] || [ "$regenerate_choice" = "Y" ]; then
193
- return 0
194
- fi
195
-
196
- return 1
197
- }
198
-
199
- generate_worker_subdomain_label() {
200
- 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
201
- }
202
-
203
- compose_worker_domain() {
204
- local worker_name=$1
205
- local worker_subdomain=$2
206
-
207
- worker_name=$(normalize_worker_label_value "$worker_name")
208
- worker_subdomain=$(normalize_worker_subdomain_value "$worker_subdomain")
209
-
210
- if [ -z "$worker_name" ] || [ -z "$worker_subdomain" ]; then
211
- return 1
212
- fi
213
-
214
- if ! is_valid_worker_label "$worker_name" || ! is_valid_worker_subdomain "$worker_subdomain"; then
215
- return 1
216
- fi
217
-
218
- printf '%s.%s' "$worker_name" "$worker_subdomain"
219
- }
220
-
221
- infer_worker_subdomain_from_domain() {
222
- local worker_name=$1
223
- local worker_domain=$2
224
- local worker_subdomain=""
225
-
226
- worker_name=$(normalize_worker_label_value "$worker_name")
227
- worker_domain=$(normalize_domain_value "$worker_domain")
228
- worker_domain=$(printf '%s' "$worker_domain" | tr '[:upper:]' '[:lower:]')
229
-
230
- if [ -z "$worker_name" ] || [ -z "$worker_domain" ] || is_placeholder "$worker_name" || is_placeholder "$worker_domain"; then
231
- printf '%s' ""
232
- return 0
233
- fi
234
-
235
- case "$worker_domain" in
236
- "$worker_name".*)
237
- worker_subdomain="${worker_domain#${worker_name}.}"
238
- worker_subdomain=$(normalize_worker_subdomain_value "$worker_subdomain")
239
-
240
- if is_valid_worker_subdomain "$worker_subdomain"; then
241
- printf '%s' "$worker_subdomain"
242
- return 0
243
- fi
244
- ;;
245
- esac
246
-
247
- printf '%s' ""
248
- }
249
-
250
- write_env_var() {
251
- local var_name=$1
252
- local var_value=$2
253
- local env_file_value="$var_value"
254
-
255
- var_value=$(strip_carriage_returns "$var_value")
256
- env_file_value="$var_value"
257
-
258
- 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" ] || [ "$var_name" = "USER_KV_ENCRYPTION_PRIVATE_KEY" ] || [ "$var_name" = "USER_KV_ENCRYPTION_PUBLIC_KEY" ] || [ "$var_name" = "EXPORT_ENCRYPTION_KEYS_JSON" ] || [ "$var_name" = "DATA_AT_REST_ENCRYPTION_KEYS_JSON" ] || [ "$var_name" = "USER_KV_ENCRYPTION_KEYS_JSON" ]; then
259
- # Store as a quoted string so sourced .env preserves escaped newline markers (\n)
260
- env_file_value=${env_file_value//\"/\\\"}
261
- env_file_value="\"$env_file_value\""
262
- fi
263
-
264
- local escaped_var_name
265
- local replacement_line
266
- escaped_var_name=$(escape_for_sed_pattern "$var_name")
267
- replacement_line=$(escape_for_sed_replacement "$var_name=$env_file_value")
268
-
269
- if grep -q "^$escaped_var_name=" .env; then
270
- # Replace all occurrences so intentional duplicates in .env.example stay in sync.
271
- sed -i "s|^$escaped_var_name=.*|$replacement_line|g" .env
272
- dedupe_env_var_entries "$var_name"
273
- else
274
- echo "$var_name=$env_file_value" >> .env
275
- fi
276
- }
277
-
278
- update_private_key_registry() {
279
- local registry_var_name=$1
280
- local active_key_var_name=$2
281
- local current_key_id=$3
282
- local private_key_value=$4
283
- local registry_label=$5
284
- local existing_registry_json=""
285
- local updated_registry_json=""
286
- local registry_entry_count=""
287
-
288
- if [ -z "$registry_var_name" ] || [ -z "$active_key_var_name" ] || [ -z "$current_key_id" ] || [ -z "$private_key_value" ]; then
289
- echo -e "${YELLOW}⚠️ Skipping $registry_label key registry update due to missing inputs${NC}"
290
- return 0
291
- fi
292
-
293
- existing_registry_json="${!registry_var_name}"
294
- existing_registry_json=$(strip_carriage_returns "$existing_registry_json")
295
-
296
- if [ -z "$existing_registry_json" ] || is_placeholder "$existing_registry_json"; then
297
- existing_registry_json="{}"
298
- fi
299
-
300
- updated_registry_json=$(node -e "const raw = process.argv[1] || '{}'; const keyId = process.argv[2] || ''; const privateKey = process.argv[3] || ''; if (!keyId || !privateKey) process.exit(1); const normalized = { activeKeyId: null, keys: {} }; try { const parsed = JSON.parse(raw); if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) { if (parsed.keys && typeof parsed.keys === 'object' && !Array.isArray(parsed.keys)) { normalized.keys = Object.fromEntries(Object.entries(parsed.keys).filter(([id, pem]) => typeof id === 'string' && id.trim().length > 0 && typeof pem === 'string' && pem.trim().length > 0)); if (typeof parsed.activeKeyId === 'string' && parsed.activeKeyId.trim().length > 0) normalized.activeKeyId = parsed.activeKeyId.trim(); } else { normalized.keys = Object.fromEntries(Object.entries(parsed).filter(([id, pem]) => id !== 'activeKeyId' && id !== 'keys' && typeof id === 'string' && id.trim().length > 0 && typeof pem === 'string' && pem.trim().length > 0)); if (typeof parsed.activeKeyId === 'string' && parsed.activeKeyId.trim().length > 0) normalized.activeKeyId = parsed.activeKeyId.trim(); } } } catch (_) {} normalized.keys[keyId] = privateKey; normalized.activeKeyId = keyId; process.stdout.write(JSON.stringify(normalized));" "$existing_registry_json" "$current_key_id" "$private_key_value" 2>/dev/null || true)
301
-
302
- if [ -z "$updated_registry_json" ]; then
303
- echo -e "${RED}❌ Error: Failed to update $registry_label key registry JSON${NC}"
304
- exit 1
305
- fi
306
-
307
- printf -v "$registry_var_name" '%s' "$updated_registry_json"
308
- export "$registry_var_name"
309
- write_env_var "$registry_var_name" "$updated_registry_json"
310
-
311
- printf -v "$active_key_var_name" '%s' "$current_key_id"
312
- export "$active_key_var_name"
313
- write_env_var "$active_key_var_name" "$current_key_id"
314
-
315
- registry_entry_count=$(node -e "const raw = process.argv[1] || '{}'; try { const parsed = JSON.parse(raw); if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) { process.stdout.write('0'); process.exit(0); } const keys = parsed.keys && typeof parsed.keys === 'object' && !Array.isArray(parsed.keys) ? parsed.keys : parsed; const count = Object.entries(keys).filter(([id, pem]) => id !== 'activeKeyId' && id !== 'keys' && typeof id === 'string' && id.trim().length > 0 && typeof pem === 'string' && pem.trim().length > 0).length; process.stdout.write(String(count)); } catch (_) { process.stdout.write('0'); }" "$updated_registry_json")
316
- echo -e "${GREEN}✅ Updated $registry_label key registry ($registry_entry_count key IDs tracked)${NC}"
317
- echo -e "${GREEN}✅ $active_key_var_name: $current_key_id${NC}"
318
- }
319
-
320
- escape_for_sed_replacement() {
321
- printf '%s' "$1" | sed -e 's/[&|\\]/\\&/g'
322
- }