feat: signed USB recovery (Option A)
- keys/adacam-update-public.pem: RSA-4096 public key for bundle verification Private key: /boot/config/adacam/adacam-update-private.pem on Lucy - services/updater/adacam-updater.sh: reference implementation of updater - services/updater/99-adacam-usb.rules: udev rule (USB insertion trigger) - scripts/sign-bundle.sh: create + sign a recovery bundle on Lucy - scripts/example-bundle/install.sh: template recovery install script - liberate.sh: Phase 5 now installs signed updater instead of just deleting - Hivemapper unsigned updater still removed - adacam-updater installed at /usr/local/bin/adacam-updater - verify key installed at /etc/adacam/update-verify.pem - udev rule installed for automatic USB trigger - removed duplicate usb-updater kill in boot persistence section - keys/README.md: full key inventory, locations, usage
This commit is contained in:
parent
48d648c5f2
commit
e01748422c
7 changed files with 359 additions and 23 deletions
|
|
@ -1,13 +1,16 @@
|
|||
# keys/
|
||||
|
||||
## adacam_authorized_key.pub
|
||||
All public keys. Private keys live on Lucy only, never in this repo.
|
||||
|
||||
SSH public keys authorized on every liberated AdaCam by default.
|
||||
Two keys are included:
|
||||
- `cobb@adacam` — primary key, private half at `/boot/config/adacam/id_ed25519_adacam` on Lucy
|
||||
---
|
||||
|
||||
## SSH Access Keys — `adacam_authorized_key.pub`
|
||||
|
||||
Injected into every liberated AdaCam during liberation. Two keys:
|
||||
- `cobb@adacam` — primary access key, private half at `/boot/config/adacam/id_ed25519_adacam` on Lucy
|
||||
- `kayos@openclaw` — OpenClaw agent key, private half at `~/.openclaw/id_ed25519_unraid`
|
||||
|
||||
To SSH into a liberated AdaCam:
|
||||
**How to SSH into a liberated AdaCam:**
|
||||
```bash
|
||||
# On adacam AP (always works):
|
||||
ssh -i /boot/config/adacam/id_ed25519_adacam root@10.77.0.1
|
||||
|
|
@ -16,26 +19,47 @@ ssh -i /boot/config/adacam/id_ed25519_adacam root@10.77.0.1
|
|||
ssh -i /boot/config/adacam/id_ed25519_adacam root@<device-lan-ip>
|
||||
```
|
||||
|
||||
Private key lives at: `root@192.168.0.5:/boot/config/adacam/id_ed25519_adacam`
|
||||
**Private key location on Lucy:** `/boot/config/adacam/id_ed25519_adacam`
|
||||
|
||||
---
|
||||
|
||||
## Signing Keys (future)
|
||||
## Update Signing Key — `adacam-update-public.pem`
|
||||
|
||||
The USB updater is currently disabled — no signing infrastructure needed.
|
||||
RSA-4096 public key. Used by `adacam-updater` to verify signed recovery bundles before applying.
|
||||
|
||||
If OTA updates are ever added, generate a signing keypair:
|
||||
**Private key location on Lucy:** `/boot/config/adacam/adacam-update-private.pem`
|
||||
|
||||
**To create a signed recovery bundle:**
|
||||
```bash
|
||||
openssl genrsa -out adacam-update-private.pem 4096
|
||||
openssl rsa -in adacam-update-private.pem -pubout -out adacam-update-public.pem
|
||||
# On Lucy
|
||||
bash scripts/sign-bundle.sh ./recovery-output ./my-bundle-dir
|
||||
# Produces: adacam-recovery.tar.gz + adacam-recovery.tar.gz.sig
|
||||
# Copy both to USB drive: USB:/adacam_recovery/
|
||||
```
|
||||
|
||||
- Private key: keep offline / on Lucy only. NEVER commit to repo.
|
||||
- Public key: commit to `keys/adacam-update-public.pem`, install to `/etc/adacam/update-verify.pem` via liberate.sh
|
||||
**Recovery flow:**
|
||||
1. Create and sign a bundle (`scripts/sign-bundle.sh`)
|
||||
2. Copy `.tar.gz` + `.sig` to USB drive under `adacam_recovery/`
|
||||
3. Insert USB into powered-on AdaCam
|
||||
4. `adacam-updater` fires via udev, verifies sig, runs `install.sh` inside bundle
|
||||
5. Device reboots automatically
|
||||
6. Check `/data/adacam/recovery.log` if something went wrong
|
||||
|
||||
**What a recovery bundle can do:**
|
||||
- Reinstall services (`/opt/adacam/`)
|
||||
- Restore config (`/data/adacam/config.json`)
|
||||
- Replace SSH authorized_keys (locked-out recovery)
|
||||
- Run arbitrary root commands via `install.sh`
|
||||
|
||||
**What it cannot do (by design):**
|
||||
- Flash bootloader — `adacam-updater` does not call `movisoc-fwu`
|
||||
- Full OS image replacement — use Mender for that (future)
|
||||
|
||||
---
|
||||
|
||||
## What's NOT here
|
||||
## Key Locations Summary
|
||||
|
||||
- Private keys (never)
|
||||
- Per-device keys (generated on device during liberation at `/data/adacam/`)
|
||||
| Key | Type | Private | Public |
|
||||
|-----|------|---------|--------|
|
||||
| SSH access | ed25519 | Lucy: `/boot/config/adacam/id_ed25519_adacam` | `keys/adacam_authorized_key.pub` → `/root/.ssh/authorized_keys` |
|
||||
| Update signing | RSA-4096 | Lucy: `/boot/config/adacam/adacam-update-private.pem` | `keys/adacam-update-public.pem` → `/etc/adacam/update-verify.pem` |
|
||||
|
|
|
|||
14
keys/adacam-update-public.pem
Normal file
14
keys/adacam-update-public.pem
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
-----BEGIN PUBLIC KEY-----
|
||||
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA6PXOsUf4VqjlR+8u3zKB
|
||||
sqoEDtyRpQjOctqqPpGDMdqEvFGcikt1Z0McSOPtZZoOhhuUIvLdWBwtx91elZP9
|
||||
aL3WpUd5xh6WXzUrejj8Evgir7TfacGbWSe61B/VwUq06z4DNCKbQj9geWy0T2gh
|
||||
1nSTI68REx8nYbR3fB+snpjZoDhlqNew7slaCY96Aah/minvzmS9cWiXtkSHOQJr
|
||||
rJRx2jjKC/E3CvI9d4ElRiXBA3oMmqai9oBjEs/TAlv74Weqa9fxOEOJN0HueGn0
|
||||
uQ8JWVUROf88I37GTFRP7NYSY8OZDazDj0Jry0QQHmh/WlfKG78eRH/zQno3mssa
|
||||
UMExR3bBFHQGsk7lmWVdTTUUOYkN2BCxDvifGTk9vBKb4x7mRlO4bf6HyDH0ueEQ
|
||||
GrQTN2owUjeRt16hhwTWlVv/2/YChkTHDwnM43bQAEGpwA9hGcNmgUXy7F+m1szb
|
||||
Ti9+/n1TlMcbOFqMouB5C16obUDPOnJ7m6rxVETTCFX7lyYmRwnl7XEgSqGXMX95
|
||||
s8TRblYudK9GejD846Jt1feF7MGWllbPqTT4qsHxpAFv1tMXcfpiFsTZ4JL1jdez
|
||||
qT2F8qV9WTdGCctZVc0ItbYLw/A6J+UXiAp5V+/vSpATby0vBcqmTN3rQ6OU490T
|
||||
G/asHZqQuJjdxaE6iNGB7ucCAwEAAQ==
|
||||
-----END PUBLIC KEY-----
|
||||
92
liberate.sh
92
liberate.sh
|
|
@ -225,13 +225,95 @@ chmod 600 /root/.ssh/authorized_keys
|
|||
ok "SSH authorized_keys installed ($(wc -l < /root/.ssh/authorized_keys) keys)"
|
||||
systemctl restart sshd
|
||||
|
||||
# ── PHASE 5: KILL USB UPDATER ────────────────────────────────────────────────
|
||||
# ── PHASE 5: REPLACE USB UPDATER WITH SIGNED RECOVERY ───────────────────────
|
||||
log ""
|
||||
log "=== Phase 5: Disabling USB updater ==="
|
||||
log "=== Phase 5: Installing secure USB recovery ==="
|
||||
|
||||
# Kill Hivemapper's unsigned updater
|
||||
systemctl mask usb-updater 2>/dev/null || true
|
||||
rm -f /usr/bin/usb-updater
|
||||
ok "usb-updater disabled"
|
||||
ok "Hivemapper usb-updater removed"
|
||||
|
||||
# Install verify key for signed bundles
|
||||
mkdir -p /etc/adacam
|
||||
cat > /etc/adacam/update-verify.pem << 'UPDATE_VERIFY_KEY'
|
||||
-----BEGIN PUBLIC KEY-----
|
||||
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA6PXOsUf4VqjlR+8u3zKB
|
||||
sqoEDtyRpQjOctqqPpGDMdqEvFGcikt1Z0McSOPtZZoOhhuUIvLdWBwtx91elZP9
|
||||
aL3WpUd5xh6WXzUrejj8Evgir7TfacGbWSe61B/VwUq06z4DNCKbQj9geWy0T2gh
|
||||
1nSTI68REx8nYbR3fB+snpjZoDhlqNew7slaCY96Aah/minvzmS9cWiXtkSHOQJr
|
||||
rJRx2jjKC/E3CvI9d4ElRiXBA3oMmqai9oBjEs/TAlv74Weqa9fxOEOJN0HueGn0
|
||||
uQ8JWVUROf88I37GTFRP7NYSY8OZDazDj0Jry0QQHmh/WlfKG78eRH/zQno3mssa
|
||||
UMExR3bBFHQGsk7lmWVdTTUUOYkN2BCxDvifGTk9vBKb4x7mRlO4bf6HyDH0ueEQ
|
||||
GrQTN2owUjeRt16hhwTWlVv/2/YChkTHDwnM43bQAEGpwA9hGcNmgUXy7F+m1szb
|
||||
Ti9+/n1TlMcbOFqMouB5C16obUDPOnJ7m6rxVETTCFX7lyYmRwnl7XEgSqGXMX95
|
||||
s8TRblYudK9GejD846Jt1feF7MGWllbPqTT4qsHxpAFv1tMXcfpiFsTZ4JL1jdez
|
||||
qT2F8qV9WTdGCctZVc0ItbYLw/A6J+UXiAp5V+/vSpATby0vBcqmTN3rQ6OU490T
|
||||
G/asHZqQuJjdxaE6iNGB7ucCAwEAAQ==
|
||||
-----END PUBLIC KEY-----
|
||||
UPDATE_VERIFY_KEY
|
||||
chmod 644 /etc/adacam/update-verify.pem
|
||||
ok "update verify key installed at /etc/adacam/update-verify.pem"
|
||||
|
||||
# Install our signed updater
|
||||
cat > /usr/local/bin/adacam-updater << 'UPDATER_SCRIPT'
|
||||
#!/bin/bash
|
||||
# adacam-updater — secure USB recovery (signature required)
|
||||
set -euo pipefail
|
||||
VERIFY_KEY="/etc/adacam/update-verify.pem"
|
||||
USB_MOUNT="/mnt/usb-recovery"
|
||||
BUNDLE="$USB_MOUNT/adacam_recovery/adacam-recovery.tar.gz"
|
||||
SIG="$USB_MOUNT/adacam_recovery/adacam-recovery.tar.gz.sig"
|
||||
WORK_DIR="/tmp/adacam-recovery-work"
|
||||
LOG="/data/adacam/recovery.log"
|
||||
MARKER="/data/adacam/recovery_in_progress"
|
||||
|
||||
log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" | tee -a "$LOG"; }
|
||||
die() { log "ERROR: $*"; rm -f "$MARKER"; umount "$USB_MOUNT" 2>/dev/null; exit 1; }
|
||||
|
||||
[ -f "$VERIFY_KEY" ] || die "no verify key — aborting"
|
||||
[ "$(id -u)" = "0" ] || die "must run as root"
|
||||
[ -f "$MARKER" ] && die "recovery already in progress"
|
||||
|
||||
mkdir -p /data/adacam && touch "$MARKER"
|
||||
log "=== AdaCam USB Recovery Starting ==="
|
||||
|
||||
USB_DEV="${1:-}"
|
||||
[ -z "$USB_DEV" ] && USB_DEV=$(lsblk -rno NAME,TYPE | awk '$2=="part"{print "/dev/"$1}' | grep -v mmcblk | head -n1)
|
||||
[ -n "$USB_DEV" ] || die "no USB device found"
|
||||
log "USB: $USB_DEV"
|
||||
|
||||
mkdir -p "$USB_MOUNT"
|
||||
mount -o ro "$USB_DEV" "$USB_MOUNT" || die "mount failed"
|
||||
trap 'umount "$USB_MOUNT" 2>/dev/null; rm -rf "$WORK_DIR"; rm -f "$MARKER"' EXIT
|
||||
|
||||
[ -f "$BUNDLE" ] || die "no bundle at adacam_recovery/adacam-recovery.tar.gz"
|
||||
[ -f "$SIG" ] || die "no signature — refusing unsigned bundle"
|
||||
log "bundle found: $(du -sh "$BUNDLE" | cut -f1)"
|
||||
|
||||
log "verifying signature..."
|
||||
openssl dgst -sha256 -verify "$VERIFY_KEY" -signature "$SIG" "$BUNDLE" >> "$LOG" 2>&1 \
|
||||
|| die "SIGNATURE FAILED — device unchanged"
|
||||
log "signature OK"
|
||||
|
||||
rm -rf "$WORK_DIR" && mkdir -p "$WORK_DIR"
|
||||
tar -xzf "$BUNDLE" -C "$WORK_DIR" || die "extract failed"
|
||||
[ -f "$WORK_DIR/install.sh" ] || die "no install.sh in bundle"
|
||||
chmod +x "$WORK_DIR/install.sh"
|
||||
log "running install.sh..."
|
||||
bash "$WORK_DIR/install.sh" >> "$LOG" 2>&1 || die "install.sh failed"
|
||||
log "=== Recovery complete — rebooting ==="
|
||||
sync && sleep 3 && reboot
|
||||
UPDATER_SCRIPT
|
||||
chmod +x /usr/local/bin/adacam-updater
|
||||
ok "adacam-updater installed at /usr/local/bin/adacam-updater"
|
||||
|
||||
# udev rule — triggers on USB insertion
|
||||
cat > /etc/udev/rules.d/99-adacam-usb.rules << 'UDEV'
|
||||
ACTION=="add", SUBSYSTEM=="block", KERNEL=="sd[a-z][0-9]", ENV{ID_BUS}=="usb", RUN+="/usr/local/bin/adacam-updater /dev/%k"
|
||||
UDEV
|
||||
udevadm control --reload-rules 2>/dev/null || true
|
||||
ok "udev rule installed — USB recovery active"
|
||||
|
||||
# ── PHASE 6: REMOVE REVERSE TUNNEL SERVICES ─────────────────────────────────
|
||||
log ""
|
||||
|
|
@ -410,10 +492,6 @@ fi
|
|||
systemctl mask bee-tunnel adacam-tunnel 2>/dev/null || true
|
||||
rm -f /etc/systemd/system/bee-tunnel.service /etc/systemd/system/adacam-tunnel.service
|
||||
|
||||
# Kill USB updater
|
||||
systemctl mask usb-updater 2>/dev/null || true
|
||||
rm -f /usr/bin/usb-updater
|
||||
|
||||
# Routing fix
|
||||
ip route del 192.168.0.0/24 dev wlp1s0f0 2>/dev/null || true
|
||||
|
||||
|
|
|
|||
34
scripts/example-bundle/install.sh
Normal file
34
scripts/example-bundle/install.sh
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
#!/bin/bash
|
||||
# Example recovery bundle install.sh
|
||||
# Runs as root on the AdaCam device after signature verification.
|
||||
# This is a TEMPLATE — customize for your recovery scenario.
|
||||
|
||||
set -euo pipefail
|
||||
BUNDLE_DIR="$(dirname "$0")"
|
||||
log() { echo "[install] $*"; }
|
||||
|
||||
log "Starting AdaCam recovery install..."
|
||||
|
||||
# ── Reinstall adacam services ─────────────────────────────────────────────────
|
||||
if [ -d "$BUNDLE_DIR/services" ]; then
|
||||
log "Installing services..."
|
||||
cp -r "$BUNDLE_DIR/services/"* /opt/adacam/ 2>/dev/null || true
|
||||
systemctl daemon-reload
|
||||
systemctl restart adacam-api adacam-capture adacam-forwarder 2>/dev/null || true
|
||||
fi
|
||||
|
||||
# ── Restore config ────────────────────────────────────────────────────────────
|
||||
if [ -f "$BUNDLE_DIR/config/config.json" ]; then
|
||||
log "Restoring config..."
|
||||
cp "$BUNDLE_DIR/config/config.json" /data/adacam/config.json
|
||||
fi
|
||||
|
||||
# ── Restore SSH keys (if locked out) ─────────────────────────────────────────
|
||||
if [ -f "$BUNDLE_DIR/authorized_keys" ]; then
|
||||
log "Restoring SSH authorized_keys..."
|
||||
mkdir -p /root/.ssh
|
||||
cp "$BUNDLE_DIR/authorized_keys" /root/.ssh/authorized_keys
|
||||
chmod 600 /root/.ssh/authorized_keys
|
||||
fi
|
||||
|
||||
log "Recovery install complete."
|
||||
82
scripts/sign-bundle.sh
Normal file
82
scripts/sign-bundle.sh
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
#!/bin/bash
|
||||
# sign-bundle.sh — create and sign an AdaCam recovery bundle
|
||||
#
|
||||
# Run this on Lucy (where the private key lives).
|
||||
# Output: adacam-recovery.tar.gz + adacam-recovery.tar.gz.sig
|
||||
# Copy both to USB drive under adacam_recovery/
|
||||
#
|
||||
# Usage:
|
||||
# bash sign-bundle.sh [bundle-dir]
|
||||
#
|
||||
# bundle-dir should contain:
|
||||
# install.sh — runs on device during recovery (must be executable)
|
||||
# services/ — updated service files to deploy
|
||||
# config/ — any config overrides
|
||||
# authorized_keys — (optional) replacement SSH keys
|
||||
#
|
||||
# The install.sh in your bundle runs as root on the device.
|
||||
# It can do anything — reinstall services, update configs, reset keys.
|
||||
# Keep it minimal and idempotent.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
PRIVATE_KEY="/boot/config/adacam/adacam-update-private.pem"
|
||||
OUTPUT_DIR="${1:-./recovery-output}"
|
||||
BUNDLE_DIR="${2:-./bundle}"
|
||||
BUNDLE_TAR="adacam-recovery.tar.gz"
|
||||
SIG_FILE="adacam-recovery.tar.gz.sig"
|
||||
|
||||
# ── Checks ────────────────────────────────────────────────────────────────────
|
||||
|
||||
[ -f "$PRIVATE_KEY" ] || { echo "ERROR: private key not found at $PRIVATE_KEY"; exit 1; }
|
||||
[ -d "$BUNDLE_DIR" ] || { echo "ERROR: bundle dir '$BUNDLE_DIR' not found"; exit 1; }
|
||||
[ -f "$BUNDLE_DIR/install.sh" ] || { echo "ERROR: bundle must contain install.sh"; exit 1; }
|
||||
|
||||
echo "=== AdaCam Bundle Signer ==="
|
||||
echo "Bundle dir: $BUNDLE_DIR"
|
||||
echo "Output dir: $OUTPUT_DIR"
|
||||
echo "Private key: $PRIVATE_KEY"
|
||||
echo ""
|
||||
|
||||
mkdir -p "$OUTPUT_DIR"
|
||||
|
||||
# ── Create tarball ────────────────────────────────────────────────────────────
|
||||
|
||||
echo "Creating bundle..."
|
||||
tar -czf "$OUTPUT_DIR/$BUNDLE_TAR" -C "$BUNDLE_DIR" .
|
||||
BUNDLE_SIZE=$(du -sh "$OUTPUT_DIR/$BUNDLE_TAR" | cut -f1)
|
||||
echo "Bundle: $OUTPUT_DIR/$BUNDLE_TAR ($BUNDLE_SIZE)"
|
||||
|
||||
# ── Sign ──────────────────────────────────────────────────────────────────────
|
||||
|
||||
echo "Signing..."
|
||||
openssl dgst -sha256 \
|
||||
-sign "$PRIVATE_KEY" \
|
||||
-out "$OUTPUT_DIR/$SIG_FILE" \
|
||||
"$OUTPUT_DIR/$BUNDLE_TAR"
|
||||
|
||||
echo "Signature: $OUTPUT_DIR/$SIG_FILE"
|
||||
|
||||
# ── Verify (sanity check) ─────────────────────────────────────────────────────
|
||||
|
||||
PUBLIC_KEY="$(dirname "$PRIVATE_KEY")/adacam-update-public.pem"
|
||||
if [ -f "$PUBLIC_KEY" ]; then
|
||||
echo "Verifying signature..."
|
||||
openssl dgst -sha256 -verify "$PUBLIC_KEY" \
|
||||
-signature "$OUTPUT_DIR/$SIG_FILE" \
|
||||
"$OUTPUT_DIR/$BUNDLE_TAR" && echo "Signature verified OK"
|
||||
fi
|
||||
|
||||
# ── USB instructions ──────────────────────────────────────────────────────────
|
||||
|
||||
echo ""
|
||||
echo "=== USB Drive Setup ==="
|
||||
echo "Copy these two files to your USB drive:"
|
||||
echo ""
|
||||
echo " USB_DRIVE/adacam_recovery/$BUNDLE_TAR"
|
||||
echo " USB_DRIVE/adacam_recovery/$SIG_FILE"
|
||||
echo ""
|
||||
echo "Insert USB into powered-on AdaCam."
|
||||
echo "Recovery runs automatically, device reboots when done."
|
||||
echo ""
|
||||
echo "Log on device: /data/adacam/recovery.log"
|
||||
6
services/updater/99-adacam-usb.rules
Normal file
6
services/updater/99-adacam-usb.rules
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
# udev rule — trigger adacam-updater when USB mass storage is inserted
|
||||
# Install to: /etc/udev/rules.d/99-adacam-usb.rules
|
||||
|
||||
ACTION=="add", SUBSYSTEM=="block", KERNEL=="sd[a-z][0-9]", \
|
||||
ENV{ID_BUS}=="usb", \
|
||||
RUN+="/usr/local/bin/adacam-updater /dev/%k"
|
||||
98
services/updater/adacam-updater.sh
Normal file
98
services/updater/adacam-updater.sh
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
#!/bin/bash
|
||||
# adacam-updater — secure USB recovery for AdaCam
|
||||
#
|
||||
# Triggered by udev when a USB drive is inserted.
|
||||
# Looks for a signed recovery bundle on the drive.
|
||||
# Verifies RSA-4096 signature before touching anything.
|
||||
# No signature = no action. No exceptions.
|
||||
#
|
||||
# Bundle format on USB drive:
|
||||
# /adacam_recovery/adacam-recovery.tar.gz
|
||||
# /adacam_recovery/adacam-recovery.tar.gz.sig
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
VERIFY_KEY="/etc/adacam/update-verify.pem"
|
||||
USB_MOUNT="/mnt/usb-recovery"
|
||||
BUNDLE_DIR="adacam_recovery"
|
||||
BUNDLE_NAME="adacam-recovery.tar.gz"
|
||||
SIG_NAME="adacam-recovery.tar.gz.sig"
|
||||
WORK_DIR="/tmp/adacam-recovery-work"
|
||||
LOG="/data/adacam/recovery.log"
|
||||
MARKER="/data/adacam/recovery_in_progress"
|
||||
|
||||
log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" | tee -a "$LOG"; }
|
||||
die() { log "ERROR: $*"; rm -f "$MARKER"; exit 1; }
|
||||
|
||||
# ── Sanity checks ─────────────────────────────────────────────────────────────
|
||||
|
||||
[ -f "$VERIFY_KEY" ] || die "no verify key at $VERIFY_KEY — cannot proceed"
|
||||
[ "$(id -u)" = "0" ] || die "must run as root"
|
||||
|
||||
# Only one recovery at a time
|
||||
[ -f "$MARKER" ] && die "recovery already in progress (marker exists)"
|
||||
|
||||
mkdir -p /data/adacam
|
||||
touch "$MARKER"
|
||||
log "=== AdaCam USB Recovery Starting ==="
|
||||
|
||||
# ── Mount USB ─────────────────────────────────────────────────────────────────
|
||||
|
||||
USB_DEV="${1:-}"
|
||||
if [ -z "$USB_DEV" ]; then
|
||||
# Auto-detect first USB mass storage device
|
||||
USB_DEV=$(lsblk -rno NAME,TYPE | awk '$2=="part"{print "/dev/"$1}' | grep -v mmcblk | head -n1)
|
||||
fi
|
||||
|
||||
[ -n "$USB_DEV" ] || die "no USB device found"
|
||||
log "USB device: $USB_DEV"
|
||||
|
||||
mkdir -p "$USB_MOUNT"
|
||||
mount -o ro "$USB_DEV" "$USB_MOUNT" || die "failed to mount $USB_DEV"
|
||||
log "mounted $USB_DEV at $USB_MOUNT"
|
||||
|
||||
cleanup() {
|
||||
umount "$USB_MOUNT" 2>/dev/null || true
|
||||
rm -rf "$WORK_DIR"
|
||||
rm -f "$MARKER"
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
# ── Find bundle ───────────────────────────────────────────────────────────────
|
||||
|
||||
BUNDLE="$USB_MOUNT/$BUNDLE_DIR/$BUNDLE_NAME"
|
||||
SIG="$USB_MOUNT/$BUNDLE_DIR/$SIG_NAME"
|
||||
|
||||
[ -f "$BUNDLE" ] || die "no bundle found at $BUNDLE_DIR/$BUNDLE_NAME — nothing to do"
|
||||
[ -f "$SIG" ] || die "no signature found at $BUNDLE_DIR/$SIG_NAME — refusing unsigned bundle"
|
||||
|
||||
log "found bundle: $(du -sh "$BUNDLE" | cut -f1)"
|
||||
|
||||
# ── Verify signature ──────────────────────────────────────────────────────────
|
||||
|
||||
log "verifying signature..."
|
||||
if ! openssl dgst -sha256 -verify "$VERIFY_KEY" -signature "$SIG" "$BUNDLE" >> "$LOG" 2>&1; then
|
||||
die "SIGNATURE VERIFICATION FAILED — bundle rejected, device unchanged"
|
||||
fi
|
||||
|
||||
log "signature OK — bundle is authentic"
|
||||
|
||||
# ── Extract and run ───────────────────────────────────────────────────────────
|
||||
|
||||
rm -rf "$WORK_DIR"
|
||||
mkdir -p "$WORK_DIR"
|
||||
|
||||
log "extracting bundle..."
|
||||
tar -xzf "$BUNDLE" -C "$WORK_DIR" || die "failed to extract bundle"
|
||||
|
||||
INSTALL_SCRIPT="$WORK_DIR/install.sh"
|
||||
[ -f "$INSTALL_SCRIPT" ] || die "no install.sh in bundle — malformed recovery package"
|
||||
[ -x "$INSTALL_SCRIPT" ] || chmod +x "$INSTALL_SCRIPT"
|
||||
|
||||
log "running install.sh..."
|
||||
bash "$INSTALL_SCRIPT" >> "$LOG" 2>&1 || die "install.sh failed — check $LOG"
|
||||
|
||||
log "=== Recovery complete — rebooting in 5s ==="
|
||||
sync
|
||||
sleep 5
|
||||
reboot
|
||||
Loading…
Add table
Add a link
Reference in a new issue