CI / Client installer (macos-latest) (push) Canceled after 0s
CI / Client installer (ubuntu-latest) (push) Canceled after 0s
CI / Client installer (windows-latest) (push) Canceled after 0s
CI / test (22) (push) Canceled after 0s
CI / test (24) (push) Canceled after 0s
CI / release-smoke (push) Canceled after 0s
160 lines
6.2 KiB
Bash
160 lines
6.2 KiB
Bash
#!/bin/sh
|
|
set -eu
|
|
|
|
ding_source_bases='{{NODE_SOURCE_BASES_POSIX}}'
|
|
ding_installer_url='{{INSTALLER_URL}}'
|
|
ding_installer_sha256='{{INSTALLER_SHA256}}'
|
|
ding_public_key_url='{{PUBLIC_KEY_URL}}'
|
|
ding_public_key_sha256='{{PUBLIC_KEY_SHA256}}'
|
|
ding_manifest_url='{{MANIFEST_URL}}'
|
|
|
|
ding_temp_dir="$(mktemp -d "${TMPDIR:-/tmp}/dingmcp-install.XXXXXX")"
|
|
trap 'rm -rf "$ding_temp_dir"' EXIT HUP INT TERM
|
|
|
|
ding_hash_file() {
|
|
if command -v sha256sum >/dev/null 2>&1; then
|
|
sha256sum "$1" | awk '{print $1}'
|
|
elif command -v shasum >/dev/null 2>&1; then
|
|
shasum -a 256 "$1" | awk '{print $1}'
|
|
else
|
|
echo '缺少 sha256sum 或 shasum,无法安全安装' >&2
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
ding_fetch() {
|
|
if command -v curl >/dev/null 2>&1; then
|
|
if ding_fetch_http="$(curl --fail --location --silent --show-error --connect-timeout 10 --max-time 300 \
|
|
--write-out '%{http_code}' --output "$2" "$1")"; then
|
|
return 0
|
|
else
|
|
ding_fetch_status=$?
|
|
fi
|
|
if { [ "$ding_fetch_status" -eq 22 ] && [ "$ding_fetch_http" = '404' ]; } \
|
|
|| [ "$ding_fetch_status" -eq 5 ] || [ "$ding_fetch_status" -eq 6 ] \
|
|
|| [ "$ding_fetch_status" -eq 7 ] || [ "$ding_fetch_status" -eq 18 ] \
|
|
|| [ "$ding_fetch_status" -eq 28 ] || [ "$ding_fetch_status" -eq 35 ] \
|
|
|| [ "$ding_fetch_status" -eq 52 ] || [ "$ding_fetch_status" -eq 55 ] \
|
|
|| [ "$ding_fetch_status" -eq 56 ]; then
|
|
return 75
|
|
fi
|
|
echo "下载失败且不允许换源(HTTP ${ding_fetch_http:-unknown} / curl $ding_fetch_status):$1" >&2
|
|
return 1
|
|
elif command -v wget >/dev/null 2>&1; then
|
|
ding_wget_log="${2}.wget.log"
|
|
if wget --https-only --timeout=300 --server-response --output-document="$2" "$1" 2>"$ding_wget_log"; then
|
|
rm -f "$ding_wget_log"
|
|
return 0
|
|
else
|
|
ding_fetch_status=$?
|
|
fi
|
|
ding_fetch_http="$(awk '/^ HTTP\/[0-9.]+ [0-9][0-9][0-9]/{code=$2} END{print code}' "$ding_wget_log")"
|
|
cat "$ding_wget_log" >&2
|
|
rm -f "$ding_wget_log"
|
|
if [ "$ding_fetch_http" = '404' ] || [ "$ding_fetch_status" -eq 4 ] || [ "$ding_fetch_status" -eq 5 ]; then
|
|
return 75
|
|
fi
|
|
echo "下载失败且不允许换源(HTTP ${ding_fetch_http:-unknown} / wget $ding_fetch_status):$1" >&2
|
|
return 1
|
|
else
|
|
echo '缺少 curl 或 wget,无法下载安装文件' >&2
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
ding_download_verified() {
|
|
ding_download_target="$1"
|
|
ding_download_expected="$2"
|
|
shift 2
|
|
ding_download_succeeded=0
|
|
for ding_download_url in "$@"; do
|
|
rm -f "$ding_download_target"
|
|
if ding_fetch "$ding_download_url" "$ding_download_target"; then
|
|
ding_download_succeeded=1
|
|
ding_download_actual="$(ding_hash_file "$ding_download_target")"
|
|
if [ "$ding_download_actual" != "$ding_download_expected" ]; then
|
|
echo "下载文件 SHA-256 不匹配,停止安装:$ding_download_url" >&2
|
|
return 1
|
|
fi
|
|
return 0
|
|
else
|
|
ding_download_status=$?
|
|
if [ "$ding_download_status" -ne 75 ]; then return 1; fi
|
|
fi
|
|
done
|
|
if [ "$ding_download_succeeded" -eq 0 ]; then
|
|
echo '所有下载源均不可用' >&2
|
|
fi
|
|
return 1
|
|
}
|
|
|
|
ding_test_node() {
|
|
[ -x "$1" ] || return 1
|
|
"$1" -e 'const [a,b]=process.versions.node.split(".").map(Number);process.exit(a>22||(a===22&&b>=13)?0:1)' >/dev/null 2>&1
|
|
}
|
|
|
|
case "$(uname -s)" in
|
|
Linux) ding_os='linux' ;;
|
|
Darwin) ding_os='darwin' ;;
|
|
*) echo "不支持的操作系统:$(uname -s)" >&2; exit 1 ;;
|
|
esac
|
|
case "$(uname -m)" in
|
|
x86_64|amd64) ding_arch='x64' ;;
|
|
arm64|aarch64) ding_arch='arm64' ;;
|
|
*) echo "不支持的 CPU 架构:$(uname -m)" >&2; exit 1 ;;
|
|
esac
|
|
|
|
case "$ding_os-$ding_arch" in
|
|
linux-x64) ding_node_file='{{NODE_LINUX_X64_FILE}}'; ding_node_sha256='{{NODE_LINUX_X64_SHA256}}' ;;
|
|
linux-arm64) ding_node_file='{{NODE_LINUX_ARM64_FILE}}'; ding_node_sha256='{{NODE_LINUX_ARM64_SHA256}}' ;;
|
|
darwin-x64) ding_node_file='{{NODE_DARWIN_X64_FILE}}'; ding_node_sha256='{{NODE_DARWIN_X64_SHA256}}' ;;
|
|
darwin-arm64) ding_node_file='{{NODE_DARWIN_ARM64_FILE}}'; ding_node_sha256='{{NODE_DARWIN_ARM64_SHA256}}' ;;
|
|
esac
|
|
|
|
ding_node_path=''
|
|
if command -v node >/dev/null 2>&1 && command -v npm >/dev/null 2>&1 && ding_test_node "$(command -v node)"; then
|
|
ding_node_path="$(command -v node)"
|
|
else
|
|
if [ -n "${DINGTALK_APPROVAL_CLIENT_HOME:-}" ]; then
|
|
ding_client_root="$DINGTALK_APPROVAL_CLIENT_HOME"
|
|
elif [ "$ding_os" = 'darwin' ]; then
|
|
ding_client_root="$HOME/Library/Application Support/dingtalk-approval"
|
|
else
|
|
ding_client_root="${XDG_DATA_HOME:-$HOME/.local/share}/dingtalk-approval"
|
|
fi
|
|
ding_runtime_name="${ding_node_file%.tar.gz}"
|
|
ding_runtime_parent="$ding_client_root/node"
|
|
ding_runtime_dir="$ding_runtime_parent/$ding_runtime_name"
|
|
ding_node_path="$ding_runtime_dir/bin/node"
|
|
ding_npm_cli="$ding_runtime_dir/lib/node_modules/npm/bin/npm-cli.js"
|
|
if ! ding_test_node "$ding_node_path" || [ ! -f "$ding_npm_cli" ]; then
|
|
mkdir -p "$ding_runtime_parent"
|
|
chmod 700 "$ding_client_root" "$ding_runtime_parent" 2>/dev/null || true
|
|
ding_runtime_archive="$ding_temp_dir/$ding_node_file"
|
|
ding_runtime_urls=''
|
|
for ding_source_base in $ding_source_bases; do
|
|
ding_runtime_urls="$ding_runtime_urls $ding_source_base$ding_node_file"
|
|
done
|
|
# The URLs are fixed by the signed release process and contain no whitespace.
|
|
# shellcheck disable=SC2086
|
|
ding_download_verified "$ding_runtime_archive" "$ding_node_sha256" $ding_runtime_urls
|
|
ding_extract_root="$ding_temp_dir/node-extract"
|
|
mkdir -p "$ding_extract_root"
|
|
tar -xzf "$ding_runtime_archive" -C "$ding_extract_root"
|
|
ding_extracted_dir="$ding_extract_root/$ding_runtime_name"
|
|
if ! ding_test_node "$ding_extracted_dir/bin/node" || [ ! -f "$ding_extracted_dir/lib/node_modules/npm/bin/npm-cli.js" ]; then
|
|
echo '便携 Node 归档缺少可用的 node 或 npm-cli.js' >&2
|
|
exit 1
|
|
fi
|
|
rm -rf "$ding_runtime_dir"
|
|
mv "$ding_extracted_dir" "$ding_runtime_dir"
|
|
fi
|
|
fi
|
|
|
|
ding_installer="$ding_temp_dir/installer.mjs"
|
|
ding_public_key="$ding_temp_dir/release-signing-public.pem"
|
|
ding_download_verified "$ding_installer" "$ding_installer_sha256" "$ding_installer_url"
|
|
ding_download_verified "$ding_public_key" "$ding_public_key_sha256" "$ding_public_key_url"
|
|
|
|
"$ding_node_path" "$ding_installer" install --manifest-url "$ding_manifest_url" --public-key "$ding_public_key" --json
|