diff --git a/Resources/Views/metadata.leaf b/Resources/Views/metadata.leaf index 0d6091e..e736551 100644 --- a/Resources/Views/metadata.leaf +++ b/Resources/Views/metadata.leaf @@ -29,7 +29,7 @@ KeptWhy it has to beGone after Recipient account and deviceAn envelope cannot be delivered without an address#if(retention.deleteOnAck):the moment your app confirms receipt#else:#(retention.deliveredDays) day(s) once delivered#endif - Arrival time and approximate sizeOrdering, and the size is the ciphertext itself#if(retention.deleteOnAck):the moment your app confirms receipt#else:#(retention.deliveredDays) day(s) once delivered#endif + Arrival time and exact sizeOrdering, and the size is the ciphertext itself — so the length of a message is not hidden, to the byte. Sizes group by kind: a read receipt is not the size of a photo, and a one-word reply is not the size of a paragraph. Nothing has to be decrypted to see that, and it is a weak but real guess about what an envelope carries. Hiding it means padding messages on the sending device before they are encrypted — a change to the apps rather than to this server, because the server cannot pad what it must not read. It has not been made yet.#if(retention.deleteOnAck):the moment your app confirms receipt#else:#(retention.deliveredDays) day(s) once delivered#endif Sender account and deviceIdentified sends only — a sealed send stores neither#if(retention.deleteOnAck):the moment your app confirms receipt#else:#(retention.deliveredDays) day(s) once delivered#endif The ciphertextIt is the message; the server holds no key that opens it#(retention.undeliveredDays) days if never collected Attachment blobs (photos, voice notes, stories — all ciphertext)Devices fetch them separately from the envelope that references them#(retention.attachmentDays) days diff --git a/Tests/FlamenetRelayTests/PublicPagesTests.swift b/Tests/FlamenetRelayTests/PublicPagesTests.swift index 8335083..0fbdb41 100644 --- a/Tests/FlamenetRelayTests/PublicPagesTests.swift +++ b/Tests/FlamenetRelayTests/PublicPagesTests.swift @@ -213,6 +213,21 @@ final class PublicPagesTests: XCTestCase { XCTAssertEqual(offenders, [], "\n" + offenders.joined(separator: "\n")) } + /// ⚠️ **The transparency page has to be accurate in the unflattering + /// direction too.** `/metadata` called what it stores the "approximate + /// size" of a message. It is not approximate: the ciphertext length is + /// exact, and lengths group by kind, so a byte count is a weak guess about + /// what an envelope carries (relay#59). A page that undersells what it + /// keeps is worse than one that keeps more and says so. + func testMetadataDoesNotUndersellWhatItKeeps() throws { + let page = try String(contentsOf: views.appendingPathComponent("metadata.leaf"), + encoding: .utf8) + XCTAssertFalse(page.localizedCaseInsensitiveContains("approximate size"), + "the stored ciphertext length is exact, not approximate") + XCTAssertTrue(page.localizedCaseInsensitiveContains("exact size"), + "the page no longer states that the size it keeps is exact") + } + func testTheSafetyPageCarriesAReachableContact() throws { let page = try String(contentsOf: views.appendingPathComponent("safety.leaf"), encoding: .utf8)