Guides
Safe File Presentation
C1 completes generic non-image file presentation over the existing ADR-0015 attachment pipeline. The transport, manifest, chunk encryption, consent, resumption, quotas, and hard no-mesh-airtime rules are unchanged. This document is the user promise, security boundary, and qualification contract.
1. User promise
Every attachment row treats its authenticated filename and media type as sender-provided, untrusted hints. Komms never describes a received file as safe, never opens a completed file automatically, never uploads it for scanning, and never fetches a remote preview. A local malware engine may inspect an exported file if the operating system or user has configured one, but Komms does not promise that such an engine exists or detected every threat.
Completed inbound files always retain caller-selected protected export. A smaller reviewed set of matching, non-active filename/media-type pairs may also offer an explicit Open action. That action first warns that the file was not scanned, then materializes exact verified bytes in app-private temporary storage and hands them to the operating system. Suspicious files remain export-only.
2. Shared fail-closed policy
kult-node derives one bounded presentation record from the sanitized basename
and lowercase media-type hint:
kindis an inert icon/label category: image, audio, video, document, archive, executable, or other;open_policyisprotected_media,external_open, orexport_only; and- warnings are canonically ordered
media_type_mismatch,dangerous_type,unrecognized_type, andmissing_filenametokens.
Executable/script/installer and active-document extensions or media types are classified as executable and export-only. A known extension whose expected media types do not include the supplied hint is export-only. Unknown types, unknown or malformed extensions, and missing filenames are export-only. Only a recognized matching pair enters the explicit external-open path. Existing bounded canonical JPEG/PNG and WAV paths remain protected media; this policy does not create a generic decoder.
The comparison is deliberately small and auditable. It is not content sniffing, malware detection, sandboxing, or proof that the sender labelled bytes honestly. Filename text is bidirectionally isolated in the three shells and warning meaning never depends on color alone.
3. Interfaces and lifecycle
Rust exposes classify_attachment_file; attachment object records include the
same decision. Strict RPC uses attachment_file_presentation, the CLI uses
kult file-presentation MEDIA_TYPE [FILENAME], and UniFFI exports
attachment_file_presentation plus typed enums and records.
Desktop, Android, and iOS show the sender-provided-name warning, exact progress,
policy cautions, and export action. Open is visible only for a completed inbound
primary object with external_open policy and always requires a second explicit
confirmation. Desktop retains protected temporary materializations only for the
unlocked session. Android uses an app-private cache file and a read-only
FileProvider grant, cleaning session and startup orphans. iOS uses a
complete-protection temporary export and removes it when the system-viewer sheet
closes or the row disappears. Failure before handoff removes the transient.
Open/export does not change delivery state, create a receipt, enqueue work, contact a scanner, or alter internet/LAN/mesh/sneakernet behavior. Large-file and resume behavior remains the independently sealed, verified F3 chunk lifecycle.
4. Qualification matrix
For the core, every wrapper, and each shell:
- Match
report.pdfwithapplication/pdf; verify an inert document row, explicit external-open policy, no auto-open, and an unscanned warning before handoff. - Present
invoice.pdf.exeasapplication/pdf; verify executable styling, mismatch plus dangerous warnings, export-only behavior, and exact export. - Exercise HTML, JavaScript, shell, installer, SVG, and executable hints; verify none enters protected-media or external-open paths.
- Exercise unknown type/extension and missing filename cases; verify stable fallback naming, warnings, bidi isolation, and export-only behavior.
- Interrupt and resume a large transfer, restart after verified chunks, and inject duplicate/reordered/corrupt chunks; verify exact progress and that no presentation action appears before integrity-checked completion.
- Cancel, reject, lock, background, close, and restart around export/open; verify protected temporary plaintext is removed and sealed progress remains honest.
- Record queues and mesh frames before every presentation action; verify no new delivery work and zero bulk mesh airtime.
- With keyboard-only navigation, screen readers, large text, RTL content, high contrast, and reduced motion, verify filename, type, warnings, progress, confirmation, Open, and Export remain understandable and operable.
fixtures/c1-file-presentation-parity.json pins the cross-language policy.
Rust/FFI, strict RPC, Kotlin/JVM, Swift binding, and desktop tests must agree with
it. Android debug-APK and iOS Simulator builds provide automated compilation
evidence; real Android/iOS file-picker and external-open interaction remains part
of the M5 hands-on qualification gate and must not be reported as completed
stable-release qualification.
5. Explicit non-goals
C1 adds no wire field, capability, preview payload, thumbnail, remote service, scanner dependency, cloud analysis, archive extraction, office/PDF renderer, generic media codec, executable launch path, or mesh exception. Video editing, rich document preview, and claims about third-party viewer safety remain out of scope.