From f472ff7caba6fd2847414ae52bc439c29dcfb547 Mon Sep 17 00:00:00 2001 From: Jack Kingsman Date: Sun, 8 Mar 2026 12:34:47 -0700 Subject: [PATCH] Fix multibyte meshcore-decoder dep hell --- Dockerfile | 7 +- LICENSES.md | 2 +- frontend/.npmrc | 1 + frontend/AGENTS.md | 4 + frontend/lib/meshcore-decoder/LICENSE.md | 21 + frontend/lib/meshcore-decoder/README.md | 453 ++++++++++++++ frontend/lib/meshcore-decoder/dist/cli.d.ts | 3 + .../lib/meshcore-decoder/dist/cli.d.ts.map | 1 + frontend/lib/meshcore-decoder/dist/cli.js | 409 +++++++++++++ frontend/lib/meshcore-decoder/dist/cli.js.map | 1 + .../dist/crypto/channel-crypto.d.ts | 15 + .../dist/crypto/channel-crypto.d.ts.map | 1 + .../dist/crypto/channel-crypto.js | 94 +++ .../dist/crypto/channel-crypto.js.map | 1 + .../dist/crypto/ed25519-verifier.d.ts | 48 ++ .../dist/crypto/ed25519-verifier.d.ts.map | 1 + .../dist/crypto/ed25519-verifier.js | 217 +++++++ .../dist/crypto/ed25519-verifier.js.map | 1 + .../dist/crypto/key-manager.d.ts | 23 + .../dist/crypto/key-manager.d.ts.map | 1 + .../dist/crypto/key-manager.js | 60 ++ .../dist/crypto/key-manager.js.map | 1 + .../dist/crypto/orlp-ed25519-wasm.d.ts | 34 ++ .../dist/crypto/orlp-ed25519-wasm.d.ts.map | 1 + .../dist/crypto/orlp-ed25519-wasm.js | 150 +++++ .../dist/crypto/orlp-ed25519-wasm.js.map | 1 + .../dist/decoder/packet-decoder.d.ts | 51 ++ .../dist/decoder/packet-decoder.d.ts.map | 1 + .../dist/decoder/packet-decoder.js | 576 ++++++++++++++++++ .../dist/decoder/packet-decoder.js.map | 1 + .../dist/decoder/payload-decoders/ack.d.ts | 11 + .../decoder/payload-decoders/ack.d.ts.map | 1 + .../dist/decoder/payload-decoders/ack.js | 78 +++ .../dist/decoder/payload-decoders/ack.js.map | 1 + .../dist/decoder/payload-decoders/advert.d.ts | 24 + .../decoder/payload-decoders/advert.d.ts.map | 1 + .../dist/decoder/payload-decoders/advert.js | 244 ++++++++ .../decoder/payload-decoders/advert.js.map | 1 + .../payload-decoders/anon-request.d.ts | 11 + .../payload-decoders/anon-request.d.ts.map | 1 + .../decoder/payload-decoders/anon-request.js | 123 ++++ .../payload-decoders/anon-request.js.map | 1 + .../decoder/payload-decoders/control.d.ts | 16 + .../decoder/payload-decoders/control.d.ts.map | 1 + .../dist/decoder/payload-decoders/control.js | 279 +++++++++ .../decoder/payload-decoders/control.js.map | 1 + .../decoder/payload-decoders/group-text.d.ts | 12 + .../payload-decoders/group-text.d.ts.map | 1 + .../decoder/payload-decoders/group-text.js | 118 ++++ .../payload-decoders/group-text.js.map | 1 + .../dist/decoder/payload-decoders/path.d.ts | 5 + .../decoder/payload-decoders/path.d.ts.map | 1 + .../dist/decoder/payload-decoders/path.js | 97 +++ .../dist/decoder/payload-decoders/path.js.map | 1 + .../decoder/payload-decoders/request.d.ts | 11 + .../decoder/payload-decoders/request.d.ts.map | 1 + .../dist/decoder/payload-decoders/request.js | 129 ++++ .../decoder/payload-decoders/request.js.map | 1 + .../decoder/payload-decoders/response.d.ts | 11 + .../payload-decoders/response.d.ts.map | 1 + .../dist/decoder/payload-decoders/response.js | 120 ++++ .../decoder/payload-decoders/response.js.map | 1 + .../payload-decoders/text-message.d.ts | 11 + .../payload-decoders/text-message.d.ts.map | 1 + .../decoder/payload-decoders/text-message.js | 120 ++++ .../payload-decoders/text-message.js.map | 1 + .../dist/decoder/payload-decoders/trace.d.ts | 12 + .../decoder/payload-decoders/trace.d.ts.map | 1 + .../dist/decoder/payload-decoders/trace.js | 136 +++++ .../decoder/payload-decoders/trace.js.map | 1 + frontend/lib/meshcore-decoder/dist/index.d.ts | 36 ++ .../lib/meshcore-decoder/dist/index.d.ts.map | 1 + frontend/lib/meshcore-decoder/dist/index.js | 91 +++ .../lib/meshcore-decoder/dist/index.js.map | 1 + .../meshcore-decoder/dist/types/crypto.d.ts | 22 + .../dist/types/crypto.d.ts.map | 1 + .../lib/meshcore-decoder/dist/types/crypto.js | 5 + .../meshcore-decoder/dist/types/crypto.js.map | 1 + .../meshcore-decoder/dist/types/enums.d.ts | 52 ++ .../dist/types/enums.d.ts.map | 1 + .../lib/meshcore-decoder/dist/types/enums.js | 64 ++ .../meshcore-decoder/dist/types/enums.js.map | 1 + .../meshcore-decoder/dist/types/packet.d.ts | 57 ++ .../dist/types/packet.d.ts.map | 1 + .../lib/meshcore-decoder/dist/types/packet.js | 3 + .../meshcore-decoder/dist/types/packet.js.map | 1 + .../meshcore-decoder/dist/types/payloads.d.ts | 128 ++++ .../dist/types/payloads.d.ts.map | 1 + .../meshcore-decoder/dist/types/payloads.js | 3 + .../dist/types/payloads.js.map | 1 + .../dist/utils/auth-token.d.ts | 58 ++ .../dist/utils/auth-token.d.ts.map | 1 + .../meshcore-decoder/dist/utils/auth-token.js | 194 ++++++ .../dist/utils/auth-token.js.map | 1 + .../dist/utils/enum-names.d.ts | 26 + .../dist/utils/enum-names.d.ts.map | 1 + .../meshcore-decoder/dist/utils/enum-names.js | 93 +++ .../dist/utils/enum-names.js.map | 1 + .../lib/meshcore-decoder/dist/utils/hex.d.ts | 17 + .../meshcore-decoder/dist/utils/hex.d.ts.map | 1 + .../lib/meshcore-decoder/dist/utils/hex.js | 44 ++ .../meshcore-decoder/dist/utils/hex.js.map | 1 + .../lib/meshcore-decoder/lib/build-wasm.sh | 27 + .../lib/orlp-ed25519-wrapper.c | 65 ++ .../lib/meshcore-decoder/lib/orlp-ed25519.js | 20 + .../meshcore-decoder/lib/orlp-ed25519.wasm | Bin 0 -> 57094 bytes .../lib/meshcore-decoder/lib/orlp-wrapper.cc | 0 frontend/lib/meshcore-decoder/package.json | 56 ++ frontend/package.json | 4 +- 109 files changed, 4841 insertions(+), 8 deletions(-) create mode 100644 frontend/.npmrc create mode 100644 frontend/lib/meshcore-decoder/LICENSE.md create mode 100644 frontend/lib/meshcore-decoder/README.md create mode 100644 frontend/lib/meshcore-decoder/dist/cli.d.ts create mode 100644 frontend/lib/meshcore-decoder/dist/cli.d.ts.map create mode 100644 frontend/lib/meshcore-decoder/dist/cli.js create mode 100644 frontend/lib/meshcore-decoder/dist/cli.js.map create mode 100644 frontend/lib/meshcore-decoder/dist/crypto/channel-crypto.d.ts create mode 100644 frontend/lib/meshcore-decoder/dist/crypto/channel-crypto.d.ts.map create mode 100644 frontend/lib/meshcore-decoder/dist/crypto/channel-crypto.js create mode 100644 frontend/lib/meshcore-decoder/dist/crypto/channel-crypto.js.map create mode 100644 frontend/lib/meshcore-decoder/dist/crypto/ed25519-verifier.d.ts create mode 100644 frontend/lib/meshcore-decoder/dist/crypto/ed25519-verifier.d.ts.map create mode 100644 frontend/lib/meshcore-decoder/dist/crypto/ed25519-verifier.js create mode 100644 frontend/lib/meshcore-decoder/dist/crypto/ed25519-verifier.js.map create mode 100644 frontend/lib/meshcore-decoder/dist/crypto/key-manager.d.ts create mode 100644 frontend/lib/meshcore-decoder/dist/crypto/key-manager.d.ts.map create mode 100644 frontend/lib/meshcore-decoder/dist/crypto/key-manager.js create mode 100644 frontend/lib/meshcore-decoder/dist/crypto/key-manager.js.map create mode 100644 frontend/lib/meshcore-decoder/dist/crypto/orlp-ed25519-wasm.d.ts create mode 100644 frontend/lib/meshcore-decoder/dist/crypto/orlp-ed25519-wasm.d.ts.map create mode 100644 frontend/lib/meshcore-decoder/dist/crypto/orlp-ed25519-wasm.js create mode 100644 frontend/lib/meshcore-decoder/dist/crypto/orlp-ed25519-wasm.js.map create mode 100644 frontend/lib/meshcore-decoder/dist/decoder/packet-decoder.d.ts create mode 100644 frontend/lib/meshcore-decoder/dist/decoder/packet-decoder.d.ts.map create mode 100644 frontend/lib/meshcore-decoder/dist/decoder/packet-decoder.js create mode 100644 frontend/lib/meshcore-decoder/dist/decoder/packet-decoder.js.map create mode 100644 frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/ack.d.ts create mode 100644 frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/ack.d.ts.map create mode 100644 frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/ack.js create mode 100644 frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/ack.js.map create mode 100644 frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/advert.d.ts create mode 100644 frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/advert.d.ts.map create mode 100644 frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/advert.js create mode 100644 frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/advert.js.map create mode 100644 frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/anon-request.d.ts create mode 100644 frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/anon-request.d.ts.map create mode 100644 frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/anon-request.js create mode 100644 frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/anon-request.js.map create mode 100644 frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/control.d.ts create mode 100644 frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/control.d.ts.map create mode 100644 frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/control.js create mode 100644 frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/control.js.map create mode 100644 frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/group-text.d.ts create mode 100644 frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/group-text.d.ts.map create mode 100644 frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/group-text.js create mode 100644 frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/group-text.js.map create mode 100644 frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/path.d.ts create mode 100644 frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/path.d.ts.map create mode 100644 frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/path.js create mode 100644 frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/path.js.map create mode 100644 frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/request.d.ts create mode 100644 frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/request.d.ts.map create mode 100644 frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/request.js create mode 100644 frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/request.js.map create mode 100644 frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/response.d.ts create mode 100644 frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/response.d.ts.map create mode 100644 frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/response.js create mode 100644 frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/response.js.map create mode 100644 frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/text-message.d.ts create mode 100644 frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/text-message.d.ts.map create mode 100644 frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/text-message.js create mode 100644 frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/text-message.js.map create mode 100644 frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/trace.d.ts create mode 100644 frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/trace.d.ts.map create mode 100644 frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/trace.js create mode 100644 frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/trace.js.map create mode 100644 frontend/lib/meshcore-decoder/dist/index.d.ts create mode 100644 frontend/lib/meshcore-decoder/dist/index.d.ts.map create mode 100644 frontend/lib/meshcore-decoder/dist/index.js create mode 100644 frontend/lib/meshcore-decoder/dist/index.js.map create mode 100644 frontend/lib/meshcore-decoder/dist/types/crypto.d.ts create mode 100644 frontend/lib/meshcore-decoder/dist/types/crypto.d.ts.map create mode 100644 frontend/lib/meshcore-decoder/dist/types/crypto.js create mode 100644 frontend/lib/meshcore-decoder/dist/types/crypto.js.map create mode 100644 frontend/lib/meshcore-decoder/dist/types/enums.d.ts create mode 100644 frontend/lib/meshcore-decoder/dist/types/enums.d.ts.map create mode 100644 frontend/lib/meshcore-decoder/dist/types/enums.js create mode 100644 frontend/lib/meshcore-decoder/dist/types/enums.js.map create mode 100644 frontend/lib/meshcore-decoder/dist/types/packet.d.ts create mode 100644 frontend/lib/meshcore-decoder/dist/types/packet.d.ts.map create mode 100644 frontend/lib/meshcore-decoder/dist/types/packet.js create mode 100644 frontend/lib/meshcore-decoder/dist/types/packet.js.map create mode 100644 frontend/lib/meshcore-decoder/dist/types/payloads.d.ts create mode 100644 frontend/lib/meshcore-decoder/dist/types/payloads.d.ts.map create mode 100644 frontend/lib/meshcore-decoder/dist/types/payloads.js create mode 100644 frontend/lib/meshcore-decoder/dist/types/payloads.js.map create mode 100644 frontend/lib/meshcore-decoder/dist/utils/auth-token.d.ts create mode 100644 frontend/lib/meshcore-decoder/dist/utils/auth-token.d.ts.map create mode 100644 frontend/lib/meshcore-decoder/dist/utils/auth-token.js create mode 100644 frontend/lib/meshcore-decoder/dist/utils/auth-token.js.map create mode 100644 frontend/lib/meshcore-decoder/dist/utils/enum-names.d.ts create mode 100644 frontend/lib/meshcore-decoder/dist/utils/enum-names.d.ts.map create mode 100644 frontend/lib/meshcore-decoder/dist/utils/enum-names.js create mode 100644 frontend/lib/meshcore-decoder/dist/utils/enum-names.js.map create mode 100644 frontend/lib/meshcore-decoder/dist/utils/hex.d.ts create mode 100644 frontend/lib/meshcore-decoder/dist/utils/hex.d.ts.map create mode 100644 frontend/lib/meshcore-decoder/dist/utils/hex.js create mode 100644 frontend/lib/meshcore-decoder/dist/utils/hex.js.map create mode 100644 frontend/lib/meshcore-decoder/lib/build-wasm.sh create mode 100644 frontend/lib/meshcore-decoder/lib/orlp-ed25519-wrapper.c create mode 100644 frontend/lib/meshcore-decoder/lib/orlp-ed25519.js create mode 100644 frontend/lib/meshcore-decoder/lib/orlp-ed25519.wasm create mode 100644 frontend/lib/meshcore-decoder/lib/orlp-wrapper.cc create mode 100644 frontend/lib/meshcore-decoder/package.json diff --git a/Dockerfile b/Dockerfile index 24ee0a9..4384131 100644 --- a/Dockerfile +++ b/Dockerfile @@ -5,11 +5,8 @@ ARG COMMIT_HASH=unknown WORKDIR /build -RUN apt-get update \ - && apt-get install -y --no-install-recommends git \ - && rm -rf /var/lib/apt/lists/* - -COPY frontend/package.json ./ +COPY frontend/package.json frontend/.npmrc ./ +COPY frontend/lib/meshcore-decoder ./lib/meshcore-decoder RUN npm install COPY frontend/ ./ diff --git a/LICENSES.md b/LICENSES.md index 10971fa..77a7c2f 100644 --- a/LICENSES.md +++ b/LICENSES.md @@ -1141,7 +1141,7 @@ SOFTWARE. -### meshcore-hashtag-cracker (1.7.0) — MIT +### meshcore-hashtag-cracker (1.10.0) — MIT
Full license text diff --git a/frontend/.npmrc b/frontend/.npmrc new file mode 100644 index 0000000..c7d3517 --- /dev/null +++ b/frontend/.npmrc @@ -0,0 +1 @@ +install-links=true diff --git a/frontend/AGENTS.md b/frontend/AGENTS.md index 095bd53..47c9e4a 100644 --- a/frontend/AGENTS.md +++ b/frontend/AGENTS.md @@ -12,6 +12,7 @@ Keep it aligned with `frontend/src` source code. - Tailwind utility classes + local CSS (`index.css`, `styles.css`) - Sonner (toasts) - Leaflet / react-leaflet (map) +- Vendored `@michaelhart/meshcore-decoder` in `frontend/lib/meshcore-decoder` (local file dependency for multibyte-support build) - `meshcore-hashtag-cracker` + `nosleep.js` (channel cracker) ## Frontend Map @@ -138,6 +139,9 @@ frontend/src/ ├── useContactsAndChannels.test.ts ├── useWebSocket.dispatch.test.ts └── useWebSocket.lifecycle.test.ts + +frontend/lib/ +└── meshcore-decoder/ # Vendored local decoder package used by app + hashtag cracker ``` ## Architecture Notes diff --git a/frontend/lib/meshcore-decoder/LICENSE.md b/frontend/lib/meshcore-decoder/LICENSE.md new file mode 100644 index 0000000..26bad0b --- /dev/null +++ b/frontend/lib/meshcore-decoder/LICENSE.md @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2025 Michael Hart (https://github.com/michaelhart) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/frontend/lib/meshcore-decoder/README.md b/frontend/lib/meshcore-decoder/README.md new file mode 100644 index 0000000..c7c37a5 --- /dev/null +++ b/frontend/lib/meshcore-decoder/README.md @@ -0,0 +1,453 @@ +# MeshCore Decoder + +A TypeScript library for decoding MeshCore mesh networking packets with full cryptographic support. Uses WebAssembly (WASM) for Ed25519 key derivation through the [orlp/ed25519 library](https://github.com/orlp/ed25519). + +This powers the [MeshCore Packet Analyzer](https://analyzer.letsme.sh/). + +## Features + +- **Packet Decoding**: Decode MeshCore packets +- **Built-in Decryption**: Decrypt GroupText, TextMessage, and other encrypted payloads +- **Developer Friendly**: TypeScript-first with full type safety and portability of JavaScript + +## Installation + +### Install to a single project + +```bash +npm install @michaelhart/meshcore-decoder +``` + +### Install CLI (install globally) + +```bash +npm install -g @michaelhart/meshcore-decoder +``` + +## Quick Start + +```typescript +import { + MeshCoreDecoder, + PayloadType, + Utils, + DecodedPacket, + AdvertPayload +} from '@michaelhart/meshcore-decoder'; + +// Decode a MeshCore packet +const hexData: string = '11007E7662676F7F0850A8A355BAAFBFC1EB7B4174C340442D7D7161C9474A2C94006CE7CF682E58408DD8FCC51906ECA98EBF94A037886BDADE7ECD09FD92B839491DF3809C9454F5286D1D3370AC31A34593D569E9A042A3B41FD331DFFB7E18599CE1E60992A076D50238C5B8F85757375354522F50756765744D65736820436F75676172'; + +const packet: DecodedPacket = MeshCoreDecoder.decode(hexData); + +console.log(`Route Type: ${Utils.getRouteTypeName(packet.routeType)}`); +console.log(`Payload Type: ${Utils.getPayloadTypeName(packet.payloadType)}`); +console.log(`Message Hash: ${packet.messageHash}`); + +if (packet.payloadType === PayloadType.Advert && packet.payload.decoded) { + const advert: AdvertPayload = packet.payload.decoded as AdvertPayload; + console.log(`Device Name: ${advert.appData.name}`); + console.log(`Device Role: ${Utils.getDeviceRoleName(advert.appData.deviceRole)}`); + if (advert.appData.location) { + console.log(`Location: ${advert.appData.location.latitude}, ${advert.appData.location.longitude}`); + } +} +``` + +## Full Packet Structure Example + +Here's what a complete decoded packet looks like: + +```typescript +import { MeshCoreDecoder, DecodedPacket } from '@michaelhart/meshcore-decoder'; + +const hexData: string = '11007E7662676F7F0850A8A355BAAFBFC1EB7B4174C340442D7D7161C9474A2C94006CE7CF682E58408DD8FCC51906ECA98EBF94A037886BDADE7ECD09FD92B839491DF3809C9454F5286D1D3370AC31A34593D569E9A042A3B41FD331DFFB7E18599CE1E60992A076D50238C5B8F85757375354522F50756765744D65736820436F75676172'; + +const packet: DecodedPacket = MeshCoreDecoder.decode(hexData); + +console.log(JSON.stringify(packet, null, 2)); +``` + +**Output:** +```json +{ + "messageHash": "F9C060FE", + "routeType": 1, + "payloadType": 4, + "payloadVersion": 0, + "pathLength": 0, + "path": null, + "payload": { + "raw": "7E7662676F7F0850A8A355BAAFBFC1EB7B4174C340442D7D7161C9474A2C94006CE7CF682E58408DD8FCC51906ECA98EBF94A037886BDADE7ECD09FD92B839491DF3809C9454F5286D1D3370AC31A34593D569E9A042A3B41FD331DFFB7E18599CE1E60992A076D50238C5B8F85757375354522F50756765744D65736820436F75676172", + "decoded": { + "type": 4, + "version": 0, + "isValid": true, + "publicKey": "7E7662676F7F0850A8A355BAAFBFC1EB7B4174C340442D7D7161C9474A2C9400", + "timestamp": 1758455660, + "signature": "2E58408DD8FCC51906ECA98EBF94A037886BDADE7ECD09FD92B839491DF3809C9454F5286D1D3370AC31A34593D569E9A042A3B41FD331DFFB7E18599CE1E609", + "appData": { + "flags": 146, + "deviceRole": 2, + "hasLocation": true, + "hasName": true, + "location": { + "latitude": 47.543968, + "longitude": -122.108616 + }, + "name": "WW7STR/PugetMesh Cougar" + } + } + }, + "totalBytes": 134, + "isValid": true +} +``` + +## Packet Support + +| Value | Name | Description | Decoding | Decryption | Segment Analysis | +|-------|------|-------------|----------|------------|------------------| +| `0x00` | Request | Request (destination/source hashes + MAC) | ✅ | 🚧 | ✅ | +| `0x01` | Response | Response to REQ or ANON_REQ | ✅ | 🚧 | ✅ | +| `0x02` | Plain text message | Plain text message | ✅ | 🚧 | ✅ | +| `0x03` | Acknowledgment | Acknowledgment | ✅ | N/A | ✅ | +| `0x04` | Node advertisement | Node advertisement | ✅ | N/A | ✅ | +| `0x05` | Group text message | Group text message | ✅ | ✅ | ✅ | +| `0x06` | Group datagram | Group datagram | 🚧 | 🚧 | 🚧 | +| `0x07` | Anonymous request | Anonymous request | ✅ | 🚧 | ✅ | +| `0x08` | Returned path | Returned path | ✅ | N/A | ✅ | +| `0x09` | Trace | Trace a path, collecting SNI for each hop | ✅ | N/A | ✅ | +| `0x0A` | Multi-part packet | Packet is part of a sequence of packets | 🚧 | 🚧 | 🚧 | +| `0x0F` | Custom packet | Custom packet (raw bytes, custom encryption) | 🚧 | 🚧 | 🚧 | + +**Legend:** +- ✅ Fully implemented +- 🚧 Planned/In development +- `-` Not applicable + +For some packet types not yet supported here, they may not exist in MeshCore yet or I have yet to observe these packet types on the mesh. + +## Decryption Support + +Simply provide your channel secret keys and the library handles everything else: + +```typescript +import { + MeshCoreDecoder, + PayloadType, + CryptoKeyStore, + DecodedPacket, + GroupTextPayload +} from '@michaelhart/meshcore-decoder'; + +// Create a key store with channel secret keys +const keyStore: CryptoKeyStore = MeshCoreDecoder.createKeyStore({ + channelSecrets: [ + '8b3387e9c5cdea6ac9e5edbaa115cd72', // Public channel (channel hash 11) + 'ff2b7d74e8d20f71505bda9ea8d59a1c', // A different channel's secret + ] +}); + +const groupTextHexData: string = '...'; // Your encrypted GroupText packet hex + +// Decode encrypted GroupText message +const encryptedPacket: DecodedPacket = MeshCoreDecoder.decode(groupTextHexData, { keyStore }); + +if (encryptedPacket.payloadType === PayloadType.GroupText && encryptedPacket.payload.decoded) { + const groupText: GroupTextPayload = encryptedPacket.payload.decoded as GroupTextPayload; + + if (groupText.decrypted) { + console.log(`Sender: ${groupText.decrypted.sender}`); + console.log(`Message: ${groupText.decrypted.message}`); + console.log(`Timestamp: ${new Date(groupText.decrypted.timestamp * 1000).toISOString()}`); + } else { + console.log('Message encrypted (no key available)'); + } +} +``` + +The library automatically: +- Calculates channel hashes from your secret keys using SHA256 +- Handles hash collisions (multiple keys with same first byte) by trying all matching keys +- Verifies message authenticity using HMAC-SHA256 +- Decrypts using AES-128 ECB + +## Packet Structure Analysis + +For detailed packet analysis and debugging, use `analyzeStructure()` to get byte-level breakdowns: + +```typescript +import { MeshCoreDecoder, PacketStructure } from '@michaelhart/meshcore-decoder'; + +console.log('=== Packet Breakdown ==='); +const hexData: string = '11007E7662676F7F0850A8A355BAAFBFC1EB7B4174C340442D7D7161C9474A2C94006CE7CF682E58408DD8FCC51906ECA98EBF94A037886BDADE7ECD09FD92B839491DF3809C9454F5286D1D3370AC31A34593D569E9A042A3B41FD331DFFB7E18599CE1E60992A076D50238C5B8F85757375354522F50756765744D65736820436F75676172'; + +console.log('Packet length:', hexData.length); +console.log('Expected bytes:', hexData.length / 2); + +const structure: PacketStructure = MeshCoreDecoder.analyzeStructure(hexData); +console.log('\nMain segments:'); +structure.segments.forEach((seg, i) => { + console.log(`${i+1}. ${seg.name} (bytes ${seg.startByte}-${seg.endByte}): ${seg.value}`); +}); + +console.log('\nPayload segments:'); +structure.payload.segments.forEach((seg, i) => { + console.log(`${i+1}. ${seg.name} (bytes ${seg.startByte}-${seg.endByte}): ${seg.value}`); + console.log(` Description: ${seg.description}`); +}); +``` + +**Output:** +``` +=== Packet Breakdown === +Packet length: 268 +Expected bytes: 134 + +Main segments: +1. Header (bytes 0-0): 0x11 +2. Path Length (bytes 1-1): 0x00 +3. Payload (bytes 2-133): 7E7662676F7F0850A8A355BAAFBFC1EB7B4174C340442D7D7161C9474A2C94006CE7CF682E58408DD8FCC51906ECA98EBF94A037886BDADE7ECD09FD92B839491DF3809C9454F5286D1D3370AC31A34593D569E9A042A3B41FD331DFFB7E18599CE1E60992A076D50238C5B8F85757375354522F50756765744D65736820436F75676172 + +Payload segments: +1. Public Key (bytes 0-31): 7E7662676F7F0850A8A355BAAFBFC1EB7B4174C340442D7D7161C9474A2C9400 + Description: Ed25519 public key +2. Timestamp (bytes 32-35): 6CE7CF68 + Description: 1758455660 (2025-09-21T11:54:20Z) +3. Signature (bytes 36-99): 2E58408DD8FCC51906ECA98EBF94A037886BDADE7ECD09FD92B839491DF3809C9454F5286D1D3370AC31A34593D569E9A042A3B41FD331DFFB7E18599CE1E609 + Description: Ed25519 signature +4. App Flags (bytes 100-100): 92 + Description: Binary: 10010010 | Bits 0-3 (Role): Room server | Bit 4 (Location): Yes | Bit 5 (Feature1): No | Bit 6 (Feature2): No | Bit 7 (Name): Yes +5. Latitude (bytes 101-104): A076D502 + Description: 47.543968° (47.543968) +6. Longitude (bytes 105-108): 38C5B8F8 + Description: -122.108616° (-122.108616) +7. Node Name (bytes 109-131): 5757375354522F50756765744D65736820436F75676172 + Description: Node name: "WW7STR/PugetMesh Cougar" +``` + +The `analyzeStructure()` method provides: +- **Header breakdown** with bit-level field analysis +- **Byte-accurate segments** with start/end positions +- **Payload field parsing** for all supported packet types +- **Human-readable descriptions** for each field + +## Ed25519 Key Derivation + +The library includes MeshCore-compatible Ed25519 key derivation using the exact orlp/ed25519 algorithm via WebAssembly: + +```typescript +import { Utils } from '@michaelhart/meshcore-decoder'; + +// Derive public key from MeshCore private key (64-byte format) +const privateKey = '18469d6140447f77de13cd8d761e605431f52269fbff43b0925752ed9e6745435dc6a86d2568af8b70d3365db3f88234760c8ecc645ce469829bc45b65f1d5d5'; + +const publicKey = await Utils.derivePublicKey(privateKey); +console.log('Derived Public Key:', publicKey); +// Output: 4852B69364572B52EFA1B6BB3E6D0ABED4F389A1CBFBB60A9BBA2CCE649CAF0E + +// Validate a key pair +const isValid = await Utils.validateKeyPair(privateKey, publicKey); +console.log('Key pair valid:', isValid); // true +``` + +### Command Line Interface + +For quick analysis from the terminal, install globally and use the CLI: + +```bash +# Install globally +npm install -g @michaelhart/meshcore-decoder + +# Analyze a packet +meshcore-decoder 11007E7662676F7F0850A8A355BAAFBFC1EB7B4174C340442D7D7161C9474A2C94006CE7CF682E58408DD8FCC51906ECA98EBF94A037886BDADE7ECD09FD92B839491DF3809C9454F5286D1D3370AC31A34593D569E9A042A3B41FD331DFFB7E18599CE1E60992A076D50238C5B8F85757375354522F50756765744D65736820436F75676172 + +# With decryption (provide channel secrets) +meshcore-decoder 150011C3C1354D619BAE9590E4D177DB7EEAF982F5BDCF78005D75157D9535FA90178F785D --key 8b3387e9c5cdea6ac9e5edbaa115cd72 + +# Show detailed structure analysis +meshcore-decoder --structure 11007E7662676F7F0850A8A355BAAFBFC1EB7B4174C340442D7D7161C9474A2C94006CE7CF682E58408DD8FCC51906ECA98EBF94A037886BDADE7ECD09FD92B839491DF3809C9454F5286D1D3370AC31A34593D569E9A042A3B41FD331DFFB7E18599CE1E60992A076D50238C5B8F85757375354522F50756765744D65736820436F75676172 + +# JSON output +meshcore-decoder --json 11007E7662676F7F0850A8A355BAAFBFC1EB7B4174C340442D7D7161C9474A2C94006CE7CF682E58408DD8FCC51906ECA98EBF94A037886BDADE7ECD09FD92B839491DF3809C9454F5286D1D3370AC31A34593D569E9A042A3B41FD331DFFB7E18599CE1E60992A076D50238C5B8F85757375354522F50756765744D65736820436F75676172 + +# Derive public key from MeshCore private key +meshcore-decoder derive-key 18469d6140447f77de13cd8d761e605431f52269fbff43b0925752ed9e6745435dc6a86d2568af8b70d3365db3f88234760c8ecc645ce469829bc45b65f1d5d5 + +# Validate key pair +meshcore-decoder derive-key 18469d6140447f77de13cd8d761e605431f52269fbff43b0925752ed9e6745435dc6a86d2568af8b70d3365db3f88234760c8ecc645ce469829bc45b65f1d5d5 --validate 4852b69364572b52efa1b6bb3e6d0abed4f389a1cbfbb60a9bba2cce649caf0e + +# Key derivation with JSON output +meshcore-decoder derive-key 18469d6140447f77de13cd8d761e605431f52269fbff43b0925752ed9e6745435dc6a86d2568af8b70d3365db3f88234760c8ecc645ce469829bc45b65f1d5d5 --json +``` + + +## Using with Angular + +The library works in Angular (and other browser-based) applications but requires additional configuration for WASM support and browser compatibility. + +### 1. Configure Assets in `angular.json` + +Add the WASM files to your Angular assets configuration: + +```json +{ + "projects": { + "your-app": { + "architect": { + "build": { + "options": { + "assets": [ + // ... your existing assets ... + { + "glob": "orlp-ed25519.*", + "input": "./node_modules/@michaelhart/meshcore-decoder/lib", + "output": "assets/" + } + ] + } + } + } + } + } +} +``` + +### 2. Create a WASM Service + +Create `src/app/services/meshcore-wasm.ts`: + +```typescript +import { Injectable } from '@angular/core'; +import { BehaviorSubject } from 'rxjs'; + +@Injectable({ providedIn: 'root' }) +export class MeshCoreWasmService { + private wasm: any = null; + public ready = new BehaviorSubject(false); + + constructor() { + this.loadWasm(); + } + + private async loadWasm() { + try { + const jsResponse = await fetch('/assets/orlp-ed25519.js'); + const jsText = await jsResponse.text(); + + const script = document.createElement('script'); + script.textContent = jsText; + document.head.appendChild(script); + + this.wasm = await (window as any).OrlpEd25519({ + locateFile: (path: string) => path === 'orlp-ed25519.wasm' ? '/assets/orlp-ed25519.wasm' : path + }); + + this.ready.next(true); + } catch (error) { + console.error('WASM load failed:', error); + this.ready.next(false); + } + } + + derivePublicKey(privateKeyHex: string): string | null { + if (!this.wasm) return null; + + const privateKeyBytes = this.hexToBytes(privateKeyHex); + const privateKeyPtr = 1024; + const publicKeyPtr = 1088; + + this.wasm.HEAPU8.set(privateKeyBytes, privateKeyPtr); + + const result = this.wasm.ccall('orlp_derive_public_key', 'number', ['number', 'number'], [publicKeyPtr, privateKeyPtr]); + + if (result === 0) { + const publicKeyBytes = this.wasm.HEAPU8.subarray(publicKeyPtr, publicKeyPtr + 32); + return this.bytesToHex(publicKeyBytes); + } + + return null; + } + + private hexToBytes(hex: string): Uint8Array { + const bytes = new Uint8Array(hex.length / 2); + for (let i = 0; i < hex.length; i += 2) { + bytes[i / 2] = parseInt(hex.substr(i, 2), 16); + } + return bytes; + } + + private bytesToHex(bytes: Uint8Array): string { + return Array.from(bytes).map(b => b.toString(16).padStart(2, '0')).join('').toUpperCase(); + } +} +``` + +### 3. Basic Usage + +```typescript +import { MeshCorePacketDecoder } from '@michaelhart/meshcore-decoder'; +import { MeshCoreWasmService } from './services/meshcore-wasm'; + +// Basic packet decoding (works immediately) +const packet = MeshCorePacketDecoder.decode(hexData); + +// Key derivation (wait for WASM) +wasmService.ready.subscribe(isReady => { + if (isReady) { + const publicKey = wasmService.derivePublicKey(privateKeyHex); + } +}); +``` + +### Angular/Browser: Important Notes + +- **WASM Loading**: The library uses WebAssembly for Ed25519 key derivation. This requires proper asset configuration and a service to handle async WASM loading. +- **Browser Compatibility**: The library automatically detects the environment and uses Web Crypto API in browsers, Node.js crypto in Node.js. +- **Async Operations**: Key derivation is async due to WASM loading. Always wait for the `WasmService.ready` observable. +- **Error Handling**: WASM operations may fail in some environments. Always wrap in try-catch blocks. + + +## Development + +```bash +# Install dependencies +npm install + +# Run tests +npm test + +# Run tests in watch mode +npm run test:watch + +# Build for production +npm run build + +# Development with ts-node +npm run dev +``` + +## License + +MIT License + +Copyright (c) 2025 Michael Hart (https://github.com/michaelhart) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/frontend/lib/meshcore-decoder/dist/cli.d.ts b/frontend/lib/meshcore-decoder/dist/cli.d.ts new file mode 100644 index 0000000..faaadd5 --- /dev/null +++ b/frontend/lib/meshcore-decoder/dist/cli.d.ts @@ -0,0 +1,3 @@ +#!/usr/bin/env node +export {}; +//# sourceMappingURL=cli.d.ts.map \ No newline at end of file diff --git a/frontend/lib/meshcore-decoder/dist/cli.d.ts.map b/frontend/lib/meshcore-decoder/dist/cli.d.ts.map new file mode 100644 index 0000000..f022439 --- /dev/null +++ b/frontend/lib/meshcore-decoder/dist/cli.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""} \ No newline at end of file diff --git a/frontend/lib/meshcore-decoder/dist/cli.js b/frontend/lib/meshcore-decoder/dist/cli.js new file mode 100644 index 0000000..0b71086 --- /dev/null +++ b/frontend/lib/meshcore-decoder/dist/cli.js @@ -0,0 +1,409 @@ +#!/usr/bin/env node +"use strict"; +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { enumerable: true, get: function() { return m[k]; } }; + } + Object.defineProperty(o, k2, desc); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__importStar) || (function () { + var ownKeys = function(o) { + ownKeys = Object.getOwnPropertyNames || function (o) { + var ar = []; + for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; + return ar; + }; + return ownKeys(o); + }; + return function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); + __setModuleDefault(result, mod); + return result; + }; +})(); +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const packet_decoder_1 = require("./decoder/packet-decoder"); +const enums_1 = require("./types/enums"); +const enum_names_1 = require("./utils/enum-names"); +const index_1 = require("./index"); +const commander_1 = require("commander"); +const chalk_1 = __importDefault(require("chalk")); +const packageJson = __importStar(require("../package.json")); +commander_1.program + .name('meshcore-decoder') + .description('CLI tool for decoding MeshCore packets') + .version(packageJson.version); +// Default decode command +commander_1.program + .command('decode', { isDefault: true }) + .description('Decode a MeshCore packet') + .argument('', 'Hex string of the packet to decode') + .option('-k, --key ', 'Channel secret keys for decryption (hex)') + .option('-j, --json', 'Output as JSON instead of formatted text') + .option('-s, --structure', 'Show detailed packet structure analysis') + .action(async (hex, options) => { + try { + // Clean up hex input + const cleanHex = hex.replace(/\s+/g, '').replace(/^0x/i, ''); + // Create key store if keys provided + let keyStore; + if (options.key && options.key.length > 0) { + keyStore = packet_decoder_1.MeshCorePacketDecoder.createKeyStore({ + channelSecrets: options.key + }); + } + // Decode packet with signature verification + const packet = await packet_decoder_1.MeshCorePacketDecoder.decodeWithVerification(cleanHex, { keyStore }); + if (options.json) { + // JSON output + if (options.structure) { + const structure = await packet_decoder_1.MeshCorePacketDecoder.analyzeStructureWithVerification(cleanHex, { keyStore }); + console.log(JSON.stringify({ packet, structure }, null, 2)); + } + else { + console.log(JSON.stringify(packet, null, 2)); + } + } + else { + // Formatted output + console.log(chalk_1.default.cyan('=== MeshCore Packet Analysis ===\n')); + if (!packet.isValid) { + console.log(chalk_1.default.red('❌ Invalid Packet')); + if (packet.errors) { + packet.errors.forEach(error => console.log(chalk_1.default.red(` ${error}`))); + } + } + else { + console.log(chalk_1.default.green('✅ Valid Packet')); + } + console.log(`${chalk_1.default.bold('Message Hash:')} ${packet.messageHash}`); + console.log(`${chalk_1.default.bold('Route Type:')} ${(0, enum_names_1.getRouteTypeName)(packet.routeType)}`); + console.log(`${chalk_1.default.bold('Payload Type:')} ${(0, enum_names_1.getPayloadTypeName)(packet.payloadType)}`); + console.log(`${chalk_1.default.bold('Total Bytes:')} ${packet.totalBytes}`); + if (packet.path && packet.path.length > 0) { + console.log(`${chalk_1.default.bold('Path:')} ${packet.path.join(' → ')}`); + } + // Show payload details (even for invalid packets) + if (packet.payload.decoded) { + console.log(chalk_1.default.cyan('\n=== Payload Details ===')); + showPayloadDetails(packet.payload.decoded); + } + // Exit with error code if packet is invalid + if (!packet.isValid) { + process.exit(1); + } + // Show structure if requested + if (options.structure) { + const structure = await packet_decoder_1.MeshCorePacketDecoder.analyzeStructureWithVerification(cleanHex, { keyStore }); + console.log(chalk_1.default.cyan('\n=== Packet Structure ===')); + console.log(chalk_1.default.yellow('\nMain Segments:')); + structure.segments.forEach((seg, i) => { + console.log(`${i + 1}. ${chalk_1.default.bold(seg.name)} (bytes ${seg.startByte}-${seg.endByte}): ${seg.value}`); + if (seg.description) { + console.log(` ${chalk_1.default.dim(seg.description)}`); + } + }); + if (structure.payload.segments.length > 0) { + console.log(chalk_1.default.yellow('\nPayload Segments:')); + structure.payload.segments.forEach((seg, i) => { + console.log(`${i + 1}. ${chalk_1.default.bold(seg.name)} (bytes ${seg.startByte}-${seg.endByte}): ${seg.value}`); + console.log(` ${chalk_1.default.dim(seg.description)}`); + }); + } + } + } + } + catch (error) { + console.error(chalk_1.default.red('Error:'), error.message); + process.exit(1); + } +}); +function showPayloadDetails(payload) { + switch (payload.type) { + case enums_1.PayloadType.Advert: + const advert = payload; + console.log(`${chalk_1.default.bold('Device Role:')} ${(0, enum_names_1.getDeviceRoleName)(advert.appData.deviceRole)}`); + if (advert.appData.name) { + console.log(`${chalk_1.default.bold('Device Name:')} ${advert.appData.name}`); + } + if (advert.appData.location) { + console.log(`${chalk_1.default.bold('Location:')} ${advert.appData.location.latitude}, ${advert.appData.location.longitude}`); + } + console.log(`${chalk_1.default.bold('Timestamp:')} ${new Date(advert.timestamp * 1000).toISOString()}`); + // Show signature verification status + if (advert.signatureValid !== undefined) { + if (advert.signatureValid) { + console.log(`${chalk_1.default.bold('Signature:')} ${chalk_1.default.green('✅ Valid Ed25519 signature')}`); + } + else { + console.log(`${chalk_1.default.bold('Signature:')} ${chalk_1.default.red('❌ Invalid Ed25519 signature')}`); + if (advert.signatureError) { + console.log(`${chalk_1.default.bold('Error:')} ${chalk_1.default.red(advert.signatureError)}`); + } + } + } + else { + console.log(`${chalk_1.default.bold('Signature:')} ${chalk_1.default.yellow('⚠️ Not verified (use async verification)')}`); + } + break; + case enums_1.PayloadType.GroupText: + const groupText = payload; + console.log(`${chalk_1.default.bold('Channel Hash:')} ${groupText.channelHash}`); + if (groupText.decrypted) { + console.log(chalk_1.default.green('🔓 Decrypted Message:')); + if (groupText.decrypted.sender) { + console.log(`${chalk_1.default.bold('Sender:')} ${groupText.decrypted.sender}`); + } + console.log(`${chalk_1.default.bold('Message:')} ${groupText.decrypted.message}`); + console.log(`${chalk_1.default.bold('Timestamp:')} ${new Date(groupText.decrypted.timestamp * 1000).toISOString()}`); + } + else { + console.log(chalk_1.default.yellow('🔒 Encrypted (no key available)')); + console.log(`${chalk_1.default.bold('Ciphertext:')} ${groupText.ciphertext.substring(0, 32)}...`); + } + break; + case enums_1.PayloadType.Trace: + const trace = payload; + console.log(`${chalk_1.default.bold('Trace Tag:')} ${trace.traceTag}`); + console.log(`${chalk_1.default.bold('Auth Code:')} ${trace.authCode}`); + if (trace.snrValues && trace.snrValues.length > 0) { + console.log(`${chalk_1.default.bold('SNR Values:')} ${trace.snrValues.map(snr => `${snr.toFixed(1)}dB`).join(', ')}`); + } + break; + default: + console.log(`${chalk_1.default.bold('Type:')} ${(0, enum_names_1.getPayloadTypeName)(payload.type)}`); + console.log(`${chalk_1.default.bold('Valid:')} ${payload.isValid ? '✅' : '❌'}`); + } +} +// Add key derivation command +commander_1.program + .command('derive-key') + .description('Derive Ed25519 public key from MeshCore private key') + .argument('', '64-byte private key in hex format') + .option('-v, --validate ', 'Validate against expected public key') + .option('-j, --json', 'Output as JSON') + .action(async (privateKeyHex, options) => { + try { + // Clean up hex input + const cleanPrivateKey = privateKeyHex.replace(/\s+/g, '').replace(/^0x/i, ''); + if (cleanPrivateKey.length !== 128) { + console.error(chalk_1.default.red('❌ Error: Private key must be exactly 64 bytes (128 hex characters)')); + process.exit(1); + } + if (options.json) { + // JSON output + const result = { + privateKey: cleanPrivateKey, + derivedPublicKey: await index_1.Utils.derivePublicKey(cleanPrivateKey) + }; + if (options.validate) { + const cleanExpectedKey = options.validate.replace(/\s+/g, '').replace(/^0x/i, ''); + result.expectedPublicKey = cleanExpectedKey; + result.isValid = await index_1.Utils.validateKeyPair(cleanPrivateKey, cleanExpectedKey); + result.match = result.derivedPublicKey.toLowerCase() === cleanExpectedKey.toLowerCase(); + } + console.log(JSON.stringify(result, null, 2)); + } + else { + // Formatted output + console.log(chalk_1.default.cyan('=== MeshCore Ed25519 Key Derivation ===\n')); + console.log(chalk_1.default.bold('Private Key (64 bytes):')); + console.log(chalk_1.default.gray(cleanPrivateKey)); + console.log(); + console.log(chalk_1.default.bold('Derived Public Key (32 bytes):')); + const derivedKey = await index_1.Utils.derivePublicKey(cleanPrivateKey); + console.log(chalk_1.default.green(derivedKey)); + console.log(); + if (options.validate) { + const cleanExpectedKey = options.validate.replace(/\s+/g, '').replace(/^0x/i, ''); + console.log(chalk_1.default.bold('Expected Public Key:')); + console.log(chalk_1.default.gray(cleanExpectedKey)); + console.log(); + const match = derivedKey.toLowerCase() === cleanExpectedKey.toLowerCase(); + console.log(chalk_1.default.bold('Validation:')); + console.log(match ? chalk_1.default.green('Keys match') : chalk_1.default.red('Keys do not match')); + if (!match) { + process.exit(1); + } + } + console.log(chalk_1.default.green('Key derivation completed successfully')); + } + } + catch (error) { + const errorMessage = error instanceof Error ? error.message : 'Unknown error'; + if (options.json) { + console.log(JSON.stringify({ error: errorMessage }, null, 2)); + } + else { + console.error(chalk_1.default.red(`Error: ${errorMessage}`)); + } + process.exit(1); + } +}); +// Add auth-token command +commander_1.program + .command('auth-token') + .description('Generate JWT authentication token signed with Ed25519 private key') + .argument('', '32-byte public key in hex format') + .argument('', '64-byte private key in hex format') + .option('-e, --exp ', 'Token expiration in seconds from now (default: 86400 = 24 hours)', '86400') + .option('-c, --claims ', 'Additional claims as JSON object (e.g., \'{"aud":"mqtt.example.com","sub":"device-123"}\')') + .option('-j, --json', 'Output as JSON') + .action(async (publicKeyHex, privateKeyHex, options) => { + try { + const { createAuthToken } = await Promise.resolve().then(() => __importStar(require('./utils/auth-token'))); + // Clean up hex inputs + const cleanPublicKey = publicKeyHex.replace(/\s+/g, '').replace(/^0x/i, ''); + const cleanPrivateKey = privateKeyHex.replace(/\s+/g, '').replace(/^0x/i, ''); + if (cleanPublicKey.length !== 64) { + console.error(chalk_1.default.red('❌ Error: Public key must be exactly 32 bytes (64 hex characters)')); + process.exit(1); + } + if (cleanPrivateKey.length !== 128) { + console.error(chalk_1.default.red('❌ Error: Private key must be exactly 64 bytes (128 hex characters)')); + process.exit(1); + } + const expSeconds = parseInt(options.exp); + const iat = Math.floor(Date.now() / 1000); + const exp = iat + expSeconds; + const payload = { + publicKey: cleanPublicKey.toUpperCase(), + iat, + exp + }; + // Parse and merge additional claims if provided + if (options.claims) { + try { + const additionalClaims = JSON.parse(options.claims); + Object.assign(payload, additionalClaims); + } + catch (e) { + console.error(chalk_1.default.red('❌ Error: Invalid JSON in --claims option')); + process.exit(1); + } + } + const token = await createAuthToken(payload, cleanPrivateKey, cleanPublicKey.toUpperCase()); + if (options.json) { + console.log(JSON.stringify({ + token, + payload + }, null, 2)); + } + else { + console.log(token); + } + } + catch (error) { + const errorMessage = error instanceof Error ? error.message : 'Unknown error'; + if (options.json) { + console.log(JSON.stringify({ error: errorMessage }, null, 2)); + } + else { + console.error(chalk_1.default.red(`Error: ${errorMessage}`)); + } + process.exit(1); + } +}); +// Add verify-token command +commander_1.program + .command('verify-token') + .description('Verify JWT authentication token') + .argument('', 'JWT token to verify') + .option('-p, --public-key ', 'Expected public key in hex format (optional)') + .option('-j, --json', 'Output as JSON') + .action(async (token, options) => { + try { + const { verifyAuthToken } = await Promise.resolve().then(() => __importStar(require('./utils/auth-token'))); + const cleanToken = token.trim(); + let expectedPublicKey; + if (options.publicKey) { + const cleanKey = options.publicKey.replace(/\s+/g, '').replace(/^0x/i, '').toUpperCase(); + if (cleanKey.length !== 64) { + console.error(chalk_1.default.red('❌ Error: Public key must be exactly 32 bytes (64 hex characters)')); + process.exit(1); + } + expectedPublicKey = cleanKey; + } + const payload = await verifyAuthToken(cleanToken, expectedPublicKey); + if (payload) { + const now = Math.floor(Date.now() / 1000); + const isExpired = payload.exp && now > payload.exp; + const timeToExpiry = payload.exp ? payload.exp - now : null; + if (options.json) { + console.log(JSON.stringify({ + valid: true, + expired: isExpired, + payload, + timeToExpiry + }, null, 2)); + } + else { + console.log(chalk_1.default.green('✅ Token is valid')); + console.log(chalk_1.default.cyan('\nPayload:')); + console.log(` Public Key: ${payload.publicKey}`); + console.log(` Issued At: ${new Date(payload.iat * 1000).toISOString()} (${payload.iat})`); + if (payload.exp) { + console.log(` Expires At: ${new Date(payload.exp * 1000).toISOString()} (${payload.exp})`); + if (isExpired) { + console.log(chalk_1.default.red(` Status: EXPIRED`)); + } + else { + console.log(chalk_1.default.green(` Status: Valid for ${timeToExpiry} more seconds`)); + } + } + // Show any additional claims + const standardClaims = ['publicKey', 'iat', 'exp']; + const customClaims = Object.keys(payload).filter(k => !standardClaims.includes(k)); + if (customClaims.length > 0) { + console.log(chalk_1.default.cyan('\nCustom Claims:')); + customClaims.forEach(key => { + console.log(` ${key}: ${JSON.stringify(payload[key])}`); + }); + } + } + } + else { + if (options.json) { + console.log(JSON.stringify({ + valid: false, + error: 'Token verification failed' + }, null, 2)); + } + else { + console.error(chalk_1.default.red('❌ Token verification failed')); + console.error(chalk_1.default.yellow('Possible reasons:')); + console.error(' - Invalid signature'); + console.error(' - Token format is incorrect'); + console.error(' - Public key mismatch (if --public-key was provided)'); + } + process.exit(1); + } + } + catch (error) { + const errorMessage = error instanceof Error ? error.message : 'Unknown error'; + if (options.json) { + console.log(JSON.stringify({ valid: false, error: errorMessage }, null, 2)); + } + else { + console.error(chalk_1.default.red(`Error: ${errorMessage}`)); + } + process.exit(1); + } +}); +commander_1.program.parse(); +//# sourceMappingURL=cli.js.map \ No newline at end of file diff --git a/frontend/lib/meshcore-decoder/dist/cli.js.map b/frontend/lib/meshcore-decoder/dist/cli.js.map new file mode 100644 index 0000000..9090734 --- /dev/null +++ b/frontend/lib/meshcore-decoder/dist/cli.js.map @@ -0,0 +1 @@ +{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/frontend/lib/meshcore-decoder/dist/crypto/channel-crypto.d.ts b/frontend/lib/meshcore-decoder/dist/crypto/channel-crypto.d.ts new file mode 100644 index 0000000..c29866f --- /dev/null +++ b/frontend/lib/meshcore-decoder/dist/crypto/channel-crypto.d.ts @@ -0,0 +1,15 @@ +import { DecryptionResult } from '../types/crypto'; +export declare class ChannelCrypto { + /** + * Decrypt GroupText message using MeshCore algorithm: + * - HMAC-SHA256 verification with 2-byte MAC + * - AES-128 ECB decryption + */ + static decryptGroupTextMessage(ciphertext: string, cipherMac: string, channelKey: string): DecryptionResult; + /** + * Calculate MeshCore channel hash from secret key + * Returns the first byte of SHA256(secret) as hex string + */ + static calculateChannelHash(secretKeyHex: string): string; +} +//# sourceMappingURL=channel-crypto.d.ts.map \ No newline at end of file diff --git a/frontend/lib/meshcore-decoder/dist/crypto/channel-crypto.d.ts.map b/frontend/lib/meshcore-decoder/dist/crypto/channel-crypto.d.ts.map new file mode 100644 index 0000000..c43d76b --- /dev/null +++ b/frontend/lib/meshcore-decoder/dist/crypto/channel-crypto.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"channel-crypto.d.ts","sourceRoot":"","sources":["../../src/crypto/channel-crypto.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAGnD,qBAAa,aAAa;IACxB;;;;OAIG;IACH,MAAM,CAAC,uBAAuB,CAC5B,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,GACjB,gBAAgB;IAuFnB;;;OAGG;IACH,MAAM,CAAC,oBAAoB,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM;CAK1D"} \ No newline at end of file diff --git a/frontend/lib/meshcore-decoder/dist/crypto/channel-crypto.js b/frontend/lib/meshcore-decoder/dist/crypto/channel-crypto.js new file mode 100644 index 0000000..d83294a --- /dev/null +++ b/frontend/lib/meshcore-decoder/dist/crypto/channel-crypto.js @@ -0,0 +1,94 @@ +"use strict"; +// Copyright (c) 2025 Michael Hart: https://github.com/michaelhart/meshcore-decoder +// MIT License +Object.defineProperty(exports, "__esModule", { value: true }); +exports.ChannelCrypto = void 0; +const crypto_js_1 = require("crypto-js"); +const hex_1 = require("../utils/hex"); +class ChannelCrypto { + /** + * Decrypt GroupText message using MeshCore algorithm: + * - HMAC-SHA256 verification with 2-byte MAC + * - AES-128 ECB decryption + */ + static decryptGroupTextMessage(ciphertext, cipherMac, channelKey) { + try { + // convert hex strings to byte arrays + const channelKey16 = (0, hex_1.hexToBytes)(channelKey); + const macBytes = (0, hex_1.hexToBytes)(cipherMac); + // MeshCore uses 32-byte channel secret: 16-byte key + 16 zero bytes + const channelSecret = new Uint8Array(32); + channelSecret.set(channelKey16, 0); + // Step 1: Verify HMAC-SHA256 using full 32-byte channel secret + const calculatedMac = (0, crypto_js_1.HmacSHA256)(crypto_js_1.enc.Hex.parse(ciphertext), crypto_js_1.enc.Hex.parse((0, hex_1.bytesToHex)(channelSecret))); + const calculatedMacBytes = (0, hex_1.hexToBytes)(calculatedMac.toString(crypto_js_1.enc.Hex)); + const calculatedMacFirst2 = calculatedMacBytes.slice(0, 2); + if (calculatedMacFirst2[0] !== macBytes[0] || calculatedMacFirst2[1] !== macBytes[1]) { + return { success: false, error: 'MAC verification failed' }; + } + // Step 2: Decrypt using AES-128 ECB with first 16 bytes of channel secret + const keyWords = crypto_js_1.enc.Hex.parse(channelKey); + const ciphertextWords = crypto_js_1.enc.Hex.parse(ciphertext); + const decrypted = crypto_js_1.AES.decrypt(crypto_js_1.lib.CipherParams.create({ ciphertext: ciphertextWords }), keyWords, { mode: crypto_js_1.mode.ECB, padding: crypto_js_1.pad.NoPadding }); + const decryptedBytes = (0, hex_1.hexToBytes)(decrypted.toString(crypto_js_1.enc.Hex)); + if (!decryptedBytes || decryptedBytes.length < 5) { + return { success: false, error: 'Decrypted content too short' }; + } + // parse MeshCore format: timestamp(4) + flags(1) + message_text + const timestamp = decryptedBytes[0] | + (decryptedBytes[1] << 8) | + (decryptedBytes[2] << 16) | + (decryptedBytes[3] << 24); + const flagsAndAttempt = decryptedBytes[4]; + // extract message text with UTF-8 decoding + const messageBytes = decryptedBytes.slice(5); + const decoder = new TextDecoder('utf-8'); + let messageText = decoder.decode(messageBytes); + // remove null terminator if present + const nullIndex = messageText.indexOf('\0'); + if (nullIndex >= 0) { + messageText = messageText.substring(0, nullIndex); + } + // parse sender and message (format: "sender: message") + const colonIndex = messageText.indexOf(': '); + let sender; + let content; + if (colonIndex > 0 && colonIndex < 50) { + const potentialSender = messageText.substring(0, colonIndex); + if (!/[:\[\]]/.test(potentialSender)) { + sender = potentialSender; + content = messageText.substring(colonIndex + 2); + } + else { + content = messageText; + } + } + else { + content = messageText; + } + return { + success: true, + data: { + timestamp, + flags: flagsAndAttempt, + sender, + message: content + } + }; + } + catch (error) { + return { success: false, error: error instanceof Error ? error.message : 'Decryption failed' }; + } + } + /** + * Calculate MeshCore channel hash from secret key + * Returns the first byte of SHA256(secret) as hex string + */ + static calculateChannelHash(secretKeyHex) { + const hash = (0, crypto_js_1.SHA256)(crypto_js_1.enc.Hex.parse(secretKeyHex)); + const hashBytes = (0, hex_1.hexToBytes)(hash.toString(crypto_js_1.enc.Hex)); + return hashBytes[0].toString(16).padStart(2, '0'); + } +} +exports.ChannelCrypto = ChannelCrypto; +//# sourceMappingURL=channel-crypto.js.map \ No newline at end of file diff --git a/frontend/lib/meshcore-decoder/dist/crypto/channel-crypto.js.map b/frontend/lib/meshcore-decoder/dist/crypto/channel-crypto.js.map new file mode 100644 index 0000000..ab2abb6 --- /dev/null +++ b/frontend/lib/meshcore-decoder/dist/crypto/channel-crypto.js.map @@ -0,0 +1 @@ +{"version":3,"file":"channel-crypto.js","sourceRoot":"","sources":["../../src/crypto/channel-crypto.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/frontend/lib/meshcore-decoder/dist/crypto/ed25519-verifier.d.ts b/frontend/lib/meshcore-decoder/dist/crypto/ed25519-verifier.d.ts new file mode 100644 index 0000000..97d4533 --- /dev/null +++ b/frontend/lib/meshcore-decoder/dist/crypto/ed25519-verifier.d.ts @@ -0,0 +1,48 @@ +export declare class Ed25519SignatureVerifier { + /** + * Verify an Ed25519 signature for MeshCore advertisement packets + * + * According to MeshCore protocol, the signed message for advertisements is: + * timestamp (4 bytes LE) + flags (1 byte) + location (8 bytes LE, if present) + name (variable, if present) + */ + static verifyAdvertisementSignature(publicKeyHex: string, signatureHex: string, timestamp: number, appDataHex: string): Promise; + /** + * Construct the signed message for MeshCore advertisements + * According to MeshCore source (Mesh.cpp lines 242-248): + * Format: public_key (32 bytes) + timestamp (4 bytes LE) + app_data (variable length) + */ + private static constructAdvertSignedMessage; + /** + * Get a human-readable description of what was signed + */ + static getSignedMessageDescription(publicKeyHex: string, timestamp: number, appDataHex: string): string; + /** + * Get the hex representation of the signed message for debugging + */ + static getSignedMessageHex(publicKeyHex: string, timestamp: number, appDataHex: string): string; + /** + * Derive Ed25519 public key from orlp/ed25519 private key format + * This implements the same algorithm as orlp/ed25519's ed25519_derive_pub() + * + * @param privateKeyHex - 64-byte private key in hex format (orlp/ed25519 format) + * @returns 32-byte public key in hex format + */ + static derivePublicKey(privateKeyHex: string): Promise; + /** + * Derive Ed25519 public key from orlp/ed25519 private key format (synchronous version) + * This implements the same algorithm as orlp/ed25519's ed25519_derive_pub() + * + * @param privateKeyHex - 64-byte private key in hex format (orlp/ed25519 format) + * @returns 32-byte public key in hex format + */ + static derivePublicKeySync(privateKeyHex: string): string; + /** + * Validate that a private key correctly derives to the expected public key + * + * @param privateKeyHex - 64-byte private key in hex format + * @param expectedPublicKeyHex - Expected 32-byte public key in hex format + * @returns true if the private key derives to the expected public key + */ + static validateKeyPair(privateKeyHex: string, expectedPublicKeyHex: string): Promise; +} +//# sourceMappingURL=ed25519-verifier.d.ts.map \ No newline at end of file diff --git a/frontend/lib/meshcore-decoder/dist/crypto/ed25519-verifier.d.ts.map b/frontend/lib/meshcore-decoder/dist/crypto/ed25519-verifier.d.ts.map new file mode 100644 index 0000000..00ceced --- /dev/null +++ b/frontend/lib/meshcore-decoder/dist/crypto/ed25519-verifier.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"ed25519-verifier.d.ts","sourceRoot":"","sources":["../../src/crypto/ed25519-verifier.ts"],"names":[],"mappings":"AAyEA,qBAAa,wBAAwB;IACnC;;;;;OAKG;WACU,4BAA4B,CACvC,YAAY,EAAE,MAAM,EACpB,YAAY,EAAE,MAAM,EACpB,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,OAAO,CAAC;IAkBnB;;;;OAIG;IACH,OAAO,CAAC,MAAM,CAAC,4BAA4B;IAuB3C;;OAEG;IACH,MAAM,CAAC,2BAA2B,CAChC,YAAY,EAAE,MAAM,EACpB,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,GACjB,MAAM;IAIT;;OAEG;IACH,MAAM,CAAC,mBAAmB,CACxB,YAAY,EAAE,MAAM,EACpB,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,GACjB,MAAM;IAMT;;;;;;OAMG;WACU,eAAe,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAepE;;;;;;OAMG;IACH,MAAM,CAAC,mBAAmB,CAAC,aAAa,EAAE,MAAM,GAAG,MAAM;IAezD;;;;;;OAMG;WACU,eAAe,CAAC,aAAa,EAAE,MAAM,EAAE,oBAAoB,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;CAQpG"} \ No newline at end of file diff --git a/frontend/lib/meshcore-decoder/dist/crypto/ed25519-verifier.js b/frontend/lib/meshcore-decoder/dist/crypto/ed25519-verifier.js new file mode 100644 index 0000000..d33ffd6 --- /dev/null +++ b/frontend/lib/meshcore-decoder/dist/crypto/ed25519-verifier.js @@ -0,0 +1,217 @@ +"use strict"; +// Copyright (c) 2025 Michael Hart: https://github.com/michaelhart/meshcore-decoder +// MIT License +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { enumerable: true, get: function() { return m[k]; } }; + } + Object.defineProperty(o, k2, desc); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__importStar) || (function () { + var ownKeys = function(o) { + ownKeys = Object.getOwnPropertyNames || function (o) { + var ar = []; + for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; + return ar; + }; + return ownKeys(o); + }; + return function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); + __setModuleDefault(result, mod); + return result; + }; +})(); +Object.defineProperty(exports, "__esModule", { value: true }); +exports.Ed25519SignatureVerifier = void 0; +const ed25519 = __importStar(require("@noble/ed25519")); +const hex_1 = require("../utils/hex"); +const orlp_ed25519_wasm_1 = require("./orlp-ed25519-wasm"); +// Cross-platform SHA-512 implementation +async function sha512Hash(data) { + // Browser environment - use Web Crypto API + if (typeof globalThis !== 'undefined' && globalThis.crypto && globalThis.crypto.subtle) { + const hashBuffer = await globalThis.crypto.subtle.digest('SHA-512', data); + return new Uint8Array(hashBuffer); + } + // Node.js environment - use crypto module + if (typeof require !== 'undefined') { + try { + const { createHash } = require('crypto'); + return createHash('sha512').update(data).digest(); + } + catch (error) { + // Fallback for environments where require is not available + } + } + throw new Error('No SHA-512 implementation available'); +} +function sha512HashSync(data) { + // Node.js environment - use crypto module + if (typeof require !== 'undefined') { + try { + const { createHash } = require('crypto'); + return createHash('sha512').update(data).digest(); + } + catch (error) { + // Fallback + } + } + // Browser environment fallback - use crypto-js for sync operation + try { + const CryptoJS = require('crypto-js'); + const wordArray = CryptoJS.lib.WordArray.create(data); + const hash = CryptoJS.SHA512(wordArray); + const hashBytes = new Uint8Array(64); + // Convert CryptoJS hash to Uint8Array + for (let i = 0; i < 16; i++) { + const word = hash.words[i] || 0; + hashBytes[i * 4] = (word >>> 24) & 0xff; + hashBytes[i * 4 + 1] = (word >>> 16) & 0xff; + hashBytes[i * 4 + 2] = (word >>> 8) & 0xff; + hashBytes[i * 4 + 3] = word & 0xff; + } + return hashBytes; + } + catch (error) { + // Final fallback - this should not happen since crypto-js is a dependency + throw new Error('No SHA-512 implementation available for synchronous operation'); + } +} +// Set up SHA-512 for @noble/ed25519 +ed25519.etc.sha512Async = sha512Hash; +// Always set up sync version - @noble/ed25519 requires it +// It will throw in browser environments, which @noble/ed25519 can handle +try { + ed25519.etc.sha512Sync = sha512HashSync; +} +catch (error) { + console.debug('Could not set up synchronous SHA-512:', error); +} +class Ed25519SignatureVerifier { + /** + * Verify an Ed25519 signature for MeshCore advertisement packets + * + * According to MeshCore protocol, the signed message for advertisements is: + * timestamp (4 bytes LE) + flags (1 byte) + location (8 bytes LE, if present) + name (variable, if present) + */ + static async verifyAdvertisementSignature(publicKeyHex, signatureHex, timestamp, appDataHex) { + try { + // Convert hex strings to Uint8Arrays + const publicKey = (0, hex_1.hexToBytes)(publicKeyHex); + const signature = (0, hex_1.hexToBytes)(signatureHex); + const appData = (0, hex_1.hexToBytes)(appDataHex); + // Construct the signed message according to MeshCore format + const message = this.constructAdvertSignedMessage(publicKeyHex, timestamp, appData); + // Verify the signature using noble-ed25519 + return await ed25519.verify(signature, message, publicKey); + } + catch (error) { + console.error('Ed25519 signature verification failed:', error); + return false; + } + } + /** + * Construct the signed message for MeshCore advertisements + * According to MeshCore source (Mesh.cpp lines 242-248): + * Format: public_key (32 bytes) + timestamp (4 bytes LE) + app_data (variable length) + */ + static constructAdvertSignedMessage(publicKeyHex, timestamp, appData) { + const publicKey = (0, hex_1.hexToBytes)(publicKeyHex); + // Timestamp (4 bytes, little-endian) + const timestampBytes = new Uint8Array(4); + timestampBytes[0] = timestamp & 0xFF; + timestampBytes[1] = (timestamp >> 8) & 0xFF; + timestampBytes[2] = (timestamp >> 16) & 0xFF; + timestampBytes[3] = (timestamp >> 24) & 0xFF; + // Concatenate: public_key + timestamp + app_data + const message = new Uint8Array(32 + 4 + appData.length); + message.set(publicKey, 0); + message.set(timestampBytes, 32); + message.set(appData, 36); + return message; + } + /** + * Get a human-readable description of what was signed + */ + static getSignedMessageDescription(publicKeyHex, timestamp, appDataHex) { + return `Public Key: ${publicKeyHex} + Timestamp: ${timestamp} (${new Date(timestamp * 1000).toISOString()}) + App Data: ${appDataHex}`; + } + /** + * Get the hex representation of the signed message for debugging + */ + static getSignedMessageHex(publicKeyHex, timestamp, appDataHex) { + const appData = (0, hex_1.hexToBytes)(appDataHex); + const message = this.constructAdvertSignedMessage(publicKeyHex, timestamp, appData); + return (0, hex_1.bytesToHex)(message); + } + /** + * Derive Ed25519 public key from orlp/ed25519 private key format + * This implements the same algorithm as orlp/ed25519's ed25519_derive_pub() + * + * @param privateKeyHex - 64-byte private key in hex format (orlp/ed25519 format) + * @returns 32-byte public key in hex format + */ + static async derivePublicKey(privateKeyHex) { + try { + const privateKeyBytes = (0, hex_1.hexToBytes)(privateKeyHex); + if (privateKeyBytes.length !== 64) { + throw new Error(`Invalid private key length: expected 64 bytes, got ${privateKeyBytes.length}`); + } + // Use the orlp/ed25519 WebAssembly implementation + return await (0, orlp_ed25519_wasm_1.derivePublicKey)(privateKeyHex); + } + catch (error) { + throw new Error(`Failed to derive public key: ${error instanceof Error ? error.message : 'Unknown error'}`); + } + } + /** + * Derive Ed25519 public key from orlp/ed25519 private key format (synchronous version) + * This implements the same algorithm as orlp/ed25519's ed25519_derive_pub() + * + * @param privateKeyHex - 64-byte private key in hex format (orlp/ed25519 format) + * @returns 32-byte public key in hex format + */ + static derivePublicKeySync(privateKeyHex) { + try { + const privateKeyBytes = (0, hex_1.hexToBytes)(privateKeyHex); + if (privateKeyBytes.length !== 64) { + throw new Error(`Invalid private key length: expected 64 bytes, got ${privateKeyBytes.length}`); + } + // Note: WASM operations are async, so this sync version throws an error + throw new Error('Synchronous key derivation not supported with WASM. Use derivePublicKey() instead.'); + } + catch (error) { + throw new Error(`Failed to derive public key: ${error instanceof Error ? error.message : 'Unknown error'}`); + } + } + /** + * Validate that a private key correctly derives to the expected public key + * + * @param privateKeyHex - 64-byte private key in hex format + * @param expectedPublicKeyHex - Expected 32-byte public key in hex format + * @returns true if the private key derives to the expected public key + */ + static async validateKeyPair(privateKeyHex, expectedPublicKeyHex) { + try { + return await (0, orlp_ed25519_wasm_1.validateKeyPair)(privateKeyHex, expectedPublicKeyHex); + } + catch (error) { + return false; + } + } +} +exports.Ed25519SignatureVerifier = Ed25519SignatureVerifier; +//# sourceMappingURL=ed25519-verifier.js.map \ No newline at end of file diff --git a/frontend/lib/meshcore-decoder/dist/crypto/ed25519-verifier.js.map b/frontend/lib/meshcore-decoder/dist/crypto/ed25519-verifier.js.map new file mode 100644 index 0000000..5084c9b --- /dev/null +++ b/frontend/lib/meshcore-decoder/dist/crypto/ed25519-verifier.js.map @@ -0,0 +1 @@ +{"version":3,"file":"ed25519-verifier.js","sourceRoot":"","sources":["../../src/crypto/ed25519-verifier.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/frontend/lib/meshcore-decoder/dist/crypto/key-manager.d.ts b/frontend/lib/meshcore-decoder/dist/crypto/key-manager.d.ts new file mode 100644 index 0000000..0790292 --- /dev/null +++ b/frontend/lib/meshcore-decoder/dist/crypto/key-manager.d.ts @@ -0,0 +1,23 @@ +import { CryptoKeyStore } from '../types/crypto'; +export declare class MeshCoreKeyStore implements CryptoKeyStore { + nodeKeys: Map; + private channelHashToKeys; + constructor(initialKeys?: { + channelSecrets?: string[]; + nodeKeys?: Record; + }); + addNodeKey(publicKey: string, privateKey: string): void; + hasChannelKey(channelHash: string): boolean; + hasNodeKey(publicKey: string): boolean; + /** + * Get all channel keys that match the given channel hash (handles collisions) + */ + getChannelKeys(channelHash: string): string[]; + getNodeKey(publicKey: string): string | undefined; + /** + * Add channel keys by secret keys (new simplified API) + * Automatically calculates channel hashes + */ + addChannelSecrets(secretKeys: string[]): void; +} +//# sourceMappingURL=key-manager.d.ts.map \ No newline at end of file diff --git a/frontend/lib/meshcore-decoder/dist/crypto/key-manager.d.ts.map b/frontend/lib/meshcore-decoder/dist/crypto/key-manager.d.ts.map new file mode 100644 index 0000000..577a3ea --- /dev/null +++ b/frontend/lib/meshcore-decoder/dist/crypto/key-manager.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"key-manager.d.ts","sourceRoot":"","sources":["../../src/crypto/key-manager.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAGjD,qBAAa,gBAAiB,YAAW,cAAc;IAC9C,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAa;IAGjD,OAAO,CAAC,iBAAiB,CAA+B;gBAE5C,WAAW,CAAC,EAAE;QACxB,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;QAC1B,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;KACnC;IAYD,UAAU,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,IAAI;IAKvD,aAAa,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO;IAK3C,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO;IAKtC;;OAEG;IACH,cAAc,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,EAAE;IAK7C,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAKjD;;;OAGG;IACH,iBAAiB,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,IAAI;CAW9C"} \ No newline at end of file diff --git a/frontend/lib/meshcore-decoder/dist/crypto/key-manager.js b/frontend/lib/meshcore-decoder/dist/crypto/key-manager.js new file mode 100644 index 0000000..9a434a9 --- /dev/null +++ b/frontend/lib/meshcore-decoder/dist/crypto/key-manager.js @@ -0,0 +1,60 @@ +"use strict"; +// Copyright (c) 2025 Michael Hart: https://github.com/michaelhart/meshcore-decoder +// MIT License +Object.defineProperty(exports, "__esModule", { value: true }); +exports.MeshCoreKeyStore = void 0; +const channel_crypto_1 = require("./channel-crypto"); +class MeshCoreKeyStore { + constructor(initialKeys) { + this.nodeKeys = new Map(); + // internal map for hash -> multiple keys (collision handling) + this.channelHashToKeys = new Map(); + if (initialKeys?.channelSecrets) { + this.addChannelSecrets(initialKeys.channelSecrets); + } + if (initialKeys?.nodeKeys) { + Object.entries(initialKeys.nodeKeys).forEach(([pubKey, privKey]) => { + this.addNodeKey(pubKey, privKey); + }); + } + } + addNodeKey(publicKey, privateKey) { + const normalizedPubKey = publicKey.toUpperCase(); + this.nodeKeys.set(normalizedPubKey, privateKey); + } + hasChannelKey(channelHash) { + const normalizedHash = channelHash.toLowerCase(); + return this.channelHashToKeys.has(normalizedHash); + } + hasNodeKey(publicKey) { + const normalizedPubKey = publicKey.toUpperCase(); + return this.nodeKeys.has(normalizedPubKey); + } + /** + * Get all channel keys that match the given channel hash (handles collisions) + */ + getChannelKeys(channelHash) { + const normalizedHash = channelHash.toLowerCase(); + return this.channelHashToKeys.get(normalizedHash) || []; + } + getNodeKey(publicKey) { + const normalizedPubKey = publicKey.toUpperCase(); + return this.nodeKeys.get(normalizedPubKey); + } + /** + * Add channel keys by secret keys (new simplified API) + * Automatically calculates channel hashes + */ + addChannelSecrets(secretKeys) { + for (const secretKey of secretKeys) { + const channelHash = channel_crypto_1.ChannelCrypto.calculateChannelHash(secretKey).toLowerCase(); + // Handle potential hash collisions + if (!this.channelHashToKeys.has(channelHash)) { + this.channelHashToKeys.set(channelHash, []); + } + this.channelHashToKeys.get(channelHash).push(secretKey); + } + } +} +exports.MeshCoreKeyStore = MeshCoreKeyStore; +//# sourceMappingURL=key-manager.js.map \ No newline at end of file diff --git a/frontend/lib/meshcore-decoder/dist/crypto/key-manager.js.map b/frontend/lib/meshcore-decoder/dist/crypto/key-manager.js.map new file mode 100644 index 0000000..c212f6f --- /dev/null +++ b/frontend/lib/meshcore-decoder/dist/crypto/key-manager.js.map @@ -0,0 +1 @@ +{"version":3,"file":"key-manager.js","sourceRoot":"","sources":["../../src/crypto/key-manager.ts"],"names":[],"mappings":";AAAA,mFAAmF;AACnF,cAAc;;;AAGd,qDAAiD;AAEjD,MAAa,gBAAgB;IAM3B,YAAY,WAGX;QARM,aAAQ,GAAwB,IAAI,GAAG,EAAE,CAAC;QAEjD,8DAA8D;QACtD,sBAAiB,GAAG,IAAI,GAAG,EAAoB,CAAC;QAMtD,IAAI,WAAW,EAAE,cAAc,EAAE,CAAC;YAChC,IAAI,CAAC,iBAAiB,CAAC,WAAW,CAAC,cAAc,CAAC,CAAC;QACrD,CAAC;QAED,IAAI,WAAW,EAAE,QAAQ,EAAE,CAAC;YAC1B,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,EAAE;gBACjE,IAAI,CAAC,UAAU,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;YACnC,CAAC,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,UAAU,CAAC,SAAiB,EAAE,UAAkB;QAC9C,MAAM,gBAAgB,GAAG,SAAS,CAAC,WAAW,EAAE,CAAC;QACjD,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,gBAAgB,EAAE,UAAU,CAAC,CAAC;IAClD,CAAC;IAED,aAAa,CAAC,WAAmB;QAC/B,MAAM,cAAc,GAAG,WAAW,CAAC,WAAW,EAAE,CAAC;QACjD,OAAO,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;IACpD,CAAC;IAED,UAAU,CAAC,SAAiB;QAC1B,MAAM,gBAAgB,GAAG,SAAS,CAAC,WAAW,EAAE,CAAC;QACjD,OAAO,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC;IAC7C,CAAC;IAED;;OAEG;IACH,cAAc,CAAC,WAAmB;QAChC,MAAM,cAAc,GAAG,WAAW,CAAC,WAAW,EAAE,CAAC;QACjD,OAAO,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,cAAc,CAAC,IAAI,EAAE,CAAC;IAC1D,CAAC;IAED,UAAU,CAAC,SAAiB;QAC1B,MAAM,gBAAgB,GAAG,SAAS,CAAC,WAAW,EAAE,CAAC;QACjD,OAAO,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC;IAC7C,CAAC;IAED;;;OAGG;IACH,iBAAiB,CAAC,UAAoB;QACpC,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;YACnC,MAAM,WAAW,GAAG,8BAAa,CAAC,oBAAoB,CAAC,SAAS,CAAC,CAAC,WAAW,EAAE,CAAC;YAEhF,mCAAmC;YACnC,IAAI,CAAC,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC;gBAC7C,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;YAC9C,CAAC;YACD,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,WAAW,CAAE,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QAC3D,CAAC;IACH,CAAC;CACF;AAhED,4CAgEC"} \ No newline at end of file diff --git a/frontend/lib/meshcore-decoder/dist/crypto/orlp-ed25519-wasm.d.ts b/frontend/lib/meshcore-decoder/dist/crypto/orlp-ed25519-wasm.d.ts new file mode 100644 index 0000000..8d845b9 --- /dev/null +++ b/frontend/lib/meshcore-decoder/dist/crypto/orlp-ed25519-wasm.d.ts @@ -0,0 +1,34 @@ +/** + * Derive Ed25519 public key from private key using the exact orlp/ed25519 algorithm + * + * @param privateKeyHex - 64-byte private key in hex format (orlp/ed25519 format) + * @returns 32-byte public key in hex format + */ +export declare function derivePublicKey(privateKeyHex: string): Promise; +/** + * Validate that a private key and public key pair match using orlp/ed25519 + * + * @param privateKeyHex - 64-byte private key in hex format + * @param expectedPublicKeyHex - 32-byte public key in hex format + * @returns true if the keys match, false otherwise + */ +export declare function validateKeyPair(privateKeyHex: string, expectedPublicKeyHex: string): Promise; +/** + * Sign a message using Ed25519 with orlp/ed25519 implementation + * + * @param messageHex - Message to sign in hex format + * @param privateKeyHex - 64-byte private key in hex format (orlp/ed25519 format) + * @param publicKeyHex - 32-byte public key in hex format + * @returns 64-byte signature in hex format + */ +export declare function sign(messageHex: string, privateKeyHex: string, publicKeyHex: string): Promise; +/** + * Verify an Ed25519 signature using orlp/ed25519 implementation + * + * @param signatureHex - 64-byte signature in hex format + * @param messageHex - Message that was signed in hex format + * @param publicKeyHex - 32-byte public key in hex format + * @returns true if signature is valid, false otherwise + */ +export declare function verify(signatureHex: string, messageHex: string, publicKeyHex: string): Promise; +//# sourceMappingURL=orlp-ed25519-wasm.d.ts.map \ No newline at end of file diff --git a/frontend/lib/meshcore-decoder/dist/crypto/orlp-ed25519-wasm.d.ts.map b/frontend/lib/meshcore-decoder/dist/crypto/orlp-ed25519-wasm.d.ts.map new file mode 100644 index 0000000..ef2989b --- /dev/null +++ b/frontend/lib/meshcore-decoder/dist/crypto/orlp-ed25519-wasm.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"orlp-ed25519-wasm.d.ts","sourceRoot":"","sources":["../../src/crypto/orlp-ed25519-wasm.ts"],"names":[],"mappings":"AAgBA;;;;;GAKG;AACH,wBAAsB,eAAe,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAiC5E;AAED;;;;;;GAMG;AACH,wBAAsB,eAAe,CAAC,aAAa,EAAE,MAAM,EAAE,oBAAoB,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAoC3G;AAED;;;;;;;GAOG;AACH,wBAAsB,IAAI,CAAC,UAAU,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAuC3G;AAED;;;;;;;GAOG;AACH,wBAAsB,MAAM,CAAC,YAAY,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAsC7G"} \ No newline at end of file diff --git a/frontend/lib/meshcore-decoder/dist/crypto/orlp-ed25519-wasm.js b/frontend/lib/meshcore-decoder/dist/crypto/orlp-ed25519-wasm.js new file mode 100644 index 0000000..d42ca84 --- /dev/null +++ b/frontend/lib/meshcore-decoder/dist/crypto/orlp-ed25519-wasm.js @@ -0,0 +1,150 @@ +"use strict"; +// WebAssembly wrapper for orlp/ed25519 key derivation +// This provides the exact orlp algorithm for JavaScript +Object.defineProperty(exports, "__esModule", { value: true }); +exports.derivePublicKey = derivePublicKey; +exports.validateKeyPair = validateKeyPair; +exports.sign = sign; +exports.verify = verify; +const hex_1 = require("../utils/hex"); +// Import the generated WASM module +const OrlpEd25519 = require('../../lib/orlp-ed25519.js'); +/** + * Get a fresh WASM instance + * Loads a fresh instance each time because the WASM module could behave unpredictably otherwise + */ +async function getWasmInstance() { + return await OrlpEd25519(); +} +/** + * Derive Ed25519 public key from private key using the exact orlp/ed25519 algorithm + * + * @param privateKeyHex - 64-byte private key in hex format (orlp/ed25519 format) + * @returns 32-byte public key in hex format + */ +async function derivePublicKey(privateKeyHex) { + const wasmModule = await getWasmInstance(); + const privateKeyBytes = (0, hex_1.hexToBytes)(privateKeyHex); + if (privateKeyBytes.length !== 64) { + throw new Error(`Invalid private key length: expected 64 bytes, got ${privateKeyBytes.length}`); + } + // Allocate memory buffers directly in WASM heap + const privateKeyPtr = 1024; // Use fixed memory locations + const publicKeyPtr = 1024 + 64; + // Copy private key to WASM memory + wasmModule.HEAPU8.set(privateKeyBytes, privateKeyPtr); + // Call the orlp key derivation function + const result = wasmModule.ccall('orlp_derive_public_key', 'number', ['number', 'number'], [publicKeyPtr, privateKeyPtr]); + if (result !== 0) { + throw new Error('orlp key derivation failed: invalid private key'); + } + // Read the public key from WASM memory + const publicKeyBytes = new Uint8Array(32); + publicKeyBytes.set(wasmModule.HEAPU8.subarray(publicKeyPtr, publicKeyPtr + 32)); + return (0, hex_1.bytesToHex)(publicKeyBytes); +} +/** + * Validate that a private key and public key pair match using orlp/ed25519 + * + * @param privateKeyHex - 64-byte private key in hex format + * @param expectedPublicKeyHex - 32-byte public key in hex format + * @returns true if the keys match, false otherwise + */ +async function validateKeyPair(privateKeyHex, expectedPublicKeyHex) { + try { + const wasmModule = await getWasmInstance(); + const privateKeyBytes = (0, hex_1.hexToBytes)(privateKeyHex); + const expectedPublicKeyBytes = (0, hex_1.hexToBytes)(expectedPublicKeyHex); + if (privateKeyBytes.length !== 64) { + return false; + } + if (expectedPublicKeyBytes.length !== 32) { + return false; + } + // Allocate memory buffers directly in WASM heap + const privateKeyPtr = 2048; // Use different fixed memory locations + const publicKeyPtr = 2048 + 64; + // Copy keys to WASM memory + wasmModule.HEAPU8.set(privateKeyBytes, privateKeyPtr); + wasmModule.HEAPU8.set(expectedPublicKeyBytes, publicKeyPtr); + // Call the validation function (note: C function expects public_key first, then private_key) + const result = wasmModule.ccall('orlp_validate_keypair', 'number', ['number', 'number'], [publicKeyPtr, privateKeyPtr]); + return result === 1; + } + catch (error) { + // Invalid hex strings or other errors should return false + return false; + } +} +/** + * Sign a message using Ed25519 with orlp/ed25519 implementation + * + * @param messageHex - Message to sign in hex format + * @param privateKeyHex - 64-byte private key in hex format (orlp/ed25519 format) + * @param publicKeyHex - 32-byte public key in hex format + * @returns 64-byte signature in hex format + */ +async function sign(messageHex, privateKeyHex, publicKeyHex) { + const wasmModule = await getWasmInstance(); + const messageBytes = (0, hex_1.hexToBytes)(messageHex); + const privateKeyBytes = (0, hex_1.hexToBytes)(privateKeyHex); + const publicKeyBytes = (0, hex_1.hexToBytes)(publicKeyHex); + if (privateKeyBytes.length !== 64) { + throw new Error(`Invalid private key length: expected 64 bytes, got ${privateKeyBytes.length}`); + } + if (publicKeyBytes.length !== 32) { + throw new Error(`Invalid public key length: expected 32 bytes, got ${publicKeyBytes.length}`); + } + // Allocate memory buffers with large gaps to avoid conflicts with scratch space + const messagePtr = 100000; + const privateKeyPtr = 200000; + const publicKeyPtr = 300000; + const signaturePtr = 400000; + // Copy data to WASM memory + wasmModule.HEAPU8.set(messageBytes, messagePtr); + wasmModule.HEAPU8.set(privateKeyBytes, privateKeyPtr); + wasmModule.HEAPU8.set(publicKeyBytes, publicKeyPtr); + // Call orlp_sign + wasmModule.ccall('orlp_sign', 'void', ['number', 'number', 'number', 'number', 'number'], [signaturePtr, messagePtr, messageBytes.length, publicKeyPtr, privateKeyPtr]); + // Read signature + const signatureBytes = new Uint8Array(64); + signatureBytes.set(wasmModule.HEAPU8.subarray(signaturePtr, signaturePtr + 64)); + return (0, hex_1.bytesToHex)(signatureBytes); +} +/** + * Verify an Ed25519 signature using orlp/ed25519 implementation + * + * @param signatureHex - 64-byte signature in hex format + * @param messageHex - Message that was signed in hex format + * @param publicKeyHex - 32-byte public key in hex format + * @returns true if signature is valid, false otherwise + */ +async function verify(signatureHex, messageHex, publicKeyHex) { + try { + const wasmModule = await getWasmInstance(); + const signatureBytes = (0, hex_1.hexToBytes)(signatureHex); + const messageBytes = (0, hex_1.hexToBytes)(messageHex); + const publicKeyBytes = (0, hex_1.hexToBytes)(publicKeyHex); + if (signatureBytes.length !== 64) { + return false; + } + if (publicKeyBytes.length !== 32) { + return false; + } + // Allocate memory buffers with large gaps to avoid conflicts with scratch space + const messagePtr = 500000; + const signaturePtr = 600000; + const publicKeyPtr = 700000; + // Copy data to WASM memory + wasmModule.HEAPU8.set(signatureBytes, signaturePtr); + wasmModule.HEAPU8.set(messageBytes, messagePtr); + wasmModule.HEAPU8.set(publicKeyBytes, publicKeyPtr); + // Call the orlp verify function + const result = wasmModule.ccall('orlp_verify', 'number', ['number', 'number', 'number', 'number'], [signaturePtr, messagePtr, messageBytes.length, publicKeyPtr]); + return result === 1; + } + catch (error) { + return false; + } +} +//# sourceMappingURL=orlp-ed25519-wasm.js.map \ No newline at end of file diff --git a/frontend/lib/meshcore-decoder/dist/crypto/orlp-ed25519-wasm.js.map b/frontend/lib/meshcore-decoder/dist/crypto/orlp-ed25519-wasm.js.map new file mode 100644 index 0000000..989d822 --- /dev/null +++ b/frontend/lib/meshcore-decoder/dist/crypto/orlp-ed25519-wasm.js.map @@ -0,0 +1 @@ +{"version":3,"file":"orlp-ed25519-wasm.js","sourceRoot":"","sources":["../../src/crypto/orlp-ed25519-wasm.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/frontend/lib/meshcore-decoder/dist/decoder/packet-decoder.d.ts b/frontend/lib/meshcore-decoder/dist/decoder/packet-decoder.d.ts new file mode 100644 index 0000000..b64a53b --- /dev/null +++ b/frontend/lib/meshcore-decoder/dist/decoder/packet-decoder.d.ts @@ -0,0 +1,51 @@ +import { DecodedPacket, PacketStructure } from '../types/packet'; +import { DecryptionOptions, ValidationResult, CryptoKeyStore } from '../types/crypto'; +export declare class MeshCorePacketDecoder { + /** + * Decode a raw packet from hex string + */ + static decode(hexData: string, options?: DecryptionOptions): DecodedPacket; + /** + * Decode a raw packet from hex string with signature verification for advertisements + */ + static decodeWithVerification(hexData: string, options?: DecryptionOptions): Promise; + /** + * Analyze packet structure for detailed breakdown + */ + static analyzeStructure(hexData: string, options?: DecryptionOptions): PacketStructure; + /** + * Analyze packet structure for detailed breakdown with signature verification for advertisements + */ + static analyzeStructureWithVerification(hexData: string, options?: DecryptionOptions): Promise; + /** + * Internal unified parsing method + */ + private static parseInternal; + /** + * Internal unified parsing method with signature verification for advertisements + */ + private static parseInternalAsync; + /** + * Validate packet format without full decoding + */ + static validate(hexData: string): ValidationResult; + /** + * Calculate message hash for a packet + */ + static calculateMessageHash(bytes: Uint8Array, routeType: number, payloadType: number, payloadVersion: number): string; + /** + * Create a key store for decryption + */ + static createKeyStore(initialKeys?: { + channelSecrets?: string[]; + nodeKeys?: Record; + }): CryptoKeyStore; + /** + * Decode a path_len byte into hash size, hop count, and total byte length. + * Firmware reference: Packet.h lines 79-83 + * Bits 7:6 = hash size selector: (path_len >> 6) + 1 = 1, 2, or 3 bytes per hop + * Bits 5:0 = hop count (0-63) + */ + private static decodePathLenByte; +} +//# sourceMappingURL=packet-decoder.d.ts.map \ No newline at end of file diff --git a/frontend/lib/meshcore-decoder/dist/decoder/packet-decoder.d.ts.map b/frontend/lib/meshcore-decoder/dist/decoder/packet-decoder.d.ts.map new file mode 100644 index 0000000..873cb5a --- /dev/null +++ b/frontend/lib/meshcore-decoder/dist/decoder/packet-decoder.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"packet-decoder.d.ts","sourceRoot":"","sources":["../../src/decoder/packet-decoder.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,aAAa,EAAE,eAAe,EAAkD,MAAM,iBAAiB,CAAC;AAIjH,OAAO,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAatF,qBAAa,qBAAqB;IAChC;;OAEG;IACH,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,iBAAiB,GAAG,aAAa;IAK1E;;OAEG;WACU,sBAAsB,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,iBAAiB,GAAG,OAAO,CAAC,aAAa,CAAC;IAKzG;;OAEG;IACH,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,iBAAiB,GAAG,eAAe;IAKtF;;OAEG;WACU,gCAAgC,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,iBAAiB,GAAG,OAAO,CAAC,eAAe,CAAC;IAKrH;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,aAAa;IA6Y5B;;OAEG;mBACkB,kBAAkB;IA2CvC;;OAEG;IACH,MAAM,CAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,gBAAgB;IAmDlD;;OAEG;IACH,MAAM,CAAC,oBAAoB,CAAC,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,GAAG,MAAM;IAkDtH;;OAEG;IACH,MAAM,CAAC,cAAc,CAAC,WAAW,CAAC,EAAE;QAClC,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;QAC1B,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;KACnC,GAAG,cAAc;IAIlB;;;;;OAKG;IACH,OAAO,CAAC,MAAM,CAAC,iBAAiB;CAMjC"} \ No newline at end of file diff --git a/frontend/lib/meshcore-decoder/dist/decoder/packet-decoder.js b/frontend/lib/meshcore-decoder/dist/decoder/packet-decoder.js new file mode 100644 index 0000000..c7f8763 --- /dev/null +++ b/frontend/lib/meshcore-decoder/dist/decoder/packet-decoder.js @@ -0,0 +1,576 @@ +"use strict"; +// Copyright (c) 2025 Michael Hart: https://github.com/michaelhart/meshcore-decoder +// MIT License +Object.defineProperty(exports, "__esModule", { value: true }); +exports.MeshCorePacketDecoder = void 0; +const enums_1 = require("../types/enums"); +const hex_1 = require("../utils/hex"); +const enum_names_1 = require("../utils/enum-names"); +const key_manager_1 = require("../crypto/key-manager"); +const advert_1 = require("./payload-decoders/advert"); +const trace_1 = require("./payload-decoders/trace"); +const group_text_1 = require("./payload-decoders/group-text"); +const request_1 = require("./payload-decoders/request"); +const response_1 = require("./payload-decoders/response"); +const anon_request_1 = require("./payload-decoders/anon-request"); +const ack_1 = require("./payload-decoders/ack"); +const path_1 = require("./payload-decoders/path"); +const text_message_1 = require("./payload-decoders/text-message"); +const control_1 = require("./payload-decoders/control"); +class MeshCorePacketDecoder { + /** + * Decode a raw packet from hex string + */ + static decode(hexData, options) { + const result = this.parseInternal(hexData, false, options); + return result.packet; + } + /** + * Decode a raw packet from hex string with signature verification for advertisements + */ + static async decodeWithVerification(hexData, options) { + const result = await this.parseInternalAsync(hexData, false, options); + return result.packet; + } + /** + * Analyze packet structure for detailed breakdown + */ + static analyzeStructure(hexData, options) { + const result = this.parseInternal(hexData, true, options); + return result.structure; + } + /** + * Analyze packet structure for detailed breakdown with signature verification for advertisements + */ + static async analyzeStructureWithVerification(hexData, options) { + const result = await this.parseInternalAsync(hexData, true, options); + return result.structure; + } + /** + * Internal unified parsing method + */ + static parseInternal(hexData, includeStructure, options) { + const bytes = (0, hex_1.hexToBytes)(hexData); + const segments = []; + if (bytes.length < 2) { + const errorPacket = { + messageHash: '', + routeType: enums_1.RouteType.Flood, + payloadType: enums_1.PayloadType.RawCustom, + payloadVersion: enums_1.PayloadVersion.Version1, + pathLength: 0, + path: null, + payload: { raw: '', decoded: null }, + totalBytes: bytes.length, + isValid: false, + errors: ['Packet too short (minimum 2 bytes required)'] + }; + const errorStructure = { + segments: [], + totalBytes: bytes.length, + rawHex: hexData.toUpperCase(), + messageHash: '', + payload: { + segments: [], + hex: '', + startByte: 0, + type: 'Unknown' + } + }; + return { packet: errorPacket, structure: errorStructure }; + } + try { + let offset = 0; + // parse header + const header = bytes[0]; + const routeType = header & 0x03; + const payloadType = (header >> 2) & 0x0F; + const payloadVersion = (header >> 6) & 0x03; + if (includeStructure) { + segments.push({ + name: 'Header', + description: 'Header byte breakdown', + startByte: 0, + endByte: 0, + value: `0x${header.toString(16).padStart(2, '0')}`, + headerBreakdown: { + fullBinary: header.toString(2).padStart(8, '0'), + fields: [ + { + bits: '0-1', + field: 'Route Type', + value: (0, enum_names_1.getRouteTypeName)(routeType), + binary: (header & 0x03).toString(2).padStart(2, '0') + }, + { + bits: '2-5', + field: 'Payload Type', + value: (0, enum_names_1.getPayloadTypeName)(payloadType), + binary: ((header >> 2) & 0x0F).toString(2).padStart(4, '0') + }, + { + bits: '6-7', + field: 'Version', + value: payloadVersion.toString(), + binary: ((header >> 6) & 0x03).toString(2).padStart(2, '0') + } + ] + } + }); + } + offset = 1; + // handle transport codes + let transportCodes; + if (routeType === enums_1.RouteType.TransportFlood || routeType === enums_1.RouteType.TransportDirect) { + if (bytes.length < offset + 4) { + throw new Error('Packet too short for transport codes'); + } + const code1 = bytes[offset] | (bytes[offset + 1] << 8); + const code2 = bytes[offset + 2] | (bytes[offset + 3] << 8); + transportCodes = [code1, code2]; + if (includeStructure) { + const transportCode = (bytes[offset]) | (bytes[offset + 1] << 8) | (bytes[offset + 2] << 16) | (bytes[offset + 3] << 24); + segments.push({ + name: 'Transport Code', + description: 'Used for Direct/Response routing', + startByte: offset, + endByte: offset + 3, + value: `0x${transportCode.toString(16).padStart(8, '0')}` + }); + } + offset += 4; + } + // parse path length byte (encodes hash size and hop count) + // Bits 7:6 = hash size selector: (path_len >> 6) + 1 = 1, 2, or 3 bytes per hop + // Bits 5:0 = hop count (0-63) + if (bytes.length < offset + 1) { + throw new Error('Packet too short for path length'); + } + const pathLenByte = bytes[offset]; + const { hashSize: pathHashSize, hopCount: pathHopCount, byteLength: pathByteLength } = this.decodePathLenByte(pathLenByte); + if (pathHashSize === 4) { + throw new Error('Invalid path length byte: reserved hash size (bits 7:6 = 11)'); + } + if (includeStructure) { + const hashDesc = pathHashSize > 1 ? ` × ${pathHashSize}-byte hashes (${pathByteLength} bytes)` : ''; + let pathLengthDescription; + if (pathHopCount === 0) { + pathLengthDescription = pathHashSize > 1 ? `No path data (${pathHashSize}-byte hash mode)` : 'No path data'; + } + else if (routeType === enums_1.RouteType.Direct || routeType === enums_1.RouteType.TransportDirect) { + pathLengthDescription = `${pathHopCount} hops${hashDesc} of routing instructions (decreases as packet travels)`; + } + else if (routeType === enums_1.RouteType.Flood || routeType === enums_1.RouteType.TransportFlood) { + pathLengthDescription = `${pathHopCount} hops${hashDesc} showing route taken (increases as packet floods)`; + } + else { + pathLengthDescription = `Path contains ${pathHopCount} hops${hashDesc}`; + } + segments.push({ + name: 'Path Length', + description: pathLengthDescription, + startByte: offset, + endByte: offset, + value: `0x${pathLenByte.toString(16).padStart(2, '0')}`, + headerBreakdown: { + fullBinary: pathLenByte.toString(2).padStart(8, '0'), + fields: [ + { + bits: '6-7', + field: 'Hash Size', + value: `${pathHashSize} byte${pathHashSize > 1 ? 's' : ''} per hop`, + binary: ((pathLenByte >> 6) & 0x03).toString(2).padStart(2, '0') + }, + { + bits: '0-5', + field: 'Hop Count', + value: `${pathHopCount} hop${pathHopCount !== 1 ? 's' : ''}`, + binary: (pathLenByte & 63).toString(2).padStart(6, '0') + } + ] + } + }); + } + offset += 1; + if (bytes.length < offset + pathByteLength) { + throw new Error('Packet too short for path data'); + } + // convert path data to grouped hex strings (one entry per hop) + const pathBytes = bytes.subarray(offset, offset + pathByteLength); + let path = null; + if (pathHopCount > 0) { + path = []; + for (let i = 0; i < pathHopCount; i++) { + const hopBytes = pathBytes.subarray(i * pathHashSize, (i + 1) * pathHashSize); + path.push((0, hex_1.bytesToHex)(hopBytes)); + } + } + if (includeStructure && pathHopCount > 0) { + if (payloadType === enums_1.PayloadType.Trace) { + // TRACE packets have SNR values in path (always single-byte entries) + const snrValues = []; + for (let i = 0; i < pathByteLength; i++) { + const snrRaw = bytes[offset + i]; + const snrSigned = snrRaw > 127 ? snrRaw - 256 : snrRaw; + const snrDb = snrSigned / 4.0; + snrValues.push(`${snrDb.toFixed(2)}dB (0x${snrRaw.toString(16).padStart(2, '0')})`); + } + segments.push({ + name: 'Path SNR Data', + description: `SNR values collected during trace: ${snrValues.join(', ')}`, + startByte: offset, + endByte: offset + pathByteLength - 1, + value: (0, hex_1.bytesToHex)(bytes.slice(offset, offset + pathByteLength)) + }); + } + else { + let pathDescription = 'Routing path information'; + if (routeType === enums_1.RouteType.Direct || routeType === enums_1.RouteType.TransportDirect) { + pathDescription = `Routing instructions (${pathHashSize}-byte hashes stripped at each hop as packet travels to destination)`; + } + else if (routeType === enums_1.RouteType.Flood || routeType === enums_1.RouteType.TransportFlood) { + pathDescription = `Historical route taken (${pathHashSize}-byte hashes added as packet floods through network)`; + } + segments.push({ + name: 'Path Data', + description: pathDescription, + startByte: offset, + endByte: offset + pathByteLength - 1, + value: (0, hex_1.bytesToHex)(bytes.slice(offset, offset + pathByteLength)) + }); + } + } + offset += pathByteLength; + // extract payload + const payloadBytes = bytes.subarray(offset); + const payloadHex = (0, hex_1.bytesToHex)(payloadBytes); + if (includeStructure && bytes.length > offset) { + segments.push({ + name: 'Payload', + description: `${(0, enum_names_1.getPayloadTypeName)(payloadType)} payload data`, + startByte: offset, + endByte: bytes.length - 1, + value: (0, hex_1.bytesToHex)(bytes.slice(offset)) + }); + } + // decode payload based on type and optionally get segments in one pass + let decodedPayload = null; + const payloadSegments = []; + if (payloadType === enums_1.PayloadType.Advert) { + const result = advert_1.AdvertPayloadDecoder.decode(payloadBytes, { + includeSegments: includeStructure, + segmentOffset: 0 + }); + decodedPayload = result; + if (result?.segments) { + payloadSegments.push(...result.segments); + delete result.segments; + } + } + else if (payloadType === enums_1.PayloadType.Trace) { + const result = trace_1.TracePayloadDecoder.decode(payloadBytes, path, { + includeSegments: includeStructure, + segmentOffset: 0 // Payload segments are relative to payload start + }); + decodedPayload = result; + if (result?.segments) { + payloadSegments.push(...result.segments); + delete result.segments; // Remove from decoded payload to keep it clean + } + } + else if (payloadType === enums_1.PayloadType.GroupText) { + const result = group_text_1.GroupTextPayloadDecoder.decode(payloadBytes, { + ...options, + includeSegments: includeStructure, + segmentOffset: 0 + }); + decodedPayload = result; + if (result?.segments) { + payloadSegments.push(...result.segments); + delete result.segments; + } + } + else if (payloadType === enums_1.PayloadType.Request) { + const result = request_1.RequestPayloadDecoder.decode(payloadBytes, { + includeSegments: includeStructure, + segmentOffset: 0 // Payload segments are relative to payload start + }); + decodedPayload = result; + if (result?.segments) { + payloadSegments.push(...result.segments); + delete result.segments; + } + } + else if (payloadType === enums_1.PayloadType.Response) { + const result = response_1.ResponsePayloadDecoder.decode(payloadBytes, { + includeSegments: includeStructure, + segmentOffset: 0 // Payload segments are relative to payload start + }); + decodedPayload = result; + if (result?.segments) { + payloadSegments.push(...result.segments); + delete result.segments; + } + } + else if (payloadType === enums_1.PayloadType.AnonRequest) { + const result = anon_request_1.AnonRequestPayloadDecoder.decode(payloadBytes, { + includeSegments: includeStructure, + segmentOffset: 0 + }); + decodedPayload = result; + if (result?.segments) { + payloadSegments.push(...result.segments); + delete result.segments; + } + } + else if (payloadType === enums_1.PayloadType.Ack) { + const result = ack_1.AckPayloadDecoder.decode(payloadBytes, { + includeSegments: includeStructure, + segmentOffset: 0 + }); + decodedPayload = result; + if (result?.segments) { + payloadSegments.push(...result.segments); + delete result.segments; + } + } + else if (payloadType === enums_1.PayloadType.Path) { + decodedPayload = path_1.PathPayloadDecoder.decode(payloadBytes); + } + else if (payloadType === enums_1.PayloadType.TextMessage) { + const result = text_message_1.TextMessagePayloadDecoder.decode(payloadBytes, { + includeSegments: includeStructure, + segmentOffset: 0 + }); + decodedPayload = result; + if (result?.segments) { + payloadSegments.push(...result.segments); + delete result.segments; + } + } + else if (payloadType === enums_1.PayloadType.Control) { + const result = control_1.ControlPayloadDecoder.decode(payloadBytes, { + includeSegments: includeStructure, + segmentOffset: 0 + }); + decodedPayload = result; + if (result?.segments) { + payloadSegments.push(...result.segments); + delete result.segments; + } + } + // if no segments were generated and we need structure, show basic payload info + if (includeStructure && payloadSegments.length === 0 && bytes.length > offset) { + payloadSegments.push({ + name: `${(0, enum_names_1.getPayloadTypeName)(payloadType)} Payload`, + description: `Raw ${(0, enum_names_1.getPayloadTypeName)(payloadType)} payload data (${payloadBytes.length} bytes)`, + startByte: 0, + endByte: payloadBytes.length - 1, + value: (0, hex_1.bytesToHex)(payloadBytes) + }); + } + // calculate message hash + const messageHash = this.calculateMessageHash(bytes, routeType, payloadType, payloadVersion); + const packet = { + messageHash, + routeType, + payloadType, + payloadVersion, + transportCodes, + pathLength: pathHopCount, + ...(pathHashSize > 1 ? { pathHashSize } : {}), + path, + payload: { + raw: payloadHex, + decoded: decodedPayload + }, + totalBytes: bytes.length, + isValid: true + }; + const structure = { + segments, + totalBytes: bytes.length, + rawHex: hexData.toUpperCase(), + messageHash, + payload: { + segments: payloadSegments, + hex: payloadHex, + startByte: offset, + type: (0, enum_names_1.getPayloadTypeName)(payloadType) + } + }; + return { packet, structure }; + } + catch (error) { + const errorPacket = { + messageHash: '', + routeType: enums_1.RouteType.Flood, + payloadType: enums_1.PayloadType.RawCustom, + payloadVersion: enums_1.PayloadVersion.Version1, + pathLength: 0, + path: null, + payload: { raw: '', decoded: null }, + totalBytes: bytes.length, + isValid: false, + errors: [error instanceof Error ? error.message : 'Unknown decoding error'] + }; + const errorStructure = { + segments: [], + totalBytes: bytes.length, + rawHex: hexData.toUpperCase(), + messageHash: '', + payload: { + segments: [], + hex: '', + startByte: 0, + type: 'Unknown' + } + }; + return { packet: errorPacket, structure: errorStructure }; + } + } + /** + * Internal unified parsing method with signature verification for advertisements + */ + static async parseInternalAsync(hexData, includeStructure, options) { + // First do the regular parsing + const result = this.parseInternal(hexData, includeStructure, options); + // If it's an advertisement, verify the signature + if (result.packet.payloadType === enums_1.PayloadType.Advert && result.packet.payload.decoded) { + try { + const advertPayload = result.packet.payload.decoded; + const verifiedAdvert = await advert_1.AdvertPayloadDecoder.decodeWithVerification((0, hex_1.hexToBytes)(result.packet.payload.raw), { + includeSegments: includeStructure, + segmentOffset: 0 + }); + if (verifiedAdvert) { + // Update the payload with signature verification results + result.packet.payload.decoded = verifiedAdvert; + // If the advertisement signature is invalid, mark the whole packet as invalid + if (!verifiedAdvert.isValid) { + result.packet.isValid = false; + result.packet.errors = verifiedAdvert.errors || ['Invalid advertisement signature']; + } + // Update structure segments if needed + if (includeStructure && verifiedAdvert.segments) { + result.structure.payload.segments = verifiedAdvert.segments; + delete verifiedAdvert.segments; + } + } + } + catch (error) { + console.error('Signature verification failed:', error); + } + } + return result; + } + /** + * Validate packet format without full decoding + */ + static validate(hexData) { + const bytes = (0, hex_1.hexToBytes)(hexData); + const errors = []; + if (bytes.length < 2) { + errors.push('Packet too short (minimum 2 bytes required)'); + return { isValid: false, errors }; + } + try { + let offset = 1; // Skip header + // check transport codes + const header = bytes[0]; + const routeType = header & 0x03; + if (routeType === enums_1.RouteType.TransportFlood || routeType === enums_1.RouteType.TransportDirect) { + if (bytes.length < offset + 4) { + errors.push('Packet too short for transport codes'); + } + offset += 4; + } + // check path length + if (bytes.length < offset + 1) { + errors.push('Packet too short for path length'); + } + else { + const pathLenByte = bytes[offset]; + const { hashSize, byteLength } = this.decodePathLenByte(pathLenByte); + offset += 1; + if (hashSize === 4) { + errors.push('Invalid path length byte: reserved hash size (bits 7:6 = 11)'); + } + if (bytes.length < offset + byteLength) { + errors.push('Packet too short for path data'); + } + offset += byteLength; + } + // check if we have payload data + if (offset >= bytes.length) { + errors.push('No payload data found'); + } + } + catch (error) { + errors.push(error instanceof Error ? error.message : 'Validation error'); + } + return { isValid: errors.length === 0, errors: errors.length > 0 ? errors : undefined }; + } + /** + * Calculate message hash for a packet + */ + static calculateMessageHash(bytes, routeType, payloadType, payloadVersion) { + // for TRACE packets, use the trace tag as hash + if (payloadType === enums_1.PayloadType.Trace && bytes.length >= 13) { + let offset = 1; + // skip transport codes if present + if (routeType === enums_1.RouteType.TransportFlood || routeType === enums_1.RouteType.TransportDirect) { + offset += 4; + } + // skip path data (decode path_len byte for multi-byte hops) + if (bytes.length > offset) { + const { byteLength } = this.decodePathLenByte(bytes[offset]); + offset += 1 + byteLength; + } + // extract trace tag + if (bytes.length >= offset + 4) { + const traceTag = (bytes[offset]) | (bytes[offset + 1] << 8) | (bytes[offset + 2] << 16) | (bytes[offset + 3] << 24); + return (0, hex_1.numberToHex)(traceTag, 8); + } + } + // for other packets, create hash from constant parts + const constantHeader = (payloadType << 2) | (payloadVersion << 6); + let offset = 1; + // skip transport codes if present + if (routeType === enums_1.RouteType.TransportFlood || routeType === enums_1.RouteType.TransportDirect) { + offset += 4; + } + // skip path data (decode path_len byte for multi-byte hops) + if (bytes.length > offset) { + const { byteLength } = this.decodePathLenByte(bytes[offset]); + offset += 1 + byteLength; + } + const payloadData = bytes.slice(offset); + const hashInput = [constantHeader, ...Array.from(payloadData)]; + // generate hash + let hash = 0; + for (let i = 0; i < hashInput.length; i++) { + hash = ((hash << 5) - hash + hashInput[i]) & 0xffffffff; + } + return (0, hex_1.numberToHex)(hash, 8); + } + /** + * Create a key store for decryption + */ + static createKeyStore(initialKeys) { + return new key_manager_1.MeshCoreKeyStore(initialKeys); + } + /** + * Decode a path_len byte into hash size, hop count, and total byte length. + * Firmware reference: Packet.h lines 79-83 + * Bits 7:6 = hash size selector: (path_len >> 6) + 1 = 1, 2, or 3 bytes per hop + * Bits 5:0 = hop count (0-63) + */ + static decodePathLenByte(pathLenByte) { + const hashSize = (pathLenByte >> 6) + 1; + const hopCount = pathLenByte & 63; + return { hashSize, hopCount, byteLength: hopCount * hashSize }; + } +} +exports.MeshCorePacketDecoder = MeshCorePacketDecoder; +//# sourceMappingURL=packet-decoder.js.map \ No newline at end of file diff --git a/frontend/lib/meshcore-decoder/dist/decoder/packet-decoder.js.map b/frontend/lib/meshcore-decoder/dist/decoder/packet-decoder.js.map new file mode 100644 index 0000000..04727a1 --- /dev/null +++ b/frontend/lib/meshcore-decoder/dist/decoder/packet-decoder.js.map @@ -0,0 +1 @@ +{"version":3,"file":"packet-decoder.js","sourceRoot":"","sources":["../../src/decoder/packet-decoder.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/ack.d.ts b/frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/ack.d.ts new file mode 100644 index 0000000..0551ae8 --- /dev/null +++ b/frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/ack.d.ts @@ -0,0 +1,11 @@ +import { AckPayload } from '../../types/payloads'; +import { PayloadSegment } from '../../types/packet'; +export declare class AckPayloadDecoder { + static decode(payload: Uint8Array, options?: { + includeSegments?: boolean; + segmentOffset?: number; + }): AckPayload & { + segments?: PayloadSegment[]; + } | null; +} +//# sourceMappingURL=ack.d.ts.map \ No newline at end of file diff --git a/frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/ack.d.ts.map b/frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/ack.d.ts.map new file mode 100644 index 0000000..11f95b4 --- /dev/null +++ b/frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/ack.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"ack.d.ts","sourceRoot":"","sources":["../../../src/decoder/payload-decoders/ack.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAClD,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAIpD,qBAAa,iBAAiB;IAC5B,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,UAAU,EAAE,OAAO,CAAC,EAAE;QAAE,eAAe,CAAC,EAAE,OAAO,CAAC;QAAC,aAAa,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,UAAU,GAAG;QAAE,QAAQ,CAAC,EAAE,cAAc,EAAE,CAAA;KAAE,GAAG,IAAI;CA2EzJ"} \ No newline at end of file diff --git a/frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/ack.js b/frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/ack.js new file mode 100644 index 0000000..ec95ead --- /dev/null +++ b/frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/ack.js @@ -0,0 +1,78 @@ +"use strict"; +// Copyright (c) 2025 Michael Hart: https://github.com/michaelhart/meshcore-decoder +// MIT License +Object.defineProperty(exports, "__esModule", { value: true }); +exports.AckPayloadDecoder = void 0; +const enums_1 = require("../../types/enums"); +const hex_1 = require("../../utils/hex"); +class AckPayloadDecoder { + static decode(payload, options) { + try { + // Based on MeshCore payloads.md - Ack payload structure: + // - checksum (4 bytes) - CRC checksum of message timestamp, text, and sender pubkey + if (payload.length < 4) { + const result = { + type: enums_1.PayloadType.Ack, + version: enums_1.PayloadVersion.Version1, + isValid: false, + errors: ['Ack payload too short (minimum 4 bytes for checksum)'], + checksum: '' + }; + if (options?.includeSegments) { + result.segments = [{ + name: 'Invalid Ack Data', + description: 'Ack payload too short (minimum 4 bytes required for checksum)', + startByte: options.segmentOffset || 0, + endByte: (options.segmentOffset || 0) + payload.length - 1, + value: (0, hex_1.bytesToHex)(payload) + }]; + } + return result; + } + const segments = []; + const segmentOffset = options?.segmentOffset || 0; + // parse checksum (4 bytes as hex) + const checksum = (0, hex_1.bytesToHex)(payload.subarray(0, 4)); + if (options?.includeSegments) { + segments.push({ + name: 'Checksum', + description: `CRC checksum of message timestamp, text, and sender pubkey: 0x${checksum}`, + startByte: segmentOffset, + endByte: segmentOffset + 3, + value: checksum + }); + } + // any additional data (if present) + if (options?.includeSegments && payload.length > 4) { + segments.push({ + name: 'Additional Data', + description: 'Extra data in Ack payload', + startByte: segmentOffset + 4, + endByte: segmentOffset + payload.length - 1, + value: (0, hex_1.bytesToHex)(payload.subarray(4)) + }); + } + const result = { + type: enums_1.PayloadType.Ack, + version: enums_1.PayloadVersion.Version1, + isValid: true, + checksum + }; + if (options?.includeSegments) { + result.segments = segments; + } + return result; + } + catch (error) { + return { + type: enums_1.PayloadType.Ack, + version: enums_1.PayloadVersion.Version1, + isValid: false, + errors: [error instanceof Error ? error.message : 'Failed to decode Ack payload'], + checksum: '' + }; + } + } +} +exports.AckPayloadDecoder = AckPayloadDecoder; +//# sourceMappingURL=ack.js.map \ No newline at end of file diff --git a/frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/ack.js.map b/frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/ack.js.map new file mode 100644 index 0000000..1f1a055 --- /dev/null +++ b/frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/ack.js.map @@ -0,0 +1 @@ +{"version":3,"file":"ack.js","sourceRoot":"","sources":["../../../src/decoder/payload-decoders/ack.ts"],"names":[],"mappings":";AAAA,mFAAmF;AACnF,cAAc;;;AAId,6CAAgE;AAChE,yCAA6C;AAE7C,MAAa,iBAAiB;IAC5B,MAAM,CAAC,MAAM,CAAC,OAAmB,EAAE,OAA+D;QAChG,IAAI,CAAC;YACH,yDAAyD;YACzD,oFAAoF;YAEpF,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACvB,MAAM,MAAM,GAAiD;oBAC3D,IAAI,EAAE,mBAAW,CAAC,GAAG;oBACrB,OAAO,EAAE,sBAAc,CAAC,QAAQ;oBAChC,OAAO,EAAE,KAAK;oBACd,MAAM,EAAE,CAAC,sDAAsD,CAAC;oBAChE,QAAQ,EAAE,EAAE;iBACb,CAAC;gBAEF,IAAI,OAAO,EAAE,eAAe,EAAE,CAAC;oBAC7B,MAAM,CAAC,QAAQ,GAAG,CAAC;4BACjB,IAAI,EAAE,kBAAkB;4BACxB,WAAW,EAAE,+DAA+D;4BAC5E,SAAS,EAAE,OAAO,CAAC,aAAa,IAAI,CAAC;4BACrC,OAAO,EAAE,CAAC,OAAO,CAAC,aAAa,IAAI,CAAC,CAAC,GAAG,OAAO,CAAC,MAAM,GAAG,CAAC;4BAC1D,KAAK,EAAE,IAAA,gBAAU,EAAC,OAAO,CAAC;yBAC3B,CAAC,CAAC;gBACL,CAAC;gBAED,OAAO,MAAM,CAAC;YAChB,CAAC;YAED,MAAM,QAAQ,GAAqB,EAAE,CAAC;YACtC,MAAM,aAAa,GAAG,OAAO,EAAE,aAAa,IAAI,CAAC,CAAC;YAElD,kCAAkC;YAClC,MAAM,QAAQ,GAAG,IAAA,gBAAU,EAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;YACpD,IAAI,OAAO,EAAE,eAAe,EAAE,CAAC;gBAC7B,QAAQ,CAAC,IAAI,CAAC;oBACZ,IAAI,EAAE,UAAU;oBAChB,WAAW,EAAE,iEAAiE,QAAQ,EAAE;oBACxF,SAAS,EAAE,aAAa;oBACxB,OAAO,EAAE,aAAa,GAAG,CAAC;oBAC1B,KAAK,EAAE,QAAQ;iBAChB,CAAC,CAAC;YACL,CAAC;YAED,mCAAmC;YACnC,IAAI,OAAO,EAAE,eAAe,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACnD,QAAQ,CAAC,IAAI,CAAC;oBACZ,IAAI,EAAE,iBAAiB;oBACvB,WAAW,EAAE,2BAA2B;oBACxC,SAAS,EAAE,aAAa,GAAG,CAAC;oBAC5B,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,MAAM,GAAG,CAAC;oBAC3C,KAAK,EAAE,IAAA,gBAAU,EAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;iBACvC,CAAC,CAAC;YACL,CAAC;YAED,MAAM,MAAM,GAAiD;gBAC3D,IAAI,EAAE,mBAAW,CAAC,GAAG;gBACrB,OAAO,EAAE,sBAAc,CAAC,QAAQ;gBAChC,OAAO,EAAE,IAAI;gBACb,QAAQ;aACT,CAAC;YAEF,IAAI,OAAO,EAAE,eAAe,EAAE,CAAC;gBAC7B,MAAM,CAAC,QAAQ,GAAG,QAAQ,CAAC;YAC7B,CAAC;YAED,OAAO,MAAM,CAAC;QAChB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO;gBACL,IAAI,EAAE,mBAAW,CAAC,GAAG;gBACrB,OAAO,EAAE,sBAAc,CAAC,QAAQ;gBAChC,OAAO,EAAE,KAAK;gBACd,MAAM,EAAE,CAAC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,8BAA8B,CAAC;gBACjF,QAAQ,EAAE,EAAE;aACb,CAAC;QACJ,CAAC;IACH,CAAC;CACF;AA5ED,8CA4EC"} \ No newline at end of file diff --git a/frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/advert.d.ts b/frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/advert.d.ts new file mode 100644 index 0000000..a0c7905 --- /dev/null +++ b/frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/advert.d.ts @@ -0,0 +1,24 @@ +import { AdvertPayload } from '../../types/payloads'; +import { PayloadSegment } from '../../types/packet'; +export declare class AdvertPayloadDecoder { + static decode(payload: Uint8Array, options?: { + includeSegments?: boolean; + segmentOffset?: number; + }): AdvertPayload & { + segments?: PayloadSegment[]; + } | null; + /** + * Decode advertisement payload with signature verification + */ + static decodeWithVerification(payload: Uint8Array, options?: { + includeSegments?: boolean; + segmentOffset?: number; + }): Promise; + private static parseDeviceRole; + private static readUint32LE; + private static readInt32LE; + private static sanitizeControlCharacters; +} +//# sourceMappingURL=advert.d.ts.map \ No newline at end of file diff --git a/frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/advert.d.ts.map b/frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/advert.d.ts.map new file mode 100644 index 0000000..5ad26f0 --- /dev/null +++ b/frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/advert.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"advert.d.ts","sourceRoot":"","sources":["../../../src/decoder/payload-decoders/advert.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAMpD,qBAAa,oBAAoB;IAC/B,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,UAAU,EAAE,OAAO,CAAC,EAAE;QAAE,eAAe,CAAC,EAAE,OAAO,CAAC;QAAC,aAAa,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,aAAa,GAAG;QAAE,QAAQ,CAAC,EAAE,cAAc,EAAE,CAAA;KAAE,GAAG,IAAI;IAuL3J;;OAEG;WACU,sBAAsB,CAAC,OAAO,EAAE,UAAU,EAAE,OAAO,CAAC,EAAE;QAAE,eAAe,CAAC,EAAE,OAAO,CAAC;QAAC,aAAa,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,aAAa,GAAG;QAAE,QAAQ,CAAC,EAAE,cAAc,EAAE,CAAA;KAAE,GAAG,IAAI,CAAC;IA4C1L,OAAO,CAAC,MAAM,CAAC,eAAe;IAW9B,OAAO,CAAC,MAAM,CAAC,YAAY;IAO3B,OAAO,CAAC,MAAM,CAAC,WAAW;IAM1B,OAAO,CAAC,MAAM,CAAC,yBAAyB;CAKzC"} \ No newline at end of file diff --git a/frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/advert.js b/frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/advert.js new file mode 100644 index 0000000..8d08d6b --- /dev/null +++ b/frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/advert.js @@ -0,0 +1,244 @@ +"use strict"; +// Copyright (c) 2025 Michael Hart: https://github.com/michaelhart/meshcore-decoder +// MIT License +Object.defineProperty(exports, "__esModule", { value: true }); +exports.AdvertPayloadDecoder = void 0; +const enums_1 = require("../../types/enums"); +const hex_1 = require("../../utils/hex"); +const enum_names_1 = require("../../utils/enum-names"); +const ed25519_verifier_1 = require("../../crypto/ed25519-verifier"); +class AdvertPayloadDecoder { + static decode(payload, options) { + try { + // start of appdata section: public_key(32) + timestamp(4) + signature(64) + flags(1) = 101 bytes + if (payload.length < 101) { + const result = { + type: enums_1.PayloadType.Advert, + version: enums_1.PayloadVersion.Version1, + isValid: false, + errors: ['Advertisement payload too short'], + publicKey: '', + timestamp: 0, + signature: '', + appData: { + flags: 0, + deviceRole: enums_1.DeviceRole.ChatNode, + hasLocation: false, + hasName: false + } + }; + if (options?.includeSegments) { + result.segments = [{ + name: 'Invalid Advert Data', + description: 'Advert payload too short (minimum 101 bytes required)', + startByte: options.segmentOffset || 0, + endByte: (options.segmentOffset || 0) + payload.length - 1, + value: (0, hex_1.bytesToHex)(payload) + }]; + } + return result; + } + const segments = []; + const segmentOffset = options?.segmentOffset || 0; + let currentOffset = 0; + // parse advertisement structure from payloads.md + const publicKey = (0, hex_1.bytesToHex)(payload.subarray(currentOffset, currentOffset + 32)); + if (options?.includeSegments) { + segments.push({ + name: 'Public Key', + description: 'Ed25519 public key', + startByte: segmentOffset + currentOffset, + endByte: segmentOffset + currentOffset + 31, + value: publicKey + }); + } + currentOffset += 32; + const timestamp = this.readUint32LE(payload, currentOffset); + if (options?.includeSegments) { + const timestampDate = new Date(timestamp * 1000); + segments.push({ + name: 'Timestamp', + description: `${timestamp} (${timestampDate.toISOString().slice(0, 19)}Z)`, + startByte: segmentOffset + currentOffset, + endByte: segmentOffset + currentOffset + 3, + value: (0, hex_1.bytesToHex)(payload.subarray(currentOffset, currentOffset + 4)) + }); + } + currentOffset += 4; + const signature = (0, hex_1.bytesToHex)(payload.subarray(currentOffset, currentOffset + 64)); + if (options?.includeSegments) { + segments.push({ + name: 'Signature', + description: 'Ed25519 signature', + startByte: segmentOffset + currentOffset, + endByte: segmentOffset + currentOffset + 63, + value: signature + }); + } + currentOffset += 64; + const flags = payload[currentOffset]; + if (options?.includeSegments) { + const binaryStr = flags.toString(2).padStart(8, '0'); + const deviceRole = this.parseDeviceRole(flags); + const roleName = (0, enum_names_1.getDeviceRoleName)(deviceRole); + const flagDesc = ` | Bits 0-3 (Role): ${roleName} | Bit 4 (Location): ${!!(flags & enums_1.AdvertFlags.HasLocation) ? 'Yes' : 'No'} | Bit 7 (Name): ${!!(flags & enums_1.AdvertFlags.HasName) ? 'Yes' : 'No'}`; + segments.push({ + name: 'App Flags', + description: `Binary: ${binaryStr}${flagDesc}`, + startByte: segmentOffset + currentOffset, + endByte: segmentOffset + currentOffset, + value: flags.toString(16).padStart(2, '0').toUpperCase() + }); + } + currentOffset += 1; + const advert = { + type: enums_1.PayloadType.Advert, + version: enums_1.PayloadVersion.Version1, + isValid: true, + publicKey, + timestamp, + signature, + appData: { + flags, + deviceRole: this.parseDeviceRole(flags), + hasLocation: !!(flags & enums_1.AdvertFlags.HasLocation), + hasName: !!(flags & enums_1.AdvertFlags.HasName) + } + }; + let offset = currentOffset; + // location data (if HasLocation flag is set) + if (flags & enums_1.AdvertFlags.HasLocation && payload.length >= offset + 8) { + const lat = this.readInt32LE(payload, offset) / 1000000; + const lon = this.readInt32LE(payload, offset + 4) / 1000000; + advert.appData.location = { + latitude: Math.round(lat * 1000000) / 1000000, // Keep precision + longitude: Math.round(lon * 1000000) / 1000000 + }; + if (options?.includeSegments) { + segments.push({ + name: 'Latitude', + description: `${lat}° (${lat})`, + startByte: segmentOffset + offset, + endByte: segmentOffset + offset + 3, + value: (0, hex_1.bytesToHex)(payload.subarray(offset, offset + 4)) + }); + segments.push({ + name: 'Longitude', + description: `${lon}° (${lon})`, + startByte: segmentOffset + offset + 4, + endByte: segmentOffset + offset + 7, + value: (0, hex_1.bytesToHex)(payload.subarray(offset + 4, offset + 8)) + }); + } + offset += 8; + } + // skip feature fields for now (HasFeature1, HasFeature2) + if (flags & enums_1.AdvertFlags.HasFeature1) + offset += 2; + if (flags & enums_1.AdvertFlags.HasFeature2) + offset += 2; + // name data (if HasName flag is set) + if (flags & enums_1.AdvertFlags.HasName && payload.length > offset) { + const nameBytes = payload.subarray(offset); + const rawName = new TextDecoder('utf-8').decode(nameBytes).replace(/\0.*$/, ''); + advert.appData.name = this.sanitizeControlCharacters(rawName) || rawName; + if (options?.includeSegments) { + segments.push({ + name: 'Node Name', + description: `Node name: "${advert.appData.name}"`, + startByte: segmentOffset + offset, + endByte: segmentOffset + payload.length - 1, + value: (0, hex_1.bytesToHex)(nameBytes) + }); + } + } + if (options?.includeSegments) { + advert.segments = segments; + } + return advert; + } + catch (error) { + return { + type: enums_1.PayloadType.Advert, + version: enums_1.PayloadVersion.Version1, + isValid: false, + errors: [error instanceof Error ? error.message : 'Failed to decode advertisement payload'], + publicKey: '', + timestamp: 0, + signature: '', + appData: { + flags: 0, + deviceRole: enums_1.DeviceRole.ChatNode, + hasLocation: false, + hasName: false + } + }; + } + } + /** + * Decode advertisement payload with signature verification + */ + static async decodeWithVerification(payload, options) { + // First decode normally + const advert = this.decode(payload, options); + if (!advert || !advert.isValid) { + return advert; + } + // Perform signature verification + try { + // Extract app_data from the payload (everything after public_key + timestamp + signature) + const appDataStart = 32 + 4 + 64; // public_key + timestamp + signature + const appDataBytes = payload.subarray(appDataStart); + const appDataHex = (0, hex_1.bytesToHex)(appDataBytes); + const signatureValid = await ed25519_verifier_1.Ed25519SignatureVerifier.verifyAdvertisementSignature(advert.publicKey, advert.signature, advert.timestamp, appDataHex); + advert.signatureValid = signatureValid; + if (!signatureValid) { + advert.signatureError = 'Ed25519 signature verification failed'; + advert.isValid = false; + if (!advert.errors) { + advert.errors = []; + } + advert.errors.push('Invalid Ed25519 signature'); + } + } + catch (error) { + advert.signatureValid = false; + advert.signatureError = error instanceof Error ? error.message : 'Signature verification error'; + advert.isValid = false; + if (!advert.errors) { + advert.errors = []; + } + advert.errors.push('Signature verification failed: ' + (error instanceof Error ? error.message : 'Unknown error')); + } + return advert; + } + static parseDeviceRole(flags) { + const roleValue = flags & 0x0F; + switch (roleValue) { + case 0x01: return enums_1.DeviceRole.ChatNode; + case 0x02: return enums_1.DeviceRole.Repeater; + case 0x03: return enums_1.DeviceRole.RoomServer; + case 0x04: return enums_1.DeviceRole.Sensor; + default: return enums_1.DeviceRole.ChatNode; + } + } + static readUint32LE(buffer, offset) { + return buffer[offset] | + (buffer[offset + 1] << 8) | + (buffer[offset + 2] << 16) | + (buffer[offset + 3] << 24); + } + static readInt32LE(buffer, offset) { + const value = this.readUint32LE(buffer, offset); + // convert unsigned to signed + return value > 0x7FFFFFFF ? value - 0x100000000 : value; + } + static sanitizeControlCharacters(value) { + if (!value) + return null; + const sanitized = value.trim().replace(/[\x00-\x1F\x7F]/g, ''); + return sanitized || null; + } +} +exports.AdvertPayloadDecoder = AdvertPayloadDecoder; +//# sourceMappingURL=advert.js.map \ No newline at end of file diff --git a/frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/advert.js.map b/frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/advert.js.map new file mode 100644 index 0000000..6a92c43 --- /dev/null +++ b/frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/advert.js.map @@ -0,0 +1 @@ +{"version":3,"file":"advert.js","sourceRoot":"","sources":["../../../src/decoder/payload-decoders/advert.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/anon-request.d.ts b/frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/anon-request.d.ts new file mode 100644 index 0000000..d1af515 --- /dev/null +++ b/frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/anon-request.d.ts @@ -0,0 +1,11 @@ +import { AnonRequestPayload } from '../../types/payloads'; +import { PayloadSegment } from '../../types/packet'; +export declare class AnonRequestPayloadDecoder { + static decode(payload: Uint8Array, options?: { + includeSegments?: boolean; + segmentOffset?: number; + }): AnonRequestPayload & { + segments?: PayloadSegment[]; + } | null; +} +//# sourceMappingURL=anon-request.d.ts.map \ No newline at end of file diff --git a/frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/anon-request.d.ts.map b/frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/anon-request.d.ts.map new file mode 100644 index 0000000..528cf91 --- /dev/null +++ b/frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/anon-request.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"anon-request.d.ts","sourceRoot":"","sources":["../../../src/decoder/payload-decoders/anon-request.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAIpD,qBAAa,yBAAyB;IACpC,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,UAAU,EAAE,OAAO,CAAC,EAAE;QAAE,eAAe,CAAC,EAAE,OAAO,CAAC;QAAC,aAAa,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,kBAAkB,GAAG;QAAE,QAAQ,CAAC,EAAE,cAAc,EAAE,CAAA;KAAE,GAAG,IAAI;CA8HjK"} \ No newline at end of file diff --git a/frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/anon-request.js b/frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/anon-request.js new file mode 100644 index 0000000..f0a7822 --- /dev/null +++ b/frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/anon-request.js @@ -0,0 +1,123 @@ +"use strict"; +// Copyright (c) 2025 Michael Hart: https://github.com/michaelhart/meshcore-decoder +// MIT License +Object.defineProperty(exports, "__esModule", { value: true }); +exports.AnonRequestPayloadDecoder = void 0; +const enums_1 = require("../../types/enums"); +const hex_1 = require("../../utils/hex"); +class AnonRequestPayloadDecoder { + static decode(payload, options) { + try { + // Based on MeshCore payloads.md - AnonRequest payload structure: + // - destination_hash (1 byte) + // - sender_public_key (32 bytes) + // - cipher_mac (2 bytes) + // - ciphertext (rest of payload) + if (payload.length < 35) { + const result = { + type: enums_1.PayloadType.AnonRequest, + version: enums_1.PayloadVersion.Version1, + isValid: false, + errors: ['AnonRequest payload too short (minimum 35 bytes: dest + public key + MAC)'], + destinationHash: '', + senderPublicKey: '', + cipherMac: '', + ciphertext: '', + ciphertextLength: 0 + }; + if (options?.includeSegments) { + result.segments = [{ + name: 'Invalid AnonRequest Data', + description: 'AnonRequest payload too short (minimum 35 bytes required: 1 for dest hash + 32 for public key + 2 for MAC)', + startByte: options.segmentOffset || 0, + endByte: (options.segmentOffset || 0) + payload.length - 1, + value: (0, hex_1.bytesToHex)(payload) + }]; + } + return result; + } + const segments = []; + const segmentOffset = options?.segmentOffset || 0; + let offset = 0; + // Parse destination hash (1 byte) + const destinationHash = (0, hex_1.byteToHex)(payload[0]); + if (options?.includeSegments) { + segments.push({ + name: 'Destination Hash', + description: `First byte of destination node public key: 0x${destinationHash}`, + startByte: segmentOffset + offset, + endByte: segmentOffset + offset, + value: destinationHash + }); + } + offset += 1; + // Parse sender public key (32 bytes) + const senderPublicKey = (0, hex_1.bytesToHex)(payload.subarray(1, 33)); + if (options?.includeSegments) { + segments.push({ + name: 'Sender Public Key', + description: `Ed25519 public key of the sender (32 bytes)`, + startByte: segmentOffset + offset, + endByte: segmentOffset + offset + 31, + value: senderPublicKey + }); + } + offset += 32; + // Parse cipher MAC (2 bytes) + const cipherMac = (0, hex_1.bytesToHex)(payload.subarray(33, 35)); + if (options?.includeSegments) { + segments.push({ + name: 'Cipher MAC', + description: `MAC for encrypted data verification (2 bytes)`, + startByte: segmentOffset + offset, + endByte: segmentOffset + offset + 1, + value: cipherMac + }); + } + offset += 2; + // Parse ciphertext (remaining bytes) + const ciphertext = (0, hex_1.bytesToHex)(payload.subarray(35)); + if (options?.includeSegments && payload.length > 35) { + segments.push({ + name: 'Ciphertext', + description: `Encrypted message data (${payload.length - 35} bytes). Contains encrypted plaintext with this structure: +• Timestamp (4 bytes) - send time as unix timestamp +• Sync Timestamp (4 bytes) - room server only, sender's "sync messages SINCE x" timestamp +• Password (remaining bytes) - password for repeater/room`, + startByte: segmentOffset + offset, + endByte: segmentOffset + payload.length - 1, + value: ciphertext + }); + } + const result = { + type: enums_1.PayloadType.AnonRequest, + version: enums_1.PayloadVersion.Version1, + isValid: true, + destinationHash, + senderPublicKey, + cipherMac, + ciphertext, + ciphertextLength: payload.length - 35 + }; + if (options?.includeSegments) { + result.segments = segments; + } + return result; + } + catch (error) { + return { + type: enums_1.PayloadType.AnonRequest, + version: enums_1.PayloadVersion.Version1, + isValid: false, + errors: [error instanceof Error ? error.message : 'Failed to decode AnonRequest payload'], + destinationHash: '', + senderPublicKey: '', + cipherMac: '', + ciphertext: '', + ciphertextLength: 0 + }; + } + } +} +exports.AnonRequestPayloadDecoder = AnonRequestPayloadDecoder; +//# sourceMappingURL=anon-request.js.map \ No newline at end of file diff --git a/frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/anon-request.js.map b/frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/anon-request.js.map new file mode 100644 index 0000000..cfdd577 --- /dev/null +++ b/frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/anon-request.js.map @@ -0,0 +1 @@ +{"version":3,"file":"anon-request.js","sourceRoot":"","sources":["../../../src/decoder/payload-decoders/anon-request.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/control.d.ts b/frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/control.d.ts new file mode 100644 index 0000000..eba4a70 --- /dev/null +++ b/frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/control.d.ts @@ -0,0 +1,16 @@ +import { ControlPayload } from '../../types/payloads'; +import { PayloadSegment } from '../../types/packet'; +export declare class ControlPayloadDecoder { + static decode(payload: Uint8Array, options?: { + includeSegments?: boolean; + segmentOffset?: number; + }): (ControlPayload & { + segments?: PayloadSegment[]; + }) | null; + private static decodeDiscoverReq; + private static decodeDiscoverResp; + private static parseTypeFilter; + private static createErrorPayload; + private static readUint32LE; +} +//# sourceMappingURL=control.d.ts.map \ No newline at end of file diff --git a/frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/control.d.ts.map b/frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/control.d.ts.map new file mode 100644 index 0000000..1e0495f --- /dev/null +++ b/frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/control.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"control.d.ts","sourceRoot":"","sources":["../../../src/decoder/payload-decoders/control.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,cAAc,EAAyD,MAAM,sBAAsB,CAAC;AAC7G,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAKpD,qBAAa,qBAAqB;IAChC,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,UAAU,EAAE,OAAO,CAAC,EAAE;QAAE,eAAe,CAAC,EAAE,OAAO,CAAC;QAAC,aAAa,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,CAAC,cAAc,GAAG;QAAE,QAAQ,CAAC,EAAE,cAAc,EAAE,CAAA;KAAE,CAAC,GAAG,IAAI;IAsB9J,OAAO,CAAC,MAAM,CAAC,iBAAiB;IAoHhC,OAAO,CAAC,MAAM,CAAC,kBAAkB;IAwHjC,OAAO,CAAC,MAAM,CAAC,eAAe;IAS9B,OAAO,CAAC,MAAM,CAAC,kBAAkB;IAgCjC,OAAO,CAAC,MAAM,CAAC,YAAY;CAM5B"} \ No newline at end of file diff --git a/frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/control.js b/frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/control.js new file mode 100644 index 0000000..a5102a9 --- /dev/null +++ b/frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/control.js @@ -0,0 +1,279 @@ +"use strict"; +// Copyright (c) 2025 Michael Hart: https://github.com/michaelhart/meshcore-decoder +// MIT License +Object.defineProperty(exports, "__esModule", { value: true }); +exports.ControlPayloadDecoder = void 0; +const enums_1 = require("../../types/enums"); +const hex_1 = require("../../utils/hex"); +const enum_names_1 = require("../../utils/enum-names"); +class ControlPayloadDecoder { + static decode(payload, options) { + try { + if (payload.length < 1) { + return this.createErrorPayload('Control payload too short (minimum 1 byte required)', payload, options); + } + const rawFlags = payload[0]; + const subType = rawFlags & 0xF0; // upper 4 bits + switch (subType) { + case enums_1.ControlSubType.NodeDiscoverReq: + return this.decodeDiscoverReq(payload, options); + case enums_1.ControlSubType.NodeDiscoverResp: + return this.decodeDiscoverResp(payload, options); + default: + return this.createErrorPayload(`Unknown control sub-type: 0x${subType.toString(16).padStart(2, '0')}`, payload, options); + } + } + catch (error) { + return this.createErrorPayload(error instanceof Error ? error.message : 'Failed to decode control payload', payload, options); + } + } + static decodeDiscoverReq(payload, options) { + const segments = []; + const segmentOffset = options?.segmentOffset ?? 0; + // Minimum size: flags(1) + type_filter(1) + tag(4) = 6 bytes + if (payload.length < 6) { + const result = { + type: enums_1.PayloadType.Control, + version: enums_1.PayloadVersion.Version1, + isValid: false, + errors: ['DISCOVER_REQ payload too short (minimum 6 bytes required)'], + subType: enums_1.ControlSubType.NodeDiscoverReq, + rawFlags: payload[0], + prefixOnly: false, + typeFilter: 0, + typeFilterNames: [], + tag: 0, + since: 0 + }; + if (options?.includeSegments) { + result.segments = [{ + name: 'Invalid DISCOVER_REQ Data', + description: 'DISCOVER_REQ payload too short (minimum 6 bytes required)', + startByte: segmentOffset, + endByte: segmentOffset + payload.length - 1, + value: (0, hex_1.bytesToHex)(payload) + }]; + } + return result; + } + let offset = 0; + // Byte 0: flags - upper 4 bits is sub_type (0x8), lowest bit is prefix_only + const rawFlags = payload[offset]; + const prefixOnly = (rawFlags & 0x01) !== 0; + if (options?.includeSegments) { + segments.push({ + name: 'Flags', + description: `Sub-type: DISCOVER_REQ (0x8) | Prefix Only: ${prefixOnly}`, + startByte: segmentOffset + offset, + endByte: segmentOffset + offset, + value: rawFlags.toString(16).padStart(2, '0').toUpperCase() + }); + } + offset += 1; + // Byte 1: type_filter - bit for each ADV_TYPE_* + const typeFilter = payload[offset]; + const typeFilterNames = this.parseTypeFilter(typeFilter); + if (options?.includeSegments) { + segments.push({ + name: 'Type Filter', + description: `Filter mask: 0b${typeFilter.toString(2).padStart(8, '0')} | Types: ${typeFilterNames.length > 0 ? typeFilterNames.join(', ') : 'None'}`, + startByte: segmentOffset + offset, + endByte: segmentOffset + offset, + value: typeFilter.toString(16).padStart(2, '0').toUpperCase() + }); + } + offset += 1; + // Bytes 2-5: tag (uint32, little endian) + const tag = this.readUint32LE(payload, offset); + if (options?.includeSegments) { + segments.push({ + name: 'Tag', + description: `Random tag for response matching: 0x${tag.toString(16).padStart(8, '0')}`, + startByte: segmentOffset + offset, + endByte: segmentOffset + offset + 3, + value: (0, hex_1.bytesToHex)(payload.slice(offset, offset + 4)) + }); + } + offset += 4; + // Optional: Bytes 6-9: since (uint32, little endian) - epoch timestamp + let since = 0; + if (payload.length >= offset + 4) { + since = this.readUint32LE(payload, offset); + if (options?.includeSegments) { + const sinceDate = since > 0 ? new Date(since * 1000).toISOString().slice(0, 19) + 'Z' : 'N/A'; + segments.push({ + name: 'Since', + description: `Filter timestamp: ${since} (${sinceDate})`, + startByte: segmentOffset + offset, + endByte: segmentOffset + offset + 3, + value: (0, hex_1.bytesToHex)(payload.slice(offset, offset + 4)) + }); + } + } + const result = { + type: enums_1.PayloadType.Control, + version: enums_1.PayloadVersion.Version1, + isValid: true, + subType: enums_1.ControlSubType.NodeDiscoverReq, + rawFlags, + prefixOnly, + typeFilter, + typeFilterNames, + tag, + since + }; + if (options?.includeSegments) { + result.segments = segments; + } + return result; + } + static decodeDiscoverResp(payload, options) { + const segments = []; + const segmentOffset = options?.segmentOffset ?? 0; + // Minimum size: flags(1) + snr(1) + tag(4) + pubkey(8 for prefix) = 14 bytes + if (payload.length < 14) { + const result = { + type: enums_1.PayloadType.Control, + version: enums_1.PayloadVersion.Version1, + isValid: false, + errors: ['DISCOVER_RESP payload too short (minimum 14 bytes required)'], + subType: enums_1.ControlSubType.NodeDiscoverResp, + rawFlags: payload.length > 0 ? payload[0] : 0, + nodeType: enums_1.DeviceRole.Unknown, + nodeTypeName: 'Unknown', + snr: 0, + tag: 0, + publicKey: '', + publicKeyLength: 0 + }; + if (options?.includeSegments) { + result.segments = [{ + name: 'Invalid DISCOVER_RESP Data', + description: 'DISCOVER_RESP payload too short (minimum 14 bytes required)', + startByte: segmentOffset, + endByte: segmentOffset + payload.length - 1, + value: (0, hex_1.bytesToHex)(payload) + }]; + } + return result; + } + let offset = 0; + // Byte 0: flags - upper 4 bits is sub_type (0x9), lower 4 bits is node_type + const rawFlags = payload[offset]; + const nodeType = (rawFlags & 0x0F); + const nodeTypeName = (0, enum_names_1.getDeviceRoleName)(nodeType); + if (options?.includeSegments) { + segments.push({ + name: 'Flags', + description: `Sub-type: DISCOVER_RESP (0x9) | Node Type: ${nodeTypeName}`, + startByte: segmentOffset + offset, + endByte: segmentOffset + offset, + value: rawFlags.toString(16).padStart(2, '0').toUpperCase() + }); + } + offset += 1; + // Byte 1: snr (signed int8, represents SNR * 4) + const snrRaw = payload[offset]; + const snrSigned = snrRaw > 127 ? snrRaw - 256 : snrRaw; + const snr = snrSigned / 4.0; + if (options?.includeSegments) { + segments.push({ + name: 'SNR', + description: `Inbound SNR: ${snr.toFixed(2)} dB (raw: ${snrRaw}, signed: ${snrSigned})`, + startByte: segmentOffset + offset, + endByte: segmentOffset + offset, + value: snrRaw.toString(16).padStart(2, '0').toUpperCase() + }); + } + offset += 1; + // Bytes 2-5: tag (uint32, little endian) - reflected from request + const tag = this.readUint32LE(payload, offset); + if (options?.includeSegments) { + segments.push({ + name: 'Tag', + description: `Reflected tag from request: 0x${tag.toString(16).padStart(8, '0')}`, + startByte: segmentOffset + offset, + endByte: segmentOffset + offset + 3, + value: (0, hex_1.bytesToHex)(payload.slice(offset, offset + 4)) + }); + } + offset += 4; + // Remaining bytes: public key (8 bytes for prefix, 32 bytes for full) + const remainingBytes = payload.length - offset; + const publicKeyLength = remainingBytes; + const publicKeyBytes = payload.slice(offset, offset + publicKeyLength); + const publicKey = (0, hex_1.bytesToHex)(publicKeyBytes); + if (options?.includeSegments) { + const keyType = publicKeyLength === 32 ? 'Full Public Key' : 'Public Key Prefix'; + segments.push({ + name: keyType, + description: `${keyType} (${publicKeyLength} bytes)`, + startByte: segmentOffset + offset, + endByte: segmentOffset + offset + publicKeyLength - 1, + value: publicKey + }); + } + const result = { + type: enums_1.PayloadType.Control, + version: enums_1.PayloadVersion.Version1, + isValid: true, + subType: enums_1.ControlSubType.NodeDiscoverResp, + rawFlags, + nodeType, + nodeTypeName, + snr, + tag, + publicKey, + publicKeyLength + }; + if (options?.includeSegments) { + result.segments = segments; + } + return result; + } + static parseTypeFilter(filter) { + const types = []; + if (filter & (1 << enums_1.DeviceRole.ChatNode)) + types.push('Chat'); + if (filter & (1 << enums_1.DeviceRole.Repeater)) + types.push('Repeater'); + if (filter & (1 << enums_1.DeviceRole.RoomServer)) + types.push('Room'); + if (filter & (1 << enums_1.DeviceRole.Sensor)) + types.push('Sensor'); + return types; + } + static createErrorPayload(error, payload, options) { + const result = { + type: enums_1.PayloadType.Control, + version: enums_1.PayloadVersion.Version1, + isValid: false, + errors: [error], + subType: enums_1.ControlSubType.NodeDiscoverReq, + rawFlags: payload.length > 0 ? payload[0] : 0, + prefixOnly: false, + typeFilter: 0, + typeFilterNames: [], + tag: 0, + since: 0 + }; + if (options?.includeSegments) { + result.segments = [{ + name: 'Invalid Control Data', + description: error, + startByte: options.segmentOffset ?? 0, + endByte: (options.segmentOffset ?? 0) + payload.length - 1, + value: (0, hex_1.bytesToHex)(payload) + }]; + } + return result; + } + static readUint32LE(buffer, offset) { + return (buffer[offset] | + (buffer[offset + 1] << 8) | + (buffer[offset + 2] << 16) | + (buffer[offset + 3] << 24)) >>> 0; // >>> 0 to ensure unsigned + } +} +exports.ControlPayloadDecoder = ControlPayloadDecoder; +//# sourceMappingURL=control.js.map \ No newline at end of file diff --git a/frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/control.js.map b/frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/control.js.map new file mode 100644 index 0000000..fea878d --- /dev/null +++ b/frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/control.js.map @@ -0,0 +1 @@ +{"version":3,"file":"control.js","sourceRoot":"","sources":["../../../src/decoder/payload-decoders/control.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/group-text.d.ts b/frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/group-text.d.ts new file mode 100644 index 0000000..978b8b0 --- /dev/null +++ b/frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/group-text.d.ts @@ -0,0 +1,12 @@ +import { GroupTextPayload } from '../../types/payloads'; +import { PayloadSegment } from '../../types/packet'; +import { DecryptionOptions } from '../../types/crypto'; +export declare class GroupTextPayloadDecoder { + static decode(payload: Uint8Array, options?: DecryptionOptions & { + includeSegments?: boolean; + segmentOffset?: number; + }): GroupTextPayload & { + segments?: PayloadSegment[]; + } | null; +} +//# sourceMappingURL=group-text.d.ts.map \ No newline at end of file diff --git a/frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/group-text.d.ts.map b/frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/group-text.d.ts.map new file mode 100644 index 0000000..4fb8137 --- /dev/null +++ b/frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/group-text.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"group-text.d.ts","sourceRoot":"","sources":["../../../src/decoder/payload-decoders/group-text.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAEpD,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAIvD,qBAAa,uBAAuB;IAClC,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,UAAU,EAAE,OAAO,CAAC,EAAE,iBAAiB,GAAG;QAAE,eAAe,CAAC,EAAE,OAAO,CAAC;QAAC,aAAa,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,gBAAgB,GAAG;QAAE,QAAQ,CAAC,EAAE,cAAc,EAAE,CAAA;KAAE,GAAG,IAAI;CAyHnL"} \ No newline at end of file diff --git a/frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/group-text.js b/frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/group-text.js new file mode 100644 index 0000000..2c0c3bd --- /dev/null +++ b/frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/group-text.js @@ -0,0 +1,118 @@ +"use strict"; +// Copyright (c) 2025 Michael Hart: https://github.com/michaelhart/meshcore-decoder +// MIT License +Object.defineProperty(exports, "__esModule", { value: true }); +exports.GroupTextPayloadDecoder = void 0; +const enums_1 = require("../../types/enums"); +const channel_crypto_1 = require("../../crypto/channel-crypto"); +const hex_1 = require("../../utils/hex"); +class GroupTextPayloadDecoder { + static decode(payload, options) { + try { + if (payload.length < 3) { + const result = { + type: enums_1.PayloadType.GroupText, + version: enums_1.PayloadVersion.Version1, + isValid: false, + errors: ['GroupText payload too short (need at least channel_hash(1) + MAC(2))'], + channelHash: '', + cipherMac: '', + ciphertext: '', + ciphertextLength: 0 + }; + if (options?.includeSegments) { + result.segments = [{ + name: 'Invalid GroupText Data', + description: 'GroupText payload too short (minimum 3 bytes required)', + startByte: options.segmentOffset || 0, + endByte: (options.segmentOffset || 0) + payload.length - 1, + value: (0, hex_1.bytesToHex)(payload) + }]; + } + return result; + } + const segments = []; + const segmentOffset = options?.segmentOffset || 0; + let offset = 0; + // channel hash (1 byte) - first byte of SHA256 of channel's shared key + const channelHash = (0, hex_1.byteToHex)(payload[offset]); + if (options?.includeSegments) { + segments.push({ + name: 'Channel Hash', + description: 'First byte of SHA256 of channel\'s shared key', + startByte: segmentOffset + offset, + endByte: segmentOffset + offset, + value: channelHash + }); + } + offset += 1; + // MAC (2 bytes) - message authentication code + const cipherMac = (0, hex_1.bytesToHex)(payload.subarray(offset, offset + 2)); + if (options?.includeSegments) { + segments.push({ + name: 'Cipher MAC', + description: 'MAC for encrypted data', + startByte: segmentOffset + offset, + endByte: segmentOffset + offset + 1, + value: cipherMac + }); + } + offset += 2; + // ciphertext (remaining bytes) - encrypted message + const ciphertext = (0, hex_1.bytesToHex)(payload.subarray(offset)); + if (options?.includeSegments && payload.length > offset) { + segments.push({ + name: 'Ciphertext', + description: 'Encrypted message content (timestamp + flags + message)', + startByte: segmentOffset + offset, + endByte: segmentOffset + payload.length - 1, + value: ciphertext + }); + } + const groupText = { + type: enums_1.PayloadType.GroupText, + version: enums_1.PayloadVersion.Version1, + isValid: true, + channelHash, + cipherMac, + ciphertext, + ciphertextLength: payload.length - 3 + }; + // attempt decryption if key store is provided + if (options?.keyStore && options.keyStore.hasChannelKey(channelHash)) { + // try all possible keys for this hash (handles collisions) + const channelKeys = options.keyStore.getChannelKeys(channelHash); + for (const channelKey of channelKeys) { + const decryptionResult = channel_crypto_1.ChannelCrypto.decryptGroupTextMessage(ciphertext, cipherMac, channelKey); + if (decryptionResult.success && decryptionResult.data) { + groupText.decrypted = { + timestamp: decryptionResult.data.timestamp, + flags: decryptionResult.data.flags, + sender: decryptionResult.data.sender, + message: decryptionResult.data.message + }; + break; // stop trying keys once we find one that works + } + } + } + if (options?.includeSegments) { + groupText.segments = segments; + } + return groupText; + } + catch (error) { + return { + type: enums_1.PayloadType.GroupText, + version: enums_1.PayloadVersion.Version1, + isValid: false, + errors: [error instanceof Error ? error.message : 'Failed to decode GroupText payload'], + channelHash: '', + cipherMac: '', + ciphertext: '', + ciphertextLength: 0 + }; + } + } +} +exports.GroupTextPayloadDecoder = GroupTextPayloadDecoder; +//# sourceMappingURL=group-text.js.map \ No newline at end of file diff --git a/frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/group-text.js.map b/frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/group-text.js.map new file mode 100644 index 0000000..b4736b5 --- /dev/null +++ b/frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/group-text.js.map @@ -0,0 +1 @@ +{"version":3,"file":"group-text.js","sourceRoot":"","sources":["../../../src/decoder/payload-decoders/group-text.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/path.d.ts b/frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/path.d.ts new file mode 100644 index 0000000..52c8121 --- /dev/null +++ b/frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/path.d.ts @@ -0,0 +1,5 @@ +import { PathPayload } from '../../types/payloads'; +export declare class PathPayloadDecoder { + static decode(payload: Uint8Array): PathPayload | null; +} +//# sourceMappingURL=path.d.ts.map \ No newline at end of file diff --git a/frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/path.d.ts.map b/frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/path.d.ts.map new file mode 100644 index 0000000..8cc326d --- /dev/null +++ b/frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/path.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"path.d.ts","sourceRoot":"","sources":["../../../src/decoder/payload-decoders/path.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAInD,qBAAa,kBAAkB;IAC7B,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,UAAU,GAAG,WAAW,GAAG,IAAI;CA6FvD"} \ No newline at end of file diff --git a/frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/path.js b/frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/path.js new file mode 100644 index 0000000..3e64d6e --- /dev/null +++ b/frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/path.js @@ -0,0 +1,97 @@ +"use strict"; +// Copyright (c) 2025 Michael Hart: https://github.com/michaelhart/meshcore-decoder +// MIT License +Object.defineProperty(exports, "__esModule", { value: true }); +exports.PathPayloadDecoder = void 0; +const enums_1 = require("../../types/enums"); +const hex_1 = require("../../utils/hex"); +class PathPayloadDecoder { + static decode(payload) { + try { + // Based on MeshCore payloads.md - Path payload structure: + // - path_len (1 byte, encoded: bits 7:6 = hash size selector, bits 5:0 = hop count) + // - path (variable length) - list of node hashes (pathHashSize bytes each) + // - extra_type (1 byte) - bundled payload type + // - extra (rest of data) - bundled payload content + if (payload.length < 2) { + return { + type: enums_1.PayloadType.Path, + version: enums_1.PayloadVersion.Version1, + isValid: false, + errors: ['Path payload too short (minimum 2 bytes: path length + extra type)'], + pathLength: 0, + pathHashes: [], + extraType: 0, + extraData: '' + }; + } + const pathLenByte = payload[0]; + const pathHashSize = (pathLenByte >> 6) + 1; + const pathHopCount = pathLenByte & 63; + const pathByteLength = pathHopCount * pathHashSize; + if (pathHashSize === 4) { + return { + type: enums_1.PayloadType.Path, + version: enums_1.PayloadVersion.Version1, + isValid: false, + errors: ['Invalid path length byte: reserved hash size (bits 7:6 = 11)'], + pathLength: 0, + pathHashes: [], + extraType: 0, + extraData: '' + }; + } + if (payload.length < 1 + pathByteLength + 1) { + return { + type: enums_1.PayloadType.Path, + version: enums_1.PayloadVersion.Version1, + isValid: false, + errors: [`Path payload too short (need ${1 + pathByteLength + 1} bytes for path length + path + extra type)`], + pathLength: pathHopCount, + ...(pathHashSize > 1 ? { pathHashSize } : {}), + pathHashes: [], + extraType: 0, + extraData: '' + }; + } + // Parse path hashes (pathHashSize bytes each) + const pathHashes = []; + for (let i = 0; i < pathHopCount; i++) { + const hashStart = 1 + i * pathHashSize; + const hashBytes = payload.subarray(hashStart, hashStart + pathHashSize); + pathHashes.push((0, hex_1.bytesToHex)(hashBytes)); + } + // Parse extra type (1 byte after path) + const extraType = payload[1 + pathByteLength]; + // Parse extra data (remaining bytes) + let extraData = ''; + if (payload.length > 1 + pathByteLength + 1) { + extraData = (0, hex_1.bytesToHex)(payload.subarray(1 + pathByteLength + 1)); + } + return { + type: enums_1.PayloadType.Path, + version: enums_1.PayloadVersion.Version1, + isValid: true, + pathLength: pathHopCount, + ...(pathHashSize > 1 ? { pathHashSize } : {}), + pathHashes, + extraType, + extraData + }; + } + catch (error) { + return { + type: enums_1.PayloadType.Path, + version: enums_1.PayloadVersion.Version1, + isValid: false, + errors: [error instanceof Error ? error.message : 'Failed to decode Path payload'], + pathLength: 0, + pathHashes: [], + extraType: 0, + extraData: '' + }; + } + } +} +exports.PathPayloadDecoder = PathPayloadDecoder; +//# sourceMappingURL=path.js.map \ No newline at end of file diff --git a/frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/path.js.map b/frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/path.js.map new file mode 100644 index 0000000..193f366 --- /dev/null +++ b/frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/path.js.map @@ -0,0 +1 @@ +{"version":3,"file":"path.js","sourceRoot":"","sources":["../../../src/decoder/payload-decoders/path.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/request.d.ts b/frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/request.d.ts new file mode 100644 index 0000000..2820dd6 --- /dev/null +++ b/frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/request.d.ts @@ -0,0 +1,11 @@ +import { RequestPayload } from '../../types/payloads'; +import { PayloadSegment } from '../../types/packet'; +export declare class RequestPayloadDecoder { + static decode(payload: Uint8Array, options?: { + includeSegments?: boolean; + segmentOffset?: number; + }): RequestPayload & { + segments?: PayloadSegment[]; + } | null; +} +//# sourceMappingURL=request.d.ts.map \ No newline at end of file diff --git a/frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/request.d.ts.map b/frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/request.d.ts.map new file mode 100644 index 0000000..199a5a3 --- /dev/null +++ b/frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/request.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"request.d.ts","sourceRoot":"","sources":["../../../src/decoder/payload-decoders/request.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAIpD,qBAAa,qBAAqB;IAChC,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,UAAU,EAAE,OAAO,CAAC,EAAE;QAAE,eAAe,CAAC,EAAE,OAAO,CAAC;QAAC,aAAa,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,cAAc,GAAG;QAAE,QAAQ,CAAC,EAAE,cAAc,EAAE,CAAA;KAAE,GAAG,IAAI;CAqI7J"} \ No newline at end of file diff --git a/frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/request.js b/frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/request.js new file mode 100644 index 0000000..f8be71b --- /dev/null +++ b/frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/request.js @@ -0,0 +1,129 @@ +"use strict"; +// Copyright (c) 2025 Michael Hart: https://github.com/michaelhart/meshcore-decoder +// MIT License +Object.defineProperty(exports, "__esModule", { value: true }); +exports.RequestPayloadDecoder = void 0; +const enums_1 = require("../../types/enums"); +const hex_1 = require("../../utils/hex"); +class RequestPayloadDecoder { + static decode(payload, options) { + try { + // Based on MeshCore payloads.md - Request payload structure: + // - destination hash (1 byte) + // - source hash (1 byte) + // - cipher MAC (2 bytes) + // - ciphertext (rest of payload) - contains encrypted timestamp, request type, and request data + if (payload.length < 4) { + const result = { + type: enums_1.PayloadType.Request, + version: enums_1.PayloadVersion.Version1, + isValid: false, + errors: ['Request payload too short (minimum 4 bytes: dest hash + source hash + MAC)'], + timestamp: 0, + requestType: enums_1.RequestType.GetStats, + requestData: '', + destinationHash: '', + sourceHash: '', + cipherMac: '', + ciphertext: '' + }; + if (options?.includeSegments) { + result.segments = [{ + name: 'Invalid Request Data', + description: 'Request payload too short (minimum 4 bytes required: 1 for dest hash + 1 for source hash + 2 for MAC)', + startByte: options.segmentOffset || 0, + endByte: (options.segmentOffset || 0) + payload.length - 1, + value: (0, hex_1.bytesToHex)(payload) + }]; + } + return result; + } + const segments = []; + const segmentOffset = options?.segmentOffset || 0; + let offset = 0; + // Parse destination hash (1 byte) + const destinationHash = (0, hex_1.bytesToHex)(payload.subarray(offset, offset + 1)); + if (options?.includeSegments) { + segments.push({ + name: 'Destination Hash', + description: `First byte of destination node public key: 0x${destinationHash}`, + startByte: segmentOffset + offset, + endByte: segmentOffset + offset, + value: destinationHash + }); + } + offset += 1; + // Parse source hash (1 byte) + const sourceHash = (0, hex_1.bytesToHex)(payload.subarray(offset, offset + 1)); + if (options?.includeSegments) { + segments.push({ + name: 'Source Hash', + description: `First byte of source node public key: 0x${sourceHash}`, + startByte: segmentOffset + offset, + endByte: segmentOffset + offset, + value: sourceHash + }); + } + offset += 1; + // Parse cipher MAC (2 bytes) + const cipherMac = (0, hex_1.bytesToHex)(payload.subarray(offset, offset + 2)); + if (options?.includeSegments) { + segments.push({ + name: 'Cipher MAC', + description: `MAC for encrypted data verification (2 bytes)`, + startByte: segmentOffset + offset, + endByte: segmentOffset + offset + 1, + value: cipherMac + }); + } + offset += 2; + // Parse ciphertext (remaining bytes) + const ciphertext = (0, hex_1.bytesToHex)(payload.subarray(offset)); + if (options?.includeSegments && payload.length > offset) { + segments.push({ + name: 'Ciphertext', + description: `Encrypted message data (${payload.length - offset} bytes). Contains encrypted plaintext with this structure: +• Timestamp (4 bytes) - send time as unix timestamp +• Request Type (1 byte) - type of request (GetStats, GetTelemetryData, etc.) +• Request Data (remaining bytes) - additional request-specific data`, + startByte: segmentOffset + offset, + endByte: segmentOffset + payload.length - 1, + value: ciphertext + }); + } + const result = { + type: enums_1.PayloadType.Request, + version: enums_1.PayloadVersion.Version1, + isValid: true, + timestamp: 0, // Encrypted, cannot be parsed without decryption + requestType: enums_1.RequestType.GetStats, // Encrypted, cannot be determined without decryption + requestData: '', + destinationHash, + sourceHash, + cipherMac, + ciphertext + }; + if (options?.includeSegments) { + result.segments = segments; + } + return result; + } + catch (error) { + return { + type: enums_1.PayloadType.Request, + version: enums_1.PayloadVersion.Version1, + isValid: false, + errors: [error instanceof Error ? error.message : 'Failed to decode request payload'], + timestamp: 0, + requestType: enums_1.RequestType.GetStats, + requestData: '', + destinationHash: '', + sourceHash: '', + cipherMac: '', + ciphertext: '' + }; + } + } +} +exports.RequestPayloadDecoder = RequestPayloadDecoder; +//# sourceMappingURL=request.js.map \ No newline at end of file diff --git a/frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/request.js.map b/frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/request.js.map new file mode 100644 index 0000000..dcfee1d --- /dev/null +++ b/frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/request.js.map @@ -0,0 +1 @@ +{"version":3,"file":"request.js","sourceRoot":"","sources":["../../../src/decoder/payload-decoders/request.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/response.d.ts b/frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/response.d.ts new file mode 100644 index 0000000..d3aeb3d --- /dev/null +++ b/frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/response.d.ts @@ -0,0 +1,11 @@ +import { ResponsePayload } from '../../types/payloads'; +import { PayloadSegment } from '../../types/packet'; +export declare class ResponsePayloadDecoder { + static decode(payload: Uint8Array, options?: { + includeSegments?: boolean; + segmentOffset?: number; + }): ResponsePayload & { + segments?: PayloadSegment[]; + } | null; +} +//# sourceMappingURL=response.d.ts.map \ No newline at end of file diff --git a/frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/response.d.ts.map b/frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/response.d.ts.map new file mode 100644 index 0000000..b6d211f --- /dev/null +++ b/frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/response.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"response.d.ts","sourceRoot":"","sources":["../../../src/decoder/payload-decoders/response.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAIpD,qBAAa,sBAAsB;IACjC,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,UAAU,EAAE,OAAO,CAAC,EAAE;QAAE,eAAe,CAAC,EAAE,OAAO,CAAC;QAAC,aAAa,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,eAAe,GAAG;QAAE,QAAQ,CAAC,EAAE,cAAc,EAAE,CAAA;KAAE,GAAG,IAAI;CAuH9J"} \ No newline at end of file diff --git a/frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/response.js b/frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/response.js new file mode 100644 index 0000000..8b0d099 --- /dev/null +++ b/frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/response.js @@ -0,0 +1,120 @@ +"use strict"; +// Copyright (c) 2025 Michael Hart: https://github.com/michaelhart/meshcore-decoder +// MIT License +Object.defineProperty(exports, "__esModule", { value: true }); +exports.ResponsePayloadDecoder = void 0; +const enums_1 = require("../../types/enums"); +const hex_1 = require("../../utils/hex"); +class ResponsePayloadDecoder { + static decode(payload, options) { + try { + // Based on MeshCore payloads.md - Response payload structure: + // - destination_hash (1 byte) + // - source_hash (1 byte) + // - cipher_mac (2 bytes) + // - ciphertext (rest of payload) + if (payload.length < 4) { + const result = { + type: enums_1.PayloadType.Response, + version: enums_1.PayloadVersion.Version1, + isValid: false, + errors: ['Response payload too short (minimum 4 bytes: dest + source + MAC)'], + destinationHash: '', + sourceHash: '', + cipherMac: '', + ciphertext: '', + ciphertextLength: 0 + }; + if (options?.includeSegments) { + result.segments = [{ + name: 'Invalid Response Data', + description: 'Response payload too short (minimum 4 bytes required)', + startByte: options.segmentOffset || 0, + endByte: (options.segmentOffset || 0) + payload.length - 1, + value: (0, hex_1.bytesToHex)(payload) + }]; + } + return result; + } + const segments = []; + const segmentOffset = options?.segmentOffset || 0; + let offset = 0; + // Destination Hash (1 byte) + const destinationHash = (0, hex_1.byteToHex)(payload[offset]); + if (options?.includeSegments) { + segments.push({ + name: 'Destination Hash', + description: 'First byte of destination node public key', + startByte: segmentOffset + offset, + endByte: segmentOffset + offset, + value: destinationHash + }); + } + offset += 1; + // source hash (1 byte) + const sourceHash = (0, hex_1.byteToHex)(payload[offset]); + if (options?.includeSegments) { + segments.push({ + name: 'Source Hash', + description: 'First byte of source node public key', + startByte: segmentOffset + offset, + endByte: segmentOffset + offset, + value: sourceHash + }); + } + offset += 1; + // cipher MAC (2 bytes) + const cipherMac = (0, hex_1.bytesToHex)(payload.subarray(offset, offset + 2)); + if (options?.includeSegments) { + segments.push({ + name: 'Cipher MAC', + description: 'MAC for encrypted data in next field', + startByte: segmentOffset + offset, + endByte: segmentOffset + offset + 1, + value: cipherMac + }); + } + offset += 2; + // ciphertext (remaining bytes) + const ciphertext = (0, hex_1.bytesToHex)(payload.subarray(offset)); + if (options?.includeSegments && payload.length > offset) { + segments.push({ + name: 'Ciphertext', + description: 'Encrypted response data (tag + content)', + startByte: segmentOffset + offset, + endByte: segmentOffset + payload.length - 1, + value: ciphertext + }); + } + const result = { + type: enums_1.PayloadType.Response, + version: enums_1.PayloadVersion.Version1, + isValid: true, + destinationHash, + sourceHash, + cipherMac, + ciphertext, + ciphertextLength: payload.length - 4 + }; + if (options?.includeSegments) { + result.segments = segments; + } + return result; + } + catch (error) { + return { + type: enums_1.PayloadType.Response, + version: enums_1.PayloadVersion.Version1, + isValid: false, + errors: [error instanceof Error ? error.message : 'Failed to decode response payload'], + destinationHash: '', + sourceHash: '', + cipherMac: '', + ciphertext: '', + ciphertextLength: 0 + }; + } + } +} +exports.ResponsePayloadDecoder = ResponsePayloadDecoder; +//# sourceMappingURL=response.js.map \ No newline at end of file diff --git a/frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/response.js.map b/frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/response.js.map new file mode 100644 index 0000000..1ee30ae --- /dev/null +++ b/frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/response.js.map @@ -0,0 +1 @@ +{"version":3,"file":"response.js","sourceRoot":"","sources":["../../../src/decoder/payload-decoders/response.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/text-message.d.ts b/frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/text-message.d.ts new file mode 100644 index 0000000..12ff65b --- /dev/null +++ b/frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/text-message.d.ts @@ -0,0 +1,11 @@ +import { TextMessagePayload } from '../../types/payloads'; +import { PayloadSegment } from '../../types/packet'; +export declare class TextMessagePayloadDecoder { + static decode(payload: Uint8Array, options?: { + includeSegments?: boolean; + segmentOffset?: number; + }): TextMessagePayload & { + segments?: PayloadSegment[]; + } | null; +} +//# sourceMappingURL=text-message.d.ts.map \ No newline at end of file diff --git a/frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/text-message.d.ts.map b/frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/text-message.d.ts.map new file mode 100644 index 0000000..2ec1b1c --- /dev/null +++ b/frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/text-message.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"text-message.d.ts","sourceRoot":"","sources":["../../../src/decoder/payload-decoders/text-message.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAIpD,qBAAa,yBAAyB;IACpC,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,UAAU,EAAE,OAAO,CAAC,EAAE;QAAE,eAAe,CAAC,EAAE,OAAO,CAAC;QAAC,aAAa,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,kBAAkB,GAAG;QAAE,QAAQ,CAAC,EAAE,cAAc,EAAE,CAAA;KAAE,GAAG,IAAI;CAuHjK"} \ No newline at end of file diff --git a/frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/text-message.js b/frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/text-message.js new file mode 100644 index 0000000..ef84601 --- /dev/null +++ b/frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/text-message.js @@ -0,0 +1,120 @@ +"use strict"; +// Copyright (c) 2025 Michael Hart: https://github.com/michaelhart/meshcore-decoder +// MIT License +Object.defineProperty(exports, "__esModule", { value: true }); +exports.TextMessagePayloadDecoder = void 0; +const enums_1 = require("../../types/enums"); +const hex_1 = require("../../utils/hex"); +class TextMessagePayloadDecoder { + static decode(payload, options) { + try { + // Based on MeshCore payloads.md - TextMessage payload structure: + // - destination_hash (1 byte) + // - source_hash (1 byte) + // - cipher_mac (2 bytes) + // - ciphertext (rest of payload) + if (payload.length < 4) { + const result = { + type: enums_1.PayloadType.TextMessage, + version: enums_1.PayloadVersion.Version1, + isValid: false, + errors: ['TextMessage payload too short (minimum 4 bytes: dest + source + MAC)'], + destinationHash: '', + sourceHash: '', + cipherMac: '', + ciphertext: '', + ciphertextLength: 0 + }; + if (options?.includeSegments) { + result.segments = [{ + name: 'Invalid TextMessage Data', + description: 'TextMessage payload too short (minimum 4 bytes required)', + startByte: options.segmentOffset || 0, + endByte: (options.segmentOffset || 0) + payload.length - 1, + value: (0, hex_1.bytesToHex)(payload) + }]; + } + return result; + } + const segments = []; + const segmentOffset = options?.segmentOffset || 0; + let offset = 0; + // Destination Hash (1 byte) + const destinationHash = (0, hex_1.byteToHex)(payload[offset]); + if (options?.includeSegments) { + segments.push({ + name: 'Destination Hash', + description: 'First byte of destination node public key', + startByte: segmentOffset + offset, + endByte: segmentOffset + offset, + value: destinationHash + }); + } + offset += 1; + // Source Hash (1 byte) + const sourceHash = (0, hex_1.byteToHex)(payload[offset]); + if (options?.includeSegments) { + segments.push({ + name: 'Source Hash', + description: 'First byte of source node public key', + startByte: segmentOffset + offset, + endByte: segmentOffset + offset, + value: sourceHash + }); + } + offset += 1; + // Cipher MAC (2 bytes) + const cipherMac = (0, hex_1.bytesToHex)(payload.subarray(offset, offset + 2)); + if (options?.includeSegments) { + segments.push({ + name: 'Cipher MAC', + description: 'MAC for encrypted data in next field', + startByte: segmentOffset + offset, + endByte: segmentOffset + offset + 1, + value: cipherMac + }); + } + offset += 2; + // Ciphertext (remaining bytes) + const ciphertext = (0, hex_1.bytesToHex)(payload.subarray(offset)); + if (options?.includeSegments && payload.length > offset) { + segments.push({ + name: 'Ciphertext', + description: 'Encrypted message data (timestamp + message text)', + startByte: segmentOffset + offset, + endByte: segmentOffset + payload.length - 1, + value: ciphertext + }); + } + const result = { + type: enums_1.PayloadType.TextMessage, + version: enums_1.PayloadVersion.Version1, + isValid: true, + destinationHash, + sourceHash, + cipherMac, + ciphertext, + ciphertextLength: payload.length - 4 + }; + if (options?.includeSegments) { + result.segments = segments; + } + return result; + } + catch (error) { + return { + type: enums_1.PayloadType.TextMessage, + version: enums_1.PayloadVersion.Version1, + isValid: false, + errors: [error instanceof Error ? error.message : 'Failed to decode TextMessage payload'], + destinationHash: '', + sourceHash: '', + cipherMac: '', + ciphertext: '', + ciphertextLength: 0 + }; + } + } +} +exports.TextMessagePayloadDecoder = TextMessagePayloadDecoder; +//# sourceMappingURL=text-message.js.map \ No newline at end of file diff --git a/frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/text-message.js.map b/frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/text-message.js.map new file mode 100644 index 0000000..962c6a3 --- /dev/null +++ b/frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/text-message.js.map @@ -0,0 +1 @@ +{"version":3,"file":"text-message.js","sourceRoot":"","sources":["../../../src/decoder/payload-decoders/text-message.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/trace.d.ts b/frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/trace.d.ts new file mode 100644 index 0000000..c35bc72 --- /dev/null +++ b/frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/trace.d.ts @@ -0,0 +1,12 @@ +import { TracePayload } from '../../types/payloads'; +import { PayloadSegment } from '../../types/packet'; +export declare class TracePayloadDecoder { + static decode(payload: Uint8Array, pathData?: string[] | null, options?: { + includeSegments?: boolean; + segmentOffset?: number; + }): TracePayload & { + segments?: PayloadSegment[]; + } | null; + private static readUint32LE; +} +//# sourceMappingURL=trace.d.ts.map \ No newline at end of file diff --git a/frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/trace.d.ts.map b/frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/trace.d.ts.map new file mode 100644 index 0000000..e9cc26c --- /dev/null +++ b/frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/trace.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"trace.d.ts","sourceRoot":"","sources":["../../../src/decoder/payload-decoders/trace.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACpD,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAIpD,qBAAa,mBAAmB;IAC9B,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,UAAU,EAAE,QAAQ,CAAC,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,CAAC,EAAE;QAAE,eAAe,CAAC,EAAE,OAAO,CAAC;QAAC,aAAa,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,YAAY,GAAG;QAAE,QAAQ,CAAC,EAAE,cAAc,EAAE,CAAA;KAAE,GAAG,IAAI;IAuItL,OAAO,CAAC,MAAM,CAAC,YAAY;CAM5B"} \ No newline at end of file diff --git a/frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/trace.js b/frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/trace.js new file mode 100644 index 0000000..075b945 --- /dev/null +++ b/frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/trace.js @@ -0,0 +1,136 @@ +"use strict"; +// Copyright (c) 2025 Michael Hart: https://github.com/michaelhart/meshcore-decoder +// MIT License +Object.defineProperty(exports, "__esModule", { value: true }); +exports.TracePayloadDecoder = void 0; +const enums_1 = require("../../types/enums"); +const hex_1 = require("../../utils/hex"); +class TracePayloadDecoder { + static decode(payload, pathData, options) { + try { + if (payload.length < 9) { + const result = { + type: enums_1.PayloadType.Trace, + version: enums_1.PayloadVersion.Version1, + isValid: false, + errors: ['Trace payload too short (need at least tag(4) + auth(4) + flags(1))'], + traceTag: '00000000', + authCode: 0, + flags: 0, + pathHashes: [] + }; + if (options?.includeSegments) { + result.segments = [{ + name: 'Invalid Trace Data', + description: 'Trace payload too short (minimum 9 bytes required)', + startByte: options.segmentOffset || 0, + endByte: (options.segmentOffset || 0) + payload.length - 1, + value: (0, hex_1.bytesToHex)(payload) + }]; + } + return result; + } + let offset = 0; + const segments = []; + const segmentOffset = options?.segmentOffset || 0; + // Trace Tag (4 bytes) - unique identifier + const traceTagRaw = this.readUint32LE(payload, offset); + const traceTag = (0, hex_1.numberToHex)(traceTagRaw, 8); + if (options?.includeSegments) { + segments.push({ + name: 'Trace Tag', + description: `Unique identifier for this trace: 0x${traceTagRaw.toString(16).padStart(8, '0')}`, + startByte: segmentOffset + offset, + endByte: segmentOffset + offset + 3, + value: (0, hex_1.bytesToHex)(payload.slice(offset, offset + 4)) + }); + } + offset += 4; + // Auth Code (4 bytes) - authentication/verification code + const authCode = this.readUint32LE(payload, offset); + if (options?.includeSegments) { + segments.push({ + name: 'Auth Code', + description: `Authentication/verification code: ${authCode}`, + startByte: segmentOffset + offset, + endByte: segmentOffset + offset + 3, + value: (0, hex_1.bytesToHex)(payload.slice(offset, offset + 4)) + }); + } + offset += 4; + // Flags (1 byte) - application-defined control flags + const flags = payload[offset]; + if (options?.includeSegments) { + segments.push({ + name: 'Flags', + description: `Application-defined control flags: 0x${flags.toString(16).padStart(2, '0')} (${flags.toString(2).padStart(8, '0')}b)`, + startByte: segmentOffset + offset, + endByte: segmentOffset + offset, + value: flags.toString(16).padStart(2, '0').toUpperCase() + }); + } + offset += 1; + // remaining bytes are path hashes (node hashes in the trace path) + const pathHashes = []; + const pathHashesStart = offset; + while (offset < payload.length) { + pathHashes.push((0, hex_1.byteToHex)(payload[offset])); + offset++; + } + if (options?.includeSegments && pathHashes.length > 0) { + const pathHashesDisplay = pathHashes.join(' '); + segments.push({ + name: 'Path Hashes', + description: `Node hashes in trace path: ${pathHashesDisplay}`, + startByte: segmentOffset + pathHashesStart, + endByte: segmentOffset + payload.length - 1, + value: (0, hex_1.bytesToHex)(payload.slice(pathHashesStart)) + }); + } + // extract SNR values from path field for TRACE packets + let snrValues; + if (pathData && pathData.length > 0) { + snrValues = pathData.map(hexByte => { + const byteValue = parseInt(hexByte, 16); + // convert unsigned byte to signed int8 (SNR values are stored as signed int8 * 4) + const snrSigned = byteValue > 127 ? byteValue - 256 : byteValue; + return snrSigned / 4.0; // convert to dB + }); + } + const result = { + type: enums_1.PayloadType.Trace, + version: enums_1.PayloadVersion.Version1, + isValid: true, + traceTag, + authCode, + flags, + pathHashes, + snrValues + }; + if (options?.includeSegments) { + result.segments = segments; + } + return result; + } + catch (error) { + return { + type: enums_1.PayloadType.Trace, + version: enums_1.PayloadVersion.Version1, + isValid: false, + errors: [error instanceof Error ? error.message : 'Failed to decode trace payload'], + traceTag: '00000000', + authCode: 0, + flags: 0, + pathHashes: [] + }; + } + } + static readUint32LE(buffer, offset) { + return buffer[offset] | + (buffer[offset + 1] << 8) | + (buffer[offset + 2] << 16) | + (buffer[offset + 3] << 24); + } +} +exports.TracePayloadDecoder = TracePayloadDecoder; +//# sourceMappingURL=trace.js.map \ No newline at end of file diff --git a/frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/trace.js.map b/frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/trace.js.map new file mode 100644 index 0000000..ad18b36 --- /dev/null +++ b/frontend/lib/meshcore-decoder/dist/decoder/payload-decoders/trace.js.map @@ -0,0 +1 @@ +{"version":3,"file":"trace.js","sourceRoot":"","sources":["../../../src/decoder/payload-decoders/trace.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/frontend/lib/meshcore-decoder/dist/index.d.ts b/frontend/lib/meshcore-decoder/dist/index.d.ts new file mode 100644 index 0000000..a63ae71 --- /dev/null +++ b/frontend/lib/meshcore-decoder/dist/index.d.ts @@ -0,0 +1,36 @@ +export { MeshCorePacketDecoder } from './decoder/packet-decoder'; +export { MeshCorePacketDecoder as MeshCoreDecoder } from './decoder/packet-decoder'; +export type { DecodedPacket, PacketStructure, PacketSegment, PayloadSegment, HeaderBreakdown } from './types/packet'; +export type { BasePayload, AdvertPayload, TracePayload, GroupTextPayload, RequestPayload, TextMessagePayload, AnonRequestPayload, AckPayload, PathPayload, ResponsePayload, ControlPayloadBase, ControlDiscoverReqPayload, ControlDiscoverRespPayload, ControlPayload, PayloadData } from './types/payloads'; +export type { CryptoKeyStore, DecryptionOptions, DecryptionResult, ValidationResult } from './types/crypto'; +export { RouteType, PayloadType, PayloadVersion, DeviceRole, AdvertFlags, RequestType, ControlSubType } from './types/enums'; +export { MeshCoreKeyStore } from './crypto/key-manager'; +export { ChannelCrypto } from './crypto/channel-crypto'; +export { Ed25519SignatureVerifier } from './crypto/ed25519-verifier'; +export { hexToBytes, bytesToHex, byteToHex, numberToHex } from './utils/hex'; +export { getRouteTypeName, getPayloadTypeName, getPayloadVersionName, getDeviceRoleName, getRequestTypeName, getControlSubTypeName } from './utils/enum-names'; +export { createAuthToken, verifyAuthToken, parseAuthToken, decodeAuthTokenPayload } from './utils/auth-token'; +export type { AuthTokenPayload, AuthToken } from './utils/auth-token'; +import * as AuthTokenUtils from './utils/auth-token'; +import { derivePublicKey, validateKeyPair, sign, verify } from './crypto/orlp-ed25519-wasm'; +export declare const Utils: { + derivePublicKey: typeof derivePublicKey; + validateKeyPair: typeof validateKeyPair; + sign: typeof sign; + verify: typeof verify; + createAuthToken(payload: AuthTokenUtils.AuthTokenPayload, privateKeyHex: string, publicKeyHex: string): Promise; + verifyAuthToken(token: string, expectedPublicKeyHex?: string): Promise; + parseAuthToken(token: string): AuthTokenUtils.AuthToken | null; + decodeAuthTokenPayload(token: string): AuthTokenUtils.AuthTokenPayload | null; + byteToHex(byte: number): string; + bytesToHex(bytes: Uint8Array): string; + numberToHex(num: number, padLength?: number): string; + hexToBytes(hex: string): Uint8Array; + getRouteTypeName(routeType: import("./types/enums").RouteType): string; + getPayloadTypeName(payloadType: import("./types/enums").PayloadType): string; + getPayloadVersionName(version: import("./types/enums").PayloadVersion): string; + getDeviceRoleName(role: import("./types/enums").DeviceRole): string; + getRequestTypeName(requestType: import("./types/enums").RequestType): string; + getControlSubTypeName(subType: import("./types/enums").ControlSubType): string; +}; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/frontend/lib/meshcore-decoder/dist/index.d.ts.map b/frontend/lib/meshcore-decoder/dist/index.d.ts.map new file mode 100644 index 0000000..a1d0772 --- /dev/null +++ b/frontend/lib/meshcore-decoder/dist/index.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AACjE,OAAO,EAAE,qBAAqB,IAAI,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAGpF,YAAY,EAAE,aAAa,EAAE,eAAe,EAAE,aAAa,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACrH,YAAY,EACV,WAAW,EACX,aAAa,EACb,YAAY,EACZ,gBAAgB,EAChB,cAAc,EACd,kBAAkB,EAClB,kBAAkB,EAClB,UAAU,EACV,WAAW,EACX,eAAe,EACf,kBAAkB,EAClB,yBAAyB,EACzB,0BAA0B,EAC1B,cAAc,EACd,WAAW,EACZ,MAAM,kBAAkB,CAAC;AAC1B,YAAY,EAAE,cAAc,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAG5G,OAAO,EACL,SAAS,EACT,WAAW,EACX,cAAc,EACd,UAAU,EACV,WAAW,EACX,WAAW,EACX,cAAc,EACf,MAAM,eAAe,CAAC;AAGvB,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AACxD,OAAO,EAAE,wBAAwB,EAAE,MAAM,2BAA2B,CAAC;AAGrE,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC7E,OAAO,EACL,gBAAgB,EAChB,kBAAkB,EAClB,qBAAqB,EACrB,iBAAiB,EACjB,kBAAkB,EAClB,qBAAqB,EACtB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,eAAe,EACf,eAAe,EACf,cAAc,EACd,sBAAsB,EACvB,MAAM,oBAAoB,CAAC;AAC5B,YAAY,EAAE,gBAAgB,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAItE,OAAO,KAAK,cAAc,MAAM,oBAAoB,CAAC;AACrD,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,4BAA4B,CAAC;AAE5F,eAAO,MAAM,KAAK;;;;;;;;;;;;;;;;;;;CAQjB,CAAC"} \ No newline at end of file diff --git a/frontend/lib/meshcore-decoder/dist/index.js b/frontend/lib/meshcore-decoder/dist/index.js new file mode 100644 index 0000000..f10bf4d --- /dev/null +++ b/frontend/lib/meshcore-decoder/dist/index.js @@ -0,0 +1,91 @@ +"use strict"; +// MeshCore Packet Decoder +// Copyright (c) 2025 Michael Hart: https://github.com/michaelhart/meshcore-decoder +// MIT License +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { enumerable: true, get: function() { return m[k]; } }; + } + Object.defineProperty(o, k2, desc); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__importStar) || (function () { + var ownKeys = function(o) { + ownKeys = Object.getOwnPropertyNames || function (o) { + var ar = []; + for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; + return ar; + }; + return ownKeys(o); + }; + return function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); + __setModuleDefault(result, mod); + return result; + }; +})(); +Object.defineProperty(exports, "__esModule", { value: true }); +exports.Utils = exports.decodeAuthTokenPayload = exports.parseAuthToken = exports.verifyAuthToken = exports.createAuthToken = exports.getControlSubTypeName = exports.getRequestTypeName = exports.getDeviceRoleName = exports.getPayloadVersionName = exports.getPayloadTypeName = exports.getRouteTypeName = exports.numberToHex = exports.byteToHex = exports.bytesToHex = exports.hexToBytes = exports.Ed25519SignatureVerifier = exports.ChannelCrypto = exports.MeshCoreKeyStore = exports.ControlSubType = exports.RequestType = exports.AdvertFlags = exports.DeviceRole = exports.PayloadVersion = exports.PayloadType = exports.RouteType = exports.MeshCoreDecoder = exports.MeshCorePacketDecoder = void 0; +var packet_decoder_1 = require("./decoder/packet-decoder"); +Object.defineProperty(exports, "MeshCorePacketDecoder", { enumerable: true, get: function () { return packet_decoder_1.MeshCorePacketDecoder; } }); +var packet_decoder_2 = require("./decoder/packet-decoder"); +Object.defineProperty(exports, "MeshCoreDecoder", { enumerable: true, get: function () { return packet_decoder_2.MeshCorePacketDecoder; } }); +// Enum exports +var enums_1 = require("./types/enums"); +Object.defineProperty(exports, "RouteType", { enumerable: true, get: function () { return enums_1.RouteType; } }); +Object.defineProperty(exports, "PayloadType", { enumerable: true, get: function () { return enums_1.PayloadType; } }); +Object.defineProperty(exports, "PayloadVersion", { enumerable: true, get: function () { return enums_1.PayloadVersion; } }); +Object.defineProperty(exports, "DeviceRole", { enumerable: true, get: function () { return enums_1.DeviceRole; } }); +Object.defineProperty(exports, "AdvertFlags", { enumerable: true, get: function () { return enums_1.AdvertFlags; } }); +Object.defineProperty(exports, "RequestType", { enumerable: true, get: function () { return enums_1.RequestType; } }); +Object.defineProperty(exports, "ControlSubType", { enumerable: true, get: function () { return enums_1.ControlSubType; } }); +// Crypto exports +var key_manager_1 = require("./crypto/key-manager"); +Object.defineProperty(exports, "MeshCoreKeyStore", { enumerable: true, get: function () { return key_manager_1.MeshCoreKeyStore; } }); +var channel_crypto_1 = require("./crypto/channel-crypto"); +Object.defineProperty(exports, "ChannelCrypto", { enumerable: true, get: function () { return channel_crypto_1.ChannelCrypto; } }); +var ed25519_verifier_1 = require("./crypto/ed25519-verifier"); +Object.defineProperty(exports, "Ed25519SignatureVerifier", { enumerable: true, get: function () { return ed25519_verifier_1.Ed25519SignatureVerifier; } }); +// Utility exports +var hex_1 = require("./utils/hex"); +Object.defineProperty(exports, "hexToBytes", { enumerable: true, get: function () { return hex_1.hexToBytes; } }); +Object.defineProperty(exports, "bytesToHex", { enumerable: true, get: function () { return hex_1.bytesToHex; } }); +Object.defineProperty(exports, "byteToHex", { enumerable: true, get: function () { return hex_1.byteToHex; } }); +Object.defineProperty(exports, "numberToHex", { enumerable: true, get: function () { return hex_1.numberToHex; } }); +var enum_names_1 = require("./utils/enum-names"); +Object.defineProperty(exports, "getRouteTypeName", { enumerable: true, get: function () { return enum_names_1.getRouteTypeName; } }); +Object.defineProperty(exports, "getPayloadTypeName", { enumerable: true, get: function () { return enum_names_1.getPayloadTypeName; } }); +Object.defineProperty(exports, "getPayloadVersionName", { enumerable: true, get: function () { return enum_names_1.getPayloadVersionName; } }); +Object.defineProperty(exports, "getDeviceRoleName", { enumerable: true, get: function () { return enum_names_1.getDeviceRoleName; } }); +Object.defineProperty(exports, "getRequestTypeName", { enumerable: true, get: function () { return enum_names_1.getRequestTypeName; } }); +Object.defineProperty(exports, "getControlSubTypeName", { enumerable: true, get: function () { return enum_names_1.getControlSubTypeName; } }); +var auth_token_1 = require("./utils/auth-token"); +Object.defineProperty(exports, "createAuthToken", { enumerable: true, get: function () { return auth_token_1.createAuthToken; } }); +Object.defineProperty(exports, "verifyAuthToken", { enumerable: true, get: function () { return auth_token_1.verifyAuthToken; } }); +Object.defineProperty(exports, "parseAuthToken", { enumerable: true, get: function () { return auth_token_1.parseAuthToken; } }); +Object.defineProperty(exports, "decodeAuthTokenPayload", { enumerable: true, get: function () { return auth_token_1.decodeAuthTokenPayload; } }); +const EnumUtils = __importStar(require("./utils/enum-names")); +const HexUtils = __importStar(require("./utils/hex")); +const AuthTokenUtils = __importStar(require("./utils/auth-token")); +const orlp_ed25519_wasm_1 = require("./crypto/orlp-ed25519-wasm"); +exports.Utils = { + ...EnumUtils, + ...HexUtils, + ...AuthTokenUtils, + derivePublicKey: orlp_ed25519_wasm_1.derivePublicKey, + validateKeyPair: orlp_ed25519_wasm_1.validateKeyPair, + sign: orlp_ed25519_wasm_1.sign, + verify: orlp_ed25519_wasm_1.verify +}; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/frontend/lib/meshcore-decoder/dist/index.js.map b/frontend/lib/meshcore-decoder/dist/index.js.map new file mode 100644 index 0000000..967279e --- /dev/null +++ b/frontend/lib/meshcore-decoder/dist/index.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA,0BAA0B;AAC1B,mFAAmF;AACnF,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAEd,2DAAiE;AAAxD,uHAAA,qBAAqB,OAAA;AAC9B,2DAAoF;AAA3E,iHAAA,qBAAqB,OAAmB;AAuBjD,eAAe;AACf,uCAQuB;AAPrB,kGAAA,SAAS,OAAA;AACT,oGAAA,WAAW,OAAA;AACX,uGAAA,cAAc,OAAA;AACd,mGAAA,UAAU,OAAA;AACV,oGAAA,WAAW,OAAA;AACX,oGAAA,WAAW,OAAA;AACX,uGAAA,cAAc,OAAA;AAGhB,iBAAiB;AACjB,oDAAwD;AAA/C,+GAAA,gBAAgB,OAAA;AACzB,0DAAwD;AAA/C,+GAAA,aAAa,OAAA;AACtB,8DAAqE;AAA5D,4HAAA,wBAAwB,OAAA;AAEjC,kBAAkB;AAClB,mCAA6E;AAApE,iGAAA,UAAU,OAAA;AAAE,iGAAA,UAAU,OAAA;AAAE,gGAAA,SAAS,OAAA;AAAE,kGAAA,WAAW,OAAA;AACvD,iDAO4B;AAN1B,8GAAA,gBAAgB,OAAA;AAChB,gHAAA,kBAAkB,OAAA;AAClB,mHAAA,qBAAqB,OAAA;AACrB,+GAAA,iBAAiB,OAAA;AACjB,gHAAA,kBAAkB,OAAA;AAClB,mHAAA,qBAAqB,OAAA;AAEvB,iDAK4B;AAJ1B,6GAAA,eAAe,OAAA;AACf,6GAAA,eAAe,OAAA;AACf,4GAAA,cAAc,OAAA;AACd,oHAAA,sBAAsB,OAAA;AAIxB,8DAAgD;AAChD,sDAAwC;AACxC,mEAAqD;AACrD,kEAA4F;AAE/E,QAAA,KAAK,GAAG;IACnB,GAAG,SAAS;IACZ,GAAG,QAAQ;IACX,GAAG,cAAc;IACjB,eAAe,EAAf,mCAAe;IACf,eAAe,EAAf,mCAAe;IACf,IAAI,EAAJ,wBAAI;IACJ,MAAM,EAAN,0BAAM;CACP,CAAC"} \ No newline at end of file diff --git a/frontend/lib/meshcore-decoder/dist/types/crypto.d.ts b/frontend/lib/meshcore-decoder/dist/types/crypto.d.ts new file mode 100644 index 0000000..430b9a7 --- /dev/null +++ b/frontend/lib/meshcore-decoder/dist/types/crypto.d.ts @@ -0,0 +1,22 @@ +export interface CryptoKeyStore { + nodeKeys: Map; + addNodeKey(publicKey: string, privateKey: string): void; + hasChannelKey(channelHash: string): boolean; + hasNodeKey(publicKey: string): boolean; + getChannelKeys(channelHash: string): string[]; +} +export interface DecryptionOptions { + keyStore?: CryptoKeyStore; + attemptDecryption?: boolean; + includeRawCiphertext?: boolean; +} +export interface DecryptionResult { + success: boolean; + data?: any; + error?: string; +} +export interface ValidationResult { + isValid: boolean; + errors?: string[]; +} +//# sourceMappingURL=crypto.d.ts.map \ No newline at end of file diff --git a/frontend/lib/meshcore-decoder/dist/types/crypto.d.ts.map b/frontend/lib/meshcore-decoder/dist/types/crypto.d.ts.map new file mode 100644 index 0000000..ea7b2bb --- /dev/null +++ b/frontend/lib/meshcore-decoder/dist/types/crypto.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"crypto.d.ts","sourceRoot":"","sources":["../../src/types/crypto.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,cAAc;IAE7B,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAG9B,UAAU,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAGxD,aAAa,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC;IAC5C,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC;IACvC,cAAc,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;CAC/C;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,EAAE,cAAc,CAAC;IAC1B,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,oBAAoB,CAAC,EAAE,OAAO,CAAC;CAChC;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,GAAG,CAAC;IACX,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;CACnB"} \ No newline at end of file diff --git a/frontend/lib/meshcore-decoder/dist/types/crypto.js b/frontend/lib/meshcore-decoder/dist/types/crypto.js new file mode 100644 index 0000000..6783ec0 --- /dev/null +++ b/frontend/lib/meshcore-decoder/dist/types/crypto.js @@ -0,0 +1,5 @@ +"use strict"; +// Copyright (c) 2025 Michael Hart: https://github.com/michaelhart/meshcore-decoder +// MIT License +Object.defineProperty(exports, "__esModule", { value: true }); +//# sourceMappingURL=crypto.js.map \ No newline at end of file diff --git a/frontend/lib/meshcore-decoder/dist/types/crypto.js.map b/frontend/lib/meshcore-decoder/dist/types/crypto.js.map new file mode 100644 index 0000000..52a1376 --- /dev/null +++ b/frontend/lib/meshcore-decoder/dist/types/crypto.js.map @@ -0,0 +1 @@ +{"version":3,"file":"crypto.js","sourceRoot":"","sources":["../../src/types/crypto.ts"],"names":[],"mappings":";AAAA,mFAAmF;AACnF,cAAc"} \ No newline at end of file diff --git a/frontend/lib/meshcore-decoder/dist/types/enums.d.ts b/frontend/lib/meshcore-decoder/dist/types/enums.d.ts new file mode 100644 index 0000000..4c64911 --- /dev/null +++ b/frontend/lib/meshcore-decoder/dist/types/enums.d.ts @@ -0,0 +1,52 @@ +export declare enum RouteType { + TransportFlood = 0, + Flood = 1, + Direct = 2, + TransportDirect = 3 +} +export declare enum PayloadType { + Request = 0, + Response = 1, + TextMessage = 2, + Ack = 3, + Advert = 4, + GroupText = 5, + GroupData = 6, + AnonRequest = 7, + Path = 8, + Trace = 9, + Multipart = 10, + Control = 11, + RawCustom = 15 +} +export declare enum ControlSubType { + NodeDiscoverReq = 128, + NodeDiscoverResp = 144 +} +export declare enum PayloadVersion { + Version1 = 0, + Version2 = 1, + Version3 = 2, + Version4 = 3 +} +export declare enum DeviceRole { + Unknown = 0, + ChatNode = 1, + Repeater = 2, + RoomServer = 3, + Sensor = 4 +} +export declare enum AdvertFlags { + HasLocation = 16, + HasFeature1 = 32, + HasFeature2 = 64, + HasName = 128 +} +export declare enum RequestType { + GetStats = 1, + Keepalive = 2,// deprecated + GetTelemetryData = 3, + GetMinMaxAvgData = 4, + GetAccessList = 5 +} +//# sourceMappingURL=enums.d.ts.map \ No newline at end of file diff --git a/frontend/lib/meshcore-decoder/dist/types/enums.d.ts.map b/frontend/lib/meshcore-decoder/dist/types/enums.d.ts.map new file mode 100644 index 0000000..4831767 --- /dev/null +++ b/frontend/lib/meshcore-decoder/dist/types/enums.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"enums.d.ts","sourceRoot":"","sources":["../../src/types/enums.ts"],"names":[],"mappings":"AAEA,oBAAY,SAAS;IACnB,cAAc,IAAO;IACrB,KAAK,IAAO;IACZ,MAAM,IAAO;IACb,eAAe,IAAO;CACvB;AAED,oBAAY,WAAW;IACrB,OAAO,IAAO;IACd,QAAQ,IAAO;IACf,WAAW,IAAO;IAClB,GAAG,IAAO;IACV,MAAM,IAAO;IACb,SAAS,IAAO;IAChB,SAAS,IAAO;IAChB,WAAW,IAAO;IAClB,IAAI,IAAO;IACX,KAAK,IAAO;IACZ,SAAS,KAAO;IAChB,OAAO,KAAO;IACd,SAAS,KAAO;CACjB;AAGD,oBAAY,cAAc;IACxB,eAAe,MAAO;IACtB,gBAAgB,MAAO;CACxB;AAED,oBAAY,cAAc;IACxB,QAAQ,IAAO;IACf,QAAQ,IAAO;IACf,QAAQ,IAAO;IACf,QAAQ,IAAO;CAChB;AAED,oBAAY,UAAU;IACpB,OAAO,IAAO;IACd,QAAQ,IAAO;IACf,QAAQ,IAAO;IACf,UAAU,IAAO;IACjB,MAAM,IAAO;CACd;AAED,oBAAY,WAAW;IACrB,WAAW,KAAO;IAClB,WAAW,KAAO;IAClB,WAAW,KAAO;IAClB,OAAO,MAAO;CACf;AAED,oBAAY,WAAW;IACrB,QAAQ,IAAO;IACf,SAAS,IAAO,CAAE,aAAa;IAC/B,gBAAgB,IAAO;IACvB,gBAAgB,IAAO;IACvB,aAAa,IAAO;CACrB"} \ No newline at end of file diff --git a/frontend/lib/meshcore-decoder/dist/types/enums.js b/frontend/lib/meshcore-decoder/dist/types/enums.js new file mode 100644 index 0000000..fed3b92 --- /dev/null +++ b/frontend/lib/meshcore-decoder/dist/types/enums.js @@ -0,0 +1,64 @@ +"use strict"; +// Reference: https://github.com/meshcore-dev/MeshCore/blob/main/docs/packet_structure.md +Object.defineProperty(exports, "__esModule", { value: true }); +exports.RequestType = exports.AdvertFlags = exports.DeviceRole = exports.PayloadVersion = exports.ControlSubType = exports.PayloadType = exports.RouteType = void 0; +var RouteType; +(function (RouteType) { + RouteType[RouteType["TransportFlood"] = 0] = "TransportFlood"; + RouteType[RouteType["Flood"] = 1] = "Flood"; + RouteType[RouteType["Direct"] = 2] = "Direct"; + RouteType[RouteType["TransportDirect"] = 3] = "TransportDirect"; +})(RouteType || (exports.RouteType = RouteType = {})); +var PayloadType; +(function (PayloadType) { + PayloadType[PayloadType["Request"] = 0] = "Request"; + PayloadType[PayloadType["Response"] = 1] = "Response"; + PayloadType[PayloadType["TextMessage"] = 2] = "TextMessage"; + PayloadType[PayloadType["Ack"] = 3] = "Ack"; + PayloadType[PayloadType["Advert"] = 4] = "Advert"; + PayloadType[PayloadType["GroupText"] = 5] = "GroupText"; + PayloadType[PayloadType["GroupData"] = 6] = "GroupData"; + PayloadType[PayloadType["AnonRequest"] = 7] = "AnonRequest"; + PayloadType[PayloadType["Path"] = 8] = "Path"; + PayloadType[PayloadType["Trace"] = 9] = "Trace"; + PayloadType[PayloadType["Multipart"] = 10] = "Multipart"; + PayloadType[PayloadType["Control"] = 11] = "Control"; + PayloadType[PayloadType["RawCustom"] = 15] = "RawCustom"; +})(PayloadType || (exports.PayloadType = PayloadType = {})); +// Control packet sub-types (upper 4 bits of first payload byte) +var ControlSubType; +(function (ControlSubType) { + ControlSubType[ControlSubType["NodeDiscoverReq"] = 128] = "NodeDiscoverReq"; + ControlSubType[ControlSubType["NodeDiscoverResp"] = 144] = "NodeDiscoverResp"; +})(ControlSubType || (exports.ControlSubType = ControlSubType = {})); +var PayloadVersion; +(function (PayloadVersion) { + PayloadVersion[PayloadVersion["Version1"] = 0] = "Version1"; + PayloadVersion[PayloadVersion["Version2"] = 1] = "Version2"; + PayloadVersion[PayloadVersion["Version3"] = 2] = "Version3"; + PayloadVersion[PayloadVersion["Version4"] = 3] = "Version4"; +})(PayloadVersion || (exports.PayloadVersion = PayloadVersion = {})); +var DeviceRole; +(function (DeviceRole) { + DeviceRole[DeviceRole["Unknown"] = 0] = "Unknown"; + DeviceRole[DeviceRole["ChatNode"] = 1] = "ChatNode"; + DeviceRole[DeviceRole["Repeater"] = 2] = "Repeater"; + DeviceRole[DeviceRole["RoomServer"] = 3] = "RoomServer"; + DeviceRole[DeviceRole["Sensor"] = 4] = "Sensor"; +})(DeviceRole || (exports.DeviceRole = DeviceRole = {})); +var AdvertFlags; +(function (AdvertFlags) { + AdvertFlags[AdvertFlags["HasLocation"] = 16] = "HasLocation"; + AdvertFlags[AdvertFlags["HasFeature1"] = 32] = "HasFeature1"; + AdvertFlags[AdvertFlags["HasFeature2"] = 64] = "HasFeature2"; + AdvertFlags[AdvertFlags["HasName"] = 128] = "HasName"; +})(AdvertFlags || (exports.AdvertFlags = AdvertFlags = {})); +var RequestType; +(function (RequestType) { + RequestType[RequestType["GetStats"] = 1] = "GetStats"; + RequestType[RequestType["Keepalive"] = 2] = "Keepalive"; + RequestType[RequestType["GetTelemetryData"] = 3] = "GetTelemetryData"; + RequestType[RequestType["GetMinMaxAvgData"] = 4] = "GetMinMaxAvgData"; + RequestType[RequestType["GetAccessList"] = 5] = "GetAccessList"; +})(RequestType || (exports.RequestType = RequestType = {})); +//# sourceMappingURL=enums.js.map \ No newline at end of file diff --git a/frontend/lib/meshcore-decoder/dist/types/enums.js.map b/frontend/lib/meshcore-decoder/dist/types/enums.js.map new file mode 100644 index 0000000..82f3335 --- /dev/null +++ b/frontend/lib/meshcore-decoder/dist/types/enums.js.map @@ -0,0 +1 @@ +{"version":3,"file":"enums.js","sourceRoot":"","sources":["../../src/types/enums.ts"],"names":[],"mappings":";AAAA,yFAAyF;;;AAEzF,IAAY,SAKX;AALD,WAAY,SAAS;IACnB,6DAAqB,CAAA;IACrB,2CAAY,CAAA;IACZ,6CAAa,CAAA;IACb,+DAAsB,CAAA;AACxB,CAAC,EALW,SAAS,yBAAT,SAAS,QAKpB;AAED,IAAY,WAcX;AAdD,WAAY,WAAW;IACrB,mDAAc,CAAA;IACd,qDAAe,CAAA;IACf,2DAAkB,CAAA;IAClB,2CAAU,CAAA;IACV,iDAAa,CAAA;IACb,uDAAgB,CAAA;IAChB,uDAAgB,CAAA;IAChB,2DAAkB,CAAA;IAClB,6CAAW,CAAA;IACX,+CAAY,CAAA;IACZ,wDAAgB,CAAA;IAChB,oDAAc,CAAA;IACd,wDAAgB,CAAA;AAClB,CAAC,EAdW,WAAW,2BAAX,WAAW,QActB;AAED,gEAAgE;AAChE,IAAY,cAGX;AAHD,WAAY,cAAc;IACxB,2EAAsB,CAAA;IACtB,6EAAuB,CAAA;AACzB,CAAC,EAHW,cAAc,8BAAd,cAAc,QAGzB;AAED,IAAY,cAKX;AALD,WAAY,cAAc;IACxB,2DAAe,CAAA;IACf,2DAAe,CAAA;IACf,2DAAe,CAAA;IACf,2DAAe,CAAA;AACjB,CAAC,EALW,cAAc,8BAAd,cAAc,QAKzB;AAED,IAAY,UAMX;AAND,WAAY,UAAU;IACpB,iDAAc,CAAA;IACd,mDAAe,CAAA;IACf,mDAAe,CAAA;IACf,uDAAiB,CAAA;IACjB,+CAAa,CAAA;AACf,CAAC,EANW,UAAU,0BAAV,UAAU,QAMrB;AAED,IAAY,WAKX;AALD,WAAY,WAAW;IACrB,4DAAkB,CAAA;IAClB,4DAAkB,CAAA;IAClB,4DAAkB,CAAA;IAClB,qDAAc,CAAA;AAChB,CAAC,EALW,WAAW,2BAAX,WAAW,QAKtB;AAED,IAAY,WAMX;AAND,WAAY,WAAW;IACrB,qDAAe,CAAA;IACf,uDAAgB,CAAA;IAChB,qEAAuB,CAAA;IACvB,qEAAuB,CAAA;IACvB,+DAAoB,CAAA;AACtB,CAAC,EANW,WAAW,2BAAX,WAAW,QAMtB"} \ No newline at end of file diff --git a/frontend/lib/meshcore-decoder/dist/types/packet.d.ts b/frontend/lib/meshcore-decoder/dist/types/packet.d.ts new file mode 100644 index 0000000..df9c8c7 --- /dev/null +++ b/frontend/lib/meshcore-decoder/dist/types/packet.d.ts @@ -0,0 +1,57 @@ +import { RouteType, PayloadType, PayloadVersion } from './enums'; +import { PayloadData } from './payloads'; +export interface DecodedPacket { + messageHash: string; + routeType: RouteType; + payloadType: PayloadType; + payloadVersion: PayloadVersion; + transportCodes?: [number, number]; + pathLength: number; + pathHashSize?: number; + path: string[] | null; + payload: { + raw: string; + decoded: PayloadData | null; + }; + totalBytes: number; + isValid: boolean; + errors?: string[]; +} +export interface PacketStructure { + segments: PacketSegment[]; + totalBytes: number; + rawHex: string; + messageHash: string; + payload: { + segments: PayloadSegment[]; + hex: string; + startByte: number; + type: string; + }; +} +export interface PacketSegment { + name: string; + description: string; + startByte: number; + endByte: number; + value: string; + headerBreakdown?: HeaderBreakdown; +} +export interface PayloadSegment { + name: string; + description: string; + startByte: number; + endByte: number; + value: string; + decryptedMessage?: string; +} +export interface HeaderBreakdown { + fullBinary: string; + fields: Array<{ + bits: string; + field: string; + value: string; + binary: string; + }>; +} +//# sourceMappingURL=packet.d.ts.map \ No newline at end of file diff --git a/frontend/lib/meshcore-decoder/dist/types/packet.d.ts.map b/frontend/lib/meshcore-decoder/dist/types/packet.d.ts.map new file mode 100644 index 0000000..d21fdf9 --- /dev/null +++ b/frontend/lib/meshcore-decoder/dist/types/packet.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"packet.d.ts","sourceRoot":"","sources":["../../src/types/packet.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AACjE,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAGzC,MAAM,WAAW,aAAa;IAE5B,WAAW,EAAE,MAAM,CAAC;IAGpB,SAAS,EAAE,SAAS,CAAC;IACrB,WAAW,EAAE,WAAW,CAAC;IACzB,cAAc,EAAE,cAAc,CAAC;IAG/B,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAClC,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;IAGtB,OAAO,EAAE;QACP,GAAG,EAAE,MAAM,CAAC;QACZ,OAAO,EAAE,WAAW,GAAG,IAAI,CAAC;KAC7B,CAAC;IAGF,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;CACnB;AAGD,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,aAAa,EAAE,CAAC;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE;QACP,QAAQ,EAAE,cAAc,EAAE,CAAC;QAC3B,GAAG,EAAE,MAAM,CAAC;QACZ,SAAS,EAAE,MAAM,CAAC;QAClB,IAAI,EAAE,MAAM,CAAC;KACd,CAAC;CACH;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,eAAe,CAAC,EAAE,eAAe,CAAC;CACnC;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,eAAe;IAC9B,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,KAAK,CAAC;QACZ,IAAI,EAAE,MAAM,CAAC;QACb,KAAK,EAAE,MAAM,CAAC;QACd,KAAK,EAAE,MAAM,CAAC;QACd,MAAM,EAAE,MAAM,CAAC;KAChB,CAAC,CAAC;CACJ"} \ No newline at end of file diff --git a/frontend/lib/meshcore-decoder/dist/types/packet.js b/frontend/lib/meshcore-decoder/dist/types/packet.js new file mode 100644 index 0000000..c0bfce0 --- /dev/null +++ b/frontend/lib/meshcore-decoder/dist/types/packet.js @@ -0,0 +1,3 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +//# sourceMappingURL=packet.js.map \ No newline at end of file diff --git a/frontend/lib/meshcore-decoder/dist/types/packet.js.map b/frontend/lib/meshcore-decoder/dist/types/packet.js.map new file mode 100644 index 0000000..58a87ba --- /dev/null +++ b/frontend/lib/meshcore-decoder/dist/types/packet.js.map @@ -0,0 +1 @@ +{"version":3,"file":"packet.js","sourceRoot":"","sources":["../../src/types/packet.ts"],"names":[],"mappings":""} \ No newline at end of file diff --git a/frontend/lib/meshcore-decoder/dist/types/payloads.d.ts b/frontend/lib/meshcore-decoder/dist/types/payloads.d.ts new file mode 100644 index 0000000..8b96e38 --- /dev/null +++ b/frontend/lib/meshcore-decoder/dist/types/payloads.d.ts @@ -0,0 +1,128 @@ +import { PayloadType, PayloadVersion, DeviceRole, RequestType, ControlSubType } from './enums'; +export interface BasePayload { + type: PayloadType; + version: PayloadVersion; + isValid: boolean; + errors?: string[]; +} +export interface AdvertPayload extends BasePayload { + publicKey: string; + timestamp: number; + signature: string; + signatureValid?: boolean; + signatureError?: string; + appData: { + flags: number; + deviceRole: DeviceRole; + hasLocation: boolean; + hasName: boolean; + location?: { + latitude: number; + longitude: number; + }; + name?: string; + }; +} +export interface TracePayload extends BasePayload { + traceTag: string; + authCode: number; + flags: number; + pathHashes: string[]; + snrValues?: number[]; +} +export interface GroupTextPayload extends BasePayload { + channelHash: string; + cipherMac: string; + ciphertext: string; + ciphertextLength: number; + decrypted?: { + timestamp: number; + flags: number; + sender?: string; + message: string; + }; +} +export interface RequestPayload extends BasePayload { + destinationHash: string; + sourceHash: string; + cipherMac: string; + ciphertext: string; + timestamp: number; + requestType: RequestType; + requestData?: string; + decrypted?: { + timestamp: number; + requestType: RequestType; + requestData?: string; + }; +} +export interface TextMessagePayload extends BasePayload { + destinationHash: string; + sourceHash: string; + cipherMac: string; + ciphertext: string; + ciphertextLength: number; + decrypted?: { + timestamp: number; + flags: number; + attempt: number; + message: string; + }; +} +export interface AnonRequestPayload extends BasePayload { + destinationHash: string; + senderPublicKey: string; + cipherMac: string; + ciphertext: string; + ciphertextLength: number; + decrypted?: { + timestamp: number; + syncTimestamp?: number; + password: string; + }; +} +export interface AckPayload extends BasePayload { + checksum: string; +} +export interface PathPayload extends BasePayload { + pathLength: number; + pathHashSize?: number; + pathHashes: string[]; + extraType: number; + extraData: string; +} +export interface ResponsePayload extends BasePayload { + destinationHash: string; + sourceHash: string; + cipherMac: string; + ciphertext: string; + ciphertextLength: number; + decrypted?: { + tag: number; + content: string; + }; +} +export interface ControlPayloadBase extends BasePayload { + subType: ControlSubType; + rawFlags: number; +} +export interface ControlDiscoverReqPayload extends ControlPayloadBase { + subType: ControlSubType.NodeDiscoverReq; + prefixOnly: boolean; + typeFilter: number; + typeFilterNames: string[]; + tag: number; + since: number; +} +export interface ControlDiscoverRespPayload extends ControlPayloadBase { + subType: ControlSubType.NodeDiscoverResp; + nodeType: DeviceRole; + nodeTypeName: string; + snr: number; + tag: number; + publicKey: string; + publicKeyLength: number; +} +export type ControlPayload = ControlDiscoverReqPayload | ControlDiscoverRespPayload; +export type PayloadData = AdvertPayload | TracePayload | GroupTextPayload | RequestPayload | TextMessagePayload | AnonRequestPayload | AckPayload | PathPayload | ResponsePayload | ControlPayload; +//# sourceMappingURL=payloads.d.ts.map \ No newline at end of file diff --git a/frontend/lib/meshcore-decoder/dist/types/payloads.d.ts.map b/frontend/lib/meshcore-decoder/dist/types/payloads.d.ts.map new file mode 100644 index 0000000..4b85ee2 --- /dev/null +++ b/frontend/lib/meshcore-decoder/dist/types/payloads.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"payloads.d.ts","sourceRoot":"","sources":["../../src/types/payloads.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/frontend/lib/meshcore-decoder/dist/types/payloads.js b/frontend/lib/meshcore-decoder/dist/types/payloads.js new file mode 100644 index 0000000..c17ddda --- /dev/null +++ b/frontend/lib/meshcore-decoder/dist/types/payloads.js @@ -0,0 +1,3 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +//# sourceMappingURL=payloads.js.map \ No newline at end of file diff --git a/frontend/lib/meshcore-decoder/dist/types/payloads.js.map b/frontend/lib/meshcore-decoder/dist/types/payloads.js.map new file mode 100644 index 0000000..c93ec59 --- /dev/null +++ b/frontend/lib/meshcore-decoder/dist/types/payloads.js.map @@ -0,0 +1 @@ +{"version":3,"file":"payloads.js","sourceRoot":"","sources":["../../src/types/payloads.ts"],"names":[],"mappings":""} \ No newline at end of file diff --git a/frontend/lib/meshcore-decoder/dist/utils/auth-token.d.ts b/frontend/lib/meshcore-decoder/dist/utils/auth-token.d.ts new file mode 100644 index 0000000..e9254c9 --- /dev/null +++ b/frontend/lib/meshcore-decoder/dist/utils/auth-token.d.ts @@ -0,0 +1,58 @@ +/** + * JWT-style token payload for MeshCore authentication + */ +export interface AuthTokenPayload { + /** Public key of the signer (32 bytes hex) */ + publicKey: string; + /** Unix timestamp when token was issued */ + iat: number; + /** Unix timestamp when token expires (optional) */ + exp?: number; + /** Audience claim (optional) */ + aud?: string; + /** Custom claims */ + [key: string]: any; +} +/** + * Encoded auth token structure + */ +export interface AuthToken { + /** Base64url-encoded header */ + header: string; + /** Base64url-encoded payload */ + payload: string; + /** Hex-encoded Ed25519 signature */ + signature: string; +} +/** + * Create a signed authentication token + * + * @param payload - Token payload containing claims + * @param privateKeyHex - 64-byte private key in hex format (orlp/ed25519 format) + * @param publicKeyHex - 32-byte public key in hex format + * @returns JWT-style token string in format: header.payload.signature + */ +export declare function createAuthToken(payload: AuthTokenPayload, privateKeyHex: string, publicKeyHex: string): Promise; +/** + * Verify and decode an authentication token + * + * @param token - JWT-style token string + * @param expectedPublicKeyHex - Expected public key in hex format (optional, will check against payload if provided) + * @returns Decoded payload if valid, null if invalid + */ +export declare function verifyAuthToken(token: string, expectedPublicKeyHex?: string): Promise; +/** + * Parse a token without verifying (useful for debugging) + * + * @param token - JWT-style token string + * @returns Parsed token structure or null if invalid format + */ +export declare function parseAuthToken(token: string): AuthToken | null; +/** + * Decode token payload without verification (useful for debugging) + * + * @param token - JWT-style token string + * @returns Decoded payload or null if invalid format + */ +export declare function decodeAuthTokenPayload(token: string): AuthTokenPayload | null; +//# sourceMappingURL=auth-token.d.ts.map \ No newline at end of file diff --git a/frontend/lib/meshcore-decoder/dist/utils/auth-token.d.ts.map b/frontend/lib/meshcore-decoder/dist/utils/auth-token.d.ts.map new file mode 100644 index 0000000..e1ddb8a --- /dev/null +++ b/frontend/lib/meshcore-decoder/dist/utils/auth-token.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"auth-token.d.ts","sourceRoot":"","sources":["../../src/utils/auth-token.ts"],"names":[],"mappings":"AAMA;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,8CAA8C;IAC9C,SAAS,EAAE,MAAM,CAAC;IAClB,2CAA2C;IAC3C,GAAG,EAAE,MAAM,CAAC;IACZ,mDAAmD;IACnD,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,gCAAgC;IAChC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,oBAAoB;IACpB,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;CACpB;AAED;;GAEG;AACH,MAAM,WAAW,SAAS;IACxB,+BAA+B;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,gCAAgC;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,oCAAoC;IACpC,SAAS,EAAE,MAAM,CAAC;CACnB;AAgDD;;;;;;;GAOG;AACH,wBAAsB,eAAe,CACnC,OAAO,EAAE,gBAAgB,EACzB,aAAa,EAAE,MAAM,EACrB,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC,MAAM,CAAC,CAwCjB;AAED;;;;;;GAMG;AACH,wBAAsB,eAAe,CACnC,KAAK,EAAE,MAAM,EACb,oBAAoB,CAAC,EAAE,MAAM,GAC5B,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC,CA0DlC;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAe9D;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,MAAM,GAAG,gBAAgB,GAAG,IAAI,CAa7E"} \ No newline at end of file diff --git a/frontend/lib/meshcore-decoder/dist/utils/auth-token.js b/frontend/lib/meshcore-decoder/dist/utils/auth-token.js new file mode 100644 index 0000000..e381a33 --- /dev/null +++ b/frontend/lib/meshcore-decoder/dist/utils/auth-token.js @@ -0,0 +1,194 @@ +"use strict"; +// Copyright (c) 2025 Michael Hart: https://github.com/michaelhart/meshcore-decoder +// MIT License +Object.defineProperty(exports, "__esModule", { value: true }); +exports.createAuthToken = createAuthToken; +exports.verifyAuthToken = verifyAuthToken; +exports.parseAuthToken = parseAuthToken; +exports.decodeAuthTokenPayload = decodeAuthTokenPayload; +const orlp_ed25519_wasm_1 = require("../crypto/orlp-ed25519-wasm"); +const hex_1 = require("./hex"); +/** + * Base64url encode (URL-safe base64 without padding) + */ +function base64urlEncode(data) { + // Convert to base64 + let base64 = ''; + if (typeof Buffer !== 'undefined') { + // Node.js + base64 = Buffer.from(data).toString('base64'); + } + else { + // Browser + const binary = String.fromCharCode(...Array.from(data)); + base64 = btoa(binary); + } + // Make URL-safe and remove padding + return base64 + .replace(/\+/g, '-') + .replace(/\//g, '_') + .replace(/=/g, ''); +} +/** + * Base64url decode + */ +function base64urlDecode(str) { + // Add padding back + let base64 = str.replace(/-/g, '+').replace(/_/g, '/'); + while (base64.length % 4) { + base64 += '='; + } + if (typeof Buffer !== 'undefined') { + // Node.js + return new Uint8Array(Buffer.from(base64, 'base64')); + } + else { + // Browser + const binary = atob(base64); + const bytes = new Uint8Array(binary.length); + for (let i = 0; i < binary.length; i++) { + bytes[i] = binary.charCodeAt(i); + } + return bytes; + } +} +/** + * Create a signed authentication token + * + * @param payload - Token payload containing claims + * @param privateKeyHex - 64-byte private key in hex format (orlp/ed25519 format) + * @param publicKeyHex - 32-byte public key in hex format + * @returns JWT-style token string in format: header.payload.signature + */ +async function createAuthToken(payload, privateKeyHex, publicKeyHex) { + // Create header + const header = { + alg: 'Ed25519', + typ: 'JWT' + }; + // Ensure publicKey is in the payload (normalize to uppercase) + if (!payload.publicKey) { + payload.publicKey = publicKeyHex.toUpperCase(); + } + else { + payload.publicKey = payload.publicKey.toUpperCase(); + } + // Ensure iat is set + if (!payload.iat) { + payload.iat = Math.floor(Date.now() / 1000); + } + // Encode header and payload + const headerJson = JSON.stringify(header); + const payloadJson = JSON.stringify(payload); + const headerBytes = new TextEncoder().encode(headerJson); + const payloadBytes = new TextEncoder().encode(payloadJson); + const headerEncoded = base64urlEncode(headerBytes); + const payloadEncoded = base64urlEncode(payloadBytes); + // Create signing input: header.payload + const signingInput = `${headerEncoded}.${payloadEncoded}`; + const signingInputBytes = new TextEncoder().encode(signingInput); + const signingInputHex = (0, hex_1.bytesToHex)(signingInputBytes); + // Sign the input using the normalized public key from payload + const signatureHex = await (0, orlp_ed25519_wasm_1.sign)(signingInputHex, privateKeyHex, payload.publicKey); + // Return token in JWT format: header.payload.signature + // Note: We use hex for signature instead of base64url for consistency with MeshCore + return `${headerEncoded}.${payloadEncoded}.${signatureHex}`; +} +/** + * Verify and decode an authentication token + * + * @param token - JWT-style token string + * @param expectedPublicKeyHex - Expected public key in hex format (optional, will check against payload if provided) + * @returns Decoded payload if valid, null if invalid + */ +async function verifyAuthToken(token, expectedPublicKeyHex) { + try { + // Parse token + const parts = token.split('.'); + if (parts.length !== 3) { + return null; + } + const [headerEncoded, payloadEncoded, signatureHex] = parts; + // Decode header and payload + const headerBytes = base64urlDecode(headerEncoded); + const payloadBytes = base64urlDecode(payloadEncoded); + const headerJson = new TextDecoder().decode(headerBytes); + const payloadJson = new TextDecoder().decode(payloadBytes); + const header = JSON.parse(headerJson); + const payload = JSON.parse(payloadJson); + // Validate header + if (header.alg !== 'Ed25519' || header.typ !== 'JWT') { + return null; + } + // Validate payload has required fields + if (!payload.publicKey || !payload.iat) { + return null; + } + // Check if expected public key matches + if (expectedPublicKeyHex && payload.publicKey.toUpperCase() !== expectedPublicKeyHex.toUpperCase()) { + return null; + } + // Check expiration if present + if (payload.exp) { + const now = Math.floor(Date.now() / 1000); + if (now > payload.exp) { + return null; // Token expired + } + } + // Verify signature + const signingInput = `${headerEncoded}.${payloadEncoded}`; + const signingInputBytes = new TextEncoder().encode(signingInput); + const signingInputHex = (0, hex_1.bytesToHex)(signingInputBytes); + const isValid = await (0, orlp_ed25519_wasm_1.verify)(signatureHex, signingInputHex, payload.publicKey); + if (!isValid) { + return null; + } + return payload; + } + catch (error) { + return null; + } +} +/** + * Parse a token without verifying (useful for debugging) + * + * @param token - JWT-style token string + * @returns Parsed token structure or null if invalid format + */ +function parseAuthToken(token) { + try { + const parts = token.split('.'); + if (parts.length !== 3) { + return null; + } + return { + header: parts[0], + payload: parts[1], + signature: parts[2] + }; + } + catch (error) { + return null; + } +} +/** + * Decode token payload without verification (useful for debugging) + * + * @param token - JWT-style token string + * @returns Decoded payload or null if invalid format + */ +function decodeAuthTokenPayload(token) { + try { + const parts = token.split('.'); + if (parts.length !== 3) { + return null; + } + const payloadBytes = base64urlDecode(parts[1]); + const payloadJson = new TextDecoder().decode(payloadBytes); + return JSON.parse(payloadJson); + } + catch (error) { + return null; + } +} +//# sourceMappingURL=auth-token.js.map \ No newline at end of file diff --git a/frontend/lib/meshcore-decoder/dist/utils/auth-token.js.map b/frontend/lib/meshcore-decoder/dist/utils/auth-token.js.map new file mode 100644 index 0000000..92bbf47 --- /dev/null +++ b/frontend/lib/meshcore-decoder/dist/utils/auth-token.js.map @@ -0,0 +1 @@ +{"version":3,"file":"auth-token.js","sourceRoot":"","sources":["../../src/utils/auth-token.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/frontend/lib/meshcore-decoder/dist/utils/enum-names.d.ts b/frontend/lib/meshcore-decoder/dist/utils/enum-names.d.ts new file mode 100644 index 0000000..a843395 --- /dev/null +++ b/frontend/lib/meshcore-decoder/dist/utils/enum-names.d.ts @@ -0,0 +1,26 @@ +import { RouteType, PayloadType, PayloadVersion, DeviceRole, RequestType, ControlSubType } from '../types/enums'; +/** + * Get human-readable name for RouteType enum value + */ +export declare function getRouteTypeName(routeType: RouteType): string; +/** + * Get human-readable name for PayloadType enum value + */ +export declare function getPayloadTypeName(payloadType: PayloadType): string; +/** + * Get human-readable name for PayloadVersion enum value + */ +export declare function getPayloadVersionName(version: PayloadVersion): string; +/** + * Get human-readable name for DeviceRole enum value + */ +export declare function getDeviceRoleName(role: DeviceRole): string; +/** + * Get human-readable name for RequestType enum value + */ +export declare function getRequestTypeName(requestType: RequestType): string; +/** + * Get human-readable name for ControlSubType enum value + */ +export declare function getControlSubTypeName(subType: ControlSubType): string; +//# sourceMappingURL=enum-names.d.ts.map \ No newline at end of file diff --git a/frontend/lib/meshcore-decoder/dist/utils/enum-names.d.ts.map b/frontend/lib/meshcore-decoder/dist/utils/enum-names.d.ts.map new file mode 100644 index 0000000..6b2f514 --- /dev/null +++ b/frontend/lib/meshcore-decoder/dist/utils/enum-names.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"enum-names.d.ts","sourceRoot":"","sources":["../../src/utils/enum-names.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,cAAc,EAAE,UAAU,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAEjH;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,SAAS,GAAG,MAAM,CAQ7D;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,WAAW,GAAG,MAAM,CAiBnE;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,cAAc,GAAG,MAAM,CAQrE;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,CAS1D;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,WAAW,GAAG,MAAM,CASnE;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,cAAc,GAAG,MAAM,CAMrE"} \ No newline at end of file diff --git a/frontend/lib/meshcore-decoder/dist/utils/enum-names.js b/frontend/lib/meshcore-decoder/dist/utils/enum-names.js new file mode 100644 index 0000000..dcbbf94 --- /dev/null +++ b/frontend/lib/meshcore-decoder/dist/utils/enum-names.js @@ -0,0 +1,93 @@ +"use strict"; +// Copyright (c) 2025 Michael Hart: https://github.com/michaelhart/meshcore-decoder +// MIT License +Object.defineProperty(exports, "__esModule", { value: true }); +exports.getRouteTypeName = getRouteTypeName; +exports.getPayloadTypeName = getPayloadTypeName; +exports.getPayloadVersionName = getPayloadVersionName; +exports.getDeviceRoleName = getDeviceRoleName; +exports.getRequestTypeName = getRequestTypeName; +exports.getControlSubTypeName = getControlSubTypeName; +const enums_1 = require("../types/enums"); +/** + * Get human-readable name for RouteType enum value + */ +function getRouteTypeName(routeType) { + switch (routeType) { + case enums_1.RouteType.Flood: return 'Flood'; + case enums_1.RouteType.Direct: return 'Direct'; + case enums_1.RouteType.TransportFlood: return 'TransportFlood'; + case enums_1.RouteType.TransportDirect: return 'TransportDirect'; + default: return `Unknown (${routeType})`; + } +} +/** + * Get human-readable name for PayloadType enum value + */ +function getPayloadTypeName(payloadType) { + switch (payloadType) { + case enums_1.PayloadType.RawCustom: return 'RawCustom'; + case enums_1.PayloadType.Trace: return 'Trace'; + case enums_1.PayloadType.Advert: return 'Advert'; + case enums_1.PayloadType.GroupText: return 'GroupText'; + case enums_1.PayloadType.GroupData: return 'GroupData'; + case enums_1.PayloadType.Request: return 'Request'; + case enums_1.PayloadType.Response: return 'Response'; + case enums_1.PayloadType.TextMessage: return 'TextMessage'; + case enums_1.PayloadType.AnonRequest: return 'AnonRequest'; + case enums_1.PayloadType.Ack: return 'Ack'; + case enums_1.PayloadType.Path: return 'Path'; + case enums_1.PayloadType.Multipart: return 'Multipart'; + case enums_1.PayloadType.Control: return 'Control'; + default: return `Unknown (0x${payloadType.toString(16)})`; + } +} +/** + * Get human-readable name for PayloadVersion enum value + */ +function getPayloadVersionName(version) { + switch (version) { + case enums_1.PayloadVersion.Version1: return 'Version 1'; + case enums_1.PayloadVersion.Version2: return 'Version 2'; + case enums_1.PayloadVersion.Version3: return 'Version 3'; + case enums_1.PayloadVersion.Version4: return 'Version 4'; + default: return `Unknown (${version})`; + } +} +/** + * Get human-readable name for DeviceRole enum value + */ +function getDeviceRoleName(role) { + switch (role) { + case enums_1.DeviceRole.Unknown: return 'Unknown'; + case enums_1.DeviceRole.ChatNode: return 'Chat Node'; + case enums_1.DeviceRole.Repeater: return 'Repeater'; + case enums_1.DeviceRole.RoomServer: return 'Room Server'; + case enums_1.DeviceRole.Sensor: return 'Sensor'; + default: return `Unknown (${role})`; + } +} +/** + * Get human-readable name for RequestType enum value + */ +function getRequestTypeName(requestType) { + switch (requestType) { + case enums_1.RequestType.GetStats: return 'Get Stats'; + case enums_1.RequestType.Keepalive: return 'Keepalive (deprecated)'; + case enums_1.RequestType.GetTelemetryData: return 'Get Telemetry Data'; + case enums_1.RequestType.GetMinMaxAvgData: return 'Get Min/Max/Avg Data'; + case enums_1.RequestType.GetAccessList: return 'Get Access List'; + default: return `Unknown (${requestType})`; + } +} +/** + * Get human-readable name for ControlSubType enum value + */ +function getControlSubTypeName(subType) { + switch (subType) { + case enums_1.ControlSubType.NodeDiscoverReq: return 'Node Discover Request'; + case enums_1.ControlSubType.NodeDiscoverResp: return 'Node Discover Response'; + default: return `Unknown (0x${subType.toString(16)})`; + } +} +//# sourceMappingURL=enum-names.js.map \ No newline at end of file diff --git a/frontend/lib/meshcore-decoder/dist/utils/enum-names.js.map b/frontend/lib/meshcore-decoder/dist/utils/enum-names.js.map new file mode 100644 index 0000000..8d06858 --- /dev/null +++ b/frontend/lib/meshcore-decoder/dist/utils/enum-names.js.map @@ -0,0 +1 @@ +{"version":3,"file":"enum-names.js","sourceRoot":"","sources":["../../src/utils/enum-names.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/frontend/lib/meshcore-decoder/dist/utils/hex.d.ts b/frontend/lib/meshcore-decoder/dist/utils/hex.d.ts new file mode 100644 index 0000000..6c5a00d --- /dev/null +++ b/frontend/lib/meshcore-decoder/dist/utils/hex.d.ts @@ -0,0 +1,17 @@ +/** + * Convert a single byte to uppercase hex string + */ +export declare function byteToHex(byte: number): string; +/** + * Convert a Uint8Array to uppercase hex string + */ +export declare function bytesToHex(bytes: Uint8Array): string; +/** + * Convert a number to uppercase hex string with specified padding + */ +export declare function numberToHex(num: number, padLength?: number): string; +/** + * Convert hex string to Uint8Array + */ +export declare function hexToBytes(hex: string): Uint8Array; +//# sourceMappingURL=hex.d.ts.map \ No newline at end of file diff --git a/frontend/lib/meshcore-decoder/dist/utils/hex.d.ts.map b/frontend/lib/meshcore-decoder/dist/utils/hex.d.ts.map new file mode 100644 index 0000000..1f7fb93 --- /dev/null +++ b/frontend/lib/meshcore-decoder/dist/utils/hex.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"hex.d.ts","sourceRoot":"","sources":["../../src/utils/hex.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE9C;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAEpD;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,GAAE,MAAU,GAAG,MAAM,CAEtE;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU,CAmBlD"} \ No newline at end of file diff --git a/frontend/lib/meshcore-decoder/dist/utils/hex.js b/frontend/lib/meshcore-decoder/dist/utils/hex.js new file mode 100644 index 0000000..7ec2e4b --- /dev/null +++ b/frontend/lib/meshcore-decoder/dist/utils/hex.js @@ -0,0 +1,44 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.byteToHex = byteToHex; +exports.bytesToHex = bytesToHex; +exports.numberToHex = numberToHex; +exports.hexToBytes = hexToBytes; +/** + * Convert a single byte to uppercase hex string + */ +function byteToHex(byte) { + return byte.toString(16).padStart(2, '0').toUpperCase(); +} +/** + * Convert a Uint8Array to uppercase hex string + */ +function bytesToHex(bytes) { + return Array.from(bytes).map(byteToHex).join(''); +} +/** + * Convert a number to uppercase hex string with specified padding + */ +function numberToHex(num, padLength = 8) { + return (num >>> 0).toString(16).padStart(padLength, '0').toUpperCase(); +} +/** + * Convert hex string to Uint8Array + */ +function hexToBytes(hex) { + // Remove any whitespace and convert to uppercase + const cleanHex = hex.replace(/\s/g, '').toUpperCase(); + // Validate hex string + if (!/^[0-9A-F]*$/.test(cleanHex)) { + throw new Error(`Invalid hex string: invalid characters at position 0`); + } + if (cleanHex.length % 2 !== 0) { + throw new Error('Invalid hex string: odd length'); + } + const bytes = new Uint8Array(cleanHex.length / 2); + for (let i = 0; i < cleanHex.length; i += 2) { + bytes[i / 2] = parseInt(cleanHex.substr(i, 2), 16); + } + return bytes; +} +//# sourceMappingURL=hex.js.map \ No newline at end of file diff --git a/frontend/lib/meshcore-decoder/dist/utils/hex.js.map b/frontend/lib/meshcore-decoder/dist/utils/hex.js.map new file mode 100644 index 0000000..77f8aee --- /dev/null +++ b/frontend/lib/meshcore-decoder/dist/utils/hex.js.map @@ -0,0 +1 @@ +{"version":3,"file":"hex.js","sourceRoot":"","sources":["../../src/utils/hex.ts"],"names":[],"mappings":";;AAGA,8BAEC;AAKD,gCAEC;AAKD,kCAEC;AAKD,gCAmBC;AA3CD;;GAEG;AACH,SAAgB,SAAS,CAAC,IAAY;IACpC,OAAO,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,WAAW,EAAE,CAAC;AAC1D,CAAC;AAED;;GAEG;AACH,SAAgB,UAAU,CAAC,KAAiB;IAC1C,OAAO,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;AACnD,CAAC;AAED;;GAEG;AACH,SAAgB,WAAW,CAAC,GAAW,EAAE,YAAoB,CAAC;IAC5D,OAAO,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC,WAAW,EAAE,CAAC;AACzE,CAAC;AAED;;GAEG;AACH,SAAgB,UAAU,CAAC,GAAW;IACpC,iDAAiD;IACjD,MAAM,QAAQ,GAAG,GAAG,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC;IAEtD,sBAAsB;IACtB,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;QAClC,MAAM,IAAI,KAAK,CAAC,sDAAsD,CAAC,CAAC;IAC1E,CAAC;IAED,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;QAC9B,MAAM,IAAI,KAAK,CAAC,gCAAgC,CAAC,CAAC;IACpD,CAAC;IAED,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAClD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,QAAQ,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;QAC5C,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IACrD,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC"} \ No newline at end of file diff --git a/frontend/lib/meshcore-decoder/lib/build-wasm.sh b/frontend/lib/meshcore-decoder/lib/build-wasm.sh new file mode 100644 index 0000000..b816ecf --- /dev/null +++ b/frontend/lib/meshcore-decoder/lib/build-wasm.sh @@ -0,0 +1,27 @@ +#!/bin/bash + +# Build orlp/ed25519 WebAssembly module + +set -e + +echo "Building orlp/ed25519 WebAssembly module..." + +# Compile all orlp source files + our wrapper to WASM +emcc \ + -O3 \ + -s WASM=1 \ + -s EXPORTED_FUNCTIONS='["_orlp_derive_public_key", "_orlp_validate_keypair", "_orlp_sign", "_orlp_verify"]' \ + -s EXPORTED_RUNTIME_METHODS='["ccall", "cwrap", "HEAPU8", "HEAP8", "HEAPU32", "HEAP32"]' \ + -s MODULARIZE=1 \ + -s EXPORT_NAME="OrlpEd25519" \ + -s ALLOW_MEMORY_GROWTH=1 \ + -s NO_EXIT_RUNTIME=1 \ + -I orlp-ed25519/src \ + orlp-ed25519/src/*.c \ + orlp-ed25519-wrapper.c \ + -o orlp-ed25519.js + +echo "WebAssembly module built successfully!" +echo "Generated files:" +echo " - orlp-ed25519.js (JavaScript loader)" +echo " - orlp-ed25519.wasm (WebAssembly binary)" diff --git a/frontend/lib/meshcore-decoder/lib/orlp-ed25519-wrapper.c b/frontend/lib/meshcore-decoder/lib/orlp-ed25519-wrapper.c new file mode 100644 index 0000000..f1254be --- /dev/null +++ b/frontend/lib/meshcore-decoder/lib/orlp-ed25519-wrapper.c @@ -0,0 +1,65 @@ +#include "orlp-ed25519/src/ed25519.h" +#include + +// WebAssembly wrapper for orlp/ed25519 key derivation + +EMSCRIPTEN_KEEPALIVE +int orlp_derive_public_key(unsigned char *public_key, const unsigned char *private_key) { + // Use orlp's ed25519_create_keypair logic but only for key derivation + // The private_key is already the 64-byte orlp format + + // Extract the first 32 bytes (the actual scalar) + unsigned char scalar[32]; + for (int i = 0; i < 32; i++) { + scalar[i] = private_key[i]; + } + + // Check orlp precondition + if (scalar[31] > 127) { + return -1; // Invalid scalar + } + + // Use orlp's internal ge_scalarmult_base function + // This is declared in ge.h but we need to access it + extern void ge_scalarmult_base(void *h, const unsigned char *a); + extern void ge_p3_tobytes(unsigned char *s, const void *h); + + // Allocate space for ge_p3 point (we don't know the exact size, but it's small) + unsigned char point[128]; // Should be enough for ge_p3 structure + + // Perform scalar multiplication: point = scalar * base_point + ge_scalarmult_base(point, scalar); + + // Convert point to bytes + ge_p3_tobytes(public_key, point); + + return 0; // Success +} + +EMSCRIPTEN_KEEPALIVE +int orlp_validate_keypair(const unsigned char *public_key, const unsigned char *private_key) { + unsigned char derived_public[32]; + + if (orlp_derive_public_key(derived_public, private_key) != 0) { + return 0; // Derivation failed + } + + // Compare derived public key with expected + for (int i = 0; i < 32; i++) { + if (derived_public[i] != public_key[i]) { + return 0; // Mismatch + } + } + + return 1; // Match +} + +EMSCRIPTEN_KEEPALIVE +void orlp_sign(unsigned char *signature, const unsigned char *message, size_t message_len, const unsigned char *public_key, const unsigned char *private_key) { + ed25519_sign(signature, message, message_len, public_key, private_key); +} + +EMSCRIPTEN_KEEPALIVE +int orlp_verify(const unsigned char *signature, const unsigned char *message, size_t message_len, const unsigned char *public_key) { + return ed25519_verify(signature, message, message_len, public_key); +} diff --git a/frontend/lib/meshcore-decoder/lib/orlp-ed25519.js b/frontend/lib/meshcore-decoder/lib/orlp-ed25519.js new file mode 100644 index 0000000..f4bb0b2 --- /dev/null +++ b/frontend/lib/meshcore-decoder/lib/orlp-ed25519.js @@ -0,0 +1,20 @@ +var OrlpEd25519 = (() => { + var _scriptName = typeof document != 'undefined' ? document.currentScript?.src : undefined; + return ( +async function(moduleArg = {}) { + var moduleRtn; + +var Module=moduleArg;var ENVIRONMENT_IS_WEB=typeof window=="object";var ENVIRONMENT_IS_WORKER=typeof WorkerGlobalScope!="undefined";var ENVIRONMENT_IS_NODE=typeof process=="object"&&process.versions?.node&&process.type!="renderer";var arguments_=[];var thisProgram="./this.program";var quit_=(status,toThrow)=>{throw toThrow};if(typeof __filename!="undefined"){_scriptName=__filename}else if(ENVIRONMENT_IS_WORKER){_scriptName=self.location.href}var scriptDirectory="";function locateFile(path){if(Module["locateFile"]){return Module["locateFile"](path,scriptDirectory)}return scriptDirectory+path}var readAsync,readBinary;if(ENVIRONMENT_IS_NODE){var fs=require("fs");scriptDirectory=__dirname+"/";readBinary=filename=>{filename=isFileURI(filename)?new URL(filename):filename;var ret=fs.readFileSync(filename);return ret};readAsync=async(filename,binary=true)=>{filename=isFileURI(filename)?new URL(filename):filename;var ret=fs.readFileSync(filename,binary?undefined:"utf8");return ret};if(process.argv.length>1){thisProgram=process.argv[1].replace(/\\/g,"/")}arguments_=process.argv.slice(2);quit_=(status,toThrow)=>{process.exitCode=status;throw toThrow}}else if(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER){try{scriptDirectory=new URL(".",_scriptName).href}catch{}{if(ENVIRONMENT_IS_WORKER){readBinary=url=>{var xhr=new XMLHttpRequest;xhr.open("GET",url,false);xhr.responseType="arraybuffer";xhr.send(null);return new Uint8Array(xhr.response)}}readAsync=async url=>{if(isFileURI(url)){return new Promise((resolve,reject)=>{var xhr=new XMLHttpRequest;xhr.open("GET",url,true);xhr.responseType="arraybuffer";xhr.onload=()=>{if(xhr.status==200||xhr.status==0&&xhr.response){resolve(xhr.response);return}reject(xhr.status)};xhr.onerror=reject;xhr.send(null)})}var response=await fetch(url,{credentials:"same-origin"});if(response.ok){return response.arrayBuffer()}throw new Error(response.status+" : "+response.url)}}}else{}var out=console.log.bind(console);var err=console.error.bind(console);var wasmBinary;var ABORT=false;var isFileURI=filename=>filename.startsWith("file://");var readyPromiseResolve,readyPromiseReject;var wasmMemory;var HEAP8,HEAPU8,HEAP16,HEAPU16,HEAP32,HEAPU32,HEAPF32,HEAPF64;var HEAP64,HEAPU64;var runtimeInitialized=false;function updateMemoryViews(){var b=wasmMemory.buffer;Module["HEAP8"]=HEAP8=new Int8Array(b);HEAP16=new Int16Array(b);Module["HEAPU8"]=HEAPU8=new Uint8Array(b);HEAPU16=new Uint16Array(b);Module["HEAP32"]=HEAP32=new Int32Array(b);Module["HEAPU32"]=HEAPU32=new Uint32Array(b);HEAPF32=new Float32Array(b);HEAPF64=new Float64Array(b);HEAP64=new BigInt64Array(b);HEAPU64=new BigUint64Array(b)}function preRun(){if(Module["preRun"]){if(typeof Module["preRun"]=="function")Module["preRun"]=[Module["preRun"]];while(Module["preRun"].length){addOnPreRun(Module["preRun"].shift())}}callRuntimeCallbacks(onPreRuns)}function initRuntime(){runtimeInitialized=true;wasmExports["b"]()}function postRun(){if(Module["postRun"]){if(typeof Module["postRun"]=="function")Module["postRun"]=[Module["postRun"]];while(Module["postRun"].length){addOnPostRun(Module["postRun"].shift())}}callRuntimeCallbacks(onPostRuns)}var runDependencies=0;var dependenciesFulfilled=null;function addRunDependency(id){runDependencies++;Module["monitorRunDependencies"]?.(runDependencies)}function removeRunDependency(id){runDependencies--;Module["monitorRunDependencies"]?.(runDependencies);if(runDependencies==0){if(dependenciesFulfilled){var callback=dependenciesFulfilled;dependenciesFulfilled=null;callback()}}}function abort(what){Module["onAbort"]?.(what);what="Aborted("+what+")";err(what);ABORT=true;what+=". Build with -sASSERTIONS for more info.";var e=new WebAssembly.RuntimeError(what);readyPromiseReject?.(e);throw e}var wasmBinaryFile;function findWasmBinary(){return locateFile("orlp-ed25519.wasm")}function getBinarySync(file){if(file==wasmBinaryFile&&wasmBinary){return new Uint8Array(wasmBinary)}if(readBinary){return readBinary(file)}throw"both async and sync fetching of the wasm failed"}async function getWasmBinary(binaryFile){if(!wasmBinary){try{var response=await readAsync(binaryFile);return new Uint8Array(response)}catch{}}return getBinarySync(binaryFile)}async function instantiateArrayBuffer(binaryFile,imports){try{var binary=await getWasmBinary(binaryFile);var instance=await WebAssembly.instantiate(binary,imports);return instance}catch(reason){err(`failed to asynchronously prepare wasm: ${reason}`);abort(reason)}}async function instantiateAsync(binary,binaryFile,imports){if(!binary&&typeof WebAssembly.instantiateStreaming=="function"&&!isFileURI(binaryFile)&&!ENVIRONMENT_IS_NODE){try{var response=fetch(binaryFile,{credentials:"same-origin"});var instantiationResult=await WebAssembly.instantiateStreaming(response,imports);return instantiationResult}catch(reason){err(`wasm streaming compile failed: ${reason}`);err("falling back to ArrayBuffer instantiation")}}return instantiateArrayBuffer(binaryFile,imports)}function getWasmImports(){return{a:wasmImports}}async function createWasm(){function receiveInstance(instance,module){wasmExports=instance.exports;wasmMemory=wasmExports["a"];updateMemoryViews();assignWasmExports(wasmExports);removeRunDependency("wasm-instantiate");return wasmExports}addRunDependency("wasm-instantiate");function receiveInstantiationResult(result){return receiveInstance(result["instance"])}var info=getWasmImports();if(Module["instantiateWasm"]){return new Promise((resolve,reject)=>{Module["instantiateWasm"](info,(mod,inst)=>{resolve(receiveInstance(mod,inst))})})}wasmBinaryFile??=findWasmBinary();var result=await instantiateAsync(wasmBinary,wasmBinaryFile,info);var exports=receiveInstantiationResult(result);return exports}class ExitStatus{name="ExitStatus";constructor(status){this.message=`Program terminated with exit(${status})`;this.status=status}}var callRuntimeCallbacks=callbacks=>{while(callbacks.length>0){callbacks.shift()(Module)}};var onPostRuns=[];var addOnPostRun=cb=>onPostRuns.push(cb);var onPreRuns=[];var addOnPreRun=cb=>onPreRuns.push(cb);var noExitRuntime=true;var stackRestore=val=>__emscripten_stack_restore(val);var stackSave=()=>_emscripten_stack_get_current();var getCFunc=ident=>{var func=Module["_"+ident];return func};var writeArrayToMemory=(array,buffer)=>{HEAP8.set(array,buffer)};var lengthBytesUTF8=str=>{var len=0;for(var i=0;i=55296&&c<=57343){len+=4;++i}else{len+=3}}return len};var stringToUTF8Array=(str,heap,outIdx,maxBytesToWrite)=>{if(!(maxBytesToWrite>0))return 0;var startIdx=outIdx;var endIdx=outIdx+maxBytesToWrite-1;for(var i=0;i=endIdx)break;heap[outIdx++]=u}else if(u<=2047){if(outIdx+1>=endIdx)break;heap[outIdx++]=192|u>>6;heap[outIdx++]=128|u&63}else if(u<=65535){if(outIdx+2>=endIdx)break;heap[outIdx++]=224|u>>12;heap[outIdx++]=128|u>>6&63;heap[outIdx++]=128|u&63}else{if(outIdx+3>=endIdx)break;heap[outIdx++]=240|u>>18;heap[outIdx++]=128|u>>12&63;heap[outIdx++]=128|u>>6&63;heap[outIdx++]=128|u&63;i++}}heap[outIdx]=0;return outIdx-startIdx};var stringToUTF8=(str,outPtr,maxBytesToWrite)=>stringToUTF8Array(str,HEAPU8,outPtr,maxBytesToWrite);var stackAlloc=sz=>__emscripten_stack_alloc(sz);var stringToUTF8OnStack=str=>{var size=lengthBytesUTF8(str)+1;var ret=stackAlloc(size);stringToUTF8(str,ret,size);return ret};var UTF8Decoder=typeof TextDecoder!="undefined"?new TextDecoder:undefined;var UTF8ArrayToString=(heapOrArray,idx=0,maxBytesToRead=NaN)=>{var endIdx=idx+maxBytesToRead;var endPtr=idx;while(heapOrArray[endPtr]&&!(endPtr>=endIdx))++endPtr;if(endPtr-idx>16&&heapOrArray.buffer&&UTF8Decoder){return UTF8Decoder.decode(heapOrArray.subarray(idx,endPtr))}var str="";while(idx>10,56320|ch&1023)}}return str};var UTF8ToString=(ptr,maxBytesToRead)=>ptr?UTF8ArrayToString(HEAPU8,ptr,maxBytesToRead):"";var ccall=(ident,returnType,argTypes,args,opts)=>{var toC={string:str=>{var ret=0;if(str!==null&&str!==undefined&&str!==0){ret=stringToUTF8OnStack(str)}return ret},array:arr=>{var ret=stackAlloc(arr.length);writeArrayToMemory(arr,ret);return ret}};function convertReturnValue(ret){if(returnType==="string"){return UTF8ToString(ret)}if(returnType==="boolean")return Boolean(ret);return ret}var func=getCFunc(ident);var cArgs=[];var stack=0;if(args){for(var i=0;i{var numericArgs=!argTypes||argTypes.every(type=>type==="number"||type==="boolean");var numericRet=returnType!=="string";if(numericRet&&numericArgs&&!opts){return getCFunc(ident)}return(...args)=>ccall(ident,returnType,argTypes,args,opts)};{if(Module["noExitRuntime"])noExitRuntime=Module["noExitRuntime"];if(Module["print"])out=Module["print"];if(Module["printErr"])err=Module["printErr"];if(Module["wasmBinary"])wasmBinary=Module["wasmBinary"];if(Module["arguments"])arguments_=Module["arguments"];if(Module["thisProgram"])thisProgram=Module["thisProgram"]}Module["ccall"]=ccall;Module["cwrap"]=cwrap;var _orlp_derive_public_key,_orlp_validate_keypair,_orlp_sign,_orlp_verify,__emscripten_stack_restore,__emscripten_stack_alloc,_emscripten_stack_get_current;function assignWasmExports(wasmExports){Module["_orlp_derive_public_key"]=_orlp_derive_public_key=wasmExports["c"];Module["_orlp_validate_keypair"]=_orlp_validate_keypair=wasmExports["d"];Module["_orlp_sign"]=_orlp_sign=wasmExports["e"];Module["_orlp_verify"]=_orlp_verify=wasmExports["f"];__emscripten_stack_restore=wasmExports["g"];__emscripten_stack_alloc=wasmExports["h"];_emscripten_stack_get_current=wasmExports["i"]}var wasmImports={};var wasmExports=await createWasm();function run(){if(runDependencies>0){dependenciesFulfilled=run;return}preRun();if(runDependencies>0){dependenciesFulfilled=run;return}function doRun(){Module["calledRun"]=true;if(ABORT)return;initRuntime();readyPromiseResolve?.(Module);Module["onRuntimeInitialized"]?.();postRun()}if(Module["setStatus"]){Module["setStatus"]("Running...");setTimeout(()=>{setTimeout(()=>Module["setStatus"](""),1);doRun()},1)}else{doRun()}}function preInit(){if(Module["preInit"]){if(typeof Module["preInit"]=="function")Module["preInit"]=[Module["preInit"]];while(Module["preInit"].length>0){Module["preInit"].shift()()}}}preInit();run();if(runtimeInitialized){moduleRtn=Module}else{moduleRtn=new Promise((resolve,reject)=>{readyPromiseResolve=resolve;readyPromiseReject=reject})} + + + return moduleRtn; +} +); +})(); +if (typeof exports === 'object' && typeof module === 'object') { + module.exports = OrlpEd25519; + // This default export looks redundant, but it allows TS to import this + // commonjs style module. + module.exports.default = OrlpEd25519; +} else if (typeof define === 'function' && define['amd']) + define([], () => OrlpEd25519); diff --git a/frontend/lib/meshcore-decoder/lib/orlp-ed25519.wasm b/frontend/lib/meshcore-decoder/lib/orlp-ed25519.wasm new file mode 100644 index 0000000000000000000000000000000000000000..c1412d559b17f3e63287c5856d1711016a12cc2e GIT binary patch literal 57094 zcmdRX1$b3Q)9~!|hkghHfWZI)j79-wqrqY|nQUgO5MLP5 z(hL@xNEPnmBP@1n9xu_B%C&>sqCG^24iGLnLN3t>!bE2X6zgwcEAE)jXe zVhA5%O;tbG?l6eL# zFVq#4;qu}Pa7D`uvzDQ_BHclsWw?w=WQNP3rNvNMUP?1@`3RSg<%22Dpjd_|b|r|S zL{5OhIE)JCm=rIWZylmIGhBX(A32*;5*HgQU_+ zr-ryjb(yt+vaV4v>UCwP)%BseUW%RD<&swBHR0i*GRt;NJl>q;BZ)UDCY^X0YQ!sq zBuvT08H`m4Q9?Q1hN4DUOEyS@XG_eLo>I{eOy!M=jmu~V9F$>A!zD+J=V2U853cItDlDt= z5K>u(s|e2oDr<8|9`igbn&HaHWlgSlSvEu~8|o^S;ZnFPxa4%<*;QOhuMZcGag~t8 zL$%_HtE9}MX;^}U-CIkIaT#Q)nQM3^XBg#KdAN;A!3jlL}-F(Wg{V2nyEH3mt0Q0?|Eh4^XYw$m3{YD{Po=Y*?nh4VbMmA ziSyOTViggfXyeE#DMC@`*Gnm$;o_c{WUtJm+)|Vv*;EjP8lz>Htx0Seaz^DV`Qjx7 zBT(lHGt*D!izW=r7qcAx{1UUSB4`MuipbV8cH#=LiD|G%?dgzu#wrCRhm<#)B->vX zppqFbZo(|bG)VHqtW8@vmx=sr{S%|);r>Yd<5HqI&icnBYk72*U$*`sjh@X^)<51_ zzj^e1_5Nv0)yAEf8ZN2RmJT1CHwIp!NUzW`^p^^j)l)ttHj6f=lGj5U>qe=bJnGSs zt)7gEC7V33-xne2r|(~Q=W~6iXfXd;65~B1o_aoQ=Wqcjv$9N{J}JS1O<~6P+lkv zBSE2>FhtO35)?r)L3wgeIj}3>riHJo%fPuYt{j{j(>qzo(Oc`fojMiVTQMXP%nTrd zO9|3pW`h^~4b)*~hK>FP=rFUyN`DXIOY2y1-qwq>K zR92vxFIC_l>U>Rin)raC1`}nte}p8b*+?(3mK@x-Yl|^TI9ahP!NTW3toB4NhMK3b@O-YLel#6>)K-RaHR-DJplH@X$GSsA=S|k@J!Aay&Z>bEi z%FGON0~dLZZ^R{T(r%w7gef%|+(o;(%rRU;xMK+?aoR`~DN0I$0FqSqao`MMxkFIP zq!1~aqTqf(8Ke<8r0Vp`sT89MluEw@vy=eiWS$Z_Mr$J2NI4b?Eixo4(Oont2JCk& zhKM0vS(`0I+F$wx$|(VZ+;rJoyxEYe8_!G^?G&U^23L$MrSGO9^qmu}q+}J+3c}OT zl}B12Qo++cjLT~|F|NGX`>bGnpGDS2q8RDQ!OH|KhdF5pBCgZEO54xb725r={Xw>x zzrF#BlqB%3%%spZj}~IWpl_{cxelfEh$e2}5Sp#pR)#Ga&1f(xd9-bxiFb9f8VRo6 z_MdiLawkWd5G989pS*X_c3u`GS`xrEm`&P4M!g-{GI3wzu8#VWi~C~X{eYQwiEN5! z_LFAsk#5jQkXAoYo|`G>T^n(LOIxIo;ib2s*?eSk{fX>%R#;X#b|%@g0b(P?EDaO6 z{i2%xd>+bnz^gXmz6+%V`b7d6qKPAkAkAK)KL&iDxU&{mO2V}jibOp ziyH;BQj+TORqSqKAD0j7MxUho0JIe>Gm^KFs&QCi?8xDANBPD&EHPB3rlq~`AC_nv zIh-?W>D&`apm-?9sT`-rQk<$&tW5gw;lo+$+gTCX-40fSZiiDSzO*Db4Uz&u6i_Dd z(e5tOmC`A6a7eVojV3I{(Ie>Bl0G6Og|c3No>z(U%E&w`<#98Dn_)dB+X1Jb1{ggx zeLT&O#JEj~#YWRlVX9|J4542mV^w^UTt1Y|Q^QI*!xYO1HdxJxF{9}xlFFGA!$yyg z(|x$&HH^mFd)RQ^Ia2|HEI>oZ#3<(Bl*J+CD}R2>oh@Wmrv@&I${_%WTD1w zOp#4eWMhg_sNocsg%MjMVvCO0GMsP{VvCO0L5Q#Dh^>T(L^XxZrszC~kei5BFUIU8 zF?&hOjM&PEtrD?SBBmbGs8Np<8a_#JC?US%;g>}0&4)-f#fuQz2(dRK_Lhjfvk;pY zu}LDPT?O-(5nG6qEW`>S&eRdxBw{liIw)iZ5@IjrE+aNe#O5r-Hb!idh;2Gz+i=3k zJ=H0WCB!du#9oA$3<)`W60tWSHZo$PL~PU$8;Dno*h?bzl8C8?!+G#2)DagY#A!n{ z(eajuEi^W~3KGR;LTq8g7KzxBh1i=BdrQRL5;65~I1$S|)e)B=#OXR>vqWsAu_443 zLTn_&Rz_@G(t=I0M$>?GwVdJ(0yHz5XFma& z=}CY>fI`KjdWa<;mH??TiV{$i0I5dG5Kx8ysah%%KnjDD4zKsKyo7~S&_toxA!hd# zvIVV_vYS$jq?C-5$7Y5!D_jN#r%)NPPb?HCdqnRk?^s61&L(oJ_vv~i_;xo6Oi zcjZAqsJ7P#rWKg-9NImO53Otj*+?-_VB)P5oiT8`yww-9<#3agV@q;}^-Xf;qJRH5 zR0NlxT8e>Wh_|3bsN2!69MG1GVm6BLZi~c;vAK+HKT6@-fyeUQ}D-<(Oj80r=ZPW=b2fVl#+?GDP zTPF)S*&W2F*jhKr9@EhZ#kj`-6r;sWNAFK5Ib>Zc#rOck$UPRxgiUad=@f=m1P_C_ z$GmhIWsgH-jCw5Tk4SchaHBaXmG}A@k9?>`IHefeCW__KVmgnAOxfcwN~MKE4uX*V zjN}yA&)hP`R(i6Vc@ZUH>L|Cln|Kz?ZARFiSPjNhF~m^$PlqHlObC2T!X%I`kz0O( z*Z}3xT19IqfqZ^KVrNLA?LSM3!JP?wsKK>sm@3mRA37QNsD%st1W9hJ{2*tWlZOTE`uy?Ok(6z+@KeK@y?k7-Sd!BcGydyt9$d(QG5%{Em@t ze#gi+XBqi~N*ej_JxjHTjxQ*T2mb`>553IlizI-;vErg|0ysHF+dqlh#Xw0zp#+HbBs1<955TzdcmT$oR|gUxAIIXMbOOY3 zthgwZ0QosaJ4}hY00SirB@&>ZCz){<@&JrG&I2&+!a9%uMK~4@l@g#R$BK)J2@uaQ z+QdrS#TY1QNJxOM{~EDsj@%KzQmV%U(BAg=-bQ-z~(U|{`P9* z`CS{I?TM16bK?A8UY^@K>HHV7Q>9&tH^OH3Xwr@(1)_UT$qbryGa{RY%w^24}+r;$Af6T=nUk<-V)oBq(q=0CV=Y{s? zfrcD(ELCuvJJB0};iPDmi-zshAu9QO4`Lx?3%fH_ns(J_*zKG3GbWv5u> z!E^_mgU(@uUa%y@CtA}J8P6~}9{G7(6{;NzA+8Y8*n~J9!udFWBN2pbc%nfsoWjLQ zxI#$->r~Kn*X?Kd=%^&8r)p78)%f?Sl6pGv4POC5NhnMEe!X=|;*?)vDK*qny^N=N zSy^3p3VJ2ZI8PUrE-P=MWS;_9sio2}OUOG+G3w-)wBn@sxOcp3*4i=3bmkSURit&^ z;T3IjwK8T62W_flJKl*o(oe&9ML*%o&) zD!Y@>o=(QRCsK5vpd++o35h16IkV-P*rpAMNpH-cv&W*>_0sCTKOA~ji8VCqtU3m7 z%>{-!BV=c!JS%n`k4>k+s<-2(^`1IKTz`*&#C^ibyrH3x+@$+Qd7rH@P&(LfRAh~~ zcQ!NpJk0R_6Ep03$80)5R-GX4zvZ$~Ch<&;$kHQpyslR;>-{z8)5)SE_RQ=qFx8964r?mTaVuV>D;?r#cyci&3leQf!Ld*<*na?2Q z+X>LMA*%+xh&F@iC`PlFxRy<4VM(yQ(^IQXlDAHhXNp?07;eaBxW&V8t7Le#D)rW} z=u#*h2mWqH^iID+E34i2Xnl8W@Yb2dF({pC@kUM?V-l7>HR(mQc%LN_1;uy| zClakArQDIyO7!FUazCfd8JnlRr&S-SB{x@zCW^7?Z%j04?Z2S<0bHMVclsi4_0;!t z*-Eu|FGuZbt?s5;!CZ^?b>3QW%4G%_61}N3Z`%yCq_a`XF^krkO7;A?9`6wY^m+!J zvA$HAw{*ltit$d)=RM3cLcI4QzH2uMnS?Bmk;&bn95>#~`RbKCv!2I`w`_DBKry); z)W^%9jTi3={r^M@j}z|$1&_5@3RWKypEweY)cG~8EA1&H1a{FiMF%ya+a>2=|b9NmHSar zHHy{kpDee0T&5T87d-_HvY@tc<$?yipvg_=2`0Dl&dr8wMKN@TzRbSGT~yQw>7cO`CIp~KoZI7XYdq;edv z5o(}0$AO{+G&&5i!Ab!MI^Ros)1)Ja_IYmFxia?&Vq1s;+C*_c`yDoAW2ge(UEBYy z8hokkqt(!nD;ieXb1`z-)^T8?!P#x#OLvQV28DFm?7l;x*)5zV9y%V7e%c7qs1*Wm z1QV1=%w;8Eaqvu_<9|Amq7xRnX%}R@5r-)B;o+jtf7g>4f9|&FEO%X(m229Q)tsSHXT19={424Jpht zPBdEF%YVU}Vx`~{Og@KXPZ@S{qJd`bCYn9$)h#DR@_5C>lDgB1tf?3Wh@c5?lqz=!?v;=q@jy(sWwzq~l`chc030|)!% z#X$f$bWsq~!a z&<-Vt-TlbW_NOh1ui``cfn0#-+|)|S#VjW#@vhfD{^N!kr2fQTGFES&&P(mn&B82~ z9?{ihC6c7V<nu?Wy9Cb|~*jI>i=wMzeE+HRU4=FKN3nD1*9gS?}ED{S2 z6fFqV0*4kzqsG14`WfHCJII?zF}S1pDu!fQ-)M1ki{7geX-|_V1}9cZU*b){eQf?O#rM|P#<6t}o7e_iRgUXUxjc&E~WoLtHJ*Od-Y zriXi(dYrj8BZMp2-mhfQS-zVyb(Y`J<5p=qkb)v-7QXZ%6IVump_Pl*tpL(rWHY$a zM6%o3&jk_{7vhoQWsa69%4Bu=mCyupEeWQ91k=E%X{ZUGfl+e@$s3I!4ZGBm1oIg( z$+508%`(m_C*8TzN+>M}QlUf)n?}?YFR4_B7eaPd6EbAmozrP?r@y=$8r*9oT_%VI zyMuld=<4p7>;j%Nb_@Lw(Km}49I0VLNSPfcQ_d#_43+tIsggU2&hjZWlR9Ig3dWM8 z-9i;39T$^+p&-(!aFE;Ss|3Z9{>bv<(H` zq-`khCv8K4pEC~!zRtWHM3CyDAl#XcgIvy74#G&0Q4s3P&q0W@fZ`)r;?4G!ojDT^ zITHQJ*pG)`GGvEyBxhm>M@oXjRgmmjeo9a%F^rC_qLe6x$-hj7n#WTp@iBj*??|Np zTiHrTVvdo+T_IGG9;y(e)t6x=og7u9RmG&_OY|8@9^ED?pEEI7)?)lQHE%2Fi%0c5 zuIVPFpi+ntNtdWRiQXg01KdEhA`=7YHzLtKl3b>Y6b(-dqQ>8OEJR49GZmqX^muHM zCqLE9!tWq@qM7~}NxzHfrBk3H;Lea3qoP_h8=Td|-hjzw9SmjxhMkqV&1QSJs zng~@CrqjuE4tE7p$Cw>_P{r(&p@X>*LzQw+o)S(k4rCwcaH=9LsU})5wD&+(IywlY zs$uEU)m=UeqLzcT{;+!F+^qi4DlVtSzplA$?%mSVB&jF&Rrbm7qglG!pDaywJ7#Ny zo|#c-q-=K3Ah$p&$}Y=(RECx=g4m&1gS`0)mgd5Hjvq8Ty{Q!Yg1X-K@9-wX+5R0g z8>twX*c7r)>bssGf4&j^*GdtC2;)Eal`YY#%jA*P_|N{bUgZA&1N#0k^_2VH#D{;{ z&VPl*|Alq4$K9=M?6lD*Q-?&kLpyCG8_Sv%6n@9><&6Vpt}^_t;Yaezx%is@TrNzms+A7ih~I@>LD32683RV zB%glapbdt@k7|%d9qle?yFwL`oP4!zpnp>31xjBxV`b{x6@S)r1~RNLP0Xg&mqX*Ae|wxQz<%Uk&iD- zZj~QhP$m&gmFZBzW#b1KHZrT}+`z&KR(7!UuR~m+=Wp`p$IUMw_<;pEZIcz|POj<8 zs#rRu(6-Fe4@PO@mYDT!c0}+oFcY~p_aU2FI?JF|nMTD+ zlFQfas7FYN0J597dA7%Fg!a!(%a;G#p71f!8w;Hx>IJ=tV~RAw>~6L=$s?qGI8$hI z8|bx&q)Z;XNfy!p3sYui%A}h!;ot=F^$pM{Bll<8H+d+t{)sXxF@-3z{tYKI%B&i% zBxM0inO2ZVHhPF5$>JvxBrWd~V9tj@Gpol{|AXN6EP${^b978FD4!n zU7RiNi?b9TDZM6-^qT%ONG5HNOn+yPXj)MPo&@@=& zwet@q_n(QO$^9QA=5HqVpNXN#{U0OdPm`NT`MZM~l-c5E%HsU*k!b9;yGL1CEn<@5hQ+$OEl(G@0du1bD zOK}bHFBJQ?5vO^-i+H(rHsa$H*Lh5_e;e@vGKsP&K4i~EoJnz=$Mh8I-$uNfDtTn$ zjvi;3m`Jlo=P<=|w0_zdt_&1%y`iJrP%Ut10r}(bGzs`OZr}XmnMBaPUc-%YX*5*k zzeFjU(_V^vwM+V(U|J(-jb^i&^}AfHU4lWjQt8S~Mt#XnB|N;C1KGB6{pP8vonRQ0 z0J+HsqH{w!y&#C^%#{FbD)UaoK$C;kb{SG!&N99^Bh#I>Bb5~+O?pWiUjw@Q-B6nv z_e@^$mZk~%w=;^K_)t2L%vFs^ia(hFbo||q=KN<#4lA1?gsGnFCaVE2D#t{VG4Yr9 zNNdRh7kco^Z~f?=k4MKLNjGxTPFD?Hqyvm{5FDO{-EYZKUU|{AEUgH z3?yoJ_vFRDoJuj)UjF<`urH;swlPvGc4~!NvlHx~oIrvDWoV>_LGm52Hku@D;%|BO zFZGlO$mZD#An$uylEd*IVB32P(;IdLX7emCi)a2ypyZK~KnMOXWhUy%DB;%rbG6Rn#V99EE@1!0#*%pApx5P zyp({K2E3Ahw+6hHfL#OLNWez}-b%n%15^q4X#h&VUjx!;%TBj?8ZcA>0UGdy1Ohc+ zm;{0}V7LT=HDH7Ua%jLv3FOp(Q4$EzfOH9jYQSg-glWJS3FOj%u@VT^fN>It(17t0 z$gKfiN+41LCP*Nvda~1(K6*iy3Or`M_J@k0)DZcIKa>3RD^OYmc}|f)=M)LFrBIUO z5e0iA^ASY?XOp5RPe&Bx>4>5N{j%dt1sZm(3h3pvqm6g#U7>oOqYc`3u`8?TJy%w; zJ47r*(0R%#mw5=sL+GS{-A;wawU;9AyY`YjV&ZcA9>e3?%kH{@(NpPnJY`)0TvS8P zkGA=p$0{a4^BShepHP!heg`YRvX|f6Ate4fT~tSNMWu+x71iYZ;p^f|`(@6)>N1(|2f=ZHaER}RfCrirC@-(HR zeEv2Q`({!}`YalMp^LumBynXGmv<@T2*z%yu4vuYE-=dp(-osT2Ks3qGh$Cd{)iH> zA{_!cQU?$m%_3FOgz5zDiY!i2P8M_IWNp`H_Y|`H?Ii`CTase@%(1zB{>6TzNHK=aamS zO_5(wA_^Lct^ykQ1ts}>1xU2V zF_1!6h*}rk=^{BL7S_rXA-_GvsmNO~o-YdTa)!ujH^NYqFwkeiG*@hS6Ub%kB<)m; zrNk;fJLV&WUHev*_O&f9Ng;i>N0yUmfDP1HLoi=h>=Z`@0Ao$9bw9k44=!3wY)gnDXzuFh!Y`P$@ym?DD zCU{0fQ>HW`?<><3SAHd06M$f)D3Kr?UZ2ONC39iWq&i=F#1_W4Tm{l3yd< zBUP?o?WR+*S|6qSN@1mhQj(isW=F{$()Fn3BVQ~!JPr^FW`F@H-|CmvHIKjnO%qN9Qa((6V{3lG-MU7$ovE z?|;v07|)v<&$F-s$~!ZIKAD(9@;9e0z5Ic~^6#$i{K3s|F2y;ap4no^o-NwSPP66x zm7O0aNNTiKUCa_9jh-Zst4E~X!(g2ko~JmTr#|{yGI|3hD`}6d_yrhYkdJamK**k> z1j*9;vh(`b^E(}4gr*M)sn}HbaOX zxtSl*q;OEcCJFG;{*L{U^&U`m_??bW?>$nbcpln#p62Nf!stzi?5QTjy2!~_HMDYh zUN2?6hodV&T~4y(h%~;ZXPyT%`nxhVSUHOfYF@~+XEgk^9ND1uvP7RyvUQrKo>xIx z*vSjigI#;H<9U+ep_e7mGebD8JwWjcBByvBR&kskrqOZ}q~l~ErUBGgLM>^JKwMUS zpi6gz@_~bsV%iYV+|de94kI(mhbb|XZqP3RwFr^5kdLDzw2TH_Pewb2%(us`}D^9V%_b}54m6X}^FooqQ>tRYU zO4Y`#6vZ5RC5?EC9IvvJZjs|vMwZpa%c6}}X-dkWSMt!p4^zrhx|tuQaAR5HR8FRn z0I}fevSX1CQz}u8MLtZaC}T82Ji=Kclt8K0Ws1%7Fr@;W8_@9(`87^9X`aOVX&&i} zN#B2j(9*`ubilw-M``0)J!&g$T&_pyZSewjNFaBEUF26$lRij5mzsPQWuPMp7nR~; z2|9`(91i{{Bc;&!lRShX-v$N*1MwpgfK04sbfUgeFvncW>*8w_Q zA+K^BAV+vQh0=il1_E>-kbyuQpm$E>ZLS04Mo&KHIzW$|$n#tW=w%c6pX&gnOt*iXF`MxfJN`*hog^5evgM=|&!&py%SVrke^ry}l4tN_L8EEZQ6*TFg! z7Gd9tQP6NwW$fqngN41%pk+*9NV)X{y~j*|61n!m<|lPv=!E=Y=aV2Dv~nP}8(I|x zoSp(7b&SNXJI{u3&8pzTn>$4n`$jmBIa+;CZ97(({s4jse13Q>FDTYo zU<0vSM9+vs$MP+rOtU-K@#GuG|EdQ3xUxR_6@G{f>OO=WXFkAy@h>57gF3kL!@ls* zjg>Ixm*ZmJvBmgRVjWy_)q&$1v=enMJca`cdqLszGhlYXN9ybaU9kAJC140x1Bp!* zi09=ZA=+J1t#*GG#EpC^77e-tO7~za5wZlfo~Z$M*S3Mj4@-%%&Bj1uXoBerIzWpr z`>S12cEZMW74cR64`Id^1w@-S&tUrWO6tQA6+tO82jZ6Pz%NI9D~5gaGi>|zEA`b% zKRmgp9^@%89opB;1rO$&#?!k`h+2i4K(IT%D0Q?x{4i{?y0S+ou5%VszsY+9>pkxS zCoau|5ozm1xk6#^L%#B2N6;IHzj;#h-PRX2e!E#fuM1GL)f9M|zYGla{ZW0g>T@V` zNl}~J3x<~q4v70h?qQMk%hi?FW@4vre}QY`2jalQnd)~>N5b_RVd6~L-|&}JWpLx| zlkj=kTpZdu9lH-H4u%z*(E3F?wc6TN*vE8ToO?V853h<6pNf1~cuh69QKTH6y;4m* zR;C&{)Ug=Ygj9)hh;w?VJ9PB>&fhK~xQsnO2e_~PdGVrW2rc-?tAT1)iAab*%Q z_S#cCS3QrKamEX4Rv9TK?>>Wt^7e$Pn?Jy#&0oW`-^RnnmF1w%lZVh^t^qo&Y6o{m z)Bk1>e+104r$We7FZ_9+54c9=!V5p9!$@0xywbR!`eE2}=#~oViu9uJ;PVT3d(~+; z8mOwatyUc3WfeUN)Px=-?yGGojfW|_Qq`a8?MA<(-^I2IbzsdO+tg2+t%483nu&#f zOa()~6RLBb7mQt07+Y44h0h9nsrGpDCC>hJA{4*53~Rlajjj6l;EV<5an6H0`0c%8 zxF5d7S&PTR)$hB2cXXI~;?!eo`}VTBx#LZ^9GEH=r;ozOW8>7xZU2CwyK|{OG;v}N z?|L|;;d(TgLgDKNXVEg=2_?_^Vg8NB@%Grc@a>UHh+C3j$F&ShPCSE$E5>1`$~LUG z+M$l8lNsxcHfEjlN;P!+CI5YVu!lrBL2H%V;jCqU|_C83Sa4p?^fHO{Y-rY3c~iji+jFxh7{(5F#)LV*mzkUkQ`v zbW%S)vl@F1oGtDaS_!GPhvLlrd$7iQ0pgP?pe6A*8j`wW!+Sw^w(IWyF&(zv>y6r> z`zi1li3_Ul+7SG{P!c|zRs$E08;tW; z2`HZbHcYDMgfTr@iY<++!NlH$q3v`BhTg~p@#n5V@(1_SJu`jqyP|E-&o>vO?R%+K z+fyEf=V_=8PD+3?nJdKN>xu9`rL!kgyaYp=ox##$&1%))UFi4YdJ(m68iV~zwseBJ|OFN zHAK^a?cvnM3)rH-ZF~r`;A!1W*s9@55qSC+_@-qIDADQ#1Wx~2-G3qxS3mJr7Z%+F z@f9-F?^^DIgEuVVkU0QH$Ni3C_a8*M0%l4o*;iT-Xthx7{J0b_s-A&mu8oYBlKI zw1j$XV>3Knq`BJb>jvoT^8&t|@iA7LxK1>EkPFKx$wJhv2IU8oz!?u3LkZg+xSj7V z9(0X?%T-swCuJY27f+_*ZtF93dh|BfcYg`=Xn7P)Js%-vjW~g`Z+k=KdU;{s%MKzk zs4Z6fGB$N+HZwm z`i(I4{HLAa%MVY&w4pokw7ZqscjOgpbf7QHy>t;4b&P@iz4AbpjHRmmJAj5Yw`1Gw z4yz`Co|7VvFO%b^Fw> zUJZdUpSVT;gv(MjtY|4C5za_xbMswADU%bZH!*%fWkSj2^eMR+{^(wZh zx(~)}or}YQZX=l$P~t)bwbPNBFy3m%t&2}X)WFYS#N$bD{LLNwZ1@%j~R4swYWU*y8Nv*X0Ru@PAQN z0Wd^nf~kBZXj(4@l9z3Ooi+C0!Fh|ZoGkb=Lwc1pKh6$m#(h`Hlm$@MNbT`O3v=ruuzKZuMl)-Z6 zEHELZDcm2D2q*GxLe~QeuAbBhTIc*3zW1N07H)C}`?@BJ+plV4_{a{T#kPI8@<31M zA5j2KRIdWL8%9CyWH8w-wfc$DJb3M3n zCX?pH26#Q{wpcXg6r6n7M{PQE8wAWCwbwf zp^YJC?JeQzToW!V90^Yg%mZaw8+A#ciE#K~P4(e>wrBshGLhCpF!!Lhe3Ov(>P=LBz$0=4{c}L!1-B25XR0>v6~BD&E5b?jeVH6 z`Xn*G^;4*Jv!h6lpbr{e34?mw2jGk4DX=Z=IT)t=rq;I)hw9~g#75g9tUr1L=2>aS z@qc`XYj2;$AHQ0R56_a#|M48vwx}s)xb8q=p-vcHD!+Qa{l}Pp&dA)RNoTNuyB&_ zF<7BmgCE3+XBpsAbiBCob5rPZZ9WWa_XW7`-xF7_dEv2ZgG944<)P=OrlR?iBN%Vb zD~5iy6`J+*7aa@#h^arusrB&^7OxeEsRcUXqa24}!F4NqTI@d5FR>rH96l~K_&cEE z{(9K1?h(kp<&lWqlLFDRL-1J1-C!TQNW7f41x>?>LXMU_u)=`bqS~Pt+){K4_IQv3 z^A!uj_GcI2$EPB3@f0(rS)#>fzjnvHb=E`ejvL^QB1K_!SV3&G>a8f%Yd6N0{shi` zwifMWtZ?OS9XQeMu=+S`FcjL;Qaxf@2cy;oLC+ee@o4$A!c-*}_)R#i7ASoj6RPxw zJvkOZ`^CM%JGdXrIdxfGU_FPup4Jh4%MXIJdp}Z7`>%z1M~|tehn9!CuXBnvrDx!M z^vC_pnqbRmBVhG{WVqLU1kv>{eg= z?A!%h)Nm=*3|pbj9#9`6W;auOFw?6eml>N z4d)tR@A>(#@>hT>b_Mh9ZwJd4=Yf!>R28jG|NUJotU zaO6z&%-iKyCFKe{ZCx88A`7Xa+eKX8tQowCsRN-03S*tRJz(U$bj;T(H*BeS53AEz z$?Z;7weIb4u&hWqF|}t2^y({? z9sK|ff8SV?t6T-f6zL(pf1ZY;uUt{*^*jc%I-nStrz;#ttBz3kz%O*2M2 z4X{M`aIDm3EY5h954O+thdaf;Qe*w^VCGFP9K9wSKd9AKoIhoUQRaoB>z31Cc-a+W zA6JJ9hr%Fit}j$+)BwMK8G@67r$Morlc80esUq~X8=`iHz~)mw;Gnw;#q(7)Vd2LY z)FC6A!F;=qy7bfBP%Hd~NbbK06Bl(8rzY5O{_W)g)0#tBzjA7`65jaMwn)IFljuG4 zLs58RICM^5pbpu70$tHP;OvD^JY_$lb~N{cJNrlAugkjO?+re}>SJ5Mygj?bZ2#iu zzq2>g8+8m{dWVaRgYQD?3}1ES>8~;0{V~|O<;S=)tu+kxKMG5~nh)3g=i$+L{jtFK zH0Zd#znIf)7@YSjq&{DM6i@YxfSv(2u(>0T*njymP>(f6ujYT?A5StMSJU43Q=fsb z>((CF(7`Uwdk@Q?nU9z_3Lrk?$_|$t5NVQ=ckaeryCkhPQw)eD*@Vc$G%=R zQEX5w?%B~ET-O&s(FWDkpNrpzxPedALaS}CD$iY<=l%u;Ry&K$8yIj{QXBPpuTk(* z{O9W0ij}cZ@c?`j{0DyFYg5zC{ecU^h1$H|BY1Y;8J2eR!$b4u!lD2HN&5waAZhT+|;5dq%PYe-0>YW1IlA}uZ}H0XaSd|#H%HST!Wh_ zAyC+BBm7jkgcznq!1Q^iU|8jPa5U^2fLmi>*W2!D=jY3ya%`+9u;dYz|KNt2^2ZMR zzQua{V%$eKzF8SD<$xKFyqKp>TsR)=8Q0*80y$7Dn}8EzVz6k_#p?2v7olB^Gw{jr z`Y^xF4`OM7Ggu7)Eop;srx*v58=uFs4{C~msU=}YpC#CYt~|~dkK^g?BVgb1LSo+S zYOt{KA@!4TUEsTN+timg(&5O+I%@k%ci{u|jM|{uET}x=g?c~zFwXsSraEm+FyxF5 z!ju7bVe6{{>hPOmVRVDlxMXlun0R=q`rE@7Fluu@+K&d{z?#+7YF|u-)XOhKwbXtX z+32jgy><}ZT((#38`9RA!_ePbx^h4xMEd|TDsjQ@N0oi>S)mk<~9$5 zhXX6)8_Qj=mI}s3eOAM$Jf+Zo>tMLva}9Rba1{&u{sf<_x~9Gebiz07zrxzT6~n%b z6g6r2?{KW!adE?ID~w85p?=$90z6sS1%Hc6!Rqa|Lf_Gw;7Zh4i1q3Kxg4!U)pH+% zZF(@~>QD~XE;%Af^s5e5MOB}uPjT7Ay*M~I1lJDO2%!Eyen#}W93oEaY>52^-4VX0JK~_ygVb<3 zCn(mw4vsscU|V+;4E2eC)gRRpm7lkP1*57!V(C9{%8zX@m&J+giZ>QBPt)1f=294T z-VX6qo~eP;YNBsgO(;#t;`(NIsPH%F+rBZL-1Zh%#uX4_PNcvYl1-mmbD&d9Pt`c33Y0iI z2=9JV3fqmY2+z;w!`tWY!}DFKuy1k`ShBVS2Ayh!0ky9~)7Y8fz!ZT;t2|XRjpwn# z_|w>SQxfdE^PAfGqgimG=uc|D6OS;n|F7b7?)k7Nbqe~PZwViUR#mG9H^3d{aiURM z72CJpg~OYSz^>=}V9$Yt;ZwRq+Pk0MbC^LVD)bU zF&_?s8eiqWHE`l$=NZnc1gU*^NJ&BLKx+h)+J{?E{SZYH$8I7D<>dktbD zuc*;csc`#FZ}DN{FW_XYr&we{FRbd`59MoC#7!essVxWe!}9AI;=O9C@TatOaPdiT z$n}Ko5-!)pMYcBTSJQrmdFl~SDs?P;eWg5@y5+>n1>*4dE#$yO~bcTo(gc1{@209NieS^PRU8h@+x zExufK4X&>77Ht=ngQT9{h$b0k95HS^j(qwhv~4~Zw;tJozt#=G-7S*9|3Gg%H{%6- zv%Wvx7+Dh5mf9m;y)Fr-y*mik!6cX-^+e6M@-h1T9)fQ_%!R4>`d~(v4)EHqI-WW{ z2H*bt3f9Ii0slIKFwgk~*kY7Jcn|4?)y-G%`OEQ8H8?>$I=KV)o!cg+8$pfgKB5ASuC`k2>^BJ$+FihNzEAO0x;HdYufY#d zgGFZX*BCYI3p9)=hG);N6TkXAz&F#%V9F;|vF4DK>gU)2z8G}}{pzoWSHt$hm;=XY zO&hCz9vFkU_Y4FF$-;D_9$ptrr=lPrsvhKvTcw76c@A59S@3#e3$!c$g<3Jv3AWxpi-m2|(7HK9 z?Gv#aUyPZK?Ve=9)_z|=uNS}Jr>hQ$1t~SKRm@_s#yuGyJX)z9KCmBd)EJ}2J?n;h zOU#22+txzkH?!1cJ1*hMT5n)#xxo-qwYXZK+B#fb=OfJ9;YZ9{G8)zdwS}t>-eSXs zbfy!I>Tk8Wg6&vuXq1``P1@&Bj|HVehs7PC!ST8{{Mhg4Z}dm!((W*)^@o^eOAql? zQZz1|UI%)8JPPOUtqeW`qwtQkqq^$zc0gwx>aMaSarvDEctvTC=jSYe=`$C>Ip3*b ze{wUJ7V))uEF=;>9ey24-D-s+R{e-AHqFJR6W^$voXuf=TO({dKN~Z9eGW-yO5&28 zy~T`Au42=qLU_Ca&4&^xuq%8Hb}w~b_(d+oe5uF8&4UrJ{l<2+!`$EC+4)VPYtB7* zbU|yV^Kc3r`?@a_UuwV-eZAFMWv=6lJy&6Pt90zR>jWrWZ{mT18$^eb{h(KsnHbVE z7dD&KLR{=W4kz|HhHrYmLf6rnFlIz5+SaFtk3VP&{x@5wnN^0-dUjo%+`kJ>I*nrJ zw(5A{^HLy!RzciXQ^kwMHQ~tJ72?aTW#IYCydvB|@e8QL_e4k17EfQI?#?s-!^ z+vI*s)zrET_)Ct#kX3jXGYC|S=%0~+k=N;Ot;lAzvm+`cb_I=mYj#B zxr4;|!nL4fK}CJB<9FyZdp!Kmavwe#`xgCsw8PKbi`3cmcVey8d(>yKMX_sByL!0o zhxqo#Kums|2;CR#RgVX5g@!p2V0)Kkn6k93dUC{Bc4{q%F;Z}=K*N8>Q?aBXay(p#JwKNlL?PN-vPACysQm0Ilia5%H$ zG)&z5Dg3Iw0GyJEA=_($wRkDm9=1WfxB;;7f?!y*;}0x%VlRGND*=*1jzQqdu=i&P*W$>QzjVOHK z1|0wF9tKysgG)*t6eDh!vBXbZq4tAu_|=>X>cfon_U<7gyt~pNgtMzPs^>tCTvB zn$_8R5@2bX31cRe!LR7Q0O((Q5;U4wK#aRT8M?N3A$E8hp;G!|_&HxF1RefbtP0DfBD7vqI;pi$;WVV`!U$|_1Eezw0}vznhdWt zSAt(7+o^SzFNE?X*Few@-Z=KkUYN3H7M|MSql!bTvDk=Y(dyggupohqrcB=en^W?N>Wc#4L#*~Z1RmT>!*%gJ zVR^gPIH1N0_`^0yeRh2&URbeCeLZ#w`YhUli(|jRne)TdKe~N_mqUAsz%#d@>)eg% zzA1ov+jqfc<96b@#35?ZmPCj@9|dn#&x7stZ;1!_ufVB$Hjz#~G)wz7#;W^TLE+&) zK<135u()hBb-|SaSpIAk{CwYdjM*?iJyyhqt55z)XP#9N8;uvQM&E_DAB_->2GwBr zu=&uZWe12GKNeJn)yDn(4 zzmxj*#!qN0|AQ#dt}tB46OAkO<%L!$d&HcAze4MpBh>y!cfr8@4{_bL`luE*h*!&Y zLX)9Ea3pytzKq(T)|`77kJqS$$3km@wVZ+#onSNw&{Eu_s=UYb}!C^!-vaa=<1@-tnO@4pw3x%GW{-u z6m19(Q%k7VzsQ3x`m_`&!~4N1b+@qm))>35xh-Btdyh@bDfM(-hjjKE~S@Jnvxpoh&HOXD0HrCrM6)H^V=bL zc~NNk=?;;rk%C)VE*3X3f5*iCL(zFS^z{Bw{5-M>QAk!sLnM@906#cb>%NZu~_$hGC?> zauCT(h(g(fjX3?o2(dP~IHx_C#~k=WIce7sE;$Ni&U*ZX{|wsXs6xjkET<0>tGUB2 zE1L3s3J*X9oj>BlDpxk5WoZKckCoDK3BhBivA|M61Nc~e9+~QXtYvp0YHrn%OQSTU zMOyLYFS==-{s|H}*+k<$?BlJ@Rk-PC!}~rAfU;i{-(_7x9cp)Ym4PxjC`>|E)M`W* z*$O_y2+CP{5jPk7fk#XRtsgTCvt~VE!Pjn3cC#~#8^_Xe_4AmxdOEsK&ZYM=vS>^F zb2j>%I4#TiMK|1kLv-(McJpozt(n_KX63i3YR?(WP#A_4W5ck*Zy8=1U*_jdjKy;2 z6#jXZ7G+hyReV?i!soKS-5r7IZ=O5FZ~Hi@xgF{Dk2i+TLKow!s(BXwX_ON8Go-1ve$wRH zXK>oKpN=>7;!Dd%l7CyqGt$c_TRD!`+qvSDT_Sy|OF`TS6;|F_LjML%;)d75(fmk_ zum593y4A)kEiIF-tLnpRUMUtQl@ZE|P@glKt&CX*(c9-~^y)mCtd+o|l_D|e(IcGA z^+j{*3;Kq=v_S6~v^O=ASAQ7)*K&*soo2H2#>=TlN{jFA@1U{6U(*l$hp;FtW}i}y z2=huYG@6csZOq2rN3+mrkjnOci9}KQK_+`Wo6_fPAd7cN^e18sin$X8t101}y&f$N zl7iuGD>R?p!<;g8sKWOh>nPg-S&JH$b$&M;*e-Zae?QQzlEKgpyMdJ{v#H(5gnq2P z#G?ay5!&2{6H^o^HP!?B=D&gOmjQgq^iJ$)=%Uo!MPzo#kg3X!!e67e{QE-{Ww}qg;-A0dbJ|=$i#8hF0(!yi0UbA%=qUhRCSDJ3dH${KGtX;#F0QTj4h^1(gNjG-d9E~qmca$--l#@e=3;rj2cZ9*i5Z4=yzyBgq1jTcLeh{ zNk8f54o7}H;X5LQ^D3;Rm?nkbiV|9Nr zERH`xu+#$7>o4F<4;pDk)>B;U^CP`uj{GRQjwF=?{)}IwzQMF0XD%m;Kk_WkMTSE8n5xiqYWCE^NW78e}$oV6E1VXSpY!)BA0?+q^@E<3Q(9*P{t#PS1pTSB3iHe|DaY$8pZIn!#eCSqSGNC0f2U|tXuxK=KW;x0xp9>w zUH)RcW)4N$#$xWMP7FWW$CrM)M>8d(kv7D$>>sb& z2Qet@p@nVM+%Uo#Rkg;qy?uq!D5{a^gC zBz_f4SB|0Ajhjy!>m-CV8Q{-v7t_}No z;U|oDALdIUEHT;sGCudI)3=I2bm2uE#oqqF2Yr=B=E0Z39_vp&hT+`q%RhmY8pr2Z zlu=myI%eiCgI`bQVCTMXG-taPS3LBW0+c(rXm26~Iv%6*HltmTJ4Zz}Q8@SH z1`Tlwfb$_KL8sT_1`2xAkjl~ZTLC{+ODTHsUuc)L~zo-*9ScenVkp zFEQz-JC?6r&%ST9#H_!^n60Fc|EQD2zBe!EpvOJZA1#NHCA|pVdB*6l85%?5W=y6bHmmq!(>nYzwV*vJ ~8D(V75N$HXB#kX=qv?B5J_|Yj4UM0Mu!2N!w9Z#&{hp~P7@SDOZppYY_7z+=SkTCsVw696 zEA$q=Vr>lVlTAhSA;B=Pcm4IBgppiud+w zF>C92Zi{(T(7T>Hgs!Dlr;~i$(b=RoQ;u({5JQev4($D(Avrgbmk(7{sTM;g9b`mGkN6?DS2jnK8Iy4O-+O$Hi14P$E#XOgbcVeGsp3*Vt}{P)j`(3yV@rltNEd1^mZ zczma8zyHtx|C7{oW)TyPWZ~MKC6)Lrx?pI=He?OK9Ca(f!;hwg!oH$>FBid+X7eNq z6?kU+V&dLMXvnW;?4iCY6`tSDA9e=NS!rp$%FZ0_eUa?P0ztFp@WoZ8ti`^rplIKbZ@?YA5_53cfzq_z`OODa6 zx1FSy_ZhE#ZR6Yg<&lmmJf!&NVR-F1 zfi1Wv@M;|;{DgiJrYlTg_gqXcb$%Rw+_?~oRtEFS2`_1zLj)D@*K})i58A|v(H`Cb zYpogdbMg)n+Y(8QX74H5*94^&CG6+>REpXW#MCoZlbT~9TVJ;a6>@vwzDNT@CrjbS z^=G(Qb`__V&&BzTQ&HG40G0DjvMnhO&=kIl**X_LqN=UYFrR~pO{pQ@l=(vn?R z=>?tO8EmnGG~J7H;fGu8VNzvJ-rDB0F7P+|=y{7q7W%VS+U@xIZ3|6n8%=Th&avAb z3b?Km&)Y3`VUJEe8$ZxM;Iif;_V{j^eqatyv=Qdw%5hk6Wf4xfEaPFjBI*0{s~A@q zNhjAe@XuNw$R_j&Ox@LJno>0r4_QTC%-=Ls|Jfdm5AGO*_^% zqE_z!3;R2eww$Y_={@>X@+p&tn}%b#;&(c|SQmrW{-o^tcj2x&5sMq1z^YciY z|C=2O|4OAl3)rDY_c3o#H^#Iy!$0JKc{Q&&eX$r-KI$pH6YnF?jWIJ9@@X zXWN1_F~d+3?jGC2?wm`KI$rY1n&*=oZwdWb_ zjn2d76&>_y|7QBj&++tPYck!eiXpr7X*?(XV#zpKTjxkKdRO7sAyu?ToWO@)yATp? zkE&=d-l1{|E%Lp5R`x{P^Jt=)sW+&!?+ZJndyLjD5#`qN_CeybD$gS+^hg%4r3)P} z>ZJ|MlNaWtD~s8Zbw*UAzMQu&^}&StI($53MKblpBwBkMg$k`~$Jve0Rx%ZM(Ftgg z8_HjITtsZlV$7dYPp ztwkO}B;Ek)KUO2mBA<;+)I-Di`SdbbpBCh3vxptaqfDe zuV&GeCm-mocNe{Tcb{?|w9~(o>-3+R6fUIR-gcJUn?lx6+1zS?Bi*)IO)Iyq zC8H(2ynBuww*ET8yTf=gLL_)9&Q@PfWkBnP*1R{mH6i zws|y+{@T;0Sw-}u<|UPnO2F3RHcY8W6MWbU+M2tVJo5Uu$*u)xzWb16FLR;Nb8buBpNZ}0@6nx5#>$J=y>sbrQG4?wm3^>FBh52RoTHYCT3QIHedAfHY zjntivf=#n1)Fz!GP)MPCAAPd8K|VD-kd&y$QGHMTWV|S;es~F$N<*|ztdKVm#Rnlr zlv3YC)*7!^N9F*UVj0Vt=A5R7O|{URt3%Git|Hws0+X8TVP}3Ag`0yYVeKCD8eeCV zTbd|r>_)CVEDz!Ga{PW+Cw-}0&r$^6Sf={s#a*|&-v=zL9jDVJd? zbA?P+OyiPY_tLpNW4X_S<8*tJ7KJ@ugjY$=QR?*>iYek0rejSSnpfzob`U8$hEiM5 zWh&b+g+Ccyj;;1qJYrNhKHaay+1A;@oII8{e}4L7io>@ z3G%J0X1Phef{$zm6&G!)Y3zfC<7vzo?ahy=wBoo~5d4}h(s-jB4Enu*?!W)VB=f(} zui_opwXYbLTi0T&Xa-$j?I^magZ(|_r1Bv^*hhvk**T&x)e}5Efur_0Fo%o+M^O2e z6dp2eIcn|D~sZ_R(B>!Zx z0b<+fYW^RJD%nmBynxo~4n#)Ec4iygM|xscFyK_2kWKxHj%tR{vXe|XqxY|MnREqGg8W>Ooc(z_}>A@6ep+Ez(4^hg#Y z9*Fb)Q{93;IghVy1O3@zNL%aA;GQV4A+e=+d909`zj+3~H#YbXT8D88$-Ka+3QGF} zd3CxwY}NFcThtGTFUg`gi-kGB<`I2*nNCWB&QZ$NO6tl9!Q}au=*t0VF0=hLMt6si z|JOnA@&C+>_3ZK8ZyF79(#0}IVdmN=g`hF(d4BX)I(AnZHD&44c(Ia;9J>d%^c*%x zdvw=5$67;o%}|3 zJgj;S@PztFR69VECBHI*_ZJD8=;;BEVIl0!+)w0Cbf3o!aE0-jN+?IBlk`(BzV2!k zEJi(I!$S&S(;h*?T9;#Eum`31zk&9#r-=UKiz$Ad+@@$gc6}|UMWPo;De(gx`f(10 z6{>vB@12PKV}=OBQo7@o4#Tzg(P=alp;um`;Au4bt=^82R^9x}PZfH)NseL^ym7SX zDob6xlWrwV=Wkguxz3ls$uIeE3e(`byRTvNy|ol({F5%5!~p6^G&y`D46H|C%Md4S z?-okE#!b{O7Kk^8ws2YZR&1W9$)wcdaqohTz)0oe%^w}E<r3 zrT!Qy`2L<4J>?b-w_l<24`1Nv(M{BH;xozk+@j}>s_@>XMf`>c`*86ty*a7L>+YPQ z*P9m5q-lM$^o<%TFWm;yo7M~C&UW9sGoicJ5@P8;%!|{kSe~E=cUZ73J4*M>@hW(`@n7-#dcXLgl)pv+@ zXlBxf=_yg+cFbWZ7Lj;+bQN7!oR27piR{o%6?`wgP2q>0kV4)g*ktM8 zM#v$excM|mQG!?7uEEBjcYKOmF>Mqb1m~GW^uy5(n!2;$c5ft8{&fHmtd_3E<>K$i zV@!Lt59!tR(JIw@P`5ZrUrqAqr0)?nRx*c_7YWxpWI9rNhjH1nlhJOFPWzn}q3uyR zGyfe=k5qanc>O)PB|d|Ks~vFeqbEX(E>q>}AU5i54Q@>}Cz8DjkB`x;=%Y0m4t_vS zmTn-`qzGJ?;7uBxnS6}FNz4e$<^83DsAzuxQ%Y&1D-Jmb?@NGMz&L?tT7i&)J^W(S zAZk1R3WqP9qD>J6e275;{#}cs_B9JgdhtS1sI$h8?BVpPq#UDXbaNS_uLy9Q%rf@_ zZte%z@xlKn$TynpT6z}iUi~exu!WB_F*`f)4q7BSp2xm{lG{mygFGW6&(N zWQ!unZ7`;cFYY*{Z_D?87PzIK%Xql62@+DjQ-k9k%I(mjY*T{ftGhIJ`dxwli(<=H z+2D$zH0>xiMe?&R6ghn+8q!u_Z2NyW-DtyBKT(03w>fM0 z24n;uLVWxX8e94iSF$>A+3P;mUrFVWLcZX^`eycVkrz!Kw+XU7N9g9DP#!znk1ju* zjA+}F7$Q5F#mM(TWKIX6CKsBipV_OH0np4j$-N(n(sQ>X^gylzU&p_N$(mgl?e9w$ zUl`!5sSp1XS43|v1R#82JSntVV(gqqfx8ML*-LlG=k{c#WG_Q+4>nQD_2JOGKb-&E zH-rX>j^Yz69kI9Y1%`$w!q@)`9eSWhuJ*@y{PA(vx@Wr@oThV=ekrc9)E*tN38|Ou8g+v4WBe zhpQ`CU_&HjeICVaKW(A?V{Y=nf7js8s#~PKc`)IQJ5~s}_$5PMvD6bEabNcYy%}bY zf+?j)PUs@3uXkD4yZh)#vSV>)dT6d^DBJmGKD3uj;^Q-);?R(He9<0L+-tc)|BU3| zp1TxhZPcmGI*!lLQO7H-{WSOcUosjrmH9@t(eA0A;gzF9BJscY(wiwX`E3S`d;Smo zPMs+7(Zt>-wxqVd4GLbJ^ju>a@&&JHmB7N@lxgBK7WYF=`7a4X6RuZoVajDc&^gVV z|1f(_m6BI^<<=uqV=uIhq_iXPxgVX+OQN>$JXY;66YV;2e1J#?q+X=+^b#o{16{?Z z44X-~=Ebj%ccmDUB3un0hDiT4?CpYon78u;cGVW3Khc=0XO4rkpfk}NTiT-?!0li5 z(&AnZ^3nofDn`P#HJJNxHSTK*9!hId(*=R+ z!)c+184Hwcr%TF9+4r;=SP;IGqGsvQ)Aj(qQT+u%?dI~gvJzw{V#s#NS&-s{TevrG z1a7>qA=AN(KHPNVEu~i2_Pm#Gl#`{hNEz1fypIMvOyJuzMKI#%OcZQeC1^3N6qKq3 z&p)BGVc{pZmaFq;B_0s(F=C7Re6iFaoCWxqVD09G@7BFP7+|Udi9I)vX=(24+(CkNG6uev0B<;>k338r}bUPS8Vcq15F$x|O~#hkKi- zQtc_tcXK4}b{TUlN0Paal{RlE!TJg7*|pUTxHhqhNryYa?LsC$RkjWa*Tk^@#B+Si zy26~ET9Kx93kD_ZqR4_+*iL^yAt&Tn?bb(N31&1VC>i+$ecWcv2_aY0NuR8aQI7vp zdVA?6#<)lEK!MNL7$wXZ6*DP>ZR7h6tfq=1j%?@1dB_{JgDsnHLwk-2`ekwpEDj0Z zzKqU7+UoDD=xhqz5HdwAchu--zc|J0ARq}!AGu=e^!Iv}5cb;ea}o!MD|qpxIXo1W2c>mHWkzL(td@eVVOk^$F*}es}Y%diTGFT5d$K)2wM(gJ&y4m-J?i-83 z&Zq(?Sm?>dGkvX&Mk3g}8A(j9dw&l^ zIXlB6awQcl4&=%sMo{FF0o-)OEX=unpU-v~jNs}}HsQ7d3?`Yg@2Zz5^XOmxD(^AH zZ#l))728qHN_gTeS)A=uW^$@~X=Fz}HC#JLx6_Kbq2>xGe$+r|%p%IRx57y0;gA`+ znvNgoCgqNuSax?LiIvGfB-0DOn%^<+XPbm9WiiY36MWb0rNaAB8LRW8nazY>6c>{N zIoCiG>klG%jSxf(6Y|mNYSb+HtDjo5iUEV84cecI5og0#PjltQ(aSUhy+~}y9&Wi^jXvG|!_LrgGzCeZMPnR1*e|L|3K#NQqWu2I$8>Aw zUY0tdk1{q5;S;qCNNm~w`eUbs2{OU#c8C~kyk4{1P13k;&H4U?&mpa92v7CFIHw{9PS@|_{UewlQ^eA!rL z{bePs(buE=hOdI3VotY&?f{nq@A+GWVRY=l30PO=VB1_v2u&$eCt1yJ88}kIm$jtu zp$az|!uXU&lDM8ZjEPxTQ*G)d+^A@zXD8L*XY+vqbHDO4`;L-Z@^`LMJBGBzB-59@ zxft_lD*ta(DjN7n7BFKM!i-;0dD~|!tUS)!H4outz7_S3>LKZHT@niy!`d?$?1bMNhOpf#g`};q2U}g+P+MZnR^~8lj+~A)HE{y(+)JWO{q!>6HzxcWLS`=~ zGXDWCkdK;*ua-aP@y!y77*Z$9c`C?@52ohPcWKu-HQG69BI_@T!+$jcN$ueU^1ghX zoBJ)GHJ&;ot}zqiXZnzN;%~f(Gel+5V0vGX&sSK*Qo*#Hq$Hf7$3CT?Yu6+g7<>|P zk|W4ZQ<0xB)__@ezWwxP=TLn0 zk)-RB3LtY&mVI2=OWtGV@Bj^Yx;3Jac|=dA-#RPt(#Hj-9Q;w!Eki%form7F9fH>V z2=Co)(R6uFUbM^vQx3i3MiZ~o10e&t{MkP^m|kNNMKe&L^Mp-kv&6-k;n1?IqG6`l zeh@%yFV)zYwMvk9rA4?=r)CjJ{X9DDU! zna@5g=qSb_&EY2o%*`Ry;b)P5<}L;Nb%5QLI;shME?iG{S{uF;2hY8u(BJJiJ*$YD z$lK8&mjseKZBBlZL+F?J8Y;0H&C<)HsHfow-|DfRDh0o1RAwfEj8pjLOXBqIVFLEF zXp!u+PT^d0q39!PSxK506vv+C4hO#AnawFW@hFjk)F;`Efzy3ifZQ>>Qq^K3?Xr>lHh{KAC{b9SB@}{eFug>9X9TXN@xGn3`hq-m z%T3_!g05g7uxERst7y&*0}8#_j~t1Scy~RHl4ZM@?TFEcd*OyRLJwY-cRJf9;(&|} zJL(fMr4`1r*x$8=w7AQJ?b_ZAos)}Ln`ITmwd^Uu%oq~K=Wxxm0=lnz5385FMoL;K zPcxFo>4_EmqE9}=Hk%^x#dcDvDr2p`7eGe#Gl?EH#AhFCe#LDJY5s9xP4kve?3Q>| z|E7uLJkMj{P$gk!{LOaT$H8dNZmvFX0a;{(F%eI1>Ke3}x&GB5erX*u9w`CMHVbC+ zu?gSR=JK5vW6A5a9FrV%pH_`ALe8-5m^06pq}t2L_`5GT8<&vI3OjmM(?_$aOK>9S zIcYWpv({~e2wo}69Sg@$*4lDfxAP>r9dBd0gf@*fauxFSYv^kG7z&-4h(%tLur|}5 zzIp{vYMDKC9(;u4_?M_WFb|U*^(m$+?xjbkfty5EQYW5Ad?$qW(tHKZ?wvX~1R-pFS z0m@jr1uy5nT#~u=+i6b706af* zh|UgwhY|4thtwyuGyOe8yDtV))`((E(n&x~#86)Ar%Xjn#1`tAlhtE8?%F4gsk^qY z39rvW`t=AtR&^ddxOjjnls-XzdJK;(pG5}aY$@x_Q2On5iuC_e#j4@!xrxBHi^j>Z zFHQ~kC1JtFt5ss~$KiCQQxn4lKe0ReF;zWYMolBnf&KTCPAAW$C5v~nQAuy;b*cv2 zwDJUHod`s__;?Drr%qxG(d7BIi&h%9;A-0$rlr>c!@jp{=DkZa^@R(9L;7L9eJ`6W z^v!h%I-+$%Gig}~8Htcu!9yIurq2CG*GIdO)t(vTKB|J<_b8)=_ec1qUEe9jX&lML zJCWu052XL?0Gvm6aj}*On3_G94|v>xcURQ;Ol?C-{O$~|`-iFR+-q8RSPiwlrQD=M z@Q%h^;O`V2=}2)bUI-rEfG9xTHkY2L7-8=~z&SyTTfPgR7y7p-EMLeq_Y0k8JG}7n zu@ltu2f|cQnal1tPs1Gxg-)Di`nUW6yY1wPb0ThRpYb`2zEZ%p%>4)TW+}EnvK4b= zAJX?qUktD<uWT>o(>f?Rf^xYnZ%UelJ2cZ zaE|MS`+iG0YNm~Z3ol?kq7zawUs(FSVDi1$#Q$CLrJzqrF#I}*4(>Y4H+EknC;3QT zCSnPLAYFVJ6-Ns{^zw{yORNw6%$Ef}fK|BzA2t3KzCKXE!-Ij;H^PN>Ia#4^#Z5dJ z_mQMU1m5533oeB`<9lyP;g4{JWgHq#8GHv{I8YBhZ|)%5HU!FUm5e2DMoCxy8-GB#nByoS=yM|4J9LII(%UxefegIjw)%sY<4Tv z-jT)7KSOB8+%5F;9?R~9C!*0vUMo-}^0kqtu{w z$BLedT9SrxJU@Q<1ubfJf?CC9>PHL{HP1%S$=S^M;BRcmO=clm3W1>xkg-X{hbA@F z)6+_)Qq@UzYzZxIc*C04348jy1|h?Kj|%(#3G;=Zm25voD-v^XJiv!eJJ?a%y+rDC zFr$FCpXtnnAILow#!NH%*bal_p$+G#b4%l98Uk zca<-sjxG`UD;|odO*M4&wLkA`o`gA9`Y2iB9<|RG*of1|1n#Mmi9OH9V!Kr+Z;!!~ zqAASnO{dVoUdIcx^5wF$yyA9 ziaM8D(>2#Z+f6jYqUp);f7bSU<{4y-{m*VFxTVu-A z3SKo!h6aA=;s0)r5c(db@Lydd^p=S6{<>b&xgH129W3}0nas>OoHm!OT*6hSRKL2>v_hyHX3!pj6N3%_oCex@^qIaSJkf+(|Cm{CJcw`jQ#Yg(jNsi*Xe+- zHGfw9o>qPAW&H>4QggKfeevt2`)(VB?&6_npRB`vn4ch@;8VOL@uQ$S{YK<2Db!X* z)1GD0bn4w*`ejx~eg`Y)?9fZ}=>M$5<_yrNdHkU5E^=GYOw$kVqLQWYXjVH-6(Peh ze!&pT9$C%je^JkVxGbmw2Rs z5t?;u`L5$yn6_HrU2pr5sKa=^s&EIjFc&xq`@CzDAp-M-{?@2i9z58DlAhYJ4cUG$ zjH+W=KfaOe_zBdUW=F%k{_st*`FMZlA2$;EG5>2=$?iEtlS)f0JE}ex>%_e%@6jU6 zOLe2;!Y2z9#r&Dn{PFa2*llvs42IkJc6N2UJ1sC(-Hog6$pu3 z&1NUf&XD%O9)4cbjnY$3@s&O2@m)B>b;tLR@)8Y-?i!5gni_0Z@p>E$DaGKOVq|n$ zkL*mg(VNt1r0Q=(PT_vs*(?QS&sOn2S}rv7Z3Yv~wn5v(q5S5{TKv}-0Q=QH=(FVn zw(k85`t;}-t10p#)6Ah1sP_sPug&@2e{;xTvlHuo7)2M}MA3DDQ&P{~!p0WmQ}DEX ztc(#_cPmkXS~IRT3Z9J2c>Mh^k?9FJ?X})dq4)G7t)4BxHvBR`adt21RaTPdv`DsG z%LHlpT69+EtKD|J3r(dO&>Fvro8;$1QlyAqzqTL8&-XBAD@|JTV;J+V3!sBH9GSP$ zBcaFO6*tLRL8aaGOhQ`}(XSP7cCRJgj;x@QYn)(z!-2+{c+stlY+<5 zKIAoLa>;1kI^mlLjd|Gj z`9$>QOgRnMKa?g9cZS*(hW@dABp)}05BICUZb@}MYilILYjpVAVOyxEz=ek>JcHan zPrfI~Sokg1==G`{xRLf0v)NC0KDfDQ zdP)yN_g)ttkZg(#`=hX6i875o?TUcqFVQeJguVN!kNz?t?>q7q4Ib&vM}?KreJNGi z=<=FY?W<;sgOzCDr_sD&oUYI;_l7GEeM#m8;kxoOZV!f=&y7H?K7T&o@AlF zHob(@P6bhZmMiMNg+k1ECwuNY5N+qyKy9!hIaS4R?brR#tzHIOJCKTUF+9DbsP)V| zR;WCkvQ#IsW961KXTedVdG8YX%h&LwUG4OH!A`zLp@Rl&5psR0=5%K91xPzir0F{( z*>tH0=r_7^)$?0%At{u(%S0e!s23Z0O%fK{o5**v2MpwfvF7ZB7)Q1gJu{CMpQ*#h z%udj@k+e=d0H-uV+18&oNvi1!SGlu}bk-@s>30pD`RHIyzZ%XKyhp{gJS_Cu#k0rw zBFW<>y~sF20g73aGNPFDGA;_8KT0^LeuNoC&qKqTqkQAAPTIC{2>Wf|PdZ9tS%jH2 zJ<|Tm+ufT5K1-hMTfK*@9Ja9wuf~y6SS0(h^FH3GsPX{gGjyM=0irLG-Q*T}eKC}- zCjyp7lWFjz(R`S54`$?q(dp(;xak_u;#*Yv9t8!nm1V& zSn~s1gtlbbaWA_qbkju~V?+PoPlE_dZ1-Z-6C*a<;xk3>HejW$M+D!MxX}b7>d6e_ zUV+*OF%*~x#b}Do6<7tm0P5KP54v-UaYv~3@LTu;aS{(mEGZvX_P!&RKyPw5`jMxf zb0jbM_jJ@)lAImKG0P{bkosGS27cES{MAdW;TFe_gU8vC%@63@x}*G`St=|t(^=;m zbK0pLL#2M=G|cY|UirQ!>zb?7-qb_~_Fv<%du%ZO-2nF1r;q}RkMdzQ2DDJril<&0 zOeHC{Sa#hBRSGJ6qDd9peOzH^xRgeoTS>a^eZ82=;Ol14M;M;nPsOs=> zl!wg5vu_jG#kqHJ*)obP*p)^D)&%h#kv2H``UqD$^qu_7mg7Tb1tM;~M&0gb$TqX) zTZ%O3bk=@$&Ndh)PJV%%WEd9q=_7E*Kosu`hs@|dG+*#|iVHVmVZkS!WYbIfdIpsH zP3VRAxQ)5Acj3agd@P!gg|6AsJk21JBHSa{?HE7QxR&r+hu6@wIvJ81U`YeccS5wa z8Y0QzOuG6vCC>d{L+2TY<@d(%>m(E^BqB{KN`(HQvNB4A#IGfV(y(_DlI%S)OI8Ub z5t)yuL`Eno4cVh4N(r6of4_g;Ja5jq&v$&j*>p1Y73laq0_~qp5WQ^=os(S(LiTqV zPrwlEbx+cQ&KWGaS^xHzVqD%_L+ZpW>RZ^go~pSfhGsSxN(RfFr+ z3Ao?c0b4R`@m7KaJiAzq8!S06`KcOO4C$fuuKghL<{M^P@Iw8LSjZB32FfdUL5XE8 z%*73&W%WwtTx!KJmW;U*lx3w^m16;|x4s`Gy#UO2JM%fqQr=pkr<=VdX^Qz~<%j z%I*>9`fEdjWB$WyTMD7NvLD+7!{PmFrpI=$f`-kmg*6)WBq;SXq_+yu%FNfuTcr-P zZ7Z0X)WGDEDNOc>A!C`DIArmTXaxBHE53&)!6p=yswNu2-{HZtaamaRqfM79iW^7u-QJRZmH4uUpR28Ot-FcbRV!}xKA zCEWyV3MXl6+e!RWbClYT8RG3-KSAJEm>^5OVAzW6MN#nYqsdU6aL zW}l!b)4e;Rs(}9YZ%_|eMRXtKrBlbc!2H$+!p1g+mix`9(f@{kePEbwTiJt7%I-wq z8o~UIZ=gJxh7~T$anWD_$ZrPX?0g3~_V!`R(O(eKzmLq^R|fryzo`csHy*rLkHMEL zF?RA3v8yw{o=IKO)sTx8EIE`rTYy$(d#L;9Bdir0r6Pmt@bi2<^On=Y7tA+zpfw8| zzFW|tjYH7iqCp#Ydf|@nXK>O{#Hd>FrW>*~WWjRR0nHJmhyE8@tS zP4HE>1T~anX)ZtW_9IKML7@KQDk;~mhKk7RR71xXGn(SC zFtG-Lhnr|tX$WNa%+b+xTA=+(3)YBAzzOG5gqr=q&G|a;(t{hT+!Y8O3PwF+5zy^l z0PDVbk`n0@&U(iR>1FWzlz<}5okaQ`^G$R!7VWMIfSyeQ{O<%kBl7)DV_yw z`$x1R&jWgFv+6-s()`%d|n272M=>Lkaq7-XXUGo8er} zT_D+p3@>2^(N(yD)*ee}KSvP5`Yguu)1P70mk%WE#8VuL2m#)e-uS&$4lVdB(bb*@ zPq`d`e{}+6<%gnT z6$it1525jW#ZY3?hJkC1G4YHn`n~LhFMHxZo?#n4)o7*T-Dz-v`Q5+jQ9Qeh59=%t ziez(XeQzpA$-80D1sAZ8EP(_$O+0jUkp7nR1G9+~dfdtvG91?9_xDriU;dQQnA1=? zp&PE{`omF^d6KVt1+!+FC{cKXm-m~JIVLx1r8R*mS?3yHi?4K^`;o~(W+b5HWq>8v3vzu=08 z#BKo(1$h6ADZCUvNYiziQKPpKR9nsAzi2ra{BIi6V^~CjT?*{xL?9$? z3^F}qFxs^hpO2K|V^%os<)IiRFok)?CeT8w5~oXo=x4@*pJrF2O>zd1bmkrG74imp zYCZYdu@^VBA0eE6c5vz30L`0ff~n>pd?`ALnjF4xD_Rduho1z4ge5R%<4#Idy^%=T zVnlU2E=u(#PFcs%lVJn~PT1mpxf#eBm;gQpE;w?1AHMxM0Xer;qFkaa+O$`}=&%(P zWpthbu~4*Msf`PCO2Ee27_7%R!AyJ{KV=>w+h1~E&{zB4Kc>8%ew47iGEhVhIqB0+dsSD@Mkdoq6R0UBL%z{r9kKdSK5Sx`{zq(` zKuK&rXbH#Tr-huDIO&Y6_7SjDcmatCoye~*PPT32gylh+C~{8+3dT*r>ZCNVDf5C< zI`e+H&`ry=P4IZdF1kA^0+;-{gI3P<@WMU|YZ*@C<%!?KURw|reBDCc?6iUNGUv(C zp(NmB_lJmcDcH%z0saG-SbSQP411Yk>(U-FmA!AGd~r7#mi|M@ zH#JP(?=qZ96osI87PS18qDrTN@y+I7+}-Yv^H+uN!xaInXY^;=Gu%v$JC>+%p2m`I z=2TRK$t(&o*-&dkc==?IG!(uCX^mglT4n$_vg#yV3~&ceBsMRO#t-I$O(x;Y(%0BOj+me1P-puF;5vdsc=@5KvZvz>=+hp!w09>AKq!zDN;-RiPkRrYq zXXJe0*oSb;crQuc#Hpi}Nj!PQMqnuLDDgG8gkMq#8Z(@cq8n{kA-okovvrWc1Qwby zT|#M-2;A#sLQn7|fX8xCvQF?ViV8JjdB!$^ob1#%3 zTm{K+!^|4)F3G?sX1R3s`6Fz~+Ds0w6Nijs0rZ+*2EzSD4Cg5l_yikCO3MLe8%qur zU5bD!LZ!4>YB?@+T#Z8F;n*?eO1CMfqi6m(O#fgGhmDugVHtL~9p+2_V|J#l?$n}9 zYh-cDvrFXfwoD9;I!oVnIKwb!I?YXzK?m925a}O;{(8+Q-p36fI)%NVo%m9t{{sTFng|t_1KE`>=%Gg8S#JgPieNShOr^2U;W2a$ zCo(%pocKL79<<`tW$N zPba_q0At^8bYo8j+L!jCSHT1XO~nw!_7q59bD{6E=W+WD9Y&`|9N8;N1eU+SQ_pwM zQ*-M<^2J`FaqkbhxhmrTA3vyto+ZBrv+ll0PnsN&}xZ9HAM_~ewNYQZdy1r=mm{3_7FHwL@R9F zQFVC=8t1B^bCe62c&32&<>iPnTLd5-2abia}XW`FeodbtYp zOIHxj)nYighLf6hcOj=q0zJ6O4byKWQLUAqu%Bxui3qZWw(11pR%`~>1cUJ+!{=S$ zXGlvIYeIKcF8q$GM;pm#V(_2^yVz%`+>zCoE!T{jwsW9=;4A8Sx(iN)?;{sJM#Ix} zqU7E|c6?E+gc2rAkmpzc+zXF`&aYL(&EE{xCq2OMWE-3d+C&eBF2wq=IO>^X!eoe2 z$<4*Wu;&6FwM_=B9;|@cMTJ;!y&b+^T@9mMK4e#)HK=4QB=ru8C~IgyTspY0d$BO4 zh1KJ0<4S52a0qVt4UwM#fw(c47Y^7M;$u@Y^04_OWa-6Wk`4>*DOQo$j(hle%8493 zDuNnX4%9VC1~Q~p;s1;%TxfS8XD?eYK9?n~9p-?dCl~3m_f2>?%@7=8{(#x6Jjp7l zMG3h`8eM%Gx5WMcj(t}^`ep+??AZy#=^L=i&O$VgF|1|!K)n+ln8R6(l>^t%p2-lK zZ*C@;O3%TdYLco5M8L0DInsJs5xi~U>8hs(AnD&R!Wk8fiV|yK1LI3_K6i)Ys@ISx z;7X@8mGIF&dm{I+9Wt!=7>3GA@GhPwUjOsK7?m2>Uf~H`KSQB~$pd=dn56MH%CUcW z6<(HJhif;qQa+VK&@3o{GN&xT!@7*Hu|&b%xEmXqpI~E*JGeE+!nJjltZJ4EG|aD zG=Atl&`vDu4&tx%#i*jB!t|6o@ULDwM&^EpwCZFmpl7M&`lS%De+ZqzlyI5q8@T(n z5oem;k{<1JR7rVEHz~q!*e*~xxr4e}3Nv2PH)773#oTgd!al2t z`_5aCw>^R2WR*p(s5yewg*eE1$_49NN}+3M0s2V}hnizG3^J=a#e8uqfT58 zFzmzW2CB|4fi~MlsKTe$OwNjvE->E&rD~-#-Jk)3!t>y3*#JD)7D|m&4`5Q`0;2wG z1F)|tgZ#o2@Z8Y~l1xtPp3wmcfr(JDev+F1>%q;=^I+?vf{hy)?{RPyN=*onL{CLb zPM86%u>y4ey^uCcOM*_u6yYsO04L?EkiYgkv-x6+TV*c59K(UqIdL5XR48N%JHWB3 zW7xd#Ic)4?bly|f@JQ$*IuLsq%YOd>O}GE>pLGYNp5hSV!iGCnzJoyi)v%+_0tzGb zfU`XVs!bGW>g*oqH2I3MpTEHO_$bVi*@gx=ZcqUm(fi?9)alh?w$hG}efKyZSGJ$< zitD1ng2fnCD+p1KhiSKt0(?`>Af5g)5E`?Y1`lq;t?FX9D`pzcFnR5f94AORCrLcZ zyTLQ;HT7WnahlcdX=QOHrdJMu+RRdhA<2lrf3mQ5$8ogLQ^iTS^+dt#8+>@EPJbOM z2C=%gSiM^Tg@XLxT(tz2tJHy*+Aw~cu?3#tB8W0NPW(@t!Dy)k1ZRtYo$nhBTek(8 zt0d{PixSp2?WHxgIw+_!O@x|?AkQifG-n(@!ZsN-7=IX!sL`YG(O9GXg-l9q1L>x5 zjPa?%Pcr{d*eVe${`C-jm#xV0U=QvnY=X;=|B`_LEAZoaMeja&ip_<*G-)g!4oEO8 z%8Nl5S=Ue2cBw*Vr8kaj*@-My8JbwM92M2ZX*09URX4H|?rpe<)x2f&EZa$p7!{|| z!rZvx=^b#NmWAD&*YOq)KUQY!8c&uEtkgh zeTNAl8?Y;>!Xd}4bZ_1`4nOWkqmKemXX8tJ8IH*orRSt0UmTCH9Yf{B2wCiZ;!7fiiyqRwQPl;z%1wA7H%a)xt!Zr4Abk zHoi@g3)N~lGa(kEz1>M}$ANFJ=AM*PeF*Wp{h?%3xn$4J<8}Y32)D79PV!A2O*IsL zkbPA>cBP+Pcc-~%zSaV^tfV~7cPs}-9dg{CKfGwbfEBP+yzdcqKK14?bqMjAay`Lv zewe_3Fdu%tvW@?RL=MNt)OgABuUscnYdiEO(`wJB4)jYHDhKMZCQ3TP!|HF=E<1DM zo=0;AkGR`{O-CIzkIMQF+_BHQ=Boc@PP6)BZlPJpAwK`^;J@zqJ=Wii52_{cDm;?4 ztKWK8ef?ZggA`lgz|slU3*VzPby0VB{p9{qFOkC)rx%mc>2Q_p%R#G`9FF!&xz0*U z3(U)P=mu~-mXd6gG*e!`YRkCHvt#pin-BC9U%$D0iSnV(Ru95VT)58ME%Mk|$#ubf zs9;=gOJkkij%`;30yaCxo@SfepD|LCN#wPv_F0SEjY*toa}3*8C(knB$U12IVx{p! zm+(kzJ8$k8Q*n;uE}3;shXb}P{Z-apso1icNcb*cd1NLc=Tnr9u^}aRnDEZRh?ayf>bm oUA? (https://github.com/michaelhart)", + "license": "MIT", + "browser": { + "crypto": false, + "fs": false + }, + "dependencies": { + "@noble/ed25519": "^2.3.0", + "chalk": "^4.1.2", + "commander": "^12.0.0", + "crypto-js": "^4.2.0" + }, + "devDependencies": { + "@babel/core": "^7.28.4", + "@babel/preset-env": "^7.28.3", + "@types/crypto-js": "^4.2.2", + "@types/jest": "^30.0.0", + "@types/node": "^24.5.2", + "@typescript-eslint/eslint-plugin": "^8.44.0", + "@typescript-eslint/parser": "^8.44.0", + "babel-jest": "^30.1.2", + "eslint": "^9.36.0", + "jest": "^30.1.3", + "prettier": "^3.6.2", + "ts-jest": "^29.4.4", + "ts-node": "^10.9.2", + "typescript": "^5.9.2" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/michaelhart/meshcore-decoder.git" + } +} diff --git a/frontend/package.json b/frontend/package.json index be87dc4..7e04e59 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -17,7 +17,7 @@ "dependencies": { "@codemirror/lang-python": "^6.2.1", "@codemirror/theme-one-dark": "^6.1.3", - "@michaelhart/meshcore-decoder": "^0.2.7", + "@michaelhart/meshcore-decoder": "file:./lib/meshcore-decoder", "@radix-ui/react-checkbox": "^1.3.3", "@radix-ui/react-dialog": "^1.1.15", "@radix-ui/react-label": "^2.1.8", @@ -31,7 +31,7 @@ "d3-force-3d": "^3.0.6", "leaflet": "^1.9.4", "lucide-react": "^0.562.0", - "meshcore-hashtag-cracker": "^1.7.0", + "meshcore-hashtag-cracker": "^1.10.0", "nosleep.js": "^0.12.0", "react": "^18.3.1", "react-dom": "^18.3.1",