@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.
- package/.env.example +2 -10
- package/README.md +5 -46
- package/app/components/actions/case-export/core-export.ts +5 -174
- package/app/components/actions/case-export/download-handlers.ts +84 -751
- package/app/components/actions/case-export/index.ts +6 -30
- package/app/components/actions/case-export/metadata-helpers.ts +0 -78
- package/app/components/actions/case-export/types-constants.ts +0 -43
- package/app/components/actions/case-import/confirmation-import.ts +75 -36
- package/app/components/actions/case-import/confirmation-package.ts +68 -1
- package/app/components/actions/case-import/index.ts +1 -1
- package/app/components/actions/case-import/orchestrator.ts +78 -53
- package/app/components/actions/case-import/zip-processing.ts +160 -330
- package/app/components/actions/generate-pdf.ts +3 -2
- package/app/components/audit/user-audit-viewer.tsx +0 -19
- package/app/components/audit/viewer/audit-viewer-header.tsx +0 -33
- package/app/components/navbar/case-modals/archive-case-modal.tsx +1 -1
- package/app/components/navbar/case-modals/export-case-modal.module.css +27 -0
- package/app/components/navbar/case-modals/export-case-modal.tsx +132 -0
- package/app/components/navbar/case-modals/export-confirmations-modal.module.css +24 -0
- package/app/components/navbar/case-modals/export-confirmations-modal.tsx +108 -0
- package/app/components/navbar/navbar.tsx +1 -1
- package/app/components/sidebar/case-import/case-import.module.css +35 -0
- package/app/components/sidebar/case-import/components/CasePreviewSection.tsx +51 -3
- package/app/components/sidebar/case-import/components/ConfirmationDialog.tsx +2 -4
- package/app/components/sidebar/case-import/components/ConfirmationPreviewSection.tsx +36 -5
- package/app/components/sidebar/case-import/hooks/useFilePreview.ts +5 -9
- package/app/components/sidebar/case-import/index.ts +1 -4
- package/app/components/sidebar/notes/class-details-shared.ts +2 -2
- package/app/components/toast/toast.module.css +36 -0
- package/app/components/toast/toast.tsx +6 -2
- package/app/components/user/manage-profile.tsx +4 -3
- package/app/config-example/config.json +1 -2
- package/app/root.tsx +0 -7
- package/app/routes/_index.tsx +1 -1
- package/app/routes/auth/login.example.tsx +22 -103
- package/app/routes/auth/login.tsx +22 -103
- package/app/routes/auth/route.ts +1 -1
- package/app/routes/striae/striae.tsx +117 -59
- package/app/services/firebase/index.ts +0 -3
- package/app/types/case.ts +1 -0
- package/app/types/export.ts +2 -2
- package/app/types/import.ts +10 -0
- package/app/utils/auth/index.ts +0 -1
- package/app/utils/data/permissions.ts +3 -2
- package/package.json +9 -16
- package/public/_headers +0 -4
- package/public/_routes.json +0 -1
- package/worker-configuration.d.ts +20 -17
- package/workers/audit-worker/src/audit-worker.example.ts +9 -806
- package/workers/audit-worker/src/config.ts +7 -0
- package/workers/audit-worker/src/crypto/data-at-rest.ts +410 -0
- package/workers/audit-worker/src/handlers/audit-routes.ts +125 -0
- package/workers/audit-worker/src/storage/audit-storage.ts +99 -0
- package/workers/audit-worker/src/types.ts +56 -0
- package/workers/audit-worker/worker-configuration.d.ts +1 -1
- package/workers/audit-worker/wrangler.jsonc.example +1 -1
- package/workers/data-worker/src/config.ts +11 -0
- package/workers/data-worker/src/data-worker.example.ts +21 -942
- package/workers/data-worker/src/handlers/decrypt-export.ts +118 -0
- package/workers/data-worker/src/handlers/signing.ts +174 -0
- package/workers/data-worker/src/handlers/storage-routes.ts +129 -0
- package/workers/data-worker/src/registry/key-registry.ts +368 -0
- package/workers/data-worker/src/types.ts +46 -0
- package/workers/data-worker/worker-configuration.d.ts +1 -1
- package/workers/data-worker/wrangler.jsonc.example +1 -1
- package/workers/image-worker/worker-configuration.d.ts +1 -1
- package/workers/image-worker/wrangler.jsonc.example +1 -1
- package/workers/pdf-worker/worker-configuration.d.ts +2 -3
- package/workers/pdf-worker/wrangler.jsonc.example +1 -1
- package/workers/user-worker/src/auth.ts +30 -0
- package/workers/user-worker/src/cleanup/account-deletion.ts +337 -0
- package/workers/user-worker/src/config.ts +4 -0
- package/workers/user-worker/src/encryption-utils.ts +25 -0
- package/workers/user-worker/src/firebase/admin.ts +152 -0
- package/workers/user-worker/src/handlers/user-routes.ts +242 -0
- package/workers/user-worker/src/registry/user-kv.ts +172 -0
- package/workers/user-worker/src/storage/user-records.ts +34 -0
- package/workers/user-worker/src/types.ts +106 -0
- package/workers/user-worker/src/user-worker.example.ts +18 -964
- package/workers/user-worker/worker-configuration.d.ts +4 -2
- package/workers/user-worker/wrangler.jsonc.example +12 -1
- package/wrangler.toml.example +1 -1
- package/app/components/actions/case-export/data-processing.ts +0 -223
- package/app/components/sidebar/case-export/case-export.module.css +0 -418
- package/app/components/sidebar/case-export/case-export.tsx +0 -310
- package/app/types/exceljs-bare.d.ts +0 -9
- package/app/utils/auth/auth.ts +0 -11
- package/public/.well-known/security.txt +0 -6
- package/public/favicon.ico +0 -0
- package/public/icon-256.png +0 -0
- package/public/icon-512.png +0 -0
- package/public/manifest.json +0 -39
- package/public/shortcut.png +0 -0
- package/public/social-image.png +0 -0
- package/public/vendor/exceljs.LICENSE +0 -22
- package/public/vendor/exceljs.bare.min.js +0 -45
- package/scripts/deploy-all.sh +0 -166
- package/scripts/deploy-config/modules/env-utils.sh +0 -322
- package/scripts/deploy-config/modules/keys.sh +0 -404
- package/scripts/deploy-config/modules/prompt.sh +0 -372
- package/scripts/deploy-config/modules/scaffolding.sh +0 -344
- package/scripts/deploy-config/modules/validation.sh +0 -365
- package/scripts/deploy-config.sh +0 -236
- package/scripts/deploy-pages-secrets.sh +0 -231
- package/scripts/deploy-pages.sh +0 -34
- package/scripts/deploy-primershear-emails.sh +0 -167
- package/scripts/deploy-worker-secrets.sh +0 -374
- package/scripts/dev.cjs +0 -23
- package/scripts/install-workers.sh +0 -88
- package/scripts/run-eslint.cjs +0 -43
- package/scripts/update-compatibility-dates.cjs +0 -124
- package/scripts/update-markdown-versions.cjs +0 -43
- package/workers/keys-worker/package.json +0 -18
- package/workers/keys-worker/src/keys.example.ts +0 -67
- package/workers/keys-worker/src/keys.ts +0 -67
- package/workers/keys-worker/worker-configuration.d.ts +0 -7447
- package/workers/keys-worker/wrangler.jsonc.example +0 -15
package/scripts/deploy-all.sh
DELETED
|
@@ -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
|
-
}
|