252 lines
6.9 KiB
Bash
Executable File
252 lines
6.9 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
# User-only installer for Qubes AppVM persistence model.
|
|
# Nothing is written to /usr, /etc, or other root-owned paths.
|
|
#
|
|
# Installs into $HOME:
|
|
# - nsigner -> ~/.local/bin/nsigner
|
|
# - startup helper -> ~/start_nsigner.sh
|
|
#
|
|
# Usage:
|
|
# bash install_qube_fips_nsigner.sh
|
|
# bash install_qube_fips_nsigner.sh --help
|
|
#
|
|
# Optional env vars:
|
|
# NSIGNER_VERSION=vX.Y.Z # optional override; default is latest release tag
|
|
# NSIGNER_GITEA_TOKEN=<token> # if n_signer release assets are private
|
|
# NSIGNER_BINARY_URL=<direct url to nsigner_static_x86_64>
|
|
|
|
NSIGNER_VERSION="${NSIGNER_VERSION:-}"
|
|
|
|
PREFIX_BIN="${HOME}/.local/bin"
|
|
|
|
log() { printf "\033[1;34m[INFO]\033[0m %s\n" "$*"; }
|
|
warn() { printf "\033[1;33m[WARN]\033[0m %s\n" "$*"; }
|
|
err() { printf "\033[1;31m[ERR ]\033[0m %s\n" "$*"; }
|
|
|
|
show_help() {
|
|
cat <<EOF
|
|
Usage: bash install_qube_fips_nsigner.sh [options]
|
|
|
|
User-only install (Qubes AppVM friendly):
|
|
- n_signer ${NSIGNER_VERSION}
|
|
- signer startup helper script
|
|
|
|
Options:
|
|
-h, --help Show this help and exit
|
|
|
|
Optional env vars:
|
|
NSIGNER_VERSION=vX.Y.Z # optional override; default is latest release tag
|
|
NSIGNER_GITEA_TOKEN=<token> # required if n_signer release assets are private
|
|
NSIGNER_BINARY_URL=<direct url to nsigner_static_x86_64>
|
|
|
|
Install paths:
|
|
~/.local/bin/nsigner
|
|
~/start_nsigner.sh
|
|
EOF
|
|
}
|
|
|
|
require_cmd() {
|
|
command -v "$1" >/dev/null 2>&1 || {
|
|
err "Missing command: $1"
|
|
exit 1
|
|
}
|
|
}
|
|
|
|
install_runtime_deps() {
|
|
if command -v apt-get >/dev/null 2>&1; then
|
|
log "Installing runtime dependencies via apt"
|
|
sudo apt-get update
|
|
sudo apt-get install -y ca-certificates curl jq
|
|
elif command -v dnf >/dev/null 2>&1; then
|
|
log "Installing runtime dependencies via dnf"
|
|
sudo dnf install -y ca-certificates curl jq
|
|
else
|
|
err "Unsupported distro: need apt-get or dnf to install runtime dependencies"
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
prepare_dirs() {
|
|
mkdir -p "${PREFIX_BIN}"
|
|
}
|
|
|
|
resolve_nsigner_version() {
|
|
local headers=()
|
|
local latest_tag=""
|
|
|
|
if [[ -n "${NSIGNER_VERSION}" ]]; then
|
|
return 0
|
|
fi
|
|
|
|
if [[ -n "${NSIGNER_GITEA_TOKEN:-}" ]]; then
|
|
headers=(-H "Authorization: token ${NSIGNER_GITEA_TOKEN}")
|
|
fi
|
|
|
|
latest_tag="$(curl -fsSL "${headers[@]}" "https://git.laantungir.net/api/v1/repos/laantungir/n_signer/releases" \
|
|
| jq -r '.[0].tag_name // empty' || true)"
|
|
|
|
if [[ -z "${latest_tag}" ]]; then
|
|
err "Could not resolve latest n_signer release tag from API."
|
|
err "Set NSIGNER_VERSION explicitly (e.g. NSIGNER_VERSION=v0.0.11)."
|
|
exit 1
|
|
fi
|
|
|
|
NSIGNER_VERSION="${latest_tag}"
|
|
}
|
|
|
|
download_nsigner_asset_url() {
|
|
local headers=()
|
|
local api_tag_url="https://git.laantungir.net/api/v1/repos/laantungir/n_signer/releases/tags/${NSIGNER_VERSION}"
|
|
|
|
if [[ -n "${NSIGNER_GITEA_TOKEN:-}" ]]; then
|
|
headers=(-H "Authorization: token ${NSIGNER_GITEA_TOKEN}")
|
|
fi
|
|
|
|
curl -fsSL "${headers[@]}" "${api_tag_url}" \
|
|
| jq -r '.assets[]?.browser_download_url // empty' \
|
|
| grep -E 'nsigner_static_x86_64$' \
|
|
| head -n1 || true
|
|
}
|
|
|
|
verify_installed_version() {
|
|
local expected="$1"
|
|
local got_line=""
|
|
local got_ver=""
|
|
|
|
if [[ ! -x "${PREFIX_BIN}/nsigner" ]]; then
|
|
err "Installed binary missing: ${PREFIX_BIN}/nsigner"
|
|
exit 1
|
|
fi
|
|
|
|
got_line="$("${PREFIX_BIN}/nsigner" --version 2>/dev/null || true)"
|
|
got_ver="$(printf '%s\n' "${got_line}" | awk '{print $2}')"
|
|
|
|
if [[ -z "${got_ver}" ]]; then
|
|
err "Could not determine installed n_signer version from: ${got_line}"
|
|
exit 1
|
|
fi
|
|
|
|
if [[ "${got_ver}" != "${expected}" ]]; then
|
|
err "Downloaded binary version mismatch: expected ${expected}, got ${got_ver}"
|
|
err "Release asset appears stale or mislabeled."
|
|
err "Use NSIGNER_BINARY_URL to pin a known-good binary, or wait for a rebuilt release artifact."
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
install_nsigner() {
|
|
local release_page=""
|
|
|
|
resolve_nsigner_version
|
|
release_page="https://git.laantungir.net/laantungir/n_signer/releases/tag/${NSIGNER_VERSION}"
|
|
|
|
log "Installing n_signer ${NSIGNER_VERSION}"
|
|
log "Release page: ${release_page}"
|
|
|
|
local asset_url="${NSIGNER_BINARY_URL:-}"
|
|
if [[ -z "${asset_url}" ]]; then
|
|
asset_url="$(download_nsigner_asset_url)"
|
|
fi
|
|
|
|
if [[ -z "${asset_url}" ]]; then
|
|
err "Could not find downloadable n_signer x86_64 release binary for ${NSIGNER_VERSION}."
|
|
err "Provide NSIGNER_BINARY_URL or NSIGNER_GITEA_TOKEN so the release asset can be resolved."
|
|
exit 1
|
|
fi
|
|
|
|
log "Using n_signer binary URL: ${asset_url}"
|
|
if [[ -n "${NSIGNER_GITEA_TOKEN:-}" ]]; then
|
|
curl -fL -H "Authorization: token ${NSIGNER_GITEA_TOKEN}" -o "${PREFIX_BIN}/nsigner" "${asset_url}"
|
|
else
|
|
curl -fL -o "${PREFIX_BIN}/nsigner" "${asset_url}"
|
|
fi
|
|
chmod 0755 "${PREFIX_BIN}/nsigner"
|
|
|
|
verify_installed_version "${NSIGNER_VERSION}"
|
|
log "Installed ${PREFIX_BIN}/nsigner from release binary"
|
|
}
|
|
|
|
write_signer_start_script() {
|
|
local script_path="${HOME}/start_nsigner.sh"
|
|
|
|
cat >"${script_path}" <<'EOF'
|
|
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
export PATH="$HOME/.local/bin:$PATH"
|
|
LISTEN_TARGET="${NSIGNER_LISTEN_TARGET:-tcp:[::]:8080}"
|
|
|
|
echo "=== n_signer startup ==="
|
|
echo "listen target: ${LISTEN_TARGET}"
|
|
|
|
# Optional: print current FIPS identity info if fipsctl is available.
|
|
if command -v fipsctl >/dev/null 2>&1; then
|
|
if fipsctl show status >/dev/null 2>&1; then
|
|
STATUS_JSON="$(fipsctl show status)"
|
|
elif sudo -n fipsctl show status >/dev/null 2>&1; then
|
|
STATUS_JSON="$(sudo -n fipsctl show status)"
|
|
else
|
|
STATUS_JSON=""
|
|
fi
|
|
|
|
if [[ -n "${STATUS_JSON}" ]]; then
|
|
FIPS_IPV6="$(printf '%s\n' "${STATUS_JSON}" | sed -n 's/.*"ipv6_addr": "\([^"]*\)".*/\1/p')"
|
|
FIPS_NPUB="$(printf '%s\n' "${STATUS_JSON}" | sed -n 's/.*"npub": "\([^"]*\)".*/\1/p')"
|
|
LISTEN_PORT="$(printf '%s\n' "${LISTEN_TARGET}" | sed -n 's/.*:\([0-9][0-9]*\)$/\1/p')"
|
|
[[ -n "${FIPS_IPV6}" ]] && echo "fips ipv6: ${FIPS_IPV6}"
|
|
[[ -n "${FIPS_NPUB}" ]] && echo "fips npub: ${FIPS_NPUB}"
|
|
if [[ -n "${FIPS_NPUB}" && -n "${LISTEN_PORT}" ]]; then
|
|
echo "fips address: http://${FIPS_NPUB}.fips:${LISTEN_PORT}"
|
|
fi
|
|
else
|
|
echo "fips status: unavailable (run as user in fips group or with sudo)"
|
|
fi
|
|
fi
|
|
|
|
echo
|
|
echo "Starting signer..."
|
|
echo "On first remote request, approve in prompt with [y] or [a]."
|
|
exec "$HOME/.local/bin/nsigner" --listen "${LISTEN_TARGET}"
|
|
EOF
|
|
|
|
chmod 0755 "${script_path}"
|
|
log "Wrote ${script_path}"
|
|
}
|
|
|
|
post_checks() {
|
|
export PATH="${PREFIX_BIN}:${PATH}"
|
|
|
|
log "Running post-install checks"
|
|
require_cmd nsigner
|
|
nsigner --version || true
|
|
|
|
log "User binaries installed in: ${PREFIX_BIN}"
|
|
log "If needed, add to shell PATH: export PATH=\"${PREFIX_BIN}:\$PATH\""
|
|
}
|
|
|
|
main() {
|
|
if [[ "${1:-}" == "-h" || "${1:-}" == "--help" ]]; then
|
|
show_help
|
|
exit 0
|
|
fi
|
|
|
|
if [[ $# -gt 0 ]]; then
|
|
err "Unknown option: $1"
|
|
show_help
|
|
exit 1
|
|
fi
|
|
|
|
install_runtime_deps
|
|
prepare_dirs
|
|
install_nsigner
|
|
write_signer_start_script
|
|
post_checks
|
|
|
|
log "Completed user-only install of n_signer"
|
|
log "Start signer with: ~/start_nsigner.sh"
|
|
}
|
|
|
|
main "$@"
|