From 37dad869bfc34efaadc95f08fc6bddb62a1a00b1 Mon Sep 17 00:00:00 2001 From: AE <98699388+A-EDev@users.noreply.github.com> Date: Sat, 7 Nov 2026 19:59:27 +0200 Subject: [PATCH] feat(sync): read every payload as exactly one gzip member --- changelog/v0.1.0-beta4.txt | 1 + src-tauri/src/sync2/payload.rs | 16 +++- .../tests/fixtures/flow-sync-2/README.md | 4 +- .../tests/fixtures/flow-sync-2/payload.json | 73 +++++++++++++++++++ src-tauri/tests/sync2_vectors.rs | 20 ++++- 5 files changed, 108 insertions(+), 6 deletions(-) diff --git a/changelog/v0.1.0-beta4.txt b/changelog/v0.1.0-beta4.txt index 1f308b7d..7ccceb94 100644 --- a/changelog/v0.1.0-beta4.txt +++ b/changelog/v0.1.0-beta4.txt @@ -35,6 +35,7 @@ SYNC - A damaged or forged object from one device no longer fails the whole sync. Reading that device's changes pauses there, and the other devices' changes still arrive. - The same holds when a new device starts from a snapshot or a profile starts syncing: a damaged or forged object no longer fails the sync, and the profile is caught up once it can be read. - A snapshot or profile name from another device that carries an out-of-range number no longer stops a synced profile from being read. +- Linked devices accept a synced object's data only in the one form every Flow app writes, so two devices can't read different data from the same object. - A malformed roster entry from another device on the local network is refused, so the group stays readable on this computer. - Joining a group over the local network now refuses a malformed welcome from the other device. - Linked devices: Replace recovery words gives your group a new recovery key from any linked device. The old words stop working, and your devices move to a new encryption key. diff --git a/src-tauri/src/sync2/payload.rs b/src-tauri/src/sync2/payload.rs index 3bf14762..e02c3157 100644 --- a/src-tauri/src/sync2/payload.rs +++ b/src-tauri/src/sync2/payload.rs @@ -1,13 +1,15 @@ use std::io::Read; use flate2::Compression; -use flate2::read::GzDecoder; +use flate2::bufread::GzDecoder; use flate2::read::GzEncoder; use super::{Error, Result}; const MIN_SIZE: usize = 256; const MAX_INFLATED: u64 = 64 * 1024 * 1024; +/// `ID1`, `ID2`, `CM` 8 and `FLG` 0 (spec/crypto.md, Payload). +const GZIP_START: [u8; 4] = [0x1f, 0x8b, 0x08, 0x00]; /// PADMÉ with a 256-byte floor. pub fn padded_size(n: usize) -> usize { @@ -38,12 +40,20 @@ pub fn decode_payload(payload: &[u8]) -> Result> { if length > rest.len() || rest[length..].iter().any(|&b| b != 0) { return Err(Error::Payload); } + let body = &rest[..length]; + if !body.starts_with(&GZIP_START) { + return Err(Error::Payload); + } + // The buffered reader of `read::GzDecoder` would hide what is left after the member. + let mut decoder = GzDecoder::new(body); let mut content = Vec::new(); - GzDecoder::new(&rest[..length]) + decoder + .by_ref() .take(MAX_INFLATED + 1) .read_to_end(&mut content) .map_err(|_| Error::Payload)?; - if content.len() as u64 > MAX_INFLATED { + // A read that stopped at the limit left the trailer, so this refuses that too. + if !decoder.into_inner().is_empty() { return Err(Error::Payload); } Ok(content) diff --git a/src-tauri/tests/fixtures/flow-sync-2/README.md b/src-tauri/tests/fixtures/flow-sync-2/README.md index 76f83ff2..7652fd19 100644 --- a/src-tauri/tests/fixtures/flow-sync-2/README.md +++ b/src-tauri/tests/fixtures/flow-sync-2/README.md @@ -10,14 +10,14 @@ All byte strings are lowercase hex, except inside roster entries, which use the | `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 | | `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 | +| `payload.json` | PADMÉ sizes; payload decoding, including another encoder's header bytes and a stored block; bad length, non-zero padding, corrupt gzip, more than one member, a bad or short trailer, any header flag, an empty body, bytes around the member | | `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 253 − 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 | | `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 diff --git a/src-tauri/tests/fixtures/flow-sync-2/payload.json b/src-tauri/tests/fixtures/flow-sync-2/payload.json index 326a1e5c..b3474789 100644 --- a/src-tauri/tests/fixtures/flow-sync-2/payload.json +++ b/src-tauri/tests/fixtures/flow-sync-2/payload.json @@ -45,6 +45,14 @@ { "content": "7b2270726f6772657373223a302e302c22766964656f4964223a22333836313963636663343563222c227761746368656441744d73223a313739333233323030303030307d0a7b2270726f6772657373223a302e312c22766964656f4964223a22396439633437346430313530222c227761746368656441744d73223a313739333233323030373931397d0a7b2270726f6772657373223a302e322c22766964656f4964223a22303036383663373736353863222c227761746368656441744d73223a313739333233323031353833387d0a7b2270726f6772657373223a302e332c22766964656f4964223a22343666396131633866656566222c227761746368656441744d73223a313739333233323032333735377d0a7b2270726f6772657373223a302e342c22766964656f4964223a22363166343938636365343635222c227761746368656441744d73223a313739333233323033313637367d0a7b2270726f6772657373223a302e352c22766964656f4964223a22316366623361376161663531222c227761746368656441744d73223a313739333233323033393539357d0a7b2270726f6772657373223a302e362c22766964656f4964223a22326232333862363165353732222c227761746368656441744d73223a313739333233323034373531347d0a7b2270726f6772657373223a302e372c22766964656f4964223a22333833336630396634613562222c227761746368656441744d73223a313739333233323035353433337d0a7b2270726f6772657373223a302e382c22766964656f4964223a22626632393961333633313262222c227761746368656441744d73223a313739333233323036333335327d0a7b2270726f6772657373223a302e392c22766964656f4964223a22633062663366636435666233222c227761746368656441744d73223a313739333233323037313237317d0a7b2270726f6772657373223a302e31302c22766964656f4964223a22623565353439633630373362222c227761746368656441744d73223a313739333233323037393139307d0a7b2270726f6772657373223a302e31312c22766964656f4964223a22393637623933333733386637222c227761746368656441744d73223a313739333233323038373130397d0a7b2270726f6772657373223a302e31322c22766964656f4964223a22653464666366636635356636222c227761746368656441744d73223a313739333233323039353032387d0a7b2270726f6772657373223a302e31332c22766964656f4964223a22363839643361323438383161222c227761746368656441744d73223a313739333233323130323934377d0a7b2270726f6772657373223a302e31342c22766964656f4964223a22373437633763663832653233222c227761746368656441744d73223a313739333233323131303836367d0a7b2270726f6772657373223a302e31352c22766964656f4964223a22666563613761656435373630222c227761746368656441744d73223a313739333233323131383738357d0a7b2270726f6772657373223a302e31362c22766964656f4964223a22633438663834333539663735222c227761746368656441744d73223a313739333233323132363730347d0a7b2270726f6772657373223a302e31372c22766964656f4964223a22333262613466626663333536222c227761746368656441744d73223a313739333233323133343632337d0a7b2270726f6772657373223a302e31382c22766964656f4964223a22306437353735383535353537222c227761746368656441744d73223a313739333233323134323534327d0a7b2270726f6772657373223a302e31392c22766964656f4964223a22653431656561353063616435222c227761746368656441744d73223a313739333233323135303436317d0a7b2270726f6772657373223a302e32302c22766964656f4964223a22353939636635323565333332222c227761746368656441744d73223a313739333233323135383338307d0a7b2270726f6772657373223a302e32312c22766964656f4964223a22653865356231323732613738222c227761746368656441744d73223a313739333233323136363239397d0a7b2270726f6772657373223a302e32322c22766964656f4964223a22336338653163346634616561222c227761746368656441744d73223a313739333233323137343231387d0a7b2270726f6772657373223a302e32332c22766964656f4964223a22643065636664656534373030222c227761746368656441744d73223a313739333233323138323133377d0a7b2270726f6772657373223a302e32342c22766964656f4964223a22393361376363653662386365222c227761746368656441744d73223a313739333233323139303035367d0a7b2270726f6772657373223a302e32352c22766964656f4964223a22363963313230306363373031222c227761746368656441744d73223a313739333233323139373937357d0a7b2270726f6772657373223a302e32362c22766964656f4964223a22633361306432346538303430222c227761746368656441744d73223a313739333233323230353839347d0a7b2270726f6772657373223a302e32372c22766964656f4964223a22373466623363663366393031222c227761746368656441744d73223a313739333233323231333831337d0a7b2270726f6772657373223a302e32382c22766964656f4964223a22613437633638636538313466222c227761746368656441744d73223a313739333233323232313733327d0a7b2270726f6772657373223a302e32392c22766964656f4964223a22306461623366653564656566222c227761746368656441744d73223a313739333233323232393635317d0a7b2270726f6772657373223a302e33302c22766964656f4964223a22393933363334306163643935222c227761746368656441744d73223a313739333233323233373537307d0a7b2270726f6772657373223a302e33312c22766964656f4964223a22303039383138656637656432222c227761746368656441744d73223a313739333233323234353438397d0a7b2270726f6772657373223a302e33322c22766964656f4964223a22623064353234306235623538222c227761746368656441744d73223a313739333233323235333430387d0a7b2270726f6772657373223a302e33332c22766964656f4964223a22343761393066353535363236222c227761746368656441744d73223a313739333233323236313332377d0a7b2270726f6772657373223a302e33342c22766964656f4964223a22643431383161666632373035222c227761746368656441744d73223a313739333233323236393234367d0a7b2270726f6772657373223a302e33352c22766964656f4964223a22363865323238656230333337222c227761746368656441744d73223a313739333233323237373136357d0a7b2270726f6772657373223a302e33362c22766964656f4964223a22333633393534323938346634222c227761746368656441744d73223a313739333233323238353038347d0a7b2270726f6772657373223a302e33372c22766964656f4964223a22313765386661623436653639222c227761746368656441744d73223a313739333233323239333030337d0a7b2270726f6772657373223a302e33382c22766964656f4964223a22666130643263653366356631222c227761746368656441744d73223a313739333233323330303932327d0a7b2270726f6772657373223a302e33392c22766964656f4964223a22303832363065303438323837222c227761746368656441744d73223a313739333233323330383834317d0a7b2270726f6772657373223a302e34302c22766964656f4964223a22636563306266643161336363222c227761746368656441744d73223a313739333233323331363736307d0a7b2270726f6772657373223a302e34312c22766964656f4964223a22306433353338336337613738222c227761746368656441744d73223a313739333233323332343637397d0a7b2270726f6772657373223a302e34322c22766964656f4964223a22646239323134356334383937222c227761746368656441744d73223a313739333233323333323539387d0a7b2270726f6772657373223a302e34332c22766964656f4964223a22363862323965383431393464222c227761746368656441744d73223a313739333233323334303531377d0a7b2270726f6772657373223a302e34342c22766964656f4964223a22613733333434386163346662222c227761746368656441744d73223a313739333233323334383433367d0a7b2270726f6772657373223a302e34352c22766964656f4964223a22303761333635323761363738222c227761746368656441744d73223a313739333233323335363335357d0a7b2270726f6772657373223a302e34362c22766964656f4964223a22373566663064376631633966222c227761746368656441744d73223a313739333233323336343237347d0a7b2270726f6772657373223a302e34372c22766964656f4964223a22663836616666303736346366222c227761746368656441744d73223a313739333233323337323139337d0a7b2270726f6772657373223a302e34382c22766964656f4964223a22623338363037643565306461222c227761746368656441744d73223a313739333233323338303131327d0a7b2270726f6772657373223a302e34392c22766964656f4964223a22383264633031326139656233222c227761746368656441744d73223a313739333233323338383033317d0a7b2270726f6772657373223a302e35302c22766964656f4964223a22663164613938346437643134222c227761746368656441744d73223a313739333233323339353935307d0a7b2270726f6772657373223a302e35312c22766964656f4964223a22383834333737383862336232222c227761746368656441744d73223a313739333233323430333836397d0a7b2270726f6772657373223a302e35322c22766964656f4964223a22313735663162363634386335222c227761746368656441744d73223a313739333233323431313738387d0a7b2270726f6772657373223a302e35332c22766964656f4964223a22643130326235663837663136222c227761746368656441744d73223a313739333233323431393730377d0a7b2270726f6772657373223a302e35342c22766964656f4964223a22353330366562386364363562222c227761746368656441744d73223a313739333233323432373632367d0a7b2270726f6772657373223a302e35352c22766964656f4964223a22666538656334333630616663222c227761746368656441744d73223a313739333233323433353534357d0a7b2270726f6772657373223a302e35362c22766964656f4964223a22646235643461633739386637222c227761746368656441744d73223a313739333233323434333436347d0a7b2270726f6772657373223a302e35372c22766964656f4964223a22373435316336396336323664222c227761746368656441744d73223a313739333233323435313338337d0a7b2270726f6772657373223a302e35382c22766964656f4964223a22393465333830306434616637222c227761746368656441744d73223a313739333233323435393330327d0a7b2270726f6772657373223a302e35392c22766964656f4964223a22376335313632623763656531222c227761746368656441744d73223a313739333233323436373232317d", "payload": "0000040a1f8b080000000000020375d73bae5c370c06e03ecb98da08f8142977295364117a26a91cd8465204debb79a71a8dc05b0ffeab237da4a8ff1fff7cfdf2e7d7f5eddbe333fc0a9f1efffe3dd797dfe7e3f383bd601d630fd1f1f8f4f8af7d1f7fadf9dbf73fe2a7689589099e7f3f7e3953f035a5ce3ac464022aa42956b1bea7d06b0a40f132cc8a7aba1654677f4fe1d71429bb361cbed7da590ab1a9bda7c86b4ac12dd5c75852344b612c56de53f43505c7eedcacb5ad98a654adfa9e525e53a8137b2fb8d4284b115394f7143b4f9a7943ddd2b46729aac2fc9ee2af297d53ad8d0b23a5298559e93da5bea60ce89bf7981adb93a51892e1a5eec0db75a9d451c0385dcc87ba1befa9b758afccc6be2d8b7143b8f4e2c177c9dc51485b75972ca62ad0c5170fbfc5ebe446e28e2d8941a02a975f3c009bd8b0b19d16655b8c085e2ec07808de6b84df35d54a56d9886e7e09c683f010df2eac755b564e48c5e0228ca761ea4d76df8335db6264297419c60331cc287f758dbfecc05148e5428c87e225b85653186da61fa520e5524c8762ad35d0902ee6acbc9f5def524c87e2e54b7bd40c35f32ca694a8de2be650ccc3170e8936b1527e268497623a144f5863cfb5c42075e3715897623a14d7e89ed1844bf7b1b2980aa097623a14973a306ea0310cb23e8cd5aa5d8ae954cc0d26c97290eca3a2877abd14d3a1d882308f6880355d4dec8ce3a5980ec52d2abcc4be384a76d1458ef1a5980ec5305be7bd340e2b8fa9452fc57c28ae352e05813666cd8ae179eb5e8af9500c501d7d6d5b332b061215bf14f3a1b8c35412e8da352b06d258ee3d4a9cb384b50ad1d0b550d66fa820d3a5980fc553309af9de6490ee4da92497623e15fb22f2d521eeaa2cc60ccba5980fc5714e357a5bf528f22cc615fc52cc8762b4e5bb7529abd42ca632c0a5980fc5fba3a4c6e2ad3b2b8608a97429e653b1538105e2e4d9de30b8cba5580ec5637d8c26131b8f6c047d4e7d976239154fd698b786e5bd98e3b8ed522c87e2d96b5c441a97674d3f8a49eba558de268a4e75c5b75799598c80e23d111f8a9b318b788bcb219bb658e292bf14cba1182cc647256b25df1b2dac976239149bee1df7f8c651b3b6c545c82ec57228de5ea230c18a8c34c6e272b814cb3916c73b0a6cea8a6e9ac538205e8ae550ec340720b5bad2b998dde3e171bd3a0ec51b678bf29e3631abf0e7abe352ac87e228173673efdcb35e2c101f7e29d64331c651612f457c64dd4f10e3ff5c31e74411536fd7ed71e4592f0ee10697623d142b4359314ecc923e83424df4fb2be66d2ef635c23ab49d358a1877552ec57a289e5da7b461357f7a88c4447b29d6b7894271c49013cbce2a3c7e111de98a39145759a1146245f96a347afaa5580fc536140b751b6b652d3d7a5fcc263f7e02e4f6e077991000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + }, + { + "content": "73686f7274", + "payload": "000000191f8b0800d2029649020b2bcec82f2a0100a290288f050000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + }, + { + "content": "73686f7274", + "payload": "0000001c1f8b0800000000000203010500faff73686f7274a290288f050000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" } ], "negatives": [ @@ -67,6 +75,71 @@ "name": "too-short", "payload": "000000", "error": "payload" + }, + { + "name": "two-members", + "payload": "000000341f8b08000000000002032bcec82f2a0100a290288f050000001f8b080000000000020353284e4dcecf4b010028560c55070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "error": "payload" + }, + { + "name": "two-identical-members", + "payload": "000000321f8b08000000000002032bcec82f2a0100a290288f050000001f8b08000000000002032bcec82f2a0100a290288f0500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "error": "payload" + }, + { + "name": "bad-crc", + "payload": "000000191f8b08000000000002032bcec82f2a0100a390288f050000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "error": "payload" + }, + { + "name": "bad-isize", + "payload": "000000191f8b08000000000002032bcec82f2a0100a290288f050000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "error": "payload" + }, + { + "name": "truncated-trailer", + "payload": "000000151f8b08000000000002032bcec82f2a0100a290288f000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "error": "payload" + }, + { + "name": "fhcrc-bad", + "payload": "0000001b1f8b080200000000020300002bcec82f2a0100a290288f05000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "error": "payload" + }, + { + "name": "empty-body", + "payload": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "error": "payload" + }, + { + "name": "reserved-flag", + "payload": "000000191f8b08200000000002032bcec82f2a0100a290288f050000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "error": "payload" + }, + { + "name": "trailing-bytes", + "payload": "000000201f8b08000000000002032bcec82f2a0100a290288f050000006761726261676500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "error": "payload" + }, + { + "name": "fname", + "payload": "0000001e1f8b08080000000002036e616d65002bcec82f2a0100a290288f05000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "error": "payload" + }, + { + "name": "bad-magic", + "payload": "000000191e8b08000000000002032bcec82f2a0100a290288f050000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "error": "payload" + }, + { + "name": "bad-method", + "payload": "000000191f8b07000000000002032bcec82f2a0100a290288f050000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "error": "payload" + }, + { + "name": "bytes-before-trailer", + "payload": "000000201f8b08000000000002032bcec82f2a010067617262616765a290288f0500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "error": "payload" } ] } diff --git a/src-tauri/tests/sync2_vectors.rs b/src-tauri/tests/sync2_vectors.rs index b8bf232d..bbb61d4d 100644 --- a/src-tauri/tests/sync2_vectors.rs +++ b/src-tauri/tests/sync2_vectors.rs @@ -23,7 +23,7 @@ use flow_desktop_lib::sync2::pairing::{ pairing_aad, pairing_commit, pairing_keys, pairing_proof, pairing_slot, }; use flow_desktop_lib::sync2::paths::{chain_path, kc_name, wrap_path}; -use flow_desktop_lib::sync2::payload::{decode_payload, padded_size}; +use flow_desktop_lib::sync2::payload::{decode_payload, encode_payload, padded_size}; use flow_desktop_lib::sync2::pipe::scanner_key; use flow_desktop_lib::sync2::recovery::{recovery_keys, recovery_secret, recovery_words}; use flow_desktop_lib::sync2::roster::{Entry, check_sender, replay_roster}; @@ -176,6 +176,24 @@ fn payloads() { } } +#[test] +fn a_payload_this_device_wrote_decodes() { + for content in [Vec::new(), b"short".to_vec(), vec![7; 1 << 20]] { + assert_eq!( + decode_payload(&encode_payload(&content).unwrap()).unwrap(), + content + ); + } +} + +#[test] +fn a_payload_stops_inflating_at_its_limit() { + let limit = 64 << 20; + let payload = |size: usize| encode_payload(&vec![0; size]).unwrap(); + assert_eq!(decode_payload(&payload(limit)).unwrap().len(), limit); + assert!(decode_payload(&payload(limit + 1)).is_err()); +} + #[test] fn member_ids_epoch_keys_and_wraps() { let v = load("keys");