25 Commits
Author SHA1 Message Date
Santiago Postorivo f356b164a6 tests: SSDP golden fixtures, push_status delta-merge spec, signing trailing-sibling lock (#114) 2026-10-14 07:16:56 +02:00
Alexey Cluster d6e0cb95ff Logging certificate id for easier remote debugging
Signed-off-by: Alexey Cluster <cluster@cluster.wtf>
2026-10-14 07:01:07 +02:00
persano 73d923b439 Revert "camera: drop client-side liveview.prepare and liveview signing"
This reverts commit 8080cb9ab7.
2026-10-08 23:39:11 +02:00
Alexey Cluster 6db7675a59 cloud: shared X-BBL + PoP headers, used for /user/ttcode
POST /v1/iot-service/api/user/ttcode answers 403 (code 8) unless it
carries the same headers /my/task enforces: X-BBL-Client-Name =
BambuStudio, X-BBL-OS-Type and the PoP pair. Move bbl_headers()/os_type
from cloud_print.cpp into obn::cloud, add obn::signing::add_pop_headers
(never sends blank values), and use both for the camera mint and for
create_task.
2026-09-27 05:46:59 +02:00
Alexey Cluster 8080cb9ab7 camera: drop client-side liveview.prepare and liveview signing
The cloud pushes liveview.prepare (with ttcode_enc) to the printer by
itself in response to POST /v1/iot-service/api/user/ttcode, so the
plugin never needs to publish it. Remove the signed prepare from
remote_camera_url, rescue_cloud_liveview and its detached republish
thread, the 84033543 frame filter, and revert the signing generalisation
(signable_root_key, ttcode -> ttcode_enc) back to print-only. This also
stops liveview frames from waiting up to 8 s on wait_for_app_cert.
2026-09-27 05:46:59 +02:00
Santiago Postorivo 667f9a22d8 feat(camera): support cloud liveview on secured printers via signed prepare and ttcode_enc (#97) 2026-09-27 02:01:07 +02:00
Alexey Cluster a367a96fa8 Auto-detect Developer Mode from print.fun bit 29
Replace the manual `developer_mode` obn.conf knob (from PR #84) with
per-printer auto-detection:

- Agent::harvest_developer_mode() reads push_status print.fun bit 29
  (clear = Developer Mode on, set = secured) into dev_mode_on_by_dev_,
  tracked live (the on-screen toggle can flip mid-session), called at
  both LAN and cloud report harvest sites.
- Agent::developer_mode_effective() returns the harvested state; before
  the first fun frame it defaults to secured only when full signing
  material (slicer key + app cert + CRL) is present, otherwise keeps
  cleartext since nothing can be signed anyway.
- Thread the decision into signing as a parameter instead of reading a
  global: maybe_sign(payload, device_pub, developer_mode) ->
  build_print_dump -> encrypt_print_fields. Both Agent send sites pass
  developer_mode_effective(dev_id).
- Drop the developer_mode field/config key and its README row.

Refine wait_for_app_cert per review: block on a condition_variable
(app_cert_cv_) notified from harvest_security_report instead of a 50ms
poll loop, and compute would_sign() once in send_message_to_printer
instead of twice.

Update signing_test to pass developer_mode as an argument and refresh
the STATUS.md field-encryption note. Full test suite passes.
2026-09-21 18:47:33 +02:00
Mitch CapperandCursor e67b86f543 bearssl deciphered for full slicer key extraction from dump
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-21 18:47:33 +02:00
Alexey Cluster 7190b17ac5 Refactor project file construction for improved ABI compliance
- Updated `sequence_id` generation to use a monotonic counter within the range 20000–29999, aligning with stock plugin behavior.
- Adjusted `md5` field to emit the literal "from_sd_card" for both `sdcard_print` and FTPS local print paths.
- Ensured `ams_mapping` is emitted as an empty array when not in use, even with `task_use_ams` set to true.
- Enhanced handling of optional fields in the `POST /my/task` body to match stock behavior, including omitting `url` and `url_enc` when empty.

Signed-off-by: Alexey Cluster <cluster@cluster.wtf>
2026-08-17 15:06:50 +02:00
Alexey Cluster ad5c007bbe Removed the slicer_cert_id field from the configuration
Signed-off-by: Alexey Cluster <cluster@cluster.wtf>
2026-07-31 21:18:15 +02:00
Alexey Cluster a1ed416615 Test fixed
Signed-off-by: Alexey Cluster <cluster@cluster.wtf>
2026-07-28 21:25:47 +02:00
Alexey Cluster 0248c6173e Comment out field erasure in encrypt_print_fields function to preserve original data structure during encryption process.
Signed-off-by: Alexey Cluster <cluster@cluster.wtf>
2026-07-28 15:55:35 +02:00
Alexey Cluster f89c7b173f Refactor app certificate usability checks to reduce warning spam
Signed-off-by: Alexey Cluster <cluster@cluster.wtf>
2026-07-28 15:18:30 +02:00
Alexey Cluster 7593a3a442 Ignore certificate expiration
Signed-off-by: Alexey Cluster <cluster@cluster.wtf>
2026-07-18 23:51:26 +02:00
Alexey Cluster 3d58c81b1a Fixed app_cert_install
Signed-off-by: Alexey Cluster <cluster@cluster.wtf>
2026-07-15 19:27:25 +02:00
Alexey Cluster c44e304e68 Cloud fixes and refactoring
Signed-off-by: Alexey Cluster <cluster@cluster.wtf>
2026-07-15 05:25:29 +02:00
Alexey Cluster 57bc7fdcb1 Enhance device-cert field encryption in MQTT signing path
- Updated the `maybe_sign` function to apply device-cert field encryption to the `print` object before signing, ensuring that the signature covers the encrypted form sent over the wire.
- The cleartext `url` is now replaced by `url_enc`, and for `gcode_line`, the cleartext `param` is replaced by `param_enc`, aligning with hardware verification.
- Introduced `prime_pub_key_from_cert_file` to seed the public key cache from an on-disk device certificate, ensuring encryption is available even after reconnects.
- Updated documentation and tests to reflect these changes, confirming that the cleartext fields are dropped as expected when encryption is applied.

Signed-off-by: Alexey Cluster <cluster@cluster.wtf>
2026-07-14 16:13:25 +02:00
Alexey Cluster 9e01c616e0 Make end-to-end cloud printing work (MVP)
Cloud prints now start reliably from Bambu Studio over the cloud path.
Key fixes:

- create_task: send X-BBL-Client-Name (configurable via obn.conf
  client_name, e.g. "BambuStudio") and a compile-time X-BBL-OS-Type;
  POST /my/task hard-fails on non-2xx instead of silently continuing
  with task_id=0. These were the cause of the 403 on /my/task.

- Fix app_certification_id() HTTP serialization (issuer:serial.lower()):
  the serial was mis-split when it ended in a hex letter, producing a
  malformed x-bbl-app-certification-id and a 403.

- run_cloud_print_job: for a cloud-connected printer collapse the
  "local print with record" entry point into a single cloud print.
  Studio tries start_local_print_with_record first and only falls back
  to start_print on <0; our record path created a cloud task AND then
  failed the redundant LAN MQTT publish, so BOTH ran and the printer
  rejected the duplicate with 0500_4004 ("can't receive new print jobs
  while printing"). The cloud dispatch from /my/task already starts the
  print, so the MQTT project_file is dropped for the cloud channel.

- get_subtask: echo the caller-owned BBLModelTask back through the
  callback instead of leaking it and leaving Studio's model-info request
  latched forever.
2026-07-13 18:55:53 +02:00
Alexey Cluster dc724f6b92 Add slicer_cert_pem / slicer_crl_pem config overrides
Allow obn.conf to point slicer_cert.pem / slicer_crl.pem at explicit paths,
mirroring the existing slicer_key_pem override. Empty values keep the
config_dir/slicer_cert.pem and config_dir/slicer_crl.pem defaults.
2026-07-12 03:44:23 +02:00
Alexey Cluster 51a2861aad Route config-dir file paths through cross-platform config::path_in_dir()
Manual "dir + \"/\" + name" concatenation is not portable to Windows. Add
config::path_in_dir() (std::filesystem join on config_dir) and use it for
slicer_key.pem, slicer_cert_id.txt, slicer_cert.pem, slicer_crl.pem and
obn.auth.json. No behavior change on POSIX.
2026-07-12 03:44:19 +02:00
Alexey Cluster 8903c4d407 Source cloud-print RSA key from app_cert_install; free cache on disconnect
Wire up the previously dead set_printer_pub_key_from_cert_pem: before a
cloud print encrypts url_enc/param_enc, a missing pubkey now triggers
the documented security.app_cert_install MQTT flow (app cert chain +
CRL read from config_dir/slicer_cert.pem, slicer_crl.pem) and the
printer_cert from the printer's report is harvested into the cert_store
cache on both the LAN and cloud message paths. The TLS-leaf snapshot on
disk stays as the LAN-direct TOFU fallback only. Also call
forget_printer on LAN disconnect (immediate and deferred) and on cloud
session teardown so cached EVP_PKEYs are released.
2026-07-12 03:43:56 +02:00
Alexey Cluster cf8d350bdf Remove H2D nozzle-id flip from MQTT signing and its model plumbing
The stock plugin's SignMessage is a pure canonicalise+sign step; it
never rewrites nozzle ids (see the reverse-networking MQTT doc). The
flip existed because Studio's DevMapping numbers dual-nozzle heads
left=1/right=0, but it was applied inside maybe_sign on MQTT
project_file payloads, which carry no ams_mapping_info at all - the
field only appears in the REST /my/task body - so on the live path it
was a no-op. Drop flip_nozzle_ids/is_h2d_printer, the printer_model
argument of maybe_sign, and the dev_model_by_id_ SSDP tracking that
existed only to feed it. If a real H2D mapping bug ever shows up, the
fix belongs in the REST task body, not in the signing layer.
2026-07-12 03:43:52 +02:00
Alexey Cluster ecaaeec7eb Enhance configuration management and signing functionality
- Introduced new settings for slicer key and certificate ID in the configuration.
- Updated session persistence path handling to prioritize user-defined paths.
- Refactored signing logic to resolve key and certificate paths based on configuration.
- Added a test stub for configuration to facilitate unit testing of signing functionality.
- Updated CMakeLists to include the new test file for signing.

Signed-off-by: Alexey Cluster <cluster@cluster.wtf>
2026-07-06 20:19:03 +02:00
Daniel Williams f48f3f2bcf Add cloud print, session persistence, and LAN multi-device support (#62)
* Add cloud print, session persistence, and LAN multi-device support

Cloud printing:
- Encrypt the url and param fields (RSA PKCS#1 v1.5) in the project_file
  command, as required by firmware for cloud prints.
- Cache each printer's public key from its TLS leaf certificate.

Cloud session:
- Persist and reload login sessions on disk (mode 0600), refreshing the
  token when needed.

LAN:
- Track per-device model and IP from SSDP so the correct nozzle mapping
  is applied before signing, and support multiple printers at once.
- Reconnect the LAN MQTT session automatically with exponential backoff.

Print jobs:
- Normalize 3MF archives to plate_1 (plate_0 rename plus in-place ZIP
  rewrite) before upload. Adds miniz as a submodule for the rewrite.

Tests:
- Add agent and cloud_print unit tests.

* Address review: timestamp-signed security header, device-cert key source

cloud_print: x-bbl-device-security-sign signs the current time in
milliseconds with a raw RSA PKCS#1 v1.5 signature (no hash), not the
request body. Add signing::device_security_sign() and use it in
create_task; sign_bytes stays as a general SHA-256 signing helper.
Adds a test that recovers the signature and checks it is a bare ms
timestamp.

cert_store: the authoritative printer public key is the device
certificate obtained over MQTT via the app_cert_install command, which
also works for cloud and proxy connections; the TLS-leaf capture is a
LAN-direct TOFU fallback only. Add set_printer_pub_key_from_cert_pem()
to install the device cert and document the key source.

* Degrade signing gracefully when no slicer key is configured

device_security_sign() threw std::runtime_error when no slicer key was
present. That exception propagated through the cloud-connect path
(bambu_network_start -> connect_cloud -> create_task), aborting cloud
connection for users with a cached login but no slicer_key.pem.

Return "" instead, matching maybe_sign's existing behaviour, and omit the
x-bbl-app-certification-id / x-bbl-device-security-sign headers in
create_task when empty. These headers are only enforced on signed writes.
2026-07-06 17:19:21 +02:00
Daniel Williams cb0d2527aa Add native signing library (PR #58)
Signed-off-by: Alexey Cluster <cluster@cluster.wtf>
2026-06-28 21:02:28 +02:00