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":";AAAA,mFAAmF;AACnF,cAAc;;;AAId,6CAAgE;AAEhE,gEAA4D;AAC5D,yCAAwD;AAExD,MAAa,uBAAuB;IAClC,MAAM,CAAC,MAAM,CAAC,OAAmB,EAAE,OAAmF;QACpH,IAAI,CAAC;YACH,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACvB,MAAM,MAAM,GAAuD;oBACjE,IAAI,EAAE,mBAAW,CAAC,SAAS;oBAC3B,OAAO,EAAE,sBAAc,CAAC,QAAQ;oBAChC,OAAO,EAAE,KAAK;oBACd,MAAM,EAAE,CAAC,sEAAsE,CAAC;oBAChF,WAAW,EAAE,EAAE;oBACf,SAAS,EAAE,EAAE;oBACb,UAAU,EAAE,EAAE;oBACd,gBAAgB,EAAE,CAAC;iBACpB,CAAC;gBAEF,IAAI,OAAO,EAAE,eAAe,EAAE,CAAC;oBAC7B,MAAM,CAAC,QAAQ,GAAG,CAAC;4BACjB,IAAI,EAAE,wBAAwB;4BAC9B,WAAW,EAAE,wDAAwD;4BACrE,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;YAClD,IAAI,MAAM,GAAG,CAAC,CAAC;YAEf,uEAAuE;YACvE,MAAM,WAAW,GAAG,IAAA,eAAS,EAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC;YAC/C,IAAI,OAAO,EAAE,eAAe,EAAE,CAAC;gBAC7B,QAAQ,CAAC,IAAI,CAAC;oBACZ,IAAI,EAAE,cAAc;oBACpB,WAAW,EAAE,+CAA+C;oBAC5D,SAAS,EAAE,aAAa,GAAG,MAAM;oBACjC,OAAO,EAAE,aAAa,GAAG,MAAM;oBAC/B,KAAK,EAAE,WAAW;iBACnB,CAAC,CAAC;YACL,CAAC;YACD,MAAM,IAAI,CAAC,CAAC;YAEZ,8CAA8C;YAC9C,MAAM,SAAS,GAAG,IAAA,gBAAU,EAAC,OAAO,CAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC;YACnE,IAAI,OAAO,EAAE,eAAe,EAAE,CAAC;gBAC7B,QAAQ,CAAC,IAAI,CAAC;oBACZ,IAAI,EAAE,YAAY;oBAClB,WAAW,EAAE,wBAAwB;oBACrC,SAAS,EAAE,aAAa,GAAG,MAAM;oBACjC,OAAO,EAAE,aAAa,GAAG,MAAM,GAAG,CAAC;oBACnC,KAAK,EAAE,SAAS;iBACjB,CAAC,CAAC;YACL,CAAC;YACD,MAAM,IAAI,CAAC,CAAC;YAEZ,mDAAmD;YACnD,MAAM,UAAU,GAAG,IAAA,gBAAU,EAAC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC;YACxD,IAAI,OAAO,EAAE,eAAe,IAAI,OAAO,CAAC,MAAM,GAAG,MAAM,EAAE,CAAC;gBACxD,QAAQ,CAAC,IAAI,CAAC;oBACZ,IAAI,EAAE,YAAY;oBAClB,WAAW,EAAE,yDAAyD;oBACtE,SAAS,EAAE,aAAa,GAAG,MAAM;oBACjC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,MAAM,GAAG,CAAC;oBAC3C,KAAK,EAAE,UAAU;iBAClB,CAAC,CAAC;YACL,CAAC;YAED,MAAM,SAAS,GAAuD;gBACpE,IAAI,EAAE,mBAAW,CAAC,SAAS;gBAC3B,OAAO,EAAE,sBAAc,CAAC,QAAQ;gBAChC,OAAO,EAAE,IAAI;gBACb,WAAW;gBACX,SAAS;gBACT,UAAU;gBACV,gBAAgB,EAAE,OAAO,CAAC,MAAM,GAAG,CAAC;aACrC,CAAC;YAEF,8CAA8C;YAC9C,IAAI,OAAO,EAAE,QAAQ,IAAI,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAC,WAAW,CAAC,EAAE,CAAC;gBACrE,2DAA2D;gBAC3D,MAAM,WAAW,GAAG,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAC,WAAW,CAAC,CAAC;gBAEjE,KAAK,MAAM,UAAU,IAAI,WAAW,EAAE,CAAC;oBACrC,MAAM,gBAAgB,GAAG,8BAAa,CAAC,uBAAuB,CAC5D,UAAU,EACV,SAAS,EACT,UAAU,CACX,CAAC;oBAEF,IAAI,gBAAgB,CAAC,OAAO,IAAI,gBAAgB,CAAC,IAAI,EAAE,CAAC;wBACtD,SAAS,CAAC,SAAS,GAAG;4BACpB,SAAS,EAAE,gBAAgB,CAAC,IAAI,CAAC,SAAS;4BAC1C,KAAK,EAAE,gBAAgB,CAAC,IAAI,CAAC,KAAK;4BAClC,MAAM,EAAE,gBAAgB,CAAC,IAAI,CAAC,MAAM;4BACpC,OAAO,EAAE,gBAAgB,CAAC,IAAI,CAAC,OAAO;yBACvC,CAAC;wBACF,MAAM,CAAC,+CAA+C;oBACxD,CAAC;gBACH,CAAC;YACH,CAAC;YAED,IAAI,OAAO,EAAE,eAAe,EAAE,CAAC;gBAC7B,SAAS,CAAC,QAAQ,GAAG,QAAQ,CAAC;YAChC,CAAC;YAED,OAAO,SAAS,CAAC;QACnB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO;gBACL,IAAI,EAAE,mBAAW,CAAC,SAAS;gBAC3B,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,oCAAoC,CAAC;gBACvF,WAAW,EAAE,EAAE;gBACf,SAAS,EAAE,EAAE;gBACb,UAAU,EAAE,EAAE;gBACd,gBAAgB,EAAE,CAAC;aACpB,CAAC;QACJ,CAAC;IACH,CAAC;CACF;AA1HD,0DA0HC"} \ 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":";AAAA,mFAAmF;AACnF,cAAc;;;AAId,6CAA6E;AAC7E,yCAA6C;AAE7C,MAAa,qBAAqB;IAChC,MAAM,CAAC,MAAM,CAAC,OAAmB,EAAE,OAA+D;QAChG,IAAI,CAAC;YACH,6DAA6D;YAC7D,8BAA8B;YAC9B,yBAAyB;YACzB,yBAAyB;YACzB,gGAAgG;YAEhG,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACvB,MAAM,MAAM,GAAqD;oBAC/D,IAAI,EAAE,mBAAW,CAAC,OAAO;oBACzB,OAAO,EAAE,sBAAc,CAAC,QAAQ;oBAChC,OAAO,EAAE,KAAK;oBACd,MAAM,EAAE,CAAC,4EAA4E,CAAC;oBACtF,SAAS,EAAE,CAAC;oBACZ,WAAW,EAAE,mBAAW,CAAC,QAAQ;oBACjC,WAAW,EAAE,EAAE;oBACf,eAAe,EAAE,EAAE;oBACnB,UAAU,EAAE,EAAE;oBACd,SAAS,EAAE,EAAE;oBACb,UAAU,EAAE,EAAE;iBACf,CAAC;gBAEF,IAAI,OAAO,EAAE,eAAe,EAAE,CAAC;oBAC7B,MAAM,CAAC,QAAQ,GAAG,CAAC;4BACjB,IAAI,EAAE,sBAAsB;4BAC5B,WAAW,EAAE,uGAAuG;4BACpH,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;YAClD,IAAI,MAAM,GAAG,CAAC,CAAC;YAEf,kCAAkC;YAClC,MAAM,eAAe,GAAG,IAAA,gBAAU,EAAC,OAAO,CAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC;YAEzE,IAAI,OAAO,EAAE,eAAe,EAAE,CAAC;gBAC7B,QAAQ,CAAC,IAAI,CAAC;oBACZ,IAAI,EAAE,kBAAkB;oBACxB,WAAW,EAAE,gDAAgD,eAAe,EAAE;oBAC9E,SAAS,EAAE,aAAa,GAAG,MAAM;oBACjC,OAAO,EAAE,aAAa,GAAG,MAAM;oBAC/B,KAAK,EAAE,eAAe;iBACvB,CAAC,CAAC;YACL,CAAC;YACD,MAAM,IAAI,CAAC,CAAC;YAEZ,6BAA6B;YAC7B,MAAM,UAAU,GAAG,IAAA,gBAAU,EAAC,OAAO,CAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC;YAEpE,IAAI,OAAO,EAAE,eAAe,EAAE,CAAC;gBAC7B,QAAQ,CAAC,IAAI,CAAC;oBACZ,IAAI,EAAE,aAAa;oBACnB,WAAW,EAAE,2CAA2C,UAAU,EAAE;oBACpE,SAAS,EAAE,aAAa,GAAG,MAAM;oBACjC,OAAO,EAAE,aAAa,GAAG,MAAM;oBAC/B,KAAK,EAAE,UAAU;iBAClB,CAAC,CAAC;YACL,CAAC;YACD,MAAM,IAAI,CAAC,CAAC;YAEZ,6BAA6B;YAC7B,MAAM,SAAS,GAAG,IAAA,gBAAU,EAAC,OAAO,CAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC;YAEnE,IAAI,OAAO,EAAE,eAAe,EAAE,CAAC;gBAC7B,QAAQ,CAAC,IAAI,CAAC;oBACZ,IAAI,EAAE,YAAY;oBAClB,WAAW,EAAE,+CAA+C;oBAC5D,SAAS,EAAE,aAAa,GAAG,MAAM;oBACjC,OAAO,EAAE,aAAa,GAAG,MAAM,GAAG,CAAC;oBACnC,KAAK,EAAE,SAAS;iBACjB,CAAC,CAAC;YACL,CAAC;YACD,MAAM,IAAI,CAAC,CAAC;YAEZ,qCAAqC;YACrC,MAAM,UAAU,GAAG,IAAA,gBAAU,EAAC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC;YAExD,IAAI,OAAO,EAAE,eAAe,IAAI,OAAO,CAAC,MAAM,GAAG,MAAM,EAAE,CAAC;gBACxD,QAAQ,CAAC,IAAI,CAAC;oBACZ,IAAI,EAAE,YAAY;oBAClB,WAAW,EAAE,2BAA2B,OAAO,CAAC,MAAM,GAAG,MAAM;;;oEAGL;oBAC1D,SAAS,EAAE,aAAa,GAAG,MAAM;oBACjC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,MAAM,GAAG,CAAC;oBAC3C,KAAK,EAAE,UAAU;iBAClB,CAAC,CAAC;YACL,CAAC;YAED,MAAM,MAAM,GAAqD;gBAC/D,IAAI,EAAE,mBAAW,CAAC,OAAO;gBACzB,OAAO,EAAE,sBAAc,CAAC,QAAQ;gBAChC,OAAO,EAAE,IAAI;gBACb,SAAS,EAAE,CAAC,EAAE,iDAAiD;gBAC/D,WAAW,EAAE,mBAAW,CAAC,QAAQ,EAAE,qDAAqD;gBACxF,WAAW,EAAE,EAAE;gBACf,eAAe;gBACf,UAAU;gBACV,SAAS;gBACT,UAAU;aACX,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,OAAO;gBACzB,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,kCAAkC,CAAC;gBACrF,SAAS,EAAE,CAAC;gBACZ,WAAW,EAAE,mBAAW,CAAC,QAAQ;gBACjC,WAAW,EAAE,EAAE;gBACf,eAAe,EAAE,EAAE;gBACnB,UAAU,EAAE,EAAE;gBACd,SAAS,EAAE,EAAE;gBACb,UAAU,EAAE,EAAE;aACf,CAAC;QACJ,CAAC;IACH,CAAC;CAEF;AAtID,sDAsIC"} \ 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 0000000..c1412d5 Binary files /dev/null and b/frontend/lib/meshcore-decoder/lib/orlp-ed25519.wasm differ diff --git a/frontend/lib/meshcore-decoder/lib/orlp-wrapper.cc b/frontend/lib/meshcore-decoder/lib/orlp-wrapper.cc new file mode 100644 index 0000000..e69de29 diff --git a/frontend/lib/meshcore-decoder/package.json b/frontend/lib/meshcore-decoder/package.json new file mode 100644 index 0000000..f4c81da --- /dev/null +++ b/frontend/lib/meshcore-decoder/package.json @@ -0,0 +1,56 @@ +{ + "name": "@michaelhart/meshcore-decoder", + "version": "0.2.7", + "description": "TypeScript library for decoding MeshCore packets", + "main": "dist/index.js", + "types": "dist/index.d.ts", + "bin": { + "meshcore-decoder": "./dist/cli.js" + }, + "scripts": { + "dev": "ts-node src/index.ts", + "test": "jest", + "test:watch": "jest --watch", + "build": "tsc", + "build:watch": "tsc --watch", + "lint": "eslint src/**/*.ts", + "format": "prettier --write src/**/*.ts" + }, + "keywords": [ + "meshcore", + "packet", + "decoder" + ], + "author": "Michael Hart (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",