feat: nl_mkimage prüft Images mit --verify
deploy.sh soll kein Image auf die Station schieben, das jede Lampe ablehnen würde. Die Prüfung sitzt in nl_mkimage, weil dort das Trailer-Layout ohnehin steht - eine zweite Kopie derselben Offsets wäre genau die Doppelung, die beim Abweichen jedes Update killt. Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Haiku 4.5
parent
cb0a4b035d
commit
0ba269a39a
@@ -22,14 +22,51 @@ def field(value: str, name: str) -> bytes:
|
||||
return raw.ljust(FIELD, b"\x00")
|
||||
|
||||
|
||||
def verify(path: Path, expect_device: str | None) -> int:
|
||||
"""Checks an _ota.img the way the firmware does before accepting it."""
|
||||
data = path.read_bytes()
|
||||
if len(data) <= TRAILER_SIZE:
|
||||
print(f"error: {path} is too short to carry a trailer", file=sys.stderr)
|
||||
return 1
|
||||
payload, trailer = data[:-TRAILER_SIZE], data[-TRAILER_SIZE:]
|
||||
if trailer[0:4] != b"NINL":
|
||||
print(f"error: {path} has no ninlight trailer", file=sys.stderr)
|
||||
return 1
|
||||
if trailer[4] != TRAILER_VERSION:
|
||||
print(f"error: {path} has trailer version {trailer[4]}, expected {TRAILER_VERSION}",
|
||||
file=sys.stderr)
|
||||
return 1
|
||||
device = trailer[5:21].rstrip(b"\x00").decode("ascii", "replace")
|
||||
version = trailer[21:37].rstrip(b"\x00").decode("ascii", "replace")
|
||||
if expect_device is not None and device != expect_device:
|
||||
print(f"error: {path} carries device '{device}', expected '{expect_device}'",
|
||||
file=sys.stderr)
|
||||
return 1
|
||||
if trailer[37:69] != hashlib.sha256(payload).digest():
|
||||
print(f"error: {path} fails its sha256 - the payload does not match the trailer",
|
||||
file=sys.stderr)
|
||||
return 1
|
||||
print(f"{device} {version} {len(data)}")
|
||||
return 0
|
||||
|
||||
|
||||
def main() -> None:
|
||||
p = argparse.ArgumentParser(description="append the ninlight OTA trailer")
|
||||
p.add_argument("--image", required=True, type=Path, help="input _gz.img")
|
||||
p.add_argument("--device", required=True, help="device id, e.g. e27_rgb")
|
||||
p.add_argument("--version", required=True, help="firmware version")
|
||||
p.add_argument("--out", required=True, type=Path, help="output _ota.img")
|
||||
p.add_argument("--image", type=Path, help="input _gz.img")
|
||||
p.add_argument("--device", help="device id, e.g. e27_rgb")
|
||||
p.add_argument("--version", help="firmware version")
|
||||
p.add_argument("--out", type=Path, help="output _ota.img")
|
||||
p.add_argument("--verify", type=Path, help="check an existing _ota.img instead of building one")
|
||||
p.add_argument("--expect-device", help="with --verify: require this device id")
|
||||
a = p.parse_args()
|
||||
|
||||
if a.verify is not None:
|
||||
raise SystemExit(verify(a.verify, a.expect_device))
|
||||
|
||||
for name in ("image", "device", "version", "out"):
|
||||
if getattr(a, name) is None:
|
||||
p.error(f"--{name} is required unless --verify is given")
|
||||
|
||||
data = a.image.read_bytes()
|
||||
if len(data) > TRAILER_SIZE and data[-TRAILER_SIZE : -TRAILER_SIZE + 4] == b"NINL":
|
||||
sys.exit("error: image already carries a trailer")
|
||||
|
||||
Reference in New Issue
Block a user