Adds a "Via AnyDrop" flow for senders who need to reach someone not present on the mesh. The file is sealed client-side (XChaCha20-Poly1305), uploaded directly to an in-cluster MinIO bucket via a presigned PUT, and handed off to the recipient as a URL whose fragment carries the key. The server only ever sees ciphertext, opaque metadata blobs, and sizes. - server: transfers table (drizzle migration), /api/transfers CRUD + consume endpoint, presigned PUT/GET via @aws-sdk/client-s3, cleanup loop that purges expired + exhausted blobs. - web: @noble/ciphers sealFile/openFile, high-level sendCloud/receive helpers, CloudSharePanel on Home, /r/:id receive page, /inbox page for signed-in users (sent + received tabs). - k8s: MinIO StatefulSet with bucket-init initContainer, S3 env vars on the server Deployment (credentials pulled from minio-credentials Secret). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
139 lines
3.9 KiB
YAML
139 lines
3.9 KiB
YAML
# MinIO — S3-compatible object storage for the encrypted relay.
|
|
#
|
|
# Phase 2 context: the server never sees plaintext. Clients upload an
|
|
# XChaCha20-Poly1305 ciphertext directly to MinIO via a presigned PUT URL,
|
|
# and recipients download via a presigned GET URL. The symmetric key stays
|
|
# in the browser URL fragment (#k=...); the server only knows the storage
|
|
# key and blob size.
|
|
#
|
|
# Single-node deployment in-cluster. Bucket "transfers" is created on boot
|
|
# via a one-shot initContainer (mc mb --ignore-existing).
|
|
#
|
|
# DEPLOY-TIME REQUIREMENT: the API port (9000) must be publicly reachable at
|
|
# the host declared by S3_ENDPOINT in server.yml (s3.anydrop.arthurbarre.fr).
|
|
# Presigned URLs are signed against that host, and the browser must be able
|
|
# to resolve it. Configure an external route (traefik ingress, nginx, etc.)
|
|
# from that hostname to this Service on port 9000.
|
|
|
|
apiVersion: v1
|
|
kind: Service
|
|
metadata:
|
|
name: minio
|
|
namespace: anydrop
|
|
labels:
|
|
app: minio
|
|
spec:
|
|
clusterIP: None
|
|
selector:
|
|
app: minio
|
|
ports:
|
|
- name: api
|
|
port: 9000
|
|
targetPort: 9000
|
|
- name: console
|
|
port: 9001
|
|
targetPort: 9001
|
|
|
|
---
|
|
apiVersion: apps/v1
|
|
kind: StatefulSet
|
|
metadata:
|
|
name: minio
|
|
namespace: anydrop
|
|
spec:
|
|
serviceName: minio
|
|
replicas: 1
|
|
selector:
|
|
matchLabels:
|
|
app: minio
|
|
template:
|
|
metadata:
|
|
labels:
|
|
app: minio
|
|
spec:
|
|
initContainers:
|
|
- name: ensure-bucket
|
|
image: minio/mc:latest
|
|
command:
|
|
- /bin/sh
|
|
- -c
|
|
- |
|
|
set -e
|
|
until mc alias set local http://minio:9000 "$MINIO_ROOT_USER" "$MINIO_ROOT_PASSWORD" 2>/dev/null; do
|
|
echo "waiting for minio..."
|
|
sleep 2
|
|
done
|
|
mc mb --ignore-existing local/transfers
|
|
# Keep the bucket private — every object is served via presigned URL.
|
|
mc anonymous set none local/transfers
|
|
echo "bucket ready"
|
|
env:
|
|
- name: MINIO_ROOT_USER
|
|
valueFrom:
|
|
secretKeyRef:
|
|
name: minio-credentials
|
|
key: access_key
|
|
- name: MINIO_ROOT_PASSWORD
|
|
valueFrom:
|
|
secretKeyRef:
|
|
name: minio-credentials
|
|
key: secret_key
|
|
containers:
|
|
- name: minio
|
|
image: minio/minio:latest
|
|
args:
|
|
- server
|
|
- /data
|
|
- --console-address
|
|
- ":9001"
|
|
ports:
|
|
- containerPort: 9000
|
|
name: api
|
|
- containerPort: 9001
|
|
name: console
|
|
env:
|
|
- name: MINIO_ROOT_USER
|
|
valueFrom:
|
|
secretKeyRef:
|
|
name: minio-credentials
|
|
key: access_key
|
|
- name: MINIO_ROOT_PASSWORD
|
|
valueFrom:
|
|
secretKeyRef:
|
|
name: minio-credentials
|
|
key: secret_key
|
|
- name: MINIO_BROWSER_REDIRECT_URL
|
|
value: "https://anydrop.arthurbarre.fr/minio-console"
|
|
volumeMounts:
|
|
- name: data
|
|
mountPath: /data
|
|
livenessProbe:
|
|
httpGet:
|
|
path: /minio/health/live
|
|
port: 9000
|
|
initialDelaySeconds: 30
|
|
periodSeconds: 20
|
|
timeoutSeconds: 5
|
|
readinessProbe:
|
|
httpGet:
|
|
path: /minio/health/ready
|
|
port: 9000
|
|
initialDelaySeconds: 5
|
|
periodSeconds: 10
|
|
timeoutSeconds: 3
|
|
resources:
|
|
requests:
|
|
memory: "256Mi"
|
|
cpu: "100m"
|
|
limits:
|
|
memory: "1Gi"
|
|
cpu: "1000m"
|
|
volumeClaimTemplates:
|
|
- metadata:
|
|
name: data
|
|
spec:
|
|
accessModes: ["ReadWriteOnce"]
|
|
resources:
|
|
requests:
|
|
storage: 20Gi
|