release: 1.3.4

This commit is contained in:
Qiufeng
2026-09-11 18:28:03 +08:00
parent 511fc5d785
commit 5afcd98ebd
21 changed files with 403 additions and 187 deletions
+200 -17
View File
@@ -3,7 +3,7 @@ set -Eeuo pipefail
# TallyNote native installer. Installs the latest release by default; use
# --dry-run to preview without changing the host.
PATH=/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/bin
PATH=/usr/local/bin:/usr/bin:/usr/sbin:/sbin:/bin
export PATH
umask 077
@@ -34,6 +34,11 @@ MAX_TIME=${TALLYNOTE_INSTALL_MAX_TIME_SECONDS:-300}
RELEASE_ALLOWED_HOSTS=${TALLYNOTE_RELEASE_ALLOWED_HOSTS:-}
OPENSSL_BIN=${TALLYNOTE_OPENSSL_BIN:-openssl}
UNAME_BIN=${TALLYNOTE_UNAME_BIN:-uname}
NODE_MIN_MAJOR=24
NODE_VERSION=${TALLYNOTE_NODE_VERSION:-24.20.0}
NODE_PATH=${TALLYNOTE_NODE:-}
NODE_INSTALL_ROOT=$PREFIX/nodejs
NODE_VERSION_DETECTED=''
# Service network settings are written to the systemd EnvironmentFile on a
# fresh install. Existing values are preserved unless the corresponding
# TALLYNOTE_* variable is explicitly supplied to the installer.
@@ -57,6 +62,7 @@ INSTALL_PREVIOUS_TARGET=''
INSTALL_NEW_RELEASE=''
INSTALL_WORK_DIR=''
INSTALL_BACKUP_DIR=''
INSTALL_UNIT_TMP=''
INSTALL_BACKUP_COMPLETE=0
INSTALL_WAS_ACTIVE=0
INSTALL_PATH_WAS_ACTIVE=0
@@ -65,6 +71,12 @@ INSTALL_WAS_ENABLED=0
INSTALL_PATH_WAS_ENABLED=0
INSTALL_UPDATE_WAS_ENABLED=0
INSTALL_SYSTEMD_TOUCHED=0
INSTALL_NODE_CREATED=0
INSTALL_NODE_TARGET=''
INSTALL_NODE_MARKER_CREATED=0
INSTALL_NODE_MARKER=''
INSTALL_NODE_ROOT_CREATED=0
NODE_INSTALL_TMP=''
ADMIN_INIT_PATH=/usr/local/sbin/tallynote-admin-init
INSTALL_FIRST_INSTALL=0
DATA_DIR_TEMP_ROOT=0
@@ -402,6 +414,7 @@ configure_network_interactively() {
[[ "$REQUIRE_SIGNATURE" == true || "$REQUIRE_SIGNATURE" == false ]] || die 'TALLYNOTE_INSTALL_REQUIRE_SIGNATURE 必须是 true 或 false'
[[ "$ALLOW_DOWNGRADE" == true || "$ALLOW_DOWNGRADE" == false ]] || die 'TALLYNOTE_ALLOW_DOWNGRADE 必须是 true 或 false'
[[ "$SIGNATURE_FORMAT" == ed25519 || "$SIGNATURE_FORMAT" == gpg ]] || die '签名格式必须是 ed25519 或 gpg'
[[ "$NODE_VERSION" =~ ^24\.[0-9]+\.[0-9]+$ ]] || die 'TALLYNOTE_NODE_VERSION 必须是 24.x.y 版本号'
[[ "$MAX_RELEASE_MB" =~ ^[1-9][0-9]*$ && "$MAX_EXTRACT_MB" =~ ^[1-9][0-9]*$ && "$MAX_ARCHIVE_ENTRIES" =~ ^[1-9][0-9]*$ ]] || die '安装资源限制必须是正整数'
[[ "$CONNECT_TIMEOUT" =~ ^[1-9][0-9]*$ && "$MAX_TIME" =~ ^[1-9][0-9]*$ ]] || die '安装超时配置必须是正整数'
@@ -461,6 +474,146 @@ detect_platform() {
export TALLYNOTE_ARCH TALLYNOTE_LIBC
}
node_major_version() {
local candidate=$1 value
[[ -x "$candidate" ]] || return 1
value=$("$candidate" -p 'process.versions.node.split(".")[0]' 2>/dev/null || true)
[[ "$value" =~ ^[0-9]+$ ]] || return 1
printf '%s' "$value"
}
node_is_legacy_embedded() {
local candidate=$1 resolved
[[ -n "$candidate" ]] || return 1
resolved=$(readlink -f -- "$candidate" 2>/dev/null || realpath "$candidate" 2>/dev/null || printf '%s' "$candidate")
[[ "$resolved" == "$PREFIX/current/runtime/"* || "$resolved" == "$PREFIX/releases/"*/runtime/* ]]
}
node_is_usable() {
local candidate=$1 major resolved uid mode_bits
[[ -n "$candidate" && -x "$candidate" ]] || return 1
resolved=$(readlink -f -- "$candidate" 2>/dev/null || realpath "$candidate" 2>/dev/null || printf '%s' "$candidate")
[[ -x "$resolved" ]] || return 1
if (( EUID == 0 )); then
uid=$(stat_uid "$resolved")
mode_bits=$(stat_mode_bits "$resolved")
[[ "$uid" == 0 && $((mode_bits & 18)) -eq 0 ]] || return 1
fi
major=$(node_major_version "$candidate") || return 1
(( major >= NODE_MIN_MAJOR )) || return 1
NODE_VERSION_DETECTED=$("$candidate" -p 'process.versions.node' 2>/dev/null || true)
[[ -n "$NODE_VERSION_DETECTED" ]]
}
node_archive_name() {
local platform
case "${TALLYNOTE_LIBC}:${TALLYNOTE_ARCH}" in
glibc:x64) platform=linux-x64 ;;
glibc:arm64) platform=linux-arm64 ;;
*) die "Node.js 官方未提供当前平台的 ${NODE_MIN_MAJOR}+ 归档(${TALLYNOTE_ARCH}/${TALLYNOTE_LIBC});请先安装可用的系统 Node.js 24+ 后重试" ;;
esac
printf 'node-v%s-%s.tar.xz' "$NODE_VERSION" "$platform"
}
install_managed_node() {
local archive checksum archive_name expected actual tmp extracted target marker
archive_name=$(node_archive_name)
tmp=$(mktemp -d)
NODE_INSTALL_TMP=$tmp
archive="$tmp/$archive_name"
checksum="$tmp/SHASUMS256.txt"
stage "系统未找到 Node.js ${NODE_MIN_MAJOR}+,下载官方运行时 ${NODE_VERSION}"
append_allowed_host nodejs.org
download "https://nodejs.org/dist/v${NODE_VERSION}/${archive_name}" "$archive" $((256 * 1024 * 1024))
download "https://nodejs.org/dist/v${NODE_VERSION}/SHASUMS256.txt" "$checksum" $((4 * 1024 * 1024))
expected=$(awk -v name="$archive_name" '$2 == name { print $1; exit }' "$checksum")
[[ "$expected" =~ ^[A-Fa-f0-9]{64}$ ]] || die 'Node.js 官方校验清单中没有匹配归档'
actual=$(sha256sum "$archive" | awk '{print $1}')
[[ "${actual,,}" == "${expected,,}" ]] || die 'Node.js 官方归档 SHA-256 校验失败'
if [[ ! -e "$NODE_INSTALL_ROOT" && ! -L "$NODE_INSTALL_ROOT" ]]; then
INSTALL_NODE_ROOT_CREATED=1
fi
ensure_root_directory "$NODE_INSTALL_ROOT" 755
tar -xJf "$archive" -C "$tmp"
extracted="$tmp/${archive_name%.tar.xz}"
[[ -d "$extracted" && -x "$extracted/bin/node" ]] || die 'Node.js 官方归档结构无效'
target="$NODE_INSTALL_ROOT/${archive_name%.tar.xz}"
[[ ! -e "$target" && ! -L "$target" ]] || die "Node.js 目标目录已存在:$target"
mv -- "$extracted" "$target"
INSTALL_NODE_CREATED=1
INSTALL_NODE_TARGET=$target
marker="$NODE_INSTALL_ROOT/.tallynote-managed"
if [[ -e "$marker" || -L "$marker" ]]; then
[[ -f "$marker" && ! -L "$marker" && "$(sed -n '1p' "$marker" 2>/dev/null)" == tallynote-managed-node-v1 ]] || die 'Node.js 管理目录标记无效'
else
printf 'tallynote-managed-node-v1\n' > "$marker"
chmod 600 "$marker"
INSTALL_NODE_MARKER_CREATED=1
INSTALL_NODE_MARKER=$marker
fi
chown -R root:root "$target"
chown root:root "$marker"
NODE_PATH="$target/bin/node"
rm -rf -- "$tmp"
NODE_INSTALL_TMP=''
node_is_usable "$NODE_PATH" || die '已安装的 Node.js 运行时无法通过版本检查'
stage_done "Node.js ${NODE_VERSION_DETECTED} 已安装并记录为共享运行时"
}
cleanup_node_install_if_needed() {
local result=$? marker
if [[ -n "$NODE_INSTALL_TMP" && -d "$NODE_INSTALL_TMP" ]]; then
rm -rf -- "$NODE_INSTALL_TMP" 2>/dev/null || true
NODE_INSTALL_TMP=''
fi
if (( INSTALL_COMMITTED == 0 && INSTALL_NODE_CREATED == 1 )); then
if [[ -n "$INSTALL_NODE_TARGET" && -d "$INSTALL_NODE_TARGET" && ! -L "$INSTALL_NODE_TARGET" ]]; then
rm -rf -- "$INSTALL_NODE_TARGET" 2>/dev/null || true
fi
marker=$INSTALL_NODE_MARKER
if (( INSTALL_NODE_MARKER_CREATED == 1 )) && [[ -n "$marker" && -f "$marker" && ! -L "$marker" ]]; then
rm -f -- "$marker" 2>/dev/null || true
fi
if (( INSTALL_NODE_ROOT_CREATED == 1 )) && [[ -d "$NODE_INSTALL_ROOT" && ! -L "$NODE_INSTALL_ROOT" ]]; then
rmdir -- "$NODE_INSTALL_ROOT" 2>/dev/null || true
fi
INSTALL_NODE_CREATED=0
fi
return "$result"
}
ensure_node_runtime() {
local candidate='' managed_node marker
[[ "$NODE_INSTALL_ROOT" == "$PREFIX"/* ]] || die 'Node.js 管理目录必须位于 TallyNote 安装目录内'
if [[ -n "$NODE_PATH" ]] && ! node_is_legacy_embedded "$NODE_PATH" && node_is_usable "$NODE_PATH"; then
stage_done "复用已配置的 Node.js ${NODE_VERSION_DETECTED}:$NODE_PATH"
return 0
fi
candidate=$(command -v node || true)
if [[ -n "$candidate" ]] && node_is_usable "$candidate"; then
NODE_PATH=$candidate
stage_done "复用系统 Node.js ${NODE_VERSION_DETECTED}:$NODE_PATH"
return 0
fi
marker="$NODE_INSTALL_ROOT/.tallynote-managed"
if [[ -f "$marker" && ! -L "$marker" && "$(sed -n '1p' "$marker" 2>/dev/null)" == tallynote-managed-node-v1 ]]; then
while IFS= read -r managed_node; do
[[ -n "$managed_node" ]] || continue
if node_is_usable "$managed_node"; then
NODE_PATH=$managed_node
stage_done "复用已安装的 Node.js ${NODE_VERSION_DETECTED}:$NODE_PATH"
return 0
fi
done < <(find "$NODE_INSTALL_ROOT" -mindepth 3 -maxdepth 3 -type f -path '*/bin/node' -print 2>/dev/null | sort -V -r)
fi
if (( ! APPLY )); then
log "dry-run: 当前主机需要 Node.js ${NODE_MIN_MAJOR}+;正式安装时将从 nodejs.org 下载并校验"
return 0
fi
[[ $EUID -eq 0 ]] || die '安装 Node.js 运行时必须以 root 运行'
install_managed_node
}
require_https() {
local value=$1
case "$value" in https://*) ;; *) die "release endpoints must use HTTPS: $value" ;; esac
@@ -711,7 +864,7 @@ normalize_release_tree() {
fi
find "$root" -type d -exec chmod 755 {} +
find "$root" -type f -exec chmod 644 {} +
for item in "$root/bin"/* "$root/scripts"/*.sh "$root/runtime/bin"/* "$root/uninstall.sh"; do
for item in "$root/bin"/* "$root/scripts"/*.sh "$root/uninstall.sh"; do
[[ -f "$item" && ! -L "$item" ]] || continue
chmod 755 "$item"
done
@@ -868,6 +1021,10 @@ stop_existing_services() {
rollback_install_if_needed() {
local result=$? rollback_tmp
# This helper intentionally returns the original exit status when used as
# the early EXIT trap. Once called from this rollback trap, swallow that
# status so errexit cannot skip restoration of the previous installation.
cleanup_node_install_if_needed || true
if (( INSTALL_COMMITTED == 0 && INSTALL_SYSTEMD_TOUCHED == 1 )) && command -v systemctl >/dev/null 2>&1; then
# The failed install may have started units that were inactive before the
# attempt. Stop them before restoring files so systemd never keeps running
@@ -928,6 +1085,10 @@ rollback_install_if_needed() {
if [[ -n "$INSTALL_WORK_DIR" && -d "$INSTALL_WORK_DIR" ]]; then
rm -rf -- "$INSTALL_WORK_DIR" 2>/dev/null || true
fi
if [[ -n "$INSTALL_UNIT_TMP" && -d "$INSTALL_UNIT_TMP" && ! -L "$INSTALL_UNIT_TMP" ]]; then
rm -rf -- "$INSTALL_UNIT_TMP" 2>/dev/null || true
fi
INSTALL_UNIT_TMP=''
return "$result"
}
@@ -1077,7 +1238,7 @@ validate_existing_env() {
mode_bits=$(stat_mode_bits "$file")
(( (mode_bits & 18) == 0 )) || die '环境文件不能被组或其他用户写入'
local key key_count
for key in TALLYNOTE_INSTALL_PREFIX TALLYNOTE_DATA_DIR TALLYNOTE_HOST TALLYNOTE_PORT TALLYNOTE_PUBLIC_ORIGIN TALLYNOTE_ALLOWED_ORIGINS TALLYNOTE_ALLOW_INSECURE_HTTP TALLYNOTE_COOKIE_SECURE TALLYNOTE_UPDATE_REQUIRE_SIGNATURE TALLYNOTE_UPDATE_METADATA_URL TALLYNOTE_UPDATE_ALLOWED_HOSTS TALLYNOTE_UPDATE_PUBLIC_KEY_FILE; do
for key in TALLYNOTE_INSTALL_PREFIX TALLYNOTE_DATA_DIR TALLYNOTE_CONFIG_DIR TALLYNOTE_NODE TALLYNOTE_HOST TALLYNOTE_PORT TALLYNOTE_PUBLIC_ORIGIN TALLYNOTE_ALLOWED_ORIGINS TALLYNOTE_ALLOW_INSECURE_HTTP TALLYNOTE_COOKIE_SECURE TALLYNOTE_UPDATE_REQUIRE_SIGNATURE TALLYNOTE_UPDATE_METADATA_URL TALLYNOTE_UPDATE_ALLOWED_HOSTS TALLYNOTE_UPDATE_PUBLIC_KEY_FILE; do
key_count=$(env_key_count "$file" "$key")
[[ "$key_count" =~ ^[0-9]+$ && "$key_count" -le 1 ]] || die "环境文件包含重复配置:$key"
done
@@ -1085,6 +1246,12 @@ validate_existing_env() {
[[ -z "$value" || "${value%/}" == "${PREFIX%/}" ]] || die '环境文件中的安装目录与本次安装不一致'
value=$(read_env_value "$file" TALLYNOTE_DATA_DIR)
[[ -z "$value" || "${value%/}" == "${DATA_DIR%/}" ]] || die '环境文件中的数据目录与本次安装不一致'
value=$(read_env_value "$file" TALLYNOTE_CONFIG_DIR)
[[ -z "$value" || "${value%/}" == "${CONFIG_DIR%/}" ]] || die '环境文件中的配置目录与本次安装不一致'
value=$(read_env_value "$file" TALLYNOTE_NODE)
if [[ -n "$value" ]]; then
validate_env_value "$value" '环境文件中的 Node.js 路径'
fi
value=$(read_env_value "$file" TALLYNOTE_UPDATE_REQUIRE_SIGNATURE)
[[ -z "$value" || "$value" == true || "$value" == false ]] || die '环境文件中的签名校验配置必须是 true 或 false'
if (( $(env_key_count "$file" TALLYNOTE_HOST) )); then
@@ -1161,6 +1328,7 @@ install_release() {
safe_extract "$archive" "$tmp/unpacked"
normalize_release_tree "$tmp/unpacked"
[[ -d "$tmp/unpacked/dist" ]] || die 'release archive must contain dist/ at its root'
[[ ! -e "$tmp/unpacked/runtime" ]] || die 'release archive must not contain an embedded Node.js runtime'
[[ -x "$tmp/unpacked/bin/tallynote" ]] || die 'release archive must contain executable bin/tallynote'
[[ -f "$tmp/unpacked/package.json" && -f "$tmp/unpacked/dist/server/index.js" && -f "$tmp/unpacked/dist/server/cli/admin-init.js" && -f "$tmp/unpacked/dist/web/index.html" ]] || die 'release archive is incomplete'
[[ -f "$tmp/unpacked/systemd/tallynote.service" && -f "$tmp/unpacked/systemd/tallynote-update.service" && -f "$tmp/unpacked/systemd/tallynote-update.path" ]] || die 'release archive is missing systemd units'
@@ -1224,6 +1392,9 @@ main() {
fi
detect_platform
configure_network_interactively
if [[ -z "$NODE_PATH" && -f "$CONFIG_DIR/tallynote.env" ]]; then
NODE_PATH=$(read_env_value "$CONFIG_DIR/tallynote.env" TALLYNOTE_NODE 2>/dev/null || true)
fi
validate_listen_host "$INSTALL_HOST"
validate_listen_port "$INSTALL_PORT"
if (( APPLY && NETWORK_INTERACTIVE )); then
@@ -1310,6 +1481,11 @@ main() {
for command_name in curl sha256sum tar install sed awk find systemctl; do
command -v "$command_name" >/dev/null 2>&1 || die "$command_name is required"
done
# Install the cleanup trap before downloading a managed Node.js runtime. A
# failed runtime download or extraction must not leave a partial toolchain
# behind even when release acquisition has not started yet.
trap cleanup_node_install_if_needed EXIT
ensure_node_runtime
if [[ "$REQUIRE_SIGNATURE" == true || -n "$SIGNATURE_URL" || -n "$SIGNING_KEY" || -n "$UPDATE_PUBLIC_KEY_FILE" ]]; then
command -v "$OPENSSL_BIN" >/dev/null 2>&1 || die 'openssl is required when signature verification is enabled'
fi
@@ -1394,24 +1570,26 @@ main() {
[[ -f "$release_dir/systemd/tallynote.env.example" && -f "$release_dir/scripts/tallynote-update-runner.sh" && -x "$release_dir/uninstall.sh" && -x "$release_dir/bin/tallynote-admin-init" && -f "$release_dir/dist/server/cli/admin-init.js" ]] || die 'release package is missing update/uninstall/admin-init support files'
stage '安装 systemd 单元、更新辅助程序和卸载器'
install -d -m 755 /usr/local/sbin /usr/local/libexec /etc/systemd/system
local unit_tmp
unit_tmp=$(mktemp -d)
sed "s#/opt/tallynote#$PREFIX#g; s#/var/lib/tallynote#$DATA_DIR#g" "$release_dir/systemd/tallynote.service" > "$unit_tmp/tallynote.service"
sed "s#/opt/tallynote#$PREFIX#g; s#/var/lib/tallynote#$DATA_DIR#g; s#/var/lib/tallynote-backups#$(dirname -- "$DATA_DIR")/tallynote-backups#g" "$release_dir/systemd/tallynote-update.service" > "$unit_tmp/tallynote-update.service"
sed "s#/opt/tallynote#$PREFIX#g; s#/var/lib/tallynote#$DATA_DIR#g" "$release_dir/systemd/tallynote-update.path" > "$unit_tmp/tallynote-update.path"
sed "s#/opt/tallynote#$PREFIX#g; s#/etc/tallynote#$CONFIG_DIR#g" "$release_dir/bin/tallynote-admin-init" > "$unit_tmp/tallynote-admin-init"
install -o root -g root -m 644 "$unit_tmp/tallynote.service" /etc/systemd/system/tallynote.service
install -o root -g root -m 644 "$unit_tmp/tallynote-update.service" /etc/systemd/system/tallynote-update.service
install -o root -g root -m 644 "$unit_tmp/tallynote-update.path" /etc/systemd/system/tallynote-update.path
install -o root -g root -m 755 "$unit_tmp/tallynote-admin-init" "$ADMIN_INIT_PATH"
rm -rf "$unit_tmp"
install -o root -g root -m 755 "$release_dir/scripts/tallynote-update.sh" /usr/local/sbin/tallynote-update
install -o root -g root -m 755 "$release_dir/scripts/tallynote-update-runner.sh" /usr/local/libexec/tallynote-update-runner
INSTALL_UNIT_TMP=$(mktemp -d)
sed "s#/opt/tallynote#$PREFIX#g; s#/var/lib/tallynote#$DATA_DIR#g; s#/etc/tallynote#$CONFIG_DIR#g" "$release_dir/systemd/tallynote.service" > "$INSTALL_UNIT_TMP/tallynote.service"
sed "s#/opt/tallynote#$PREFIX#g; s#/var/lib/tallynote-backups#$(dirname -- "$DATA_DIR")/tallynote-backups#g; s#/var/lib/tallynote#$DATA_DIR#g; s#/etc/tallynote#$CONFIG_DIR#g" "$release_dir/systemd/tallynote-update.service" > "$INSTALL_UNIT_TMP/tallynote-update.service"
sed "s#/opt/tallynote#$PREFIX#g; s#/var/lib/tallynote#$DATA_DIR#g" "$release_dir/systemd/tallynote-update.path" > "$INSTALL_UNIT_TMP/tallynote-update.path"
sed "s#/opt/tallynote#$PREFIX#g; s#/etc/tallynote#$CONFIG_DIR#g" "$release_dir/bin/tallynote-admin-init" > "$INSTALL_UNIT_TMP/tallynote-admin-init"
install -o root -g root -m 644 "$INSTALL_UNIT_TMP/tallynote.service" /etc/systemd/system/tallynote.service
install -o root -g root -m 644 "$INSTALL_UNIT_TMP/tallynote-update.service" /etc/systemd/system/tallynote-update.service
install -o root -g root -m 644 "$INSTALL_UNIT_TMP/tallynote-update.path" /etc/systemd/system/tallynote-update.path
install -o root -g root -m 755 "$INSTALL_UNIT_TMP/tallynote-admin-init" "$ADMIN_INIT_PATH"
sed "s#/opt/tallynote#$PREFIX#g; s#/var/lib/tallynote#$DATA_DIR#g; s#/etc/tallynote#$CONFIG_DIR#g" "$release_dir/scripts/tallynote-update.sh" > "$INSTALL_UNIT_TMP/tallynote-update.sh"
sed "s#/opt/tallynote#$PREFIX#g; s#/var/lib/tallynote#$DATA_DIR#g; s#/etc/tallynote#$CONFIG_DIR#g" "$release_dir/scripts/tallynote-update-runner.sh" > "$INSTALL_UNIT_TMP/tallynote-update-runner.sh"
install -o root -g root -m 755 "$INSTALL_UNIT_TMP/tallynote-update.sh" /usr/local/sbin/tallynote-update
install -o root -g root -m 755 "$INSTALL_UNIT_TMP/tallynote-update-runner.sh" /usr/local/libexec/tallynote-update-runner
rm -rf -- "$INSTALL_UNIT_TMP"
INSTALL_UNIT_TMP=''
install -o root -g root -m 755 "$release_dir/uninstall.sh" /usr/local/sbin/tallynote-uninstall
ensure_root_directory "$(dirname -- "$DATA_DIR")/tallynote-backups" 700
local env_created=0
if [[ ! -f "$CONFIG_DIR/tallynote.env" ]]; then
sed "s#/opt/tallynote#$PREFIX#g; s#/var/lib/tallynote#$DATA_DIR#g" "$release_dir/systemd/tallynote.env.example" > "$CONFIG_DIR/tallynote.env"
sed "s#/opt/tallynote#$PREFIX#g; s#/var/lib/tallynote#$DATA_DIR#g; s#/etc/tallynote#$CONFIG_DIR#g" "$release_dir/systemd/tallynote.env.example" > "$CONFIG_DIR/tallynote.env"
chown root:root "$CONFIG_DIR/tallynote.env"
chmod 640 "$CONFIG_DIR/tallynote.env"
env_created=1
@@ -1463,6 +1641,11 @@ main() {
if [[ -n "${TALLYNOTE_ALLOW_INSECURE_HTTP+x}" ]]; then set_env_key TALLYNOTE_ALLOW_INSECURE_HTTP "$INSTALL_ALLOW_INSECURE_HTTP"; fi
ensure_env_key TALLYNOTE_INSTALL_PREFIX "$PREFIX"
ensure_env_key TALLYNOTE_DATA_DIR "$DATA_DIR"
ensure_env_key TALLYNOTE_CONFIG_DIR "$CONFIG_DIR"
configured_node=$(read_env_value "$CONFIG_DIR/tallynote.env" TALLYNOTE_NODE 2>/dev/null || true)
if [[ -z "$configured_node" ]] || node_is_legacy_embedded "$configured_node" || ! node_is_usable "$configured_node"; then
set_env_key TALLYNOTE_NODE "$NODE_PATH"
fi
ensure_env_key TALLYNOTE_UPDATE_STRATEGY systemd
ensure_env_key TALLYNOTE_UPDATE_METADATA_URL "$RELEASE_API_URL"
ensure_env_key TALLYNOTE_UPDATE_ALLOWED_HOSTS "$RELEASE_ALLOWED_HOSTS"