- PROJECT_STATUS.md: full project log (hardware, partitions, artifacts, lessons learned, next steps) - scripts/build/build-artifact-from-existing.py: rebuild artifact from existing data tar with new header - scripts/build/build-v5-patched-updater.sh: patch system.img usb-updater + build artifact - recovery/usb-updater-v5-patched: patched usb-updater with SSH recovery prepended adacam-ssh-fix-v5.mender: 403MB, SHA256 acfbd16db9620f23785f8b103ffaeff6aed780f383273a61a23c8002f2bf0980 Status: PENDING TEST on replacement Bee (192.168.0.10)
104 lines
3.7 KiB
Python
104 lines
3.7 KiB
Python
import tarfile, hashlib, io, os
|
|
|
|
EXISTING = '/workspace/projects/adacam/recovery/adacam-ssh-fix.mender'
|
|
OUT = '/workspace/projects/adacam/recovery/adacam-ssh-fix-v4.mender'
|
|
|
|
SSH_FIX = b"""#!/bin/bash
|
|
# Debug: write status to USB so we can see if this actually ran
|
|
USB_LOG=/mnt/usb/hivemapper_update/state_script.log
|
|
echo "STATE SCRIPT RAN at $(date)" > $USB_LOG 2>/dev/null || true
|
|
|
|
cat > /etc/ssh/sshd_config << 'SSHEOF'
|
|
PermitRootLogin yes
|
|
AuthorizedKeysFile .ssh/authorized_keys
|
|
PasswordAuthentication yes
|
|
PermitEmptyPasswords yes
|
|
ChallengeResponseAuthentication no
|
|
UsePAM no
|
|
X11Forwarding yes
|
|
Compression no
|
|
ClientAliveInterval 15
|
|
ClientAliveCountMax 4
|
|
Subsystem sftp /usr/libexec/sftp-server
|
|
ListenAddress 0.0.0.0
|
|
SSHEOF
|
|
mkdir -p /home/root/.ssh
|
|
cat > /home/root/.ssh/authorized_keys << 'KEYS'
|
|
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIK87jxvlXvo60pxwdtyJsXeFsb4KsAiFx4FnyXz81kh7 cobb@adacam
|
|
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOQxwJU91TCxds34P18D3xRbu7rxlrgTUoml/H8nxeDK kayos@openclaw
|
|
KEYS
|
|
chmod 700 /home/root/.ssh
|
|
chmod 600 /home/root/.ssh/authorized_keys
|
|
systemctl restart sshd 2>/dev/null || kill -HUP $(pgrep -x sshd | head -1) 2>/dev/null
|
|
echo "SSHD RESTARTED at $(date)" >> $USB_LOG 2>/dev/null || true
|
|
echo "overlay path: $(ls -la /data/overlay/current/ssh/ 2>&1)" >> $USB_LOG 2>/dev/null || true
|
|
echo "sshd_config written: $(cat /etc/ssh/sshd_config 2>/dev/null | head -3)" >> $USB_LOG 2>/dev/null || true
|
|
exit 0
|
|
"""
|
|
|
|
def sha256b(b):
|
|
return hashlib.sha256(b).hexdigest()
|
|
|
|
def sha256f(p):
|
|
h = hashlib.sha256()
|
|
with open(p,'rb') as f:
|
|
while True:
|
|
c = f.read(1024*1024)
|
|
if not c: break
|
|
h.update(c)
|
|
return h.hexdigest()
|
|
|
|
print('Extracting existing artifact...')
|
|
with tarfile.open(EXISTING,'r:') as art:
|
|
version_data = art.extractfile('version').read()
|
|
os.makedirs('/tmp/aw2/data',exist_ok=True)
|
|
art.extract(art.getmember('data/0000.tar.gz'),'/tmp/aw2/')
|
|
|
|
dtp = '/tmp/aw2/data/0000.tar.gz'
|
|
print(f'data tar: {os.path.getsize(dtp)/1024/1024:.0f}MB')
|
|
|
|
print('Hashing files in data tar...')
|
|
file_hashes = {}
|
|
with tarfile.open(dtp,'r:gz') as dt:
|
|
for m in dt.getmembers():
|
|
f = dt.extractfile(m)
|
|
if not f: continue
|
|
h = hashlib.sha256()
|
|
while True:
|
|
c = f.read(1024*1024)
|
|
if not c: break
|
|
h.update(c)
|
|
file_hashes[m.name] = h.hexdigest()
|
|
print(f' {m.name}: {h.hexdigest()[:16]}...')
|
|
|
|
print('Building header...')
|
|
hdr_buf = io.BytesIO()
|
|
with tarfile.open(fileobj=hdr_buf, mode='w:gz') as hdr:
|
|
for name,data in [
|
|
('header-info', b'{"payloads":[{"type":"dm-verity-update"}],"artifact_provides":{"artifact_name":"adacam-ssh-fix-v2"},"artifact_depends":{"device_type":["keembay"]}}'),
|
|
('headers/0000/type-info', b'{"type":"dm-verity-update"}'),
|
|
('headers/0000/meta-data', b'{}'),
|
|
]:
|
|
ti = tarfile.TarInfo(name=name); ti.size=len(data)
|
|
hdr.addfile(ti, io.BytesIO(data))
|
|
ti = tarfile.TarInfo(name='scripts/ArtifactInstall_Enter_00')
|
|
ti.size=len(SSH_FIX); ti.mode=0o755
|
|
hdr.addfile(ti, io.BytesIO(SSH_FIX))
|
|
hdr_bytes = hdr_buf.getvalue()
|
|
|
|
manifest = '\n'.join([
|
|
f'{file_hashes["system.img"]} data/0000/system.img',
|
|
f'{file_hashes["syshash.img"]} data/0000/syshash.img',
|
|
f'{file_hashes["boot.img"]} data/0000/boot.img',
|
|
f'{sha256b(hdr_bytes)} header.tar.gz',
|
|
f'{sha256b(version_data)} version',
|
|
]).encode()+b'\n'
|
|
|
|
print('Building artifact...')
|
|
with tarfile.open(OUT,'w:') as art:
|
|
for name,data in [('version',version_data),('manifest',manifest),('header.tar.gz',hdr_bytes)]:
|
|
ti=tarfile.TarInfo(name=name); ti.size=len(data)
|
|
art.addfile(ti,io.BytesIO(data))
|
|
art.add(dtp,arcname='data/0000.tar.gz')
|
|
|
|
print(f'DONE: {os.path.getsize(OUT)/1024/1024:.1f}MB')
|