mirror of
https://github.com/narrrl/narl-workspace.git
synced 2026-11-03 16:41:27 +01:00
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:
1 parent
9749c500cf
commit
1ae0665206
21 files changed
+1571
-22
No files matched your search
@@ -141,6 +141,42 @@ export interface MediaFile {
|
||||
file_node: number | null
|
||||
}
|
||||
|
||||
/** One thing a certificate, key or keystore file holds, as `/inspect` describes it. */
|
||||
export type CertItem =
|
||||
| {
|
||||
kind: 'certificate'
|
||||
subject: string
|
||||
issuer: string
|
||||
serial: string
|
||||
not_before: number
|
||||
not_after: number
|
||||
/** `RSA 2048`, `EC P-256`, `Ed25519`. */
|
||||
key: string
|
||||
names: string[]
|
||||
usage: string[]
|
||||
ca: boolean
|
||||
sha256: string
|
||||
sha1: string
|
||||
label: string | null
|
||||
}
|
||||
| { kind: 'request'; subject: string; key: string; names: string[] }
|
||||
| {
|
||||
kind: 'private_key'
|
||||
/** Null while it is still encrypted. */
|
||||
key: string | null
|
||||
encrypted: boolean
|
||||
/** The index of its certificate among the items. */
|
||||
matches: number | null
|
||||
label: string | null
|
||||
}
|
||||
| { kind: 'public_key'; key: string }
|
||||
|
||||
export interface Inspection {
|
||||
items: CertItem[]
|
||||
/** Something in the file is behind a password that was not given. */
|
||||
needs_password: boolean
|
||||
}
|
||||
|
||||
/** The vault, as `/api/vault` reports it. */
|
||||
export interface VaultStatus {
|
||||
configured: boolean
|
||||
@@ -403,6 +439,10 @@ export const api = {
|
||||
method: 'POST',
|
||||
}),
|
||||
|
||||
/** What a certificate, key or keystore holds; the password opens it for this answer only. */
|
||||
inspect: (id: number, password?: string) =>
|
||||
request<Inspection>(`/nodes/${id}/inspect`, { method: 'POST', body: body({ password }) }),
|
||||
|
||||
backupStatus: () => request<BackupStatus>('/backup'),
|
||||
|
||||
backupNow: () => request<BackupStatus>('/backup', { method: 'POST' }),
|
||||
|
||||
Reference in new issue
Block a user