@striae-org/striae 5.1.1 → 5.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +20 -1
- package/app/utils/data/permissions.ts +4 -2
- package/package.json +4 -4
- package/scripts/deploy-config/modules/env-utils.sh +322 -0
- package/scripts/deploy-config/modules/keys.sh +404 -0
- package/scripts/deploy-config/modules/prompt.sh +372 -0
- package/scripts/deploy-config/modules/scaffolding.sh +336 -0
- package/scripts/deploy-config/modules/validation.sh +365 -0
- package/scripts/deploy-config.sh +47 -1572
- package/scripts/deploy-worker-secrets.sh +100 -5
- package/worker-configuration.d.ts +6 -3
- package/workers/audit-worker/package.json +1 -1
- package/workers/audit-worker/src/audit-worker.example.ts +188 -6
- package/workers/audit-worker/wrangler.jsonc.example +1 -1
- package/workers/data-worker/package.json +1 -1
- package/workers/data-worker/src/data-worker.example.ts +344 -32
- package/workers/data-worker/wrangler.jsonc.example +1 -1
- package/workers/image-worker/package.json +1 -1
- package/workers/image-worker/src/image-worker.example.ts +190 -5
- package/workers/image-worker/wrangler.jsonc.example +1 -1
- package/workers/keys-worker/package.json +1 -1
- package/workers/keys-worker/wrangler.jsonc.example +1 -1
- package/workers/pdf-worker/package.json +1 -1
- package/workers/pdf-worker/src/pdf-worker.example.ts +0 -1
- package/workers/pdf-worker/wrangler.jsonc.example +1 -5
- package/workers/user-worker/package.json +17 -17
- package/workers/user-worker/src/encryption-utils.ts +244 -0
- package/workers/user-worker/src/user-worker.example.ts +333 -31
- package/workers/user-worker/wrangler.jsonc.example +1 -1
- package/wrangler.toml.example +1 -1
package/scripts/deploy-config.sh
CHANGED
|
@@ -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
|
|
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
|
-
|
|
150
|
-
|
|
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
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
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
|
-
|
|
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
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
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
|
-
|
|
971
|
-
|
|
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
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
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
|
-
|
|
993
|
-
|
|
994
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
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
|