aboutsummaryrefslogtreecommitdiffstats
path: root/packages
Commit message (Collapse)AuthorAgeFilesLines
* fix(android): the cast relay spools a receiver's lead to diskChristophe Besson23 hours4-44/+143
| | | | | | | | Fragments are 5-10 MB at a film's bitrate; dropped past 8 MB in memory, the TV froze for their length. Each receiver now reads from its own spool file, deleted with it; nothing is dropped short of a disk bound. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* feat(android): log what a cast does downstream of the relayChristophe Besson23 hours2-3/+57
| | | | | | | | Fragments dropped for a slow receiver, writes that block, a periodic per-client summary, and every receiver state change with its position — the only trace a freeze on the television leaves. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* feat(android): the MeshBay iconChristophe Besson23 hours10-0/+46
| | | | | | | The desktop client's icon in the adaptive icon's safe zone, over its own edge colour, so no launcher mask crops the M. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(client): the local player is silent while castingChristophe Besson23 hours2-0/+33
| | | | | | | It keeps playing to pace the relay, so it doubled the television's sound. The viewer's mute setting comes back when the cast ends. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(android): cast relay serves a clean header and restarts on its portsChristophe Besson23 hours5-12/+159
| | | | | | | | The init is what precedes the first moof; ports are reused like Node's; the SDK is read on the main thread; a cast that fails says why on screen, and success waits until the receiver actually plays. Never a VPN's address. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(client): a seek's first segments are held while it lands, not droppedChristophe Besson23 hours3-3/+106
| | | | | | | | They are the new stream, header first. Dropped, a cast relay restarted at the landing got no ftyp/moov and the receiver gave up; they are now replayed in order once reinitAt/resumeAt is done. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* feat(android): casting through a LAN relay and the platform cast SDKChristophe Besson23 hours17-35/+1176
| | | | | | | | A port of cast-relay.js (backlog also bounded in bytes), discovery and control with the default media receiver, relay calls kept in order, and a foreground service plus a WebView kept visible so a cast survives the screen going off. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* feat(android): downloads to disk and uploads through the system pickerChristophe Besson23 hours10-11/+624
| | | | | | | | Native save over the Storage Access Framework and MediaStore, chunks sent as binary bridge messages, a chosen folder that has gone asks rather than redirects, unfinished files removed on abort and after a killed process. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(client): a download written to disk no longer holds the whole fileChristophe Besson23 hours2-0/+57
| | | | | | | pipelinedDownload kept every chunk's resolved promise until the end; a 2 GB download held 2 GB in the page. Each is released once read. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* feat(android): device key, bundle key and node identities held nativelyChristophe Besson23 hours18-8/+1327
| | | | | | | | Keystore-wrapped store, a Kotlin port of keyring.js and transcripts.js held to the shared vectors, the same keys/device/secrets bridge as the desktop, and a native confirmation before browser access is widened. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(client): the node setup welcome is for a build that has a nodeChristophe Besson23 hours2-1/+15
| | | | | | | Gated on capabilities.nodeAdmin rather than on any bridge, so a phone with no groups sees its invitations and the join link. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* feat(android): client shell with the interface from the packageChristophe Besson23 hours26-0/+1560
| | | | | | | | WebView over the packaged UI (copied from hub/static at build time), the desktop CSP as a header, a bridge answering our top-level document only, hub calls from native to the signed-in hub. Keys stay in the page for now. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* test(hub): shared keyring and transcript vectorsChristophe Besson23 hours3-0/+716
| | | | | | | One file every bundle/transcript implementation must reproduce, generated from the desktop keyring; checked against it and against the specification. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Merge branch 'main' of meshbay.org:meshbayChristophe Besson2 days45-6062/+502
|\
| * refactor(mnp): remove ten operator messages no client sent0.17Christophe Besson2 days20-4335/+132
| | | | | | | | | | | | | | | | | | node_status, node_settings_set, roster_read, denylist_read, denylist_clear, node_reload and the signed gek_rotate, member_unpin, transfer_limits, group_detach leave MNP 6.0; the Node page and the CLI do this work over loopback. Their ops keep their tests, moved to the ops level. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
| * fix(client): no confirmation dialog for adding a folder or its flagsChristophe Besson2 days16-64/+13
| | | | | | | | | | | | | | Removes confirmFolder (addRoot, attachGroup) and the writable confirmation added in e4f6177, with their two catalogue keys. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
| * feat(mnp): sharing a folder is decided on the node's machine only (MNP 6.0)Christophe Besson2 days36-1714/+408
| | | | | | | | | | | | | | | | | | | | root_add, root_update and group_attach leave MNP: adding a directory and switching writable/removable go through the loopback API (native dialog in the desktop app) or the CLI. The operator's Settings tab still lists the roots from any browser, read-only. The desktop app refuses to sign those ops; a loopback flag change now reaches open pages (publish_roots). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* | test(node): node.toml fixtures use POSIX paths, and a Windows-impossible ↵Christophe Besson2 days2-8/+13
|/ | | | | | | | | | | folder is skipped The root fixtures wrote `path = C:\Users\...`, which is not valid TOML: node_toml now reads values with tomllib, so the four tests failed on Windows. The node and the app always write paths with `/`, as the other fixtures do. A folder named with a quote and a newline cannot exist on Windows. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* feat(client): list cast receivers as they answerChristophe Besson2 days6-46/+205
| | | | | | | | The scan still runs six seconds, but the picker polls what it has found and shows each receiver immediately. A rescan no longer has its timer cut short by the scan it replaced. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* test(hub): wrap a docstring ruff flaggedChristophe Besson3 days1-3/+3
| | | | Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(client): rotating a group key asks nothingChristophe Besson3 days13-25/+3
| | | | | | | Rotation narrows rather than widens: members still connected receive the new key, and nothing already shared changes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(client): hosting a group asks nothing when its folder came from the pickerChristophe Besson3 days11-12/+1
| | | | | | | The folder chosen in the native picker is the consent; the dialog that followed on every group creation asked the same thing twice. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(hub): a username is unique whatever its caseChristophe Besson3 days2-4/+34
| | | | | | | | Registration refuses a name that differs from an existing one only by case; accounts that already do keep their names, and a pending retry needs the exact name (F-26). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(hub): what an offer or a node message costs the hub is boundedChristophe Besson3 days3-25/+113
| | | | | | | | | An offer's IP-log row (kept a year) was written before any check, for any string named as a node; it is written once the offer goes to a node. The ICE list is capped (64 candidates, 32 KiB). A node's update_groups, a database read each, is budgeted like chat_notify and claims at most 1000 groups (F-22). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(client): the audit export never hands a spreadsheet a formulaChristophe Besson3 days3-5/+48
| | | | | | | A cell starting with = + - @ (or a tab or carriage return) gets a leading apostrophe; the export carries text members chose (F-29). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* chore: remove a spike page served in production and an unused derivationChristophe Besson3 days4-453/+1
| | | | | | | | static/webrtc-test.html posted a raw password to /login from the hub's own origin; meshbay_common/keyderive.py derived keys from a password and nothing called it (F-32). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(node): the clear fields beside a chat message are boundedChristophe Besson3 days2-2/+48
| | | | | | | | sender_name and thread_id travel in clear beside the sealed envelope and were stored and relayed whatever their type and size. A name longer than a username or a thread id that is not a short id is now dropped (F-27). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(node): a member is told a media tool failed, not what ffmpeg saidChristophe Besson3 days4-3/+30
| | | | | | | | Stream, transcode and subtitle failures sent the exception's text — operator paths, versions — to the member. Fixed messages now, the cause in the log (F-24). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(node): the reaper deletes only the .part files the node wroteChristophe Besson3 days2-11/+34
| | | | | | | | Any *.part older than a day in a writable root was deleted — a browser's download in progress in a shared folder included. Only names carrying the node's tag (name.<8 hex>.part) are reaped now (F-28). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(node): a revoked account is disconnected, not only refused next timeChristophe Besson3 days2-13/+84
| | | | | | | | A user revocation closed nothing: the denylist stopped the next connection and left the live ones streaming and chatting. Revocations now go through one method that closes the account's or the group's sessions (F-21). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix: an MBK2 bundle is opened once and stored again as MBK3Christophe Besson3 days6-8/+216
| | | | | | | | | | | | Transitional. The Argon2 run that makes M makes A, the key MBK2 bundles were sealed under; a session keeps it as a decrypt-only key (IndexedDB in a browser, the key storage in the desktop app). A client meeting an MBK2 bundle opens it — or its recovery copy — and stores the same identity as MBK3 once connected; the desktop app reseals or withdraws it as browser access says. A session without A asks for the passphrase once. Older formats stay refused by name. Replaces the unpin-and-reinvite step the 0.17 flag day required on every node. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix: downloads are marked and keep their extension; Explorer files are refusedChristophe Besson3 days9-5/+108
| | | | | | | | | | | The desktop app writes the Mark-of-the-Web on each file it saves on Windows, as a browser does. Bidirectional controls are reserved characters in a saved name (portable-name.js and paths.sanitize_for_download, and again in the main process), so a name cannot display one extension and carry another. The node refuses uploads of files Windows Explorer acts on by itself: desktop.ini, .lnk, .url, .scf, .library-ms, .searchConnector-ms (F-19). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(hub): a stranger who knows your name locks only browsers you never usedChristophe Besson3 days6-21/+272
| | | | | | | | | | | A sign-in from a browser that presented no token is answered with one (known_browser, kept hashed, twenty per account); a later sign-in presenting it counts failures on its own row, which nobody else can spend. Passphrase checks inside an open session (change, e-mail, deletion, device, pepper) count on the account's own row, so a locked name no longer stops its owner there either; /me reports that row. Reset and erasure forget the browsers (F-15). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(node): one member holds a share of the node, sized past real useChristophe Besson3 days9-28/+278
| | | | | | | | | | | | | | 128 peer sessions on the node, at most 64 per account (the hub names the account with each offer; the node's own account is not counted). One account plays at most half the stream slots, rounded up, and runs two subtitle extractions at once. Frames after the handshake are 8 MiB (was 64), decoded with per-container bounds, and a frame refused for either ends the session instead of jamming its buffer (F-16). Sized for the heaviest real member: twenty groups on one node, three devices and a tab, up to 52 sessions. Measured: ~0.15 MiB and one fd per idle session. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(hub): a group name fits its column and carries no control charactersChristophe Besson3 days3-4/+58
| | | | | | | | Over 128 characters was a 500 on PostgreSQL; line breaks, C0/C1 controls and bidi overrides are refused (joiners stay, for emoji). The creation form caps the field at 128 (F-13, what remains of it). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(node): an upload never replaces a file, nor shares a part with anotherChristophe Besson3 days4-12/+151
| | | | | | | | | | | A name an upload in flight will take is reserved; each upload writes its own `name.<tag>.part`; the finished file is published by a hard link, which refuses an existing target, and takes the next free name if one appeared meanwhile — the last ack names it. Two members sending one name at once wrote one part and published it twice; a file copied in during an upload was replaced (F-09). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(node): ffprobe over a member's file is bounded, and stopped when it isChristophe Besson3 days3-1/+84
| | | | | | | | | | | probe_video waits 30 s at most and kills ffprobe on a timeout or when its caller gives up — a cancelled wait left the process running. The seek probe kills what it timed out on. Stream, subtitle and enrichment requests no longer hang on a file that keeps ffprobe busy (F-18, timeouts; the protocol whitelist was dropped: ffmpeg already confines nested protocols of a local input, measured on 8.0 against HLS and concat inputs). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(node): link previews connect to the address they checked, without blockingChristophe Besson3 days3-55/+198
| | | | | | | | | | The name is resolved off the event loop and every answer checked; the socket is then opened to that IP literal through a pinned httpcore backend, TLS still verifying the certificate for the name, and no proxy from the environment. A name that answers clean and then with a LAN address no longer gets a request sent there, and a slow name no longer stalls the node (F-12). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(node): how a hosted group admits people is the operator's, not the hub'sChristophe Besson3 days11-33/+202
| | | | | | | | | | | attach_group no longer copies join_policy and visibility from the hub's answer: they come with the operator's request (the desktop creation form, `group add --open`) and default to invite/private; the CLI says when the hub lists the group otherwise. Every string written into node.toml is escaped (toml_string) and read back through tomllib, so a group or folder name cannot write lines of its own (F-17). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix: an identity signs a named kind, and a device approval answers a requestChristophe Besson4 days17-66/+636
| | | | | | | | | | | The desktop main process builds every transcript itself from fields (transcripts.js) and signs no raw bytes; the page's identity has the same contract (crypto.js transcriptFor). The keyring seals no bundle while browser access is off. On the node, device_add must redeem a pending request filed by the same keys, and device_revoke is signed under its own prefix (meshbay:device_revoke:v1), so a retirement signature admits nothing. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(hub): the pepper and a device key take the passphrase, not a tokenChristophe Besson4 days9-39/+134
| | | | | | | | | POST /me/bundle-pepper (was GET) and POST /users/devices require auth_key. A refreshed or lifted token could otherwise fetch the pepper, or register a device whose every sign-in carries it. Both callers have just been given the passphrase. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* feat: browser access, decided in the desktop applicationChristophe Besson4 days19-5/+231
| | | | | | | | | Off for an account made there: its identities stay on the device and nothing is left on nodes. Turned on from the Profile page behind a native confirmation; each node is settled when its group next opens. The hub keeps a mirror a browser reads to say why a group will not open; it grants nothing. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* feat(client): the desktop application keeps M and every node identity in its ↵Christophe Besson4 days25-59/+873
| | | | | | | | | | | | main process keyring.js derives, opens, mints, seals, signs and agrees there; the page gets public keys and a handle. Argon2 comes from the page's own WebAssembly build (Electron's crypto has none). Without OS key storage the page keeps its keys as a browser does. A node's bundle is settled after connecting, re-sealed when the key changed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* refactor(hub): the transport holds an identity, never a private keyChristophe Besson4 days13-99/+140
| | | | | | | | Two public keys, sign() and shared(); the apps take transport.signFn. What holds the keys (this page, or the desktop main process) is the identity's business alone. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* chore: bump version to 0.17.0, and the client minimum with itChristophe Besson4 days8-9/+13
| | | | Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* feat: bundles sealed per node under the passphrase and the hub's pepperChristophe Besson4 days30-479/+682
| | | | | | | | | The session key is M = HKDF(Argon2(passphrase) || pepper, account id); each node's bundle key and the playlist key derive from it. Bundles are MBK3, bound to account and node; MBK1/MBK2 are refused by name, never replaced silently. Playlists move to key v2 and are re-sealed over unreadable node copies. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* feat(hub): a bundle pepper per account, handed only to a proven sessionChristophe Besson4 days5-0/+283
| | | | | | | | Sealed at rest and bound to the account; returned by sign-in, device sign-in, a passphrase change and GET /me/bundle-pepper, never by a refresh, to a node token, in a token or in a log. Erasure clears it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(hub): a downloaded file opens in a tab only under a type that runs nothingChristophe Besson4 days5-24/+111
| | | | | | | Open is offered for PDFs, raster images, audio, video and plain text, typed from the name; HTML, SVG and the rest are not opened in the hub's origin. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix: the page connects to its own origin and reCAPTCHA, nowhere elseChristophe Besson4 days3-9/+20
| | | | | | | | connect-src drops https: and wss: in both policies. Checked against Google's reCAPTCHA test keys: in Chrome widget, token and registration unchanged; in Firefox the widget loads; no violation reported in either. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(client): the page names node operations, and the app confirms what ↵Christophe Besson4 days23-191/+548
| | | | | | | | | | | widens the node node:call is replaced by named operations with checked arguments; hosting a group, sharing an unpicked folder, key rotation, denylist clearing and a change of node account are confirmed by a native dialog. Every channel checks its sender, secrets:get/set/clear are gone, node:start writes the app's own hub. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>