Files
flamenet-messenger-android/engine/src/test/kotlin/io/flamenet/e2e/FileEnvelopeInteropTest.kt
T
Paul HittandClaude Fable 5.1 4dd544083c Remove machine-writing tells from comments and docs
Emoji markers, markdown bold inside code comments, and em-dashes are
gone from source comments, string literals, scripts, Gradle files and
the markdown docs. Counted before and after:

  emoji markers   2680 -> 1 (the emoji picker's own list, which is the feature)
  em-dashes       2490 -> 9 (table placeholders and fenced code)

Two warning glyphs in user-facing strings in ChatScreens.kt are removed
as well; the sentences say the same thing without them. Two backtick
test names carried an em-dash and now carry a comma.

Nothing else changed. 1208 tests pass, counted from the result XML.
The three obfs4 interop tests are opted out with OBFS4_INTEROP_OPTOUT=1
for this run, as their own message instructs when no bridge is set up.

CONTRIBUTING gets a four-line rule so it does not grow back.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-08 18:52:12 -04:00

165 lines
6.7 KiB
Kotlin

package io.flamenet.e2e
import org.json.JSONObject
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertNotNull
import kotlin.test.assertTrue
import kotlin.test.assertFalse
/**
* Documents sent between the two apps.
*
* The envelope in [IOS_FILE] was produced by the iOS build, not by this
* engine. Two implementations of one format that each only test against
* themselves agree right up to the day somebody sends a real file, and the
* symptom is a message that arrives as "[unsupported attachment]" with no clue
* why. This is the test that catches a drift in the field names before then.
*/
class FileEnvelopeInteropTest {
// Standard base64 with padding, which is what Bytes.unb64 decodes.
private val key = "ERERERERERERERERERERERERERERERERERERERERERE="
private val digest = "IiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiI="
/** As iOS assembles it: `fn`, `cls`, `cmp` as additive top-level keys. */
private val iosFile = """
{"fnc":1,"kind":"file","caption":"📎 Lease agreement.pdf",
"att":{"id":"${"a".repeat(64)}","key":"$key","digest":"$digest",
"bytes":4096,"mime":"application/pdf","w":0,"h":0},
"fn":"Lease agreement.pdf","cls":2,"cmp":[0,1]}
""".trimIndent().replace("\n", "")
@Test
fun `a file envelope from iOS parses with its name and label`() {
val content = Content.parse(iosFile)
val ref = assertNotNull(content.attachment, "no attachment parsed")
assertEquals(Attachment.FILE, ref.kind)
assertEquals("Lease agreement.pdf", ref.filename)
assertEquals(2, ref.classification)
assertEquals(listOf(0, 1), ref.compartments)
assertEquals(4096, ref.bytes)
assertEquals("application/pdf", ref.mime)
}
/** It must be recognised, not merely tolerated. */
@Test
fun `a file is a known kind rather than needing a newer client`() {
val content = Content.parse(iosFile)
assertFalse(content.needsNewerClient, "file is still treated as an unknown kind")
assertFalse(content.isControl, "a document is not control traffic")
}
@Test
fun `this engine assembles the same shape it parses`() {
val ref = Attachment.Ref(
kind = Attachment.FILE,
id = "b".repeat(64),
key = ByteArray(32) { 0x11 },
digest = ByteArray(32) { 0x22 },
bytes = 2048,
mime = "application/pdf",
filename = "Settlement draft.docx",
classification = 3,
compartments = listOf(2),
)
val json = Content.attachment(ref)
val parsed = JSONObject(json)
assertEquals("file", parsed.getString("kind"))
assertEquals("Settlement draft.docx", parsed.getString("fn"))
assertEquals(3, parsed.getInt("cls"))
assertEquals(1, parsed.getJSONArray("cmp").length())
val back = assertNotNull(Content.parse(json).attachment)
assertEquals("Settlement draft.docx", back.filename)
assertEquals(3, back.classification)
assertEquals(listOf(2), back.compartments)
}
/**
* The compatibility rule, on this side too: never captionless, because
* a build that predates this kind shows only the caption.
*/
@Test
fun `a file envelope always carries a caption naming the document`() {
val ref = Attachment.Ref(
kind = Attachment.FILE, id = "c".repeat(64),
key = ByteArray(32) { 0x11 }, digest = ByteArray(32) { 0x22 },
bytes = 10, mime = "application/pdf", filename = "notes.txt",
)
val json = Content.attachment(ref)
assertTrue(json.contains("\"caption\""), "a file envelope went out captionless")
assertEquals("📎 notes.txt", Content.parse(json).text)
}
@Test
fun `a caption the sender wrote is not replaced`() {
val ref = Attachment.Ref(
kind = Attachment.FILE, id = "d".repeat(64),
key = ByteArray(32) { 0x11 }, digest = ByteArray(32) { 0x22 },
bytes = 10, mime = "application/pdf", filename = "notes.txt",
)
assertEquals("signed copy", Content.parse(Content.attachment(ref, "signed copy")).text)
}
/** An older peer sends no `fn`/`cls`/`cmp`. It must parse, not throw. */
@Test
fun `an envelope without the new fields still parses`() {
val older = """
{"fnc":1,"kind":"file","caption":"📎 old.pdf",
"att":{"id":"${"e".repeat(64)}","key":"$key","digest":"$digest",
"bytes":10,"mime":"application/pdf","w":0,"h":0}}
""".trimIndent().replace("\n", "")
val ref = assertNotNull(Content.parse(older).attachment)
assertEquals("", ref.filename)
assertEquals(0, ref.classification)
assertEquals(emptyList(), ref.compartments)
}
/**
* The additive property that makes any of this safe: a photo envelope
* from this engine still carries none of the file keys, so a peer that has
* never heard of them reads it exactly as before.
*/
@Test
fun `a photo envelope carries none of the file keys`() {
val photo = Attachment.Ref(
kind = Attachment.IMAGE, id = "f".repeat(64),
key = ByteArray(32) { 0x11 }, digest = ByteArray(32) { 0x22 },
bytes = 1000, mime = "image/jpeg", width = 100, height = 200,
)
val json = Content.attachment(photo, "hi")
assertFalse(json.contains("\"fn\""), "a photo envelope carried file fields")
assertFalse(json.contains("\"cls\""))
assertFalse(json.contains("\"cmp\""))
}
/**
* A filename from a peer is display text and a name, never a path.
* Carried verbatim, and nothing here should ever join it onto a directory.
*/
@Test
fun `a hostile filename survives as plain text`() {
val hostile = """
{"fnc":1,"kind":"file","caption":"x",
"att":{"id":"${"a".repeat(64)}","key":"$key","digest":"$digest",
"bytes":1,"mime":"application/pdf","w":0,"h":0},
"fn":"../../../etc/passwd","cls":0,"cmp":[]}
""".trimIndent().replace("\n", "")
assertEquals("../../../etc/passwd",
assertNotNull(Content.parse(hostile).attachment).filename)
}
@Test
fun `a file in a group keeps its routing`() {
val ref = Attachment.Ref(
kind = Attachment.FILE, id = "a".repeat(64),
key = ByteArray(32) { 0x11 }, digest = ByteArray(32) { 0x22 },
bytes = 1, mime = "application/pdf", filename = "g.pdf",
)
val content = Content.parse(Content.attachment(ref, groupId = "g-123"))
assertEquals("g-123", content.groupId)
assertEquals(Attachment.FILE, content.attachment?.kind)
}
}