files: PDFs, text, code, tables and certificates open in place

The file pane decided what to show by MIME type, and uploads keep a
type only when it cannot execute, so a .md, a .json or a .pem arrived
as application/octet-stream and got "no preview". It now goes by name
first (preview.ts), and a file with a name it does not know has its
first 8 KiB looked at: no NUL bytes and valid UTF-8 means text.

- text and code: the first 256 KiB with line numbers, as before
- markdown: rendered through the same sanitiser as documents, with a
  source toggle
- CSV/TSV: a table of the first 500 rows, quotes respected
- PDF: the browser's own viewer in a frame. Only a PDF is served
  without the sandbox CSP (Chrome's viewer will not start under it),
  with frame-ancestors 'self' and X-Frame-Options SAMEORIGIN; the app
  CSP allows same-origin frames.
- certificates, keys, keystores: POST /api/nodes/{id}/inspect reads
  PEM (chains, keys, requests, public keys), DER and PKCS#12 on the
  server, in pure Rust, including the RC2/3DES keystores that
  openssl -legacy and older keychains write. It answers with subject,
  issuer, validity, key, names, usage and fingerprints, and pairs each
  private key with its certificate by public key. A password is asked
  for only when needed, used for that one answer and never stored;
  no key material is ever sent back. Sealed files are read through the
  vault, and only while it is open.

The tests read throwaway fixtures under src/routes/testdata, made with
the openssl commands listed beside them; .gitignore lets their .pem
files past a global *.pem rule.
This commit is contained in:
nvrl committed 2026-10-20 09:57:09 +02:00
1 parent 9749c500cf
commit 1ae0665206
21 files changed
+1571 -22

No files matched your search

+9
View File
@@ -64,6 +64,15 @@ russh-sftp = "3"
# speaks rand_core 0.10, one major version past the `rand` used everywhere else.
rand10 = { package = "rand", version = "0.10" }
# Reading certificates, keys and keystores for the file view, in pure Rust —
# there is no OpenSSL to lean on. p12-keystore brings RC2 and 3DES for the
# keystores older tools still export; pkcs8 opens encrypted PKCS#8 keys.
x509-parser = "0.18"
p12-keystore = "0.4"
pkcs8 = { version = "0.11", features = ["encryption", "3des", "std"] }
sec1 = { version = "0.8", features = ["der"] }
sha1 = "0.10"
[dev-dependencies]
# A paused clock, so tests of timed loops do not wait in real time.
tokio = { version = "1", features = ["test-util"] }