initial commit
This commit is contained in:
134
docs/filedrop-integration-contract.md
Normal file
134
docs/filedrop-integration-contract.md
Normal file
@@ -0,0 +1,134 @@
|
||||
# File Drop Integration Contract
|
||||
|
||||
Version: `filedrop.v1`
|
||||
|
||||
The File Drop service is backend/API-first. UI code is only an integration example. Host systems discover an active dropbox, encrypt locally to the advertised recipient key, then commit ciphertext and the E2EE envelope to the intake endpoint.
|
||||
|
||||
## Discovery
|
||||
|
||||
`GET /api/dropbox/current`
|
||||
|
||||
Response:
|
||||
|
||||
```json
|
||||
{
|
||||
"contractVersion": "filedrop.v1",
|
||||
"dropboxId": "default",
|
||||
"fingerprint": "recipient-key-fingerprint",
|
||||
"key": {
|
||||
"fingerprint": "recipient-key-fingerprint",
|
||||
"publicKey": { "kty": "EC", "crv": "P-256", "x": "...", "y": "..." },
|
||||
"source": "configured",
|
||||
"status": "active"
|
||||
},
|
||||
"label": "Interling secure intake",
|
||||
"publicKey": { "kty": "EC", "crv": "P-256", "x": "...", "y": "..." },
|
||||
"source": "configured",
|
||||
"status": "active",
|
||||
"recipientKeys": [
|
||||
{
|
||||
"fingerprint": "recipient-key-fingerprint",
|
||||
"publicKey": { "kty": "EC", "crv": "P-256", "x": "...", "y": "..." },
|
||||
"source": "configured",
|
||||
"status": "active"
|
||||
},
|
||||
{
|
||||
"fingerprint": "master-recovery-fingerprint",
|
||||
"publicKey": { "kty": "EC", "crv": "P-256", "x": "...", "y": "..." },
|
||||
"source": "configured",
|
||||
"status": "active"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Integrations must show or otherwise pin the recipient `fingerprint` where key authenticity matters.
|
||||
|
||||
The `key.status` value is one of `active`, `rotating`, or `revoked`. Upload UIs must not accept new files for revoked keys.
|
||||
|
||||
## Upload Commit
|
||||
|
||||
`POST /api/uploads/intake`
|
||||
|
||||
Content type: `multipart/form-data`
|
||||
|
||||
Fields:
|
||||
|
||||
- `ciphertext`: encrypted file bytes.
|
||||
- `envelope`: JSON E2EE envelope from `@addideas/sefidrop/e2ee`.
|
||||
- `contactName`: sender name.
|
||||
- `contactEmail`: sender email.
|
||||
- `dropboxId`: discovery response id.
|
||||
- `routingLabel`: operational routing label.
|
||||
- `serviceType`: optional operational service type.
|
||||
- `languagePair`: optional operational language pair.
|
||||
- `requestedDeadline`: optional operational date.
|
||||
- `projectPublicId`: optional existing order id for project-specific drop links.
|
||||
|
||||
The original filename, note, MIME type, and other sensitive sender metadata stay in the encrypted E2EE metadata envelope.
|
||||
New integrations should encrypt to every active `recipientKeys[]` entry and submit an envelope with `recipients[]`. The legacy `recipient` field remains required and mirrors the first recipient wrap for older consumers.
|
||||
|
||||
Response:
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "upload-id",
|
||||
"orderId": "INTAKE-20260710-XXXXXXXX",
|
||||
"storageKey": "upload-id.enc",
|
||||
"status": "ciphertext_received"
|
||||
}
|
||||
```
|
||||
|
||||
## Event
|
||||
|
||||
Each accepted upload emits a `filedrop.upload.received` event. Interling records that event in `project_events`, links the ciphertext row to an order, and exposes it in the portal timeline.
|
||||
|
||||
The event payload is intentionally host-neutral:
|
||||
|
||||
```json
|
||||
{
|
||||
"contractVersion": "filedrop.v1",
|
||||
"eventType": "filedrop.upload.received",
|
||||
"occurredAt": "2026-07-10T17:32:07.000Z",
|
||||
"sender": { "contactEmail": "client@example.com" },
|
||||
"routing": {
|
||||
"dropboxId": "default",
|
||||
"serviceType": "translation",
|
||||
"languagePair": "DE -> EN"
|
||||
},
|
||||
"storage": {
|
||||
"driver": "local",
|
||||
"key": "upload-id.enc",
|
||||
"manifestKey": "upload-id.json"
|
||||
},
|
||||
"upload": {
|
||||
"id": "upload-id",
|
||||
"ciphertextByteLength": 12345,
|
||||
"ciphertextSha256": "base64url-sha256",
|
||||
"recipientKeyFingerprint": "recipient-key-fingerprint",
|
||||
"recipientKeyFingerprints": ["recipient-key-fingerprint", "master-recovery-fingerprint"]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Webhook Signature
|
||||
|
||||
Future standalone deployments can deliver the same event via webhook instead of direct DB integration.
|
||||
|
||||
Signed webhook deliveries use these headers:
|
||||
|
||||
- `x-filedrop-webhook-id`: stable id for idempotency.
|
||||
- `x-filedrop-timestamp`: Unix timestamp in seconds.
|
||||
- `x-filedrop-signature`: HMAC-SHA256 signature, formatted as `v1=<hex>`.
|
||||
|
||||
The signature input is:
|
||||
|
||||
```txt
|
||||
<timestamp>.<raw request body>
|
||||
```
|
||||
|
||||
Receivers should reject old timestamps and verify the signature with a shared webhook secret.
|
||||
|
||||
## Storage Boundary
|
||||
|
||||
The package exposes a `FileDropStorage` interface. The current Interling host uses the local filesystem adapter; a standalone service can provide S3-compatible storage without changing the upload commit contract.
|
||||
59
docs/return-file-key-model.md
Normal file
59
docs/return-file-key-model.md
Normal file
@@ -0,0 +1,59 @@
|
||||
# Return File Key Model
|
||||
|
||||
File drops and returned deliverables use the same browser-only cryptographic boundary, but they need different recipient discovery.
|
||||
|
||||
## Principle
|
||||
|
||||
The server stores ciphertext, public keys, key fingerprints, wrapped content keys, routing metadata, and audit events. It must not receive private keys or plaintext file bytes.
|
||||
|
||||
Each encrypted file should have one content key and one or more recipient key wraps:
|
||||
|
||||
- office intake key for incoming client material;
|
||||
- assigned contractor key for source files that need contractor access;
|
||||
- client account key for deliverables returned through the portal;
|
||||
- master recovery key for operational recovery.
|
||||
|
||||
The existing single-recipient envelope remains valid for simple file drops. New envelopes include `recipients[]` while keeping the legacy `recipient` field readable.
|
||||
|
||||
## Client Delivery
|
||||
|
||||
Client accounts need a recipient key pair before they can receive encrypted deliverables.
|
||||
|
||||
Recommended flow:
|
||||
|
||||
1. The browser creates or imports a P-256 recipient key pair.
|
||||
2. The private key stays browser-side and can be downloaded as a JSON key file or pasted/imported later.
|
||||
3. The public key and fingerprint are registered with the host system.
|
||||
4. Deliverables are encrypted in the browser to the client public key and the master recovery public key.
|
||||
5. The client decrypts in the browser by presenting the private key file or pasted private key.
|
||||
|
||||
For non-technical clients, the private-key file is the least ambiguous first UX. Passphrase-protected key files can be added later.
|
||||
|
||||
## Contractor Access
|
||||
|
||||
Contractors should have their own registered public key. When a source file needs contractor access, an authorized office browser decrypts or unwraps the content key and re-encrypts/rewraps it to the contractor key. The server only receives the updated recipient wrap.
|
||||
|
||||
Contractor deliverables are uploaded as encrypted ciphertext and recorded as a source-deliverable pair:
|
||||
|
||||
- source file id;
|
||||
- deliverable file id;
|
||||
- contractor user id;
|
||||
- delivery status and review timestamps.
|
||||
|
||||
## Master Recovery Key
|
||||
|
||||
The master recovery key is a public key configured in the host system. Its private key should be kept offline or in a controlled operator keystore, never in the application database.
|
||||
|
||||
Every real encrypted file should include a master recipient wrap. Recovery is then possible by importing the master private key in a browser-only operator tool and re-encrypting the content key to a new client or contractor key.
|
||||
|
||||
## Host API Shape
|
||||
|
||||
A host system should provide:
|
||||
|
||||
- recipient key registration for account keys;
|
||||
- active public-key discovery for client, contractor, office, and master recipients;
|
||||
- encrypted file upload for source and deliverable purposes;
|
||||
- recipient wrap update for assignment/recovery workflows;
|
||||
- encrypted file download with access checks only.
|
||||
|
||||
The host remains responsible for orders, users, payment state, permissions, and audit trails. Sefidrop remains responsible for the ciphertext and envelope contract.
|
||||
Reference in New Issue
Block a user