277 lines
10 KiB
Bash
277 lines
10 KiB
Bash
#!/bin/bash
|
|
# liberate.sh — AdaCam Liberation Script v0.4
|
|
# Converts a factory Hivemapper Bee (HDC-S) into an AdaCam.
|
|
#
|
|
# Usage: ssh root@192.168.0.10 'bash -s' < liberate.sh
|
|
#
|
|
# CRITICAL: Only /data is reliably writable on this device.
|
|
# /etc may be writable. /root, /usr, /var — assume read-only.
|
|
#
|
|
# This version:
|
|
# - Does NOT touch SSH config (password auth stays enabled)
|
|
# - Does NOT remove usb-updater (our recovery path)
|
|
# - Does NOT write to /usr/local/bin, /etc/udev, /etc/systemd
|
|
# - Only writes to /data/adacam/ and appends to /etc/hosts
|
|
|
|
set -euo pipefail
|
|
|
|
# ── Constants ────────────────────────────────────────────────────────────────
|
|
ADACAM_DATA="/data/adacam"
|
|
ADACAM_AP_IP="10.77.0.1"
|
|
ADACAM_AP_DHCP_START="10.77.0.100"
|
|
ADACAM_AP_DHCP_END="10.77.0.200"
|
|
|
|
# ── Logging ──────────────────────────────────────────────────────────────────
|
|
log() { echo "[liberate] $1"; }
|
|
ok() { echo "[liberate] ✓ $1"; }
|
|
warn() { echo "[liberate] ⚠ $1"; }
|
|
die() { echo "[liberate] ✗ FATAL: $1"; exit 1; }
|
|
|
|
log ""
|
|
log "╔══════════════════════════════════════════╗"
|
|
log "║ AdaCam Liberation Script v0.4 ║"
|
|
log "║ Liberating bees from the hive ║"
|
|
log "╚══════════════════════════════════════════╝"
|
|
log ""
|
|
|
|
# ── ROOT CHECK ───────────────────────────────────────────────────────────────
|
|
[ "$(id -u)" = "0" ] || die "must run as root"
|
|
|
|
# ── ALREADY LIBERATED CHECK ──────────────────────────────────────────────────
|
|
if [ -f "$ADACAM_DATA/liberated" ]; then
|
|
die "device already liberated (marker exists at $ADACAM_DATA/liberated)"
|
|
fi
|
|
|
|
# ── WRITABILITY CHECK ────────────────────────────────────────────────────────
|
|
log "=== Checking filesystem writability ==="
|
|
|
|
check_writable() {
|
|
local path="$1"
|
|
if [ -d "$path" ] && touch "${path}/.adacam_test" 2>/dev/null; then
|
|
rm -f "${path}/.adacam_test"
|
|
ok "Writable: $path"
|
|
return 0
|
|
else
|
|
warn "Read-only or missing: $path"
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
DATA_WRITABLE=false
|
|
ETC_WRITABLE=false
|
|
VAR_WRITABLE=false
|
|
|
|
check_writable /data && DATA_WRITABLE=true
|
|
check_writable /etc && ETC_WRITABLE=true
|
|
check_writable /var && VAR_WRITABLE=true
|
|
|
|
# /data MUST be writable — that's our only safe zone
|
|
[ "$DATA_WRITABLE" = "true" ] || die "/data is not writable — cannot proceed"
|
|
|
|
# Confirm this looks like a Bee
|
|
[ -f /opt/odc-api/odc-api-bee.js ] || warn "odc-api not found — may not be a factory device"
|
|
ok "running on: $(uname -n)"
|
|
|
|
# ── DERIVE DEVICE SERIAL ─────────────────────────────────────────────────────
|
|
log ""
|
|
log "=== Detecting device serial ==="
|
|
|
|
SERIAL=""
|
|
SERIAL=$(cat /proc/device-tree/serial-number 2>/dev/null | tr -d '\0') || true
|
|
[ -z "$SERIAL" ] && SERIAL=$(ip link show wlp1s0f0 2>/dev/null | grep link/ether | awk '{print $2}' | tr -d ':') || true
|
|
[ -z "$SERIAL" ] && SERIAL=$(cat /sys/class/net/wlan0/address 2>/dev/null | tr -d ':') || true
|
|
|
|
if [ -z "$SERIAL" ]; then
|
|
die "Cannot determine device serial — check /proc/device-tree/serial-number"
|
|
fi
|
|
|
|
ok "device serial: $SERIAL"
|
|
|
|
# ── GENERATE PER-DEVICE CREDENTIALS ──────────────────────────────────────────
|
|
log ""
|
|
log "=== Generating per-device credentials ==="
|
|
|
|
WIFI_PASS=$(echo -n "adacam-${SERIAL}-2026" | sha256sum | cut -c1-12)
|
|
API_TOKEN=$(echo -n "adacam-api-${SERIAL}-token" | sha256sum | cut -c1-32)
|
|
ADACAM_AP_SSID="adacam-${SERIAL: -6}"
|
|
|
|
ok "AP SSID: $ADACAM_AP_SSID"
|
|
ok "WiFi password: $WIFI_PASS"
|
|
ok "API token: $API_TOKEN"
|
|
|
|
# ── CREATE ADACAM DATA DIRECTORY ─────────────────────────────────────────────
|
|
log ""
|
|
log "=== Setting up /data/adacam ==="
|
|
|
|
mkdir -p "$ADACAM_DATA"
|
|
mkdir -p "$ADACAM_DATA/logs"
|
|
mkdir -p "$ADACAM_DATA/cache"
|
|
|
|
echo "$SERIAL" > "$ADACAM_DATA/device_serial"
|
|
echo "$WIFI_PASS" > "$ADACAM_DATA/wifi_password"
|
|
echo "$API_TOKEN" > "$ADACAM_DATA/api_token"
|
|
chmod 600 "$ADACAM_DATA/device_serial" "$ADACAM_DATA/wifi_password" "$ADACAM_DATA/api_token"
|
|
|
|
cat > "$ADACAM_DATA/config.json" << CONFIG
|
|
{
|
|
"device_id": "$SERIAL",
|
|
"ap_ssid": "$ADACAM_AP_SSID",
|
|
"ap_ip": "$ADACAM_AP_IP",
|
|
"liberated_at": "$(date -u +%Y-%m-%dT%H:%M:%SZ)",
|
|
"liberate_version": "0.4"
|
|
}
|
|
CONFIG
|
|
chmod 644 "$ADACAM_DATA/config.json"
|
|
ok "config written to $ADACAM_DATA/config.json"
|
|
|
|
# ── PHASE 1: KILL HIVEMAPPER SERVICES ────────────────────────────────────────
|
|
log ""
|
|
log "=== Phase 1: Stopping Hivemapper services ==="
|
|
|
|
# NOTE: We do NOT touch usb-updater — it's our recovery path
|
|
KILL_SERVICES="
|
|
odc-api
|
|
mitmproxy
|
|
mender-client
|
|
here-plugin
|
|
model-zoo
|
|
collectd
|
|
hivemapper-data-logger
|
|
hivemapper-folder-purger
|
|
beekeeper-plugin
|
|
video-processor
|
|
cpu-mem-logger
|
|
vnstat
|
|
vnstatd
|
|
rm_vpu_daemon
|
|
dnf-automatic
|
|
dnf-automatic-download
|
|
dnf-automatic-install
|
|
dnf-makecache
|
|
"
|
|
|
|
for svc in $KILL_SERVICES; do
|
|
if systemctl list-unit-files "${svc}.service" 2>/dev/null | grep -q "$svc"; then
|
|
systemctl stop "${svc}.service" 2>/dev/null || true
|
|
systemctl disable "${svc}.service" 2>/dev/null || true
|
|
systemctl mask "${svc}.service" 2>/dev/null || true
|
|
ok "killed: $svc"
|
|
fi
|
|
done
|
|
|
|
# ── PHASE 2: BLOCK HIVEMAPPER DOMAINS ────────────────────────────────────────
|
|
log ""
|
|
log "=== Phase 2: Blocking Hivemapper endpoints ==="
|
|
|
|
if [ "$ETC_WRITABLE" = "true" ]; then
|
|
BLOCK_HOSTS="
|
|
hivemapper.com
|
|
api.hivemapper.com
|
|
beemaps.com
|
|
api.trybeekeeper.ai
|
|
docker.mender.io
|
|
s3.mender.io
|
|
direct.data.api.platform.here.com
|
|
api-lookup.data.api.platform.here.com
|
|
account.api.here.com
|
|
edge.hereapi.com
|
|
olp.here.com
|
|
dashcam-firmware.s3.us-west-2.amazonaws.com
|
|
cfapi.cloudflare.com
|
|
"
|
|
|
|
for host in $BLOCK_HOSTS; do
|
|
if ! grep -q "$host" /etc/hosts 2>/dev/null; then
|
|
echo "0.0.0.0 $host" >> /etc/hosts && ok "blocked: $host" || warn "failed to block: $host"
|
|
fi
|
|
done
|
|
else
|
|
warn "/etc not writable — skipping host blocking"
|
|
fi
|
|
|
|
# ── PHASE 3: AP CONFIGURATION ────────────────────────────────────────────────
|
|
log ""
|
|
log "=== Phase 3: Configuring WiFi AP ==="
|
|
|
|
# Find and update hostapd config
|
|
HOSTAPD_CONF=""
|
|
for f in /var/hostapd-2g.conf /var/hostapd.conf /etc/hostapd/hostapd.conf; do
|
|
[ -f "$f" ] && HOSTAPD_CONF="$f" && break
|
|
done
|
|
|
|
if [ -n "$HOSTAPD_CONF" ]; then
|
|
sed -i "s/^ssid=.*/ssid=$ADACAM_AP_SSID/" "$HOSTAPD_CONF" && \
|
|
sed -i "s/^wpa_passphrase=.*/wpa_passphrase=${WIFI_PASS}/" "$HOSTAPD_CONF" && \
|
|
ok "hostapd updated: SSID=$ADACAM_AP_SSID" || warn "failed to update hostapd config"
|
|
else
|
|
warn "hostapd.conf not found — AP SSID not changed"
|
|
fi
|
|
|
|
# Update dnsmasq config
|
|
DNSMASQ_WRITTEN=false
|
|
if [ "$VAR_WRITABLE" = "true" ] && [ -d /etc/dnsmasq.d ]; then
|
|
cat > /etc/dnsmasq.d/adacam.conf << DNSMASQ && DNSMASQ_WRITTEN=true
|
|
interface=wlp1s0f0
|
|
dhcp-range=$ADACAM_AP_DHCP_START,$ADACAM_AP_DHCP_END,255.255.255.0,12h
|
|
dhcp-option=3,$ADACAM_AP_IP
|
|
dhcp-option=6,$ADACAM_AP_IP
|
|
no-resolv
|
|
server=1.1.1.1
|
|
server=8.8.8.8
|
|
DNSMASQ
|
|
fi
|
|
|
|
if [ "$DNSMASQ_WRITTEN" = "true" ]; then
|
|
ok "dnsmasq config written"
|
|
else
|
|
warn "dnsmasq config not written — DHCP may not work as expected"
|
|
fi
|
|
|
|
ok "AP config prepared (changes apply after reboot)"
|
|
|
|
# ── PHASE 4: REMOVE REVERSE TUNNELS ──────────────────────────────────────────
|
|
log ""
|
|
log "=== Phase 4: Disabling reverse tunnel services ==="
|
|
|
|
for tunnel in bee-tunnel adacam-tunnel; do
|
|
systemctl stop "$tunnel" 2>/dev/null || true
|
|
systemctl mask "$tunnel" 2>/dev/null || true
|
|
done
|
|
ok "reverse tunnel services disabled"
|
|
|
|
# ── MARK LIBERATED ───────────────────────────────────────────────────────────
|
|
log ""
|
|
log "=== Marking device as liberated ==="
|
|
|
|
cat > "$ADACAM_DATA/liberated" << MARKER
|
|
liberated_at=$(date -u +%Y-%m-%dT%H:%M:%SZ)
|
|
serial=$SERIAL
|
|
version=0.4
|
|
MARKER
|
|
|
|
ok "liberation marker written to $ADACAM_DATA/liberated"
|
|
|
|
# ── SUMMARY ──────────────────────────────────────────────────────────────────
|
|
log ""
|
|
echo "════════════════════════════════════════════════════════"
|
|
echo " AdaCam Liberation Complete (v0.4)"
|
|
echo "════════════════════════════════════════════════════════"
|
|
echo ""
|
|
echo " Device Serial: $SERIAL"
|
|
echo " AP SSID: $ADACAM_AP_SSID"
|
|
echo " AP Password: $WIFI_PASS"
|
|
echo " API Token: $API_TOKEN"
|
|
echo ""
|
|
echo " Data stored at: $ADACAM_DATA/"
|
|
echo ""
|
|
echo " AFTER REBOOT:"
|
|
echo " 1. Connect to WiFi: $ADACAM_AP_SSID"
|
|
echo " 2. SSH: ssh root@$ADACAM_AP_IP"
|
|
echo " (password auth still works — factory default)"
|
|
echo ""
|
|
echo " NOTE: usb-updater is still running (recovery path)"
|
|
echo ""
|
|
echo "════════════════════════════════════════════════════════"
|
|
echo ""
|
|
log "Reboot the device to apply network changes."
|
|
log "Run: reboot"
|