Dépôt de dossiers : - flag `allowDirectories` (défaut false) par cible dans config.json + schéma. - POST /upload accepte `?path=<chemin relatif>` : l'arborescence est recréée sous `dir`, nom d'origine conservé, fichier écrasé si présent. - src/lib/paths.ts : assainissement segment par segment (pas de `..`, pas de séparateur) + vérification de confinement dans storage.ts -> aucune sortie possible de la cible. Refus 400 si la cible n'autorise pas les dossiers. - GET /targets expose `allowDirectories`. - Page : glisser-déposer d'un dossier (parcours récursif webkitGetAsEntry) + bouton « parcourir un dossier », visibles selon la cible. Très gros fichiers (~10 Go) : - `requestTimeout: 0` / `connectionTimeout: 0` : aucun timeout serveur imposé. - écriture disque avec un tampon de 1 Mio. - doc : `maxFileSizeMb` à l'échelle Go, réglages reverse proxy. Tests : +paths.test.ts, +placement (storage), +dossier & gros fichier (upload) ; 60 tests. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
88 lines
3 KiB
JSON
88 lines
3 KiB
JSON
{
|
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
"$id": "https://mediadrop.local/config.schema.json",
|
|
"title": "Configuration mediaDrop",
|
|
"type": "object",
|
|
"additionalProperties": false,
|
|
"required": ["publicUrl", "targets", "session", "oidc"],
|
|
"properties": {
|
|
"$schema": { "type": "string" },
|
|
"port": { "type": "integer", "minimum": 1, "maximum": 65535, "default": 3000 },
|
|
"host": { "type": "string", "default": "0.0.0.0" },
|
|
"publicUrl": {
|
|
"type": "string",
|
|
"format": "uri",
|
|
"description": "URL externe de base, ex. https://media.exemple.fr (sert à redirect_uri / post-logout)."
|
|
},
|
|
"targets": {
|
|
"type": "array",
|
|
"minItems": 1,
|
|
"description": "Dossiers nommés dans lesquels déposer. Le premier est la cible par défaut.",
|
|
"items": {
|
|
"type": "object",
|
|
"additionalProperties": false,
|
|
"required": ["name", "dir"],
|
|
"properties": {
|
|
"name": {
|
|
"type": "string",
|
|
"pattern": "^[A-Za-z0-9._-]+$",
|
|
"description": "Identifiant transmis par le client (?target=...)."
|
|
},
|
|
"label": { "type": "string", "description": "Libellé affiché (défaut : name)." },
|
|
"dir": { "type": "string", "description": "Chemin du dossier de destination." },
|
|
"allowDirectories": {
|
|
"type": "boolean",
|
|
"default": false,
|
|
"description": "Autoriser le dépôt de dossiers (arborescence recréée sous dir)."
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"maxFileSizeMb": { "type": "integer", "minimum": 1, "default": 512 },
|
|
"logLevel": {
|
|
"enum": ["fatal", "error", "warn", "info", "debug", "trace", "silent"],
|
|
"default": "info"
|
|
},
|
|
"allowedMimeTypes": {
|
|
"description": "Liste blanche de types MIME, ou \"all\". Absent => liste média par défaut.",
|
|
"oneOf": [
|
|
{ "const": "all" },
|
|
{ "type": "array", "items": { "type": "string" }, "minItems": 1 }
|
|
]
|
|
},
|
|
"session": {
|
|
"type": "object",
|
|
"additionalProperties": false,
|
|
"required": ["key"],
|
|
"properties": {
|
|
"key": {
|
|
"type": "string",
|
|
"description": "32 octets encodés en base64. Générer avec : openssl rand -base64 32"
|
|
},
|
|
"maxAgeHours": { "type": "number", "exclusiveMinimum": 0, "default": 12 }
|
|
}
|
|
},
|
|
"oidc": {
|
|
"type": "object",
|
|
"additionalProperties": false,
|
|
"required": ["issuer", "clientId", "clientSecret"],
|
|
"properties": {
|
|
"issuer": {
|
|
"type": "string",
|
|
"format": "uri",
|
|
"description": "Issuer OIDC (le serveur lit <issuer>/.well-known/openid-configuration)."
|
|
},
|
|
"clientId": { "type": "string" },
|
|
"clientSecret": {
|
|
"type": "string",
|
|
"description": "Secret du client confidentiel déclaré côté fournisseur."
|
|
},
|
|
"scopes": {
|
|
"type": "array",
|
|
"items": { "type": "string" },
|
|
"default": ["openid", "profile", "email"]
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|