Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog/v0.1.0-beta4.txt
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ SYNC
- On the local network, a device list entry from another device that can't be read is skipped, and the rest of the list still syncs.
- Linked devices: a device name that can't be read is left out instead of hiding the device list or stopping a rename. The latest readable name is shown.
- A snapshot, acknowledgement or LAN request that names a log position too large to read exactly is now refused as invalid.
- Linked devices accept only device keys and signatures that every Flow app reads the same way, so devices can't disagree about who is in a group.
- A damaged file in a WebDAV folder's roster no longer stops every device from syncing. It is skipped and the rest of the roster is read.
- Sync no longer hangs on a store that keeps answering with the same page. It stops reading and tries again at the next sync.
- Sync stops reading an answer larger than it can be, from a Flow server, a WebDAV folder, the live channel or a device on your network, so a broken or hostile store can't use up memory.
Expand Down
5 changes: 3 additions & 2 deletions src-tauri/src/sync2/curve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,14 @@ use x25519_dalek::{PublicKey, StaticSecret};

use super::{Error, Result};

/// Rejects non-canonical encodings and small-order keys (spec/crypto.md, Ed25519 checks).
/// Accepts only a canonical encoding of a point of order exactly L (spec/crypto.md, Ed25519
/// checks). With such a key, `verify_strict` can only accept an `R` of order L too.
pub fn is_valid_signing_key(public_key: &[u8]) -> bool {
<[u8; 32]>::try_from(public_key)
.ok()
.filter(canonical_y)
.and_then(|bytes| VerifyingKey::from_bytes(&bytes).ok())
.is_some_and(|key| !key.is_weak())
.is_some_and(|key| !key.is_weak() && key.to_edwards().is_torsion_free())
}

/// `VerifyingKey::from_bytes` accepts y ≥ p, so the encoding is checked directly.
Expand Down
6 changes: 3 additions & 3 deletions src-tauri/tests/fixtures/flow-sync-2/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,16 @@ All byte strings are lowercase hex, except inside roster entries, which use the
|---|---|
| `canonical.json` | Canonical JSON serialization, including keys outside the Basic Multilingual Plane, which sort by UTF-16 code unit, not by code point |
| `derive.json` | `Derive` and `Hash` ([crypto.md](../crypto.md#labelled-derivation)) |
| `ed25519.json` | Strict verification: valid, tampered, wrong key, non-canonical `S`, small-order key; the eight small-order encodings; a non-canonical key encoding |
| `ed25519.json` | Strict verification: valid, tampered, wrong key, non-canonical `S`, small-order key; every small-order encoding of `R`, canonical or not; `R` and keys with a small-order part under either equation; the [ed25519-speccheck](https://github.com/novifinancial/ed25519-speccheck) set; the eight small-order encodings (`weakKeys`), non-canonical key encodings (`nonCanonicalKeys`) and keys with a small-order part (`mixedOrderKeys`), none of which may enter a roster |
| `box.json` | Box seal and open with fixed salts; tampered ciphertext, tag, commitment and salt, wrong key, wrong AAD, truncation |
| `payload.json` | PADMÉ sizes; payload decoding; bad length, non-zero padding, corrupt gzip |
| `keys.json` | Member ids, epoch commitment, purpose keys, HPKE wrap with a fixed ephemeral key, wrong-epoch and wrong-member unwraps, history chain, wrap and chain paths |
| `recovery.json` | Recovery secret, 24 words and derived keys; words with a bad checksum, 23 words, and a valid 12-word phrase |
| `envelope.json` | Log objects of each type, including a store login, opened in stream order, a live message, a snapshot blob; truncation, magic, suite, group, unknown sender, signature, tampering, replay, gap, a log read from the middle, wrong `prev`, swapped epoch, `seq` above 2<sup>53</sup> − 1, blob hash |
| `roster.json` | A chain through genesis, add, rename, remove, restore, recovery change, add, leave and rotate, with the state after each entry (including whether a rotate is due, and each member's epochs and `cut`) and the device names it carries; bad and missing signatures, unknown fields, wrong `seq`, truncated chain, removed signer, weak key, re-adding a removed device, wrong epoch sets and numbers, self-removal, renaming the recovery key, a non-member signer, a used recovery key; a leave by a non-member, by the recovery member and by the last device, a leave removing another device or carrying an epoch, a rotate without an epoch, with a removal, or wrapped to a device that left; six forks and their winners, including leave against remove and rotate, and concurrent rotates; a genesis whose group id isn't the one its keys commit to; a `cut` on the wrong op, for a device not removed, empty, or at `seq` 0; `replacements`, entries on top of the chain where the device that set the recovery key is removed or has left |
| `roster.json` | A chain through genesis, add, rename, remove, restore, recovery change, add, leave and rotate, with the state after each entry (including whether a rotate is due, and each member's epochs and `cut`) and the device names it carries; bad and missing signatures, unknown fields, wrong `seq`, truncated chain, removed signer, weak key, a key with a small-order part, an identity `R`, re-adding a removed device, wrong epoch sets and numbers, self-removal, renaming the recovery key, a non-member signer, a used recovery key; a leave by a non-member, by the recovery member and by the last device, a leave removing another device or carrying an epoch, a rotate without an epoch, with a removal, or wrapped to a device that left; six forks and their winners, including leave against remove and rotate, and concurrent rotates; a genesis whose group id isn't the one its keys commit to; a `cut` on the wrong op, for a device not removed, empty, or at `seq` 0; `replacements`, entries on top of the chain where the device that set the recovery key is removed or has left |
| `forks.json` | Named entries, and cases that settle a store's view of them: `applied` is what the device had applied, `view` is the store's answer, `pins` the chosen entries, `linear` a Flow server. Each case gives the outcome and, in any order of `view`, the same chain, standing entries that lost and start an epoch, contested set and sides |
| `senders.json` | Step 2 of [reading an envelope](../store.md#reading-an-envelope): a roster, then `senders` with who may write under which epoch and how far along its log, then `walks` of a log down from a `cut`, with the hashes found from the lowest `seq` up or the check that refuses it. An empty string in `log` is an object the store doesn't have |
| `pairing.json` | Pairing keys, SAS, mailbox slot, and a sealed `join` message |
| `pairing.json` | Commitment, proof, the scanner's first message, pairing keys, SAS, mailbox slot, and a sealed `join` message; `refused` holds a shower key that doesn't match the commitment and a proof made with another token |
| `lan.json` | Discovery tag, hello AAD, transcripts, session keys, frame AAD |

## Using them
Expand Down
Loading
Loading