| Commit message (Collapse) | Author | Age | Files | Lines |
| |
|
|
| |
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
| |
|
|
| |
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
| |
|
|
| |
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
| |
On a Pixel, Chrome still lists the refused address when search gives
up, so nothing tells it from a silent node. The connection given up on
now runs to its own verdict and the refusal is reported then.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
| |
Search gives up before ICE does, so the refusal is read from the
connection then; the walk moves on to the group's other nodes, and the
page lists the refused groups with a link to each.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
| |
Each failed attempt reaches the group page, which shows the same message
and buttons as at opening while the reconnect goes on. Try now gives up
an attempt still waiting on ICE and starts the next at once.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
| |
|
|
|
|
|
| |
A constant in startStream hid resumeAt, so a reconnection with read-ahead
left the player waiting and the film froze at the end of its buffer.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
| |
|
|
|
|
|
| |
Stream credit sent before the new handshake was refused, and the node's
"Handshake required" replaced the film.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
| |
|
|
| |
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
| |
|
|
|
|
| |
Android 17 makes it a permission for an application targeting SDK 37.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
|
|
|
| |
Moving between mobile data and the node's Wi-Fi left the connection on
the network it had left until ICE gave up, and a group that had failed
was never tried again: the Android application had to be killed. A
change of network or an ICE disconnection now pings the session and
reconnects one that does not answer, wakes a reconnect backing off, and
retries a group page left on an error.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
|
|
| |
Android 17 makes the local network a permission of the application, and
Chrome 155 targets it: without it the node's LAN addresses are dropped
and a group on the phone's own Wi-Fi failed with "DataChannel closed".
The transport now names that refusal and the group page says what to
allow.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
| |
At 1 no process starts and every lane of a download lands on the node's
one core. The Node page also sent every setting on each Save, pinning
untouched ones at the day's default; it sends only what changed.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
|
|
| |
While a reconnect ran, every request went out, not only its handshake: a
chunk retried between the new channel opening and the proof got
"Handshake required", which no retry treats as a dropped connection.
Only the opening messages pass now; a replaced channel's late close
event is ignored, and a closed channel is retried like a lost one.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
| |
|
|
|
|
|
| |
A tap left buttons in :hover on touchscreens (pager arrows, nav, player...).
All rules now sit in @media (hover: hover); test_hover_scoped.py holds it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
| |
|
|
| |
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
| |
|
|
|
|
|
| |
READ_SMS sits behind restricted settings outside a store and Play
keeps it for the default SMS application: not worth a second build.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
The link under the Register button was glued to the sentence before it: htm
drops whitespace that holds a line break, so "deleted.Legal information".
It also pointed at the hub's /legal/ index. Where an account is created is
where GDPR art. 13 owes the person the information about their data, so it
now links the privacy statement itself — /legal/confidentialite.fr.txt in
French, /legal/privacy-statement.en.txt in every other language — on the
hub that served the page, like every legal link. The sidebar's "Legal
information" is unchanged.
Checked in Chrome and Firefox (headless), in English and French.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Ticking "also e-mail it to me" at registration sent the recovery key R in
the register body, and the hub appended it to the verification e-mail: the
hub saw R in clear on its way out, and the resend door — no captcha — let
anyone who knew a pending username and address have the hub mail a
"recovery key" of their choosing.
The box is gone. The recovery screen offers "E-mail it to myself", a mailto:
link that opens the person's own mail application with the key filled in;
the desktop shell hands mailto: to the system (http, https and mailto only)
and the Android shell to a mail application (ACTION_SENDTO). The CLI drops
--email-recovery-key and prints the key, as before. The hub mails the code
alone, and refuses a register that still carries a recovery_key rather than
dropping it, so an older client offering the option cannot tell someone
their key was sent when it was not.
A mailbox holding R remains, with the reset code that reaches the same
mailbox, enough to recover the account's identities; the link says so, and
it is the person's choice.
Checked in Chrome and Firefox (headless, the real page against a stubbed
hub) and by the CLI's end-to-end registration against a local hub. The
Android change was not built here, and the desktop link was not clicked in
the application.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
|
|
|
| |
pip-audit reports two advisories against 2.14.0, both fixed in 2.15.0.
PYSEC-2026-4141 reaches the hub: federation.py decodes a peer's token
without verifying it first, and a deeply nested payload raises a
RecursionError there, an unauthenticated 500. PYSEC-2026-4183 does not:
no key is imported from a JWK. The builds resolve the newest release
anyway; the floor keeps an older environment from satisfying them.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
The secret a phone polls /v1/push/poll with is a credential of its own,
outside any session, and it outlived the ones that should have ended it:
"sign out everywhere" — what someone who lost a phone presses — a
passphrase change and an admin revocation left every push row in place, so
the lost phone went on reading "X posted in <group>" lines. Each now deletes
the account's rows, as a reset and an erasure already did, and the poll
refuses a revoked or deleted account whatever deleted the row or not. A
suspended one still reads: the line telling it so is one of them.
A phone still in hand is not affected for long: a refused poll makes it
forget the row, and the page registers it again at its next start.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
| |
Nothing ever set it (the page and the CLI sent null) and nothing read it
(the node's get_thread had no caller). It is no longer sent by the page or
the CLI, in clear or in the sealed payload, nor relayed or served by the
node; get_thread and its index are gone, and the protocol and design docs
no longer name it.
The node still accepts a chat_msg carrying one, from the desktop apps and
CLIs already installed, and drops it. The column stays, empty, in chat.db:
a node downgraded to an older version names it in every query.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
An account links up to MAX_NODES_PER_ACCOUNT node keys (node_keys table)
instead of the one users.pk_node_ed25519; the migration carries each
account's key over and the downgrade keeps the last one linked.
/v1/nodes/auth accepts any linked key, and its token names the key that
won it (nk). PUT /me/node_key adds a key, idempotently, 409 past the
limit; DELETE /me/node_key names the key: a browser session any of its
own, a node only its own. Unlinking a key closes that node's socket and
refuses its tokens at once, on REST and on the socket; the account's other
nodes are untouched. /pubkeys no longer gives a node key to other accounts,
and gives the caller its last linked one, which installed desktop apps read.
The node reports waiting_for_node_key while its key is unlinked and signs
in again as soon as the hub says so, so a key linked again is back within
seconds; unlinking itself signs in first to hold a token naming its key.
Profile -> Linked nodes lists each node (connected, last seen, IP, linked
since, This machine in the desktop app) with Copy and Unlink, and adds a
key by hand. The Node page banner, Create group and the desktop app add
this machine's key instead of replacing another's. Messages that pointed
at Settings -> Link Node point at Profile -> Linked nodes.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Each message's signing device is checked against the group's roster as the
page checks it (a port of transport-roster.js, held to it by the parity
test): chains of countersignatures walked from each account's roots, the
keys accepted per account and node kept in the store, the roster read again
once before a key is called changed. Only "changed" is said, under the
message; --json carries every verdict.
chat with no group opens the interactive chat: the groups, then one group's
conversation IRC-style with pushed messages arriving live and a line to
write in; Esc or /part goes back to the groups, /quit or Ctrl+Q quits. Like
the bare command, it opens on the sign-in screen when nothing is stored.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
| |
join accepts an invitation or redeems a link pasted as sent, then has the
node admit a key pair made here, with the invitation's code (a link's code
goes only to the node it names; one for a node that is away is kept for the
next connection). decline, leave and devices revoke ask first, and refuse
without --yes where there is no terminal. devices approve countersigns the
one waiting request a code matches, none when several do. browser-access is
the application's setting, kept per machine and never enabled from the hub's
mirror: on leaves a copy sealed under M on each node, off withdraws it,
unset touches nothing. A key pair made for a first contact is now kept.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
|
|
| |
A browser keeps no identity between connections, so a key approved for it
is gone by the next one: the guide, the design and the interface no longer
offer it. With browser access off, the application and the command-line
client open the account's groups; the linking form, shown in the
application only, now says "this computer".
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
"Get a linking code" called the connection the page had just closed on the
node's unknown_device refusal, so it never filed anything. It now retries
with the request filed on that connection, before the proof (MNP 6.3), and
the page tries the group again after each refusal until a linked device
approves the code. Offered only in the desktop application: a browser's
minted identity is gone by its next connection.
Approving refuses a code that matches more than one pending request:
filing needs only the account's token, so somebody holding the passphrase
who saw a code could file their own keys under it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Signs in to the hub, lists the account's groups and their folders, and
downloads and uploads files directly with each group's node, end-to-end
encrypted. With no argument it opens a two-pane interactive mode (Textual).
Session and device keys are kept encrypted under the system's key storage,
or a 0600 key file where there is none; node keys are pinned at first
contact; a new machine links as a device.
Packaged on its own on Linux (deb and rpm, on meshbay-common's venv, with a
man page generated from the parser) and frozen next to meshbay-node in the
full Windows installer, not the light one, with a self-test the build runs.
client/keys.py ports keyderive.js and is LGPL like it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Sign-up and passphrase reset sent every visitor's address and browser
details to Google, which needed a consent the sign-up form could not ask
for freely. The hub now issues its own challenge (ALTCHA's scheme, signed
with a key derived from the hub's private key, single-use, 30 minutes)
and the page solves it with SubtleCrypto while the form is filled in.
- GET /v1/users/captcha issues a challenge; 404 captcha_disabled when off.
- [captcha] enabled / max_number replace site_key / secret_key, which are
now ignored with a warning; MESHBAY_CAPTCHA_ENABLED replaces the old
variables.
- No Google origin left in the CSP of the hub, the desktop shell or the
Android shell; captcha_site_key leaves /v1/hub/info.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
A Windows tester's scan stuck for good on one directory of a large disk:
one read that never returned held the indexer's only thread, and with it
every root behind that one.
- A disk call is timed by its silence, not its length: each directory
entry listed and each megabyte read counts as an answer. After 60 s of
silence the call is abandoned on its daemon thread, the file is noted
unread and the scan goes on.
- Three silent files in a row pause the root (not persisted). Resume
skips the files already known to give no answer; a restart, a replug
or a change to the file retries them.
- The walk is per directory with os.scandir: a subdirectory that cannot
be listed costs itself, and a listing that stops answering pauses the
root at once. A scan no longer stats anything from the event loop.
- The log names the file after 10 s of silence, the indexing band shows
it, and Group settings shows the paused root, where it stuck and the
unread files with their reason, on the node's machine only.
- generate_http_api.py writes LF on Windows too.
Verified with real kernel-blocked opens (an unacknowledged oplock) in the
installed frozen app.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
| |
|
|
|
|
|
| |
The probe followed the browser's language, so its assertions on
English labels failed on a machine set to French.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
|
| |
The bar was 457 px wide and pushed the close button to 397..437 px, off a
360 px phone. Delete leaves the lightbox (it stays on the tile's menu:
right-click, or press and hold), and below 768 px the bar drops the file
name, the zoom label and 100%.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Search is an icon in the nav, left of the tray button and the bell, and marks
itself current on its page. Administration, Node, Create group and Android
Sync moved to the user menu, between Settings and the theme, each under the
condition it had in the sidebar. The sidebar keeps Public groups and the
groups.
On a phone, a tablet or the Android application the menu trigger is the
avatar alone (max-width 768px or a coarse pointer); the name is the dropdown's
first line, one line with an ellipsis. Measured: a 20-character handle put the
trigger 159 px off a 320 px screen with search and transfers in the nav, and a
64-character one pushed the dropdown 122 px off the left.
Creating a group is a desktop-application feature by design: a hand-typed
#/create-group no longer opens the form in a browser, and QUICKSTART step 6
now says to use the desktop application instead of the browser.
test_layout_responsive read only the first 768px media block; it reads them
all now.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
A whole-root walk now checks its root before every file: removed or
ejected, it stops instead of reading the drive to the end; paused, it
finishes from the hash cache alone. A paused root is not watched, not
swept by reconcile and survives a restart (roster), its indexed files
stay served. Resume runs the reconcile sweep over the root, so entries
and their enrichment are kept.
Signed root_pause / root_resume over MNP, loopback routes, CLI
`root pause|resume`, a pause button on the indexing dock and
pause/resume in the roots table of Group settings.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
A line under the Register button: creating an account accepts the hub's
terms of use, and the law requires the hub to keep the connection log (IP
address, date, action) for one year, even after the account is deleted. It
links to the legal pages of the hub in use, so a self-hosted hub shows its
own operator's documents.
A notice, not a checkbox: the account rests on the contract and the log on a
legal obligation, so there is no consent to ask for, and one that blocks
sign-up would be neither free nor withdrawable.
legalUrl() moves to platform.js, shared by the sidebar and the form.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
| |
connection_processes (default 1) starts that many processes for the
WebRTC stack; sessions and keys stay in the node. Set from node.toml
or the Node page, applied to new connections.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
|
| |
One WebRTC connection carries 5 to 6 MB/s whatever the line can do.
A leased download of 64 MB or more now opens seven more to its node,
and a lease serves the other connections of its device in its group.
Measured through the whole stack: 5 MB/s before, 24 after.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
|
| |
Slices are asked for in the address, not a Range header the WebView drops;
a settings change runs at once; the notification is updated once a second;
the SMS section says how to lift Android's restricted setting; the photo
section says whether videos are included.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
| |
A WhatsApp section takes WhatsApp's folder through the picker, sends its
encrypted Databases and Backups (not the dated copies of earlier weeks) into
<folder>/<account>-whatsapp, and names the restore set in the manifest.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
| |
Photos, videos and files record, per file, their path on the node, their path
and album on the phone, dates, size and SHA-256, uploaded as
meshbay-manifest/manifest-<date>.jsonl once the run is done.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
| |
A Files section takes folders through the system picker (no storage
permission), refuses DCIM, Pictures and Movies, skips what the photo backup
sends, and runs on the photo backup's own runner into <folder>/<account>-drive.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
| |
Videos in a photo folder are thumbnailed by the node, counted and marked in
the album, and played in the group's video player from the lightbox; the
slideshow passes them by.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
| |
A 'Videos too' option, off by default, sends them into the same YYYY/YYYY-MM
folders. Files are read from the phone a ranged chunk at a time, so a large
video is never whole in the page.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
| |
|
|
|
|
|
| |
A Calendar section sends every calendar the person can edit, as a dated .ics,
into <folder>/<account>-calendar once a day when it changed.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
| |
|
|
|
|
|
| |
A copy of the application inside a work profile offers no backup, and no
source reads another profile.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
| |
A Messages section sends the SMS added since the last copy, as restorable
<smses> XML, into <folder>/<account>-messages/YYYY. A play flavor has neither
READ_SMS nor the code that reads messages; full is the default.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
| |
Chosen once at the top of Android Sync for every kind; photos and contacts
go into <folder>/<account>-photos and -contacts. Owner and sole member are
checked at set-up and before every run.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
| |
|
|
|
|
|
| |
On a right-clicked tile and in the lightbox bar, after a confirmation, for
the node's operator or the photo's uploader, as in Files.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
| |
|
|
|
|
|
|
| |
A Contacts backup section on the Android Sync page sends a dated .vcf into
<folder>/<account>-contacts once a day when the address book changed, only
to a group the account is alone in, checked again at every run.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
| |
|
|
|
|
|
| |
A Phone section of the side menu leads to it, on the Android application
only; Settings no longer holds it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|