<feed xmlns='http://www.w3.org/2005/Atom'>
<title>meshbay.git/packages/meshbay-hub/tests/test_spa_ordering.py, branch 0.2</title>
<subtitle>MeshBay — read-only public mirror</subtitle>
<id>https://git.meshbay.org/meshbay.git/atom?h=0.2</id>
<link rel='self' href='https://git.meshbay.org/meshbay.git/atom?h=0.2'/>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/'/>
<updated>2026-08-14T09:15:27Z</updated>
<entry>
<title>test: prove a second browser works after pairing</title>
<updated>2026-08-14T09:15:27Z</updated>
<author>
<name>Christophe Besson</name>
<email>cbesson@gmail.com</email>
</author>
<published>2026-08-14T09:15:27Z</published>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/commit/?id=6309894d019421f54cff311e630f3897f7eba93e'/>
<id>urn:sha1:6309894d019421f54cff311e630f3897f7eba93e</id>
<content type='text'>
The mechanism was already there — the encrypted keypair bundle goes to the node
after a first successful connection, and any client holding the password can
recover it — but nothing exercised it. e2e.py never pushed a bundle, so the case
that matters to an ordinary user was the one case never tested.

It now does what app.js does: backs the member's keys up to the node, then opens
a second client carrying nothing but a username and a password. Against the live
deployment that client recovers its identity keys, is recognised as the same
person with no second code, gets the same group key, and browses the group.

Also guards the ordering this depends on: the keypair bundle must be fetched
before joinGroup() runs, or a browser that did not register has no key to sign
the join with — invisible on the browser that did register, broken on every
other one.

Co-Authored-By: Claude Opus 5 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>fix(client): capture the challenge values before joining, not after</title>
<updated>2026-08-14T01:51:55Z</updated>
<author>
<name>Christophe Besson</name>
<email>cbesson@gmail.com</email>
</author>
<published>2026-08-14T01:51:55Z</published>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/commit/?id=9f0904247116005bba8e32b9428dc6a2b994e705'/>
<id>urn:sha1:9f0904247116005bba8e32b9428dc6a2b994e705</id>
<content type='text'>
join_request signs a transcript over the node key and the node nonce, and runs
before the GEK proof — a first-time member has no key to prove with. Both values
were read further down, beside the proof that also uses them, so by the time
joinGroup() ran neither was set and every invited member got "Handshake
incomplete — reconnect and retry".

They are now recorded the moment the challenge arrives.

Third bug of the same shape found in a browser, and the reason is worth writing
down: QE/deploy/e2e.py cannot catch any of them. It is a second implementation of
the client, written in the right order by construction, so it passes while the
SPA fails. It proves the protocol; it proves nothing about app.js.

So this adds ordering guards over transport.js — source-level, which is not how
one would normally test behaviour, but it is what sees this class of mistake:

  - node_pk and nonce_node are captured before joinGroup() runs
  - the join happens before the GEK proof
  - the ack still verifies the key the challenge announced

Verified the way the suite requires: each fails against the source as it was, on
the ordering assertion rather than on a missing marker.

e2e.py also waits for the node to re-register rather than reporting "no nodes" at
whoever just restarted the hub.

Tests: 337 across the three packages.

Co-Authored-By: Claude Opus 5 &lt;noreply@anthropic.com&gt;
</content>
</entry>
</feed>
