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>
165 lines
6.7 KiB
Kotlin
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)
|
|
}
|
|
}
|