<feed xmlns='http://www.w3.org/2005/Atom'>
<title>meshbay.git/packages/meshbay-hub/src/meshbay_hub, branch 0.20</title>
<subtitle>MeshBay — read-only public mirror</subtitle>
<id>https://git.meshbay.org/meshbay.git/atom?h=0.20</id>
<link rel='self' href='https://git.meshbay.org/meshbay.git/atom?h=0.20'/>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/'/>
<updated>2026-10-15T15:45:41Z</updated>
<entry>
<title>chore: bump version to 0.20.0</title>
<updated>2026-10-15T15:45:41Z</updated>
<author>
<name>Christophe Besson</name>
<email>cbesson@gmail.com</email>
</author>
<published>2026-10-15T15:43:15Z</published>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/commit/?id=63aa0ddd8c0ec49fe8b52b6b486b079887ed3112'/>
<id>urn:sha1:63aa0ddd8c0ec49fe8b52b6b486b079887ed3112</id>
<content type='text'>
Co-Authored-By: Claude Opus 5.5 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>feat(android): no text messages backup, and one build again</title>
<updated>2026-10-15T13:09:58Z</updated>
<author>
<name>Christophe Besson</name>
<email>cbesson@gmail.com</email>
</author>
<published>2026-10-15T13:09:58Z</published>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/commit/?id=39cac2878de059992cb09a1ccf09b6bcece99fae'/>
<id>urn:sha1:39cac2878de059992cb09a1ccf09b6bcece99fae</id>
<content type='text'>
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 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>fix(auth): the sign-up notice links the privacy statement, with a space</title>
<updated>2026-10-15T12:33:03Z</updated>
<author>
<name>Christophe Besson</name>
<email>cbesson@gmail.com</email>
</author>
<published>2026-10-15T12:33:03Z</published>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/commit/?id=37b38e0eb15a79bbda3cd0a1b502669b32e773dc'/>
<id>urn:sha1:37b38e0eb15a79bbda3cd0a1b502669b32e773dc</id>
<content type='text'>
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 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>feat(auth): the recovery key never reaches the hub</title>
<updated>2026-10-15T12:25:00Z</updated>
<author>
<name>Christophe Besson</name>
<email>cbesson@gmail.com</email>
</author>
<published>2026-10-15T12:25:00Z</published>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/commit/?id=28c77b7648b2a44a18be64ec44344d91cccfd742'/>
<id>urn:sha1:28c77b7648b2a44a18be64ec44344d91cccfd742</id>
<content type='text'>
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 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>fix(hub): a phone's poll secret ends with the account's sessions</title>
<updated>2026-10-15T12:24:35Z</updated>
<author>
<name>Christophe Besson</name>
<email>cbesson@gmail.com</email>
</author>
<published>2026-10-15T12:24:35Z</published>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/commit/?id=2dbff20818d171242a15e3567e14292c0d63aea2'/>
<id>urn:sha1:2dbff20818d171242a15e3567e14292c0d63aea2</id>
<content type='text'>
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 &lt;group&gt;" 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 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>refactor(chat): no thread_id — chat has no threads</title>
<updated>2026-10-15T10:57:51Z</updated>
<author>
<name>Christophe Besson</name>
<email>cbesson@gmail.com</email>
</author>
<published>2026-10-15T10:57:51Z</published>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/commit/?id=a86bced1640ac1a695b95ac68b95e3fc581e687d'/>
<id>urn:sha1:a86bced1640ac1a695b95ac68b95e3fc581e687d</id>
<content type='text'>
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 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>feat(hub): one account, several linked nodes</title>
<updated>2026-10-15T07:33:28Z</updated>
<author>
<name>Christophe Besson</name>
<email>cbesson@gmail.com</email>
</author>
<published>2026-10-15T07:33:28Z</published>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/commit/?id=1e8eae1f3de765fcd8163716de6e5fe5aab5a034'/>
<id>urn:sha1:1e8eae1f3de765fcd8163716de6e5fe5aab5a034</id>
<content type='text'>
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 -&gt; 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 -&gt; Link Node point at Profile -&gt; Linked nodes.

Co-Authored-By: Claude Opus 5.5 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>docs: a browser is not linked as a device</title>
<updated>2026-10-14T21:33:17Z</updated>
<author>
<name>Christophe Besson</name>
<email>cbesson@gmail.com</email>
</author>
<published>2026-10-14T21:33:17Z</published>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/commit/?id=2acd1b17ad94536e4a0504087adcd9dc936896ea'/>
<id>urn:sha1:2acd1b17ad94536e4a0504087adcd9dc936896ea</id>
<content type='text'>
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 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>fix(client): link a device from the application; approve one match only</title>
<updated>2026-10-14T21:02:49Z</updated>
<author>
<name>Christophe Besson</name>
<email>cbesson@gmail.com</email>
</author>
<published>2026-10-14T21:02:49Z</published>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/commit/?id=3131630d900aa4a72bf880bfa9c5232bff64d6d6'/>
<id>urn:sha1:3131630d900aa4a72bf880bfa9c5232bff64d6d6</id>
<content type='text'>
"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 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>feat(hub): replace reCAPTCHA with a self-hosted proof of work</title>
<updated>2026-10-14T11:34:47Z</updated>
<author>
<name>Christophe Besson</name>
<email>cbesson@gmail.com</email>
</author>
<published>2026-10-14T11:34:47Z</published>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/commit/?id=51705056a578d2649a989bf14a056fbcfae58a6b'/>
<id>urn:sha1:51705056a578d2649a989bf14a056fbcfae58a6b</id>
<content type='text'>
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 &lt;noreply@anthropic.com&gt;
</content>
</entry>
</feed>
