This commit is contained in:
+97
-4
@@ -8,6 +8,7 @@ INSTALL_ROOT="${ERP_INSTALL_ROOT:-}"
|
||||
ALLOW_INSECURE="${ERP_UPDATE_ALLOW_INSECURE_HTTP:-0}"
|
||||
NO_SERVICE="${ERP_INSTALL_NO_SERVICE:-0}"
|
||||
TOKEN="${ERP_GITEA_TOKEN:-${OA_UPDATE_TOKEN:-}}"
|
||||
PUBLIC_URL="${ERP_PUBLIC_URL:-}"
|
||||
PUBLIC_KEY='-----BEGIN PUBLIC KEY-----
|
||||
MCowBQYDK2VwAyEAaErhcY8WZIZvPILmYnfjndVBAdOuWkvhaoHIWqNNdxI=
|
||||
-----END PUBLIC KEY-----'
|
||||
@@ -23,6 +24,7 @@ Usage: install.sh [options]
|
||||
--repository O/R Release repository (default: awaioi/ERP)
|
||||
--version VERSION Install one exact stable release
|
||||
--install-root PATH Override installation directory
|
||||
--public-url URL Public URL used for the one-time web setup link
|
||||
--allow-insecure Development only: allow plain HTTP release URLs
|
||||
--no-service Start without systemd/launchd; online update stays disabled
|
||||
EOF
|
||||
@@ -34,6 +36,7 @@ while [[ $# -gt 0 ]]; do
|
||||
--repository) [[ $# -ge 2 ]] || fail '--repository requires a value'; REPOSITORY="$2"; shift 2 ;;
|
||||
--version) [[ $# -ge 2 ]] || fail '--version requires a value'; REQUESTED_VERSION="$2"; shift 2 ;;
|
||||
--install-root) [[ $# -ge 2 ]] || fail '--install-root requires a value'; INSTALL_ROOT="$2"; shift 2 ;;
|
||||
--public-url) [[ $# -ge 2 ]] || fail '--public-url requires a value'; PUBLIC_URL="$2"; shift 2 ;;
|
||||
--allow-insecure) ALLOW_INSECURE=1; shift ;;
|
||||
--no-service) NO_SERVICE=1; shift ;;
|
||||
-h|--help) usage; exit 0 ;;
|
||||
@@ -519,6 +522,74 @@ detect_lan_address() {
|
||||
printf '%s' "${address:-127.0.0.1}"
|
||||
}
|
||||
|
||||
is_ip_address() {
|
||||
python3 - "$1" <<'PY' >/dev/null 2>&1
|
||||
import ipaddress, sys
|
||||
ipaddress.ip_address(sys.argv[1])
|
||||
PY
|
||||
}
|
||||
|
||||
detect_public_address() {
|
||||
local endpoint address
|
||||
for endpoint in \
|
||||
https://api.ipify.org \
|
||||
https://ifconfig.me/ip \
|
||||
https://icanhazip.com; do
|
||||
address="$(curl --silent --show-error --fail --location \
|
||||
--proto '=https' --proto-redir '=https' \
|
||||
--connect-timeout 3 --max-time 5 "$endpoint" 2>/dev/null \
|
||||
| tr -d '[:space:]' | head -c 128 || true)"
|
||||
if [[ -n "$address" ]] && is_ip_address "$address"; then
|
||||
printf '%s' "$address"
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
normalize_public_url() {
|
||||
python3 - "$1" <<'PY'
|
||||
import sys
|
||||
from urllib.parse import urlsplit, urlunsplit
|
||||
|
||||
value = sys.argv[1].strip()
|
||||
try:
|
||||
parsed = urlsplit(value)
|
||||
port = parsed.port
|
||||
except ValueError:
|
||||
raise SystemExit("invalid public URL")
|
||||
if parsed.scheme.lower() not in {"http", "https"} or not parsed.hostname:
|
||||
raise SystemExit("public URL must use http or https")
|
||||
if parsed.username is not None or parsed.password is not None:
|
||||
raise SystemExit("public URL must not contain credentials")
|
||||
if port is not None and not 1 <= port <= 65535:
|
||||
raise SystemExit("invalid public URL port")
|
||||
path = parsed.path or "/"
|
||||
print(urlunsplit((parsed.scheme.lower(), parsed.netloc, path, parsed.query, parsed.fragment)))
|
||||
PY
|
||||
}
|
||||
|
||||
ip_setup_base_url() {
|
||||
python3 - "$1" "$2" <<'PY'
|
||||
import ipaddress, sys
|
||||
address = ipaddress.ip_address(sys.argv[1])
|
||||
host = f"[{address}]" if address.version == 6 else str(address)
|
||||
print(f"http://{host}:{int(sys.argv[2])}/")
|
||||
PY
|
||||
}
|
||||
|
||||
append_setup_token() {
|
||||
python3 - "$1" "$2" <<'PY'
|
||||
import sys
|
||||
from urllib.parse import parse_qsl, urlencode, urlsplit, urlunsplit
|
||||
|
||||
parsed = urlsplit(sys.argv[1])
|
||||
query = [(key, value) for key, value in parse_qsl(parsed.query, keep_blank_values=True) if key != "token"]
|
||||
query.append(("token", sys.argv[2]))
|
||||
print(urlunsplit((parsed.scheme, parsed.netloc, parsed.path or "/", urlencode(query), parsed.fragment)))
|
||||
PY
|
||||
}
|
||||
|
||||
main() {
|
||||
detect_platform
|
||||
validate_service_manager
|
||||
@@ -531,9 +602,18 @@ main() {
|
||||
fi
|
||||
[[ -n "$GITEA_BASE_URL" ]] || fail 'Gitea URL is required; use --gitea-url or ERP_GITEA_BASE_URL'
|
||||
validate_download_url "$GITEA_BASE_URL"
|
||||
if [[ -n "$PUBLIC_URL" ]]; then
|
||||
case "$PUBLIC_URL" in
|
||||
http://*|https://*) ;;
|
||||
*) fail 'public URL must start with http:// or https://' ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
say "Detected $PLATFORM/$ARCH"
|
||||
check_and_install_dependencies
|
||||
if [[ -n "$PUBLIC_URL" ]]; then
|
||||
PUBLIC_URL="$(normalize_public_url "$PUBLIC_URL")" || fail 'invalid public URL'
|
||||
fi
|
||||
TMP_DIR="$(mktemp -d "${TMPDIR:-/tmp}/kaidi-erp-install.XXXXXX")"
|
||||
create_curl_config
|
||||
say 'Downloading and verifying the signed release...'
|
||||
@@ -545,11 +625,24 @@ main() {
|
||||
start_service
|
||||
wait_for_installer
|
||||
|
||||
local port="${ERP_SERVER_PORT:-8091}" address
|
||||
address="$(detect_lan_address)"
|
||||
local port="${ERP_SERVER_PORT:-8091}" lan_address public_address setup_base local_base lan_base
|
||||
lan_address="$(detect_lan_address)"
|
||||
local_base="http://127.0.0.1:${port}/"
|
||||
lan_base="$(ip_setup_base_url "$lan_address" "$port")"
|
||||
if [[ -n "$PUBLIC_URL" ]]; then
|
||||
setup_base="$PUBLIC_URL"
|
||||
elif public_address="$(detect_public_address)"; then
|
||||
setup_base="$(ip_setup_base_url "$public_address" "$port")"
|
||||
else
|
||||
setup_base="$lan_base"
|
||||
say 'Public IP detection was unavailable; using the LAN address'
|
||||
fi
|
||||
say "Kaidi ERP $VERSION installer is running"
|
||||
say "Setup URL: http://${address}:${port}/?token=${SETUP_TOKEN}"
|
||||
say "Local URL: http://127.0.0.1:${port}/?token=${SETUP_TOKEN}"
|
||||
say "Setup URL: $(append_setup_token "$setup_base" "$SETUP_TOKEN")"
|
||||
say "Local URL: $(append_setup_token "$local_base" "$SETUP_TOKEN")"
|
||||
if [[ "$lan_address" != "127.0.0.1" && "$lan_base" != "$setup_base" ]]; then
|
||||
say "LAN URL: $(append_setup_token "$lan_base" "$SETUP_TOKEN")"
|
||||
fi
|
||||
say 'Complete PostgreSQL and administrator setup in the browser. The installer will remove itself after the formal service is healthy.'
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user