Commit Graph
10 Commits
Author SHA1 Message Date
Filip StrajnarandClaude Opus 5.5 10df192b01 M9: a share on every interface links to an address others reach
A session hosted with `bind` 0.0.0.0 (or ::) kept listening on every
interface but put 0.0.0.0 in its edit and view links, URLs, join codes
and shown address, which nobody can connect to. They now name this
machine's local network address of the listener's family (loopback
without one), on the same port.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LvG6DxbDYxuPEA2pJirCLQ
2026-11-06 21:27:47 +01:00
Filip StrajnarandClaude Opus 5.5 b779e46d47 M9: a local view-only share's url is the view URL, not the edit URL
The previous fix made a local share's `link` follow the code shown, but its
top-level `url`, the session's WebSocket URL, still carried the edit token:
`collab.join {link: url}` from a view-only share joined with edit access and
the edit reached the host. The link layer now hands over the view way in as a
link and its URL (`SessionInfo::view`, a `WayIn`, in place of `view_link`), and
`collab.peers` gives a local share's `link` and `url` from the way in for the
code shown (`Live::invite`). Online shares are unchanged.

Regression test: `code_tests::a_local_view_share_s_link_and_url_only_let_people_look`
joins through the `link` and then the `url` over loopback; both are welcomed as
viewers whose edits never reach the host.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LvG6E2VLhC9d5v8VSsf4ng
2026-11-06 19:12:40 +01:00
Filip StrajnarandClaude Opus 5.5 a05201e21f M9: a local view-only share's link is the view link, not the edit link
`collab.share {via: "local", access: "view"}` showed the view-only code but
gave the session's own invite link as `link`, and that link edits: whoever
joined through it could change the host's file. A local share's `link`, top
level and in `sessions`, is now the one that goes with the code shown, and it
follows `collab.share {access}`. Online shares keep the owner's own link there,
as before.

Regression test: `code_tests::a_local_view_share_s_link_only_lets_people_look`
joins through that link over loopback and is welcomed as a viewer whose edit
never reaches the host.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LvG6E2VLhC9d5v8VSsf4ng
2026-11-06 18:45:44 +01:00
Filip Strajnar a2be6632eb M9: share a file on the local network read-only, with a view-only code
The session the app hosts for a local network share now has two secrets:
the edit code and a view-only code (same address and port, a 44-bit secret
of its own). Whoever joins with the view code is welcomed as a viewer: they
see every change and presence, the app makes the file read-only for them,
and the session refuses their batches, as a server does for view links.

Share > Local network offers Can edit / Can view before sharing starts (the
edit code then never shows) and while sharing. collab.share {via: "local",
access: "view"} does the same; share in collab.peers lists both codes and
links. There is still no comment code on the local network.

Next::Stop boxes its event: SessionInfo grew past clippy's
large_enum_variant threshold, and it only ever carries a status or an end.

Tests: loopback_tests::a_view_token_lets_people_look_and_not_edit,
code_tests::a_local_view_code_lets_people_look_and_not_edit,
live_share_tests::a_local_share_can_start_for_looking_only, and the local
share tests that asserted edit-only codes. Docs: collab-protocol.md,
collaboration-parity.md.
2026-11-06 17:03:21 +01:00
Patrick Wozniak 4b4b2bfd00 M9: a team list on figcraft-server: the files shared now, joined without a token (team_files) 2026-10-30 17:09:07 +01:00
236f3185d6 Migrate FigCraft to egui 0.37 (#1312)
* E21: require release font coverage and stabilize capture deadline tests

* E21: separate capture, IME and field-save regression phases

* M0: correct the migration qualification reference

* M-egui037: document input lifecycle and UI regression contracts

* M0: correct egui 0.37 status docs and stabilize join-code regression

---------

Co-authored-by: Dylan M. Taylor <dylan@dylanmtaylor.com>
Co-authored-by: Codebuff <noreply@codebuff.com>
2026-10-25 15:04:39 -04:00
dotCooCoo 6e86e26d14 M9: the hello deadline refuses a connection even when a read times out early
On Windows a socket's read timeout counts whole milliseconds, so a read
bounded by the hello deadline can time out a moment before it.
`next_message` then took the timeout for a closed connection: the client
got no "no hello in time" refusal, and the socket closed only after the
2 s linger. `Duplex::read` now reads again until the deadline has passed.

Tests:
- `connections_without_a_hello_are_told_why_they_end` (new): twelve
  connections that never say hello each get the refusal. Failed 5 of 10
  runs without the fix.
- `pre_hello_lifetime` notes the end of the stream on a thread of its own
  instead of reading one message per 300 ms poke, where pongs queued
  ahead of the close delayed it.
- `quiet_guests_stay_and_silent_connections_are_dropped`: the guest takes
  only the host's keepalive. Its 600 ms idle timeout also bounded the wait
  for the welcome.
- `two_files_are_hosted_and_joined_independently`: the two joins race, so
  the file whose welcome arrived last is in front. The test checks that,
  then brings B to the front.
- `a_local_share_is_joined_by_its_code_and_edits_sync`: once the share
  stops, another program's host can take the freed port and refuse the
  code.
2026-10-24 19:00:42 -07:00
Dylan M. Taylor 32735549c4 test: explain the discarded reads in the fake servers (SonarCloud)
read() returns Result<Message>, not a lock guard; these test loops
deliberately ignore what the client sent first.

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>
2026-10-23 09:44:02 -04:00
bflatastic 8f6a123f29 M9: share with a join code: stop sharing keeps the file
Online, the file is its owner's: others get links and codes of their own, and
Stop sharing (collab.stop) revokes those on the server. Whoever joined with
them is disconnected at once and told sharing was stopped (the session's end,
with their copy); the owner stays in the file, which stays on the server, and
Start sharing gives the same file new links and codes. Removing the file is a
separate, confirmed step under Advanced.

The join field is the shared text input: as tall as the Join button beside it.
2026-10-12 19:42:28 +07:00
bflatastic 6720ea4a21 M9: share with a join code: online through the built-in server or on the local network
The Share popover is one flow: Online (the file is published to the server in
Preferences and the server names its links with short codes) or Local network
(the app hosts; the code carries its address and the session's secret), one
Start sharing button, the code large with Copy code and Copy link, who is here,
can edit / can view, and Stop sharing. Join with a code is one field in the
popover, on the home screen and in the Join dialog, for a code of either kind
or an invite link.

Protocol (within version 2, new variants last): Resolve / Resolved and Admin
code. The server keeps a stretched hash and the wrapped token, never the code,
and limits wrong codes per address (with a lockout) and for everyone. Older
servers leave the links in place of a code; older apps join by link.

collab.share, collab.join {code}, code and share in collab.peers; the server
preference defaults to the built-in server and can be reset or turned off.
2026-10-12 19:42:28 +07:00