8000 cbio: authenticate the GS1 link and stream live glucose and history by shroominic · Pull Request #136 · shroominic/OpenGlucose · GitHub
[go: up one dir, main page]

Skip to content

cbio: authenticate the GS1 link and stream live glucose and history - #136

Closed
shroominic wants to merge 3 commits into
feature/cbio-gs1-livefrom
feature/cbio-gs1-glucose-live
Closed

shroominic wants to merge 3 commits into
feature/cbio-gs1-livefrom
feature/cbio-gs1-glucose-live

Conversation

@shroominic
@shroominic shroominic commented Sep 17, 2026 •
Copy link
Copy Markdown
Owner

Refs #135. Stacked on feature/cbio-gs1-live (PR #127); base is that branch,
not main. Stays open.

What this adds

The vendor's own authenticated link, sent from the phone to the real sensor,
plus the bounded live/history capability it feeds.

  • packages/cgm_cbio/lib/src/cbio_crypto.dart carries the vendor's static
    per-frame stream mask and the mask/unmask transforms. The five bytes the
    sensor sends when it wants authentication unmask to 04 00 00 00 FC, a valid
    control frame; that is what identified the encoding. Key and credential
    provenance is recorded by derivation in docs/testing/cbio-gs1-auth-material.md
    (sibling branch docs/cbio-gs1-auth-material, PR docs(cbio): GS1 auth key source and runtime call sequence #138) and is not restated in code comments, this body, or the issue.
  • packages/cgm_cbio/lib/src/cbio_vendor_frames.dart builds the masked frames
    the sensor accepts: device information, authentication, the vendor clock, and
    the 06 0A / 06 08 reads. Activation (07), reset, threshold,
    key-registration, and firmware frames are deliberately absent.
  • packages/cgm_cbio/lib/src/cbio_history_archive.dart ingests the raw 08
    stream, keeps one record per index, and reports accepted, duplicate,
    notRawBatch, gap, plus contiguous and sawOverlap instead of guessing.
  • openhealth/integration_test/cbio_glucose_authenticated_test.dart sends the
    vendor's masked sequence, logs every write byte-for-byte in masked and
    plaintext form, and can resume the raw read at any index so a bounded window
    reaches the newest record.

Proven on the live sensor

  • Authentication is accepted: 04 01 01 00 FA (result=1 status=0) for the
    address octets the 2A25 characteristic returns. Runs 1-3 first spent one
    rejected attempt (result=0 status=2) on those same six bytes reversed a
    second time; run 4 used them as read and authenticated on the first attempt.
  • The 0A path returns 1782 records, index 1..1782, and every packed field is
    zero
    ; it stops at 2026-09-12T01:38:00Z.
  • The 08 path streams 9981 records, index 1..9981, contiguous, one per
    minute, from 2026-09-10T19:57:00Z to 2026-09-17T18:17:00Z — the last
    record lands in the same minute the read ran, so this is live data and not a
    frozen archive.
  • Raw fields across that range: current 39..97, temp 274..460. The newest
    record at capture time was index 9981, raw current 50, raw temp 315.

Not claimed

  • Any unit or scale. current / 10 gives 3.9..9.7 mmol/L, which is plausible
    and matches how two independent clients read the field, but no reference
    measurement confirms it, so isUnitVerified stays false and the raw integer
    is exposed next to any converted number.
  • That the 0A field is meaningful on this sensor. It is zero throughout while
    08 carries signal, so only 08 is usable here.
  • That the archive continues past index 9981 without a break.

Safety

Four or five writes per session, all listed in the record, all logged
byte-for-byte in masked and plaintext form. No activation, reset, threshold,
calibration, key, or authentication-registration frame beyond the vendor's own
link authentication; no pairing or bond; the GATT link is released at the end of
each run; the longest read window was 300 s of read-only notifications. No
credential or key bytes appear in this PR.

Verification

  • dart format --output=none --set-exit-if-changed lib test - passed
  • dart analyze --fatal-infos - no issues
  • dart test - 60 tests passed, including the published mask vectors, the
    archive's gap/overlap/duplicate behavior, and a cross-check that the archive
    and parseCbioRawDataFrame agree on the same frames
  • flutter analyze in openhealth - no issues
  • Device runs: four bounded sessions with identical framing; 9981 raw records
    recovered across them, All tests passed!

Full record: docs/testing/cbio-gs1-glucose-live.md.

Add the vendor V120 read builders and a strict 0A glucose decoder, plus a
transport-free sync session that polls the newest index and pages stored
history under explicit budgets. Every failure path returns a status instead of
a measurement, records stay raw with isUnitVerified false, and the 08
raw-data layout is refused.

The device-backed harness sends only the documented read queries
(03 F0 04 09, 03 F0 03 0A, 06 0A <index> 00 00 C). On the live sensor all
four reads return the same five-byte frame 23 F7 6F D9 F4, which fails the
plaintext contract, so the capability currently terminates in decodeFailed.
No activation, clock, reset, threshold, key, or authentication write is sent.
…tory

The live sensor answers the vendor's own read queries once the link is
authenticated with the vendor's per-frame stream mask, and the answer is its
stored record stream: 9981 raw records, one per minute, contiguous from
2026-09-10T19:57:00Z to 2026-09-17T18:17:00Z on the last run.

- cbio_crypto.dart carries the vendor stream mask and the frame transforms.
  The five-byte prompt the sensor sends unmasks to the valid control frame
  `04 00 00 00 FC`, which is what identified the encoding.
- cbio_vendor_frames.dart builds the masked link frames the sensor accepts:
  device information, authentication, clock, and the two data reads. No
  activation, reset, threshold, key-registration, or firmware frame.
- cbio_history_archive.dart assembles the raw `08` stream into an ordered
  archive with one record per index, plus explicit gap, overlap, and
  contiguity reporting.
- The authenticated harness sends the vendor's masked sequence, records every
  write byte-for-byte in masked and plaintext form, and resumes the raw read
  at a given index so a bounded window can reach the newest record.

Proven on the sensor: authentication succeeds with the 2A25 address octets as
read (`result=1 status=0`); the `0A` path holds 1782 records that are all zero
and stop at 2026-09-12T01:38:00Z; the `08` path streams to the present with
raw `current` 39..97 and `temp` 274..460. Derived values stay marked
`isUnitVerified == false` because no reference measurement confirms the scale.
@shroominic shroominic changed the title cbio: send the vendor GS1 read queries with bounded live and history sync cbio: authenticate the GS1 link and stream live glucose and history Sep 17, 2026
@shroominic
Copy link
Copy Markdown
Owner Author

Carried by the GS1 consolidation in PR #209 (branch feature/cbio-gs1, head 3eca4f4).

This PR is contained in the consolidated line; the merge that carries it is c85f827.

Closing as subsumed by the consolidation - not as won't fix. The per-defect evidence stays in this thread, and the carrying commit above is where the change now lives.

@shroominic shroominic closed this Sep 18, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

0