#!/usr/bin/env bash set -Eeuo pipefail readonly SCRIPT_NAME="${0##*/}" SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" readonly SCRIPT_DIR # shellcheck source=../lib/reporting.sh source "${SCRIPT_DIR}/../lib/reporting.sh" readonly NETWORK_STATE="/run/tuxflotte/network/state.env" readonly HARDWARE_FILE="/run/tuxflotte/hardware/hardware.json" readonly RUNTIME_DIR="/run/tuxflotte/server" readonly ACTIVATION_FILE="${RUNTIME_DIR}/activation.json" readonly AUTHORIZATION_FILE="/run/tuxflotte/enrollment/authorization.json" readonly RESPONSE_FILE="${RUNTIME_DIR}/response.json" log() { printf '[%s] %s\n' "${SCRIPT_NAME}" "$*" >&2 } fatal() { printf '[%s] FEHLER: %s\n' "${SCRIPT_NAME}" "$*" >&2 exit 1 } require_root() { if [[ "${EUID}" -ne 0 ]]; then fatal "Das Server-Handshake-Modul muss als root ausgeführt werden." fi } prepare_runtime_directory() { install -d \ --mode=0700 \ --owner=root \ --group=root \ "${RUNTIME_DIR}" rm -f -- "${ACTIVATION_FILE}" "${RESPONSE_FILE}" } validate_inputs() { [[ -r "${NETWORK_STATE}" ]] || fatal "Netzwerkstatus nicht gefunden: ${NETWORK_STATE}" [[ -r "${HARDWARE_FILE}" ]] || fatal "Hardwareinformationen nicht gefunden: ${HARDWARE_FILE}" jq --exit-status . "${HARDWARE_FILE}" >/dev/null || fatal "Hardwaredatei enthält kein gültiges JSON." [[ -r "${AUTHORIZATION_FILE}" ]] || fatal "Enrollment-Autorisierung nicht gefunden: ${AUTHORIZATION_FILE}" jq --exit-status ' .schema_version == 1 and .authorization_type == "bootstrap_activation_code" and (.activation_code | type == "string") and (.activation_code | length > 0) ' "${AUTHORIZATION_FILE}" >/dev/null || fatal "Enrollment-Autorisierung ist ungültig." } build_activation_request() { local activation_code="$1" local hostname local machine_id hostname="$(hostname)" machine_id="$( jq --raw-output \ '.identity.machine_id // empty' \ "${HARDWARE_FILE}" )" jq \ --null-input \ --arg activation_code "${activation_code}" \ --arg hostname "${hostname}" \ --arg machine_id "${machine_id}" \ --arg client_version "0.1.0" \ --slurpfile hardware "${HARDWARE_FILE}" \ '{ activation_code: $activation_code, device_fingerprint: $hardware[0].identity.device_fingerprint, hostname: $hostname, machine_id: ( if $machine_id == "" then null else $machine_id end ), client_version: $client_version, hardware: $hardware[0] }' } send_activation_request() { local server_url # shellcheck disable=SC1090 source "${NETWORK_STATE}" server_url="${TUXFLOTTE_SERVER_URL%/health}" curl \ --silent \ --show-error \ --fail \ --location \ --header 'Content-Type: application/json' \ --data-binary "@${ACTIVATION_FILE}" \ --output "${RESPONSE_FILE}" \ "${server_url}/api/v1/activate" || fatal "Provisioning-Server konnte nicht erfolgreich kontaktiert werden." chmod 0600 "${RESPONSE_FILE}" jq --exit-status . "${RESPONSE_FILE}" >/dev/null || fatal "Serverantwort enthält kein gültiges JSON." jq --exit-status '.success == true' "${RESPONSE_FILE}" >/dev/null || fatal "Provisioning-Server hat die Aktivierung abgelehnt." log "Provisioning-Handshake erfolgreich abgeschlossen." tuxflotte_report_installation_event "activation_confirmed" } main() { require_root prepare_runtime_directory validate_inputs log "Eingabedaten für den Provisioning-Handshake sind gültig." local activation_code local activation_code activation_code="$( jq --raw-output \ '.activation_code' \ "${AUTHORIZATION_FILE}" )" build_activation_request "${activation_code}" >"${ACTIVATION_FILE}" chmod 0600 "${ACTIVATION_FILE}" jq --exit-status . "${ACTIVATION_FILE}" >/dev/null || fatal "Aktivierungsrequest enthält kein gültiges JSON." log "Aktivierungsrequest wurde unter ${ACTIVATION_FILE} gespeichert." send_activation_request } main "$@"