key        = AES-GCM, 256 bits
iv         = 12 random bytes, fresh per file
object     = iv || ciphertext
fragment   = base64url(raw key)

https://sikkerfil.no/s/<id>#k=<base64url key>

x-sikkerfil-token: <write token>
Authorization: Bearer <write token>   # the same thing, either spelling

POST /api/shares
{ "sizeBytes": 1234, "contentType": "application/pdf",
  "encryptedName": "<sealed>", "expiresInSeconds": 86400,
  "maxDownloads": 5 }
  -> 201 { "id", "writeToken", "uploadUrl", "expiresAt" }

PUT <uploadUrl>                       # iv || ciphertext
  Content-Length: 1234
  Content-Type: application/octet-stream

POST /api/shares/<id>/complete
  x-sikkerfil-token: <writeToken>
  -> 200

GET  /api/shares/<id>
POST /api/shares/<id>/download
{ "password": "..." }                 # only if passwordRequired
  -> 200 { "url" }                    # then GET it, then decrypt

GET /api/shares/<id>/audit
GET /api/shares/<id>/audit.csv

POST /api/shares
POST /api/shares/{id}/complete
GET /api/shares/{id}
POST /api/shares/{id}/download
GET /api/shares/{id}/audit
GET /api/shares/{id}/audit.csv
DELETE /api/shares/{id}
GET /api/account/shares
GET /api/health