Sharely — Documentation Technique

Version : 1.0.0 · Licence : MIT · Node.js : ≥ 18

Table des matières

1. Présentation du projet

2. Architecture

3. Stack technique

4. Structure des répertoires

5. Configuration & Variables d'environnement

6. Modèles de données

7. API REST

8. API WebSocket

9. Routes de service des fichiers

10. Authentification & Sécurité

11. Système d'upload

12. Génération de miniatures

13. E-mail & SMTP

14. Internationalisation

15. Frontend (React SPA)

16. Tableau de bord administrateur

17. RGPD / Confidentialité

18. Tâches en arrière-plan

19. Déploiement

20. Environnement de développement

21. Migrations & Scripts

22. Tests end-to-end


1. Présentation du projet

Sharely est une plateforme de partage de fichiers auto-hébergée dotée d'une interface web épurée, d'une intégration ShareX et d'un accès via API. Les utilisateurs téléversent des captures d'écran, des fichiers et des médias, puis les partagent instantanément via des liens courts.

Fonctionnalités principales

FonctionnalitéDescription
Upload webGlisser-déposer, jusqu'à 500 fichiers simultanément
Upload par morceauxFichiers jusqu'à 2 Go via upload multi-part parallèle
Intégration ShareXFichier de configuration .sxcu téléchargeable en un clic
Upload via APIAuthentification par jeton Bearer, compatible curl/wget
Visionneuse de fichiersZoom sur les images, streaming vidéo/audio (HTTP Range), PDF en ligne, code avec coloration syntaxique
Modes d'intégration*embed* (HTML OG/Twitter Card) ou *raw* (redirection directe)
MiniaturesAperçus JPEG automatiques pour les vidéos (ffmpeg) et les PDF (ghostscript)
CollectionsRegroupements de fichiers avec mot de passe et date d'expiration optionnels
Liens de partageLiens par fichier avec mot de passe, expiration et limite de téléchargement
Interface temps réelMises à jour en direct via WebSocket (upload, suppression, compteur de vues, stats admin)
Multilingue8 langues : EN, DE, FR, ES, IT, PT, JA, ZH
Tableau de bord adminStatistiques, gestion des utilisateurs, gestion des fichiers, journal d'audit (export CSV)
Conformité RGPDFonctionnalités de confidentialité conformes au RGPD (Art. 17, 20, 32, etc.)
Import XBackBoneMigration d'installations XBackBone existantes
Prêt pour Dockerdocker compose up -d démarre l'environnement complet

2. Architecture

┌─────────────────────────────────────────────────────────────┐
│                        Browser / Client                      │
│            React 18 SPA  ·  Vite  ·  Tailwind CSS           │
│   ┌──────────────────────────────────────────────────────┐   │
│   │  HTTP REST (/api/*)            WebSocket (/ws)       │   │
│   └──────────────────────────────────────────────────────┘   │
└───────────────────────────┬────────────────────┬─────────────┘
                            │ HTTP               │ WS
┌───────────────────────────▼────────────────────▼─────────────┐
│                    Express.js (app.js)                        │
│                                                               │
│  ┌──────────────┐  ┌───────────┐  ┌──────────┐  ┌────────┐  │
│  │  /api/auth   │  │  /api/*   │  │   /f/*   │  │  /s/*  │  │
│  │  /api/install│  │  routes   │  │  files   │  │ shares │  │
│  └──────────────┘  └───────────┘  └──────────┘  └────────┘  │
│                                                               │
│  Middleware: session · rate-limit · CSRF · CSP · auth        │
│                                                               │
│  ┌──────────┐  ┌──────────┐  ┌──────────┐  ┌────────────┐  │
│  │  multer  │  │  ws.js   │  │  mailer  │  │ retention  │  │
│  │  upload  │  │ WebSocket│  │ nodemailer│  │  cleanup   │  │
│  └──────────┘  └──────────┘  └──────────┘  └────────────┘  │
└───────────────────────────┬───────────────────────────────────┘
                            │
┌───────────────────────────▼───────────────────────────────────┐
│                      MongoDB (Mongoose)                        │
│  User · File · Collection · ShareLink · SiteSettings          │
│  AuditLog                                                      │
└───────────────────────────────────────────────────────────────┘
                            │
              ┌─────────────▼───────────────┐
              │     Dateisystem (uploads/)   │
              │  {folderName}/  ·  .chunks/  │
              │  .thumbnails/   ·  .avatars/ │
              └─────────────────────────────┘

Flux de données : Upload standard

Browser → POST /api/web-upload (multipart/form-data)
       → multer: Datei in uploads/{folderName}/
       → File.createUnique() → MongoDB
       → generateThumbnail() (async, non-blocking)
       → logAudit()
       → broadcast('file:uploaded') via WebSocket
       ← JSON: { files: [...] }

Flux de données : Upload ShareX

ShareX → POST /upload (token im Formular-Body)
       → multer: Datei temporär in uploads/
       → requireApiKey: Token-Lookup → User
       → fs.renameSync → uploads/{folderName}/
       → File.create() → MongoDB
       ← JSON: { url, delete_url }

3. Stack technique

CoucheTechnologieVersion
RuntimeNode.js≥ 18
Framework backendExpress.js4.x
Base de donnéesMongoDB + MongooseMongo 7, Mongoose 8.x
Sessionsexpress-session + connect-mongo
Temps réelWebSocket (ws)8.x
Upload de fichiersMulter1.x
E-mailNodemailer8.x
Hachage des mots de passebcryptjs2.x (12 tours)
Hachage des clés APISHA-256 (Node Crypto)
Limitation de débitexpress-rate-limit8.x
Import XBackBonesql.js1.x
Framework frontendReact 1818.3.x
Routage (frontend)React Router v66.x
Outil de buildVite6.x
StyleTailwind CSS + Radix UI3.x
Composants UIshadcn/ui (Radix primitives)
IcônesFontAwesome6.x
i18ni18next + react-i18next
Coloration syntaxiquehighlight.js11.x
ConteneursDocker + Docker Compose
TestsPlaywright (E2E)1.60.x

4. Structure des répertoires

sharely/
├── app.js                          # Point d'entrée Express, séquence de démarrage
├── package.json
├── .env.example                    # Modèle pour toutes les variables d'environnement
├── Dockerfile
├── docker-compose.yml
│
├── src/
│   ├── config/
│   │   └── db.js                   # Connexion MongoDB (Mongoose)
│   ├── middleware/
│   │   ├── auth.js                 # requireLogin / requireAdmin / requireApiKey
│   │   └── upload.js               # Configuration Multer, liste de blocage
│   ├── models/
│   │   ├── AuditLog.js             # Événements d'audit (TTL 90 jours)
│   │   ├── Collection.js           # Collections de fichiers
│   │   ├── File.js                 # Métadonnées des fichiers
│   │   ├── ShareLink.js            # Liens de partage par fichier
│   │   ├── SiteSettings.js         # Singleton : paramètres opérateur
│   │   └── User.js                 # Comptes utilisateurs + clés API
│   ├── routes/
│   │   ├── api.js                  # API principale (upload, galerie, admin, ...)
│   │   ├── auth.js                 # Connexion / Inscription / Réinitialisation du mot de passe
│   │   ├── files.js                # Service des fichiers, embeds OG, requêtes de plage
│   │   ├── import.js               # Migration XBackBone
│   │   ├── install.js              # Endpoint d'installation initiale
│   │   └── shares.js               # Service des fichiers via lien de partage
│   ├── jobs/
│   │   └── retentionCleanup.js     # Suppression quotidienne des fichiers expirés
│   ├── migrations/
│   │   ├── migrateApiKeyHashes.js  # Unique : textes en clair → hachages SHA-256
│   │   └── migrateUserFolders.js   # Unique : déplacement des fichiers dans les dossiers utilisateurs
│   ├── utils/
│   │   ├── audit.js                # Fonction utilitaire logAudit()
│   │   ├── generateThumbnail.js    # Intégration ffmpeg / ghostscript
│   │   ├── mailer.js               # Wrapper Nodemailer + modèles d'e-mail i18n
│   │   └── sanitizeFilename.js     # Nettoyage du nom de fichier
│   └── ws.js                       # Serveur WebSocket + dispatcher d'actions
│
├── client/                         # Frontend React
│   ├── index.html
│   ├── package.json
│   ├── vite.config.js
│   ├── tailwind.config.js
│   └── src/
│       ├── main.jsx                # Point d'entrée React
│       ├── App.jsx                 # Configuration du routeur
│       ├── index.css               # Styles globaux
│       ├── context/
│       │   └── AuthContext.jsx     # État d'authentification global
│       ├── hooks/
│       │   ├── use-toast.js        # Hook de notification toast
│       │   └── useWebSocket.js     # Connexion WS + gestionnaires d'événements
│       ├── components/
│       │   ├── Layout.jsx          # Shell de l'application (barre de navigation, sidebar)
│       │   ├── ProtectedRoute.jsx  # Garde d'authentification
│       │   ├── ShareLinkDialog.jsx # Dialogue de création de lien de partage
│       │   ├── AddToCollectionDialog.jsx
│       │   ├── CookieBanner.jsx
│       │   ├── LanguageSelector.jsx
│       │   ├── RequireEmailDialog.jsx
│       │   ├── UserAvatar.jsx
│       │   └── ui/                 # Composants de base shadcn/ui
│       ├── pages/
│       │   ├── Upload.jsx          # Page d'upload
│       │   ├── Gallery.jsx         # Galerie de fichiers
│       │   ├── FileView.jsx        # Vue détaillée d'un fichier
│       │   ├── Collections.jsx     # Vue d'ensemble des collections
│       │   ├── CollectionView.jsx  # Collection individuelle
│       │   ├── ShareView.jsx       # Page publique de lien de partage
│       │   ├── Settings.jsx        # Paramètres utilisateur
│       │   ├── Login.jsx
│       │   ├── Register.jsx
│       │   ├── ForgotPassword.jsx
│       │   ├── ResetPassword.jsx
│       │   ├── Install.jsx         # Installation initiale
│       │   ├── PrivacyPolicy.jsx
│       │   ├── TermsOfService.jsx
│       │   └── admin/
│       │       ├── Dashboard.jsx   # Page d'accueil admin
│       │       ├── Users.jsx       # Gestion des utilisateurs
│       │       ├── Files.jsx       # Gestion des fichiers
│       │       ├── AuditLog.jsx    # Vue du journal d'audit
│       │       ├── SiteSettings.jsx# Paramètres opérateur
│       │       └── Import.jsx      # Import XBackBone
│       ├── i18n/
│       │   ├── index.js            # Configuration i18next
│       │   └── locales/
│       │       ├── de.json
│       │       ├── en.json
│       │       ├── es.json
│       │       ├── fr.json
│       │       ├── it.json
│       │       ├── ja.json
│       │       ├── pt.json
│       │       └── zh.json
│       └── lib/
│           └── utils.js            # Utilitaire Tailwind (cn())
│
├── scripts/
│   ├── setup-db.js
│   ├── mongo-init.js               # Script d'initialisation MongoDB
│   ├── migrate-uploads-to-user-folders.js
│   └── generate-missing-thumbnails.js
│
├── e2e/                            # Tests Playwright
│   ├── admin.spec.js
│   ├── bulk-actions-fixes.spec.js
│   ├── gallery.spec.js
│   ├── sharelink.spec.js
│   ├── tags.spec.js
│   ├── upload.spec.js
│   ├── helpers.js
│   └── global-setup.js
│
├── uploads/                        # Fichiers uploadés (runtime)
│   ├── .thumbnails/
│   ├── .avatars/
│   └── .chunks/                    # Morceaux temporaires
│
└── docs/assets/                    # Captures d'écran et logo

5. Configuration & Variables d'environnement

Toutes les variables sont chargées depuis .env (via dotenv). Le fichier .env.example contient le modèle complet.

Champs obligatoires

VariableDescription
SESSION_SECRETSecret pour le chiffrement des sessions — chaîne aléatoire longue, ex. openssl rand -hex 32
MONGO_ROOT_PASSWORDMot de passe root MongoDB (requis uniquement pour Docker Compose)
MONGO_APP_PASSWORDMot de passe de l'utilisateur applicatif MongoDB

Toutes les variables d'environnement

VariablePar défautDescription
PORT3000Port TCP du serveur HTTP
MONGODB_URI_(construit depuis Docker Compose)_URI de connexion MongoDB complète
MONGO_ROOT_PASSWORDMot de passe root MongoDB
MONGO_APP_USERappuserNom d'utilisateur applicatif MongoDB
MONGO_APP_PASSWORDMot de passe de l'utilisateur applicatif MongoDB
MONGO_DB_NAMEsharelyNom de la base de données MongoDB
SESSION_SECRETObligatoire — secret de chiffrement des sessions
BASE_URLhttp://localhost:3000URL de base publique pour les liens de partage générés (sans / final)
SITE_NAMEsharelyNom du site dans les embeds Open Graph
MAX_FILE_SIZE_MB100Taille maximale des fichiers pour les uploads standards en Mo (uploads par morceaux jusqu'à 2 Go indépendamment)
ALLOW_REGISTRATIONtruefalse désactive l'inscription publique
SMTP_HOSTNom d'hôte du serveur SMTP ; laisser vide pour désactiver les fonctionnalités e-mail
SMTP_PORT587Port SMTP
SMTP_SECUREfalsetrue pour TLS implicite (port 465), false pour STARTTLS
SMTP_USERNom d'utilisateur SMTP
SMTP_PASSMot de passe SMTP
SMTP_FROM_(SMTP_USER)_Adresse d'expédition dans les e-mails sortants
UPLOAD_DIR./uploadsChemin absolu vers le répertoire d'upload
NODE_ENVproduction active les cookies sécurisés

6. Modèles de données

User (src/models/User.js)

{
  username:                    String (3–32, unique, alphanumérique + _-)
  password:                    String (bcrypt, 12 tours)
  role:                        'admin' | 'user'
  apiKey:                      String (héritage, vide après migration)
  apiKeyHash:                  String (SHA-256, unique, sparse)
  apiKeyPrefix:                String (8 premiers caractères du texte en clair)
  folderName:                  String (unique, sparse, max 64)
  avatarExt:                   String | null (.jpg/.png/.gif/.webp)
  embedMode:                   'embed' | 'raw'
  isActive:                    Boolean
  email:                       String (minuscules, unique, sparse)
  emailVerified:               Boolean
  emailVerificationToken:      String | null (hachage SHA-256 du texte en clair)
  emailVerificationExpires:    Date | null
  passwordResetToken:          String | null (hachage SHA-256)
  passwordResetExpires:        Date | null
  language:                    'en'|'de'|'fr'|'es'|'it'|'pt'|'ja'|'zh'
  predefinedTags:              [String] (max 100 tags × 50 caractères)
  createdAt:                   Date
}

Méthodes importantes :

File (src/models/File.js)

{
  shortId:      String (8 caractères hexadécimaux : 6 timestamp + 2 aléatoires, unique)
  deleteToken:  String (32 caractères hexadécimaux, unique)
  originalName: String (assaini)
  storedName:   String (chemin relatif : "folderName/8hex.ext")
  mimeType:     String
  size:         Number (octets)
  uploader:     ObjectId → User
  views:        Number
  tags:         [String] (max 20 × 50 caractères)
  createdAt:    Date
}

Propriétés calculées :

Algorithme Short ID :

shortId = hex(seconds_since_2024-01-01, 6 chars) + randomBytes(2).hex()

Collection (src/models/Collection.js)

{
  shortId:     String (8 Hex, unique)
  name:        String (max 100)
  description: String (max 500)
  owner:       ObjectId → User
  files:       [ObjectId → File]
  password:    String | null (bcrypt)
  expiresAt:   Date | null
  createdAt:   Date
}
Les collections expirées sont automatiquement supprimées par l'index TTL MongoDB 7 jours après leur expiration.
{
  token:         String (32 Hex, unique)
  file:          ObjectId → File
  createdBy:     ObjectId → User
  label:         String (max 100)
  password:      String | null (bcrypt)
  expiresAt:     Date | null
  downloadLimit: Number (-1 = illimité)
  downloadCount: Number
  createdAt:     Date
}
Comme les collections : délai de grâce de 7 jours après expiration via l'index TTL.

SiteSettings (src/models/SiteSettings.js)

Document singleton (_id: 'singleton') :

{
  operatorName:        String
  operatorAddress:     String
  operatorEmail:       String
  cloudflareAnalytics: Boolean
  fileRetentionDays:   Number (0 = désactivé)
  encryptionAtRest:    Boolean
  sessionDurationDays: Number (par défaut : 7)
  allowRegistration:   Boolean
}

AuditLog (src/models/AuditLog.js)

{
  timestamp: Date (index TTL : 90 jours)
  userId:    ObjectId → User | null
  username:  String | null
  action:    String
  ip:        String | null
  meta:      Mixed (métadonnées spécifiques à l'action)
}

7. API REST

URL de base : /api

Tous les endpoints JSON retournent Content-Type: application/json. Erreurs : { "error": "message" }.


Authentification (/api/auth)

MéthodeCheminAuthDescription
GET/meSessionUtilisateur connecté
POST/loginConnexion (limité : 10/15min)
POST/registerInscription (limité, premier utilisateur devient admin)
POST/logoutDéconnexion
GET/smtp-enabledVérifie si SMTP est configuré
GET/verify-email?token=Vérifier l'adresse e-mail
GET/verify-reset-token?token=Valider le jeton de réinitialisation
POST/forgot-passwordEnvoyer l'e-mail de réinitialisation du mot de passe (limité : 5/h)
POST/reset-passwordDéfinir un nouveau mot de passe

Requête de connexion :

POST /api/auth/login
{ "username": "max", "password": "meinPasswort123" }

Réponse de connexion :

{
  "user": {
    "id": "...", "username": "max", "role": "user",
    "avatarUrl": null, "email": "[email protected]",
    "emailVerified": true, "language": "de"
  }
}

Upload de fichiers

MéthodeCheminAuthDescription
POST/uploadClé APIUpload ShareX (endpoint héritage dans app.js)
POST/api/uploadClé APIUpload ShareX/API (champ : file)
POST/api/web-uploadSessionUpload web (champ : files[], max 500)
POST/api/chunk/initSessionInitialiser un upload par morceaux
POST/api/chunk/:uploadIdSessionUploader un morceau (champ : chunk)
POST/api/chunk/:uploadId/completeSessionAssembler les morceaux
DELETE/api/chunk/:uploadIdSessionAnnuler l'upload et nettoyer

Réponse d'upload API :

{
  "url": "https://example.com/f/a1b2c3d4",
  "raw": "https://example.com/f/a1b2c3d4/raw",
  "delete_url": "https://example.com/api/delete/a1b2c3d4",
  "short_id": "a1b2c3d4",
  "filename": "screenshot.png",
  "size": 102400
}

Flux d'upload par morceaux

1. POST /api/chunk/init{ uploadId: "32hex" }

2. POST /api/chunk/:uploadId (Corps : chunkIndex=N, Fichier : chunk) → { received: N }

En parallèle avec 3 à 5 morceaux simultanés

3. POST /api/chunk/:uploadId/complete{ files: [fileObject] }


Gestion des fichiers

MéthodeCheminAuthDescription
GET/api/gallerySessionPropres fichiers (admin : tous), paginé (24/page), filtres : q, type, tag, page
GET/api/file/:shortIdMétadonnées du fichier (incrémente le compteur de vues)
PATCH/api/file/:shortIdSessionMettre à jour les tags/le nom
DELETE/api/file/:shortIdSessionSupprimer un fichier
DELETE/api/delete/:shortIdClé APISupprimer un fichier (authentification par clé API)
POST/api/files/bulkSessionActions en masse : delete, tag, removeTag, addToCollection, moveToCollection
GET/api/tagsSessionToutes les suggestions de tags de l'utilisateur

Paramètres de requête de la galerie :


Paramètres utilisateur

MéthodeCheminAuthDescription
GET/api/my-keySessionAfficher le préfixe de la clé API
POST/api/regen-keySessionRégénérer la clé API
GET/api/sharex-configSessionTélécharger le fichier ShareX .sxcu (régénère la clé)
PATCH/api/user/usernameSessionChanger le nom d'utilisateur (mot de passe requis)
PATCH/api/user/passwordSessionChanger le mot de passe
PATCH/api/user/emailSessionChanger l'e-mail (envoie un e-mail de confirmation)
PATCH/api/user/languageSessionDéfinir la langue de l'interface
PATCH/api/user/embed-modeSessionDéfinir le mode d'intégration (embed/raw)
POST/api/user/resend-verificationSessionRenvoyer l'e-mail de vérification
GET/api/user/exportSessionExport des données (RGPD Art. 20) en JSON
DELETE/api/user/accountSessionSupprimer le compte (RGPD Art. 17, mot de passe requis)
GET/api/user/predefined-tagsSessionRécupérer les tags prédéfinis
PATCH/api/user/predefined-tagsSessionMettre à jour les tags prédéfinis
POST/api/user/avatarSessionUploader un avatar (max 2 Mo, JPEG/PNG/GIF/WebP)
DELETE/api/user/avatarSessionSupprimer l'avatar
GET/api/user/avatar/:userIdServir l'avatar

Liens de partage

MéthodeCheminAuthDescription
GET/api/file/:shortId/share-linksSession (Propriétaire/Admin)Tous les liens de partage d'un fichier
POST/api/file/:shortId/share-linksSession (Propriétaire/Admin)Créer un lien de partage
DELETE/api/share-links/:tokenSession (Propriétaire/Créateur/Admin)Supprimer un lien de partage
GET/api/share-links/:tokenMétadonnées du lien de partage (public)
POST/api/share-links/:token/verifyVérifier le mot de passe du lien de partage

Créer un lien de partage :

POST /api/file/a1b2c3d4/share-links
{
  "label": "Pour les collègues",
  "password": "secret",
  "expiresAt": "2025-12-31T23:59:59Z",
  "downloadLimit": 10
}

Collections

MéthodeCheminAuthDescription
GET/api/collectionsSessionPropres collections (admin : toutes)
POST/api/collectionsSessionCréer une collection
GET/api/collections/:idAfficher une collection (publique, mot de passe si défini)
PATCH/api/collections/:idSession (Propriétaire/Admin)Mettre à jour une collection
DELETE/api/collections/:idSession (Propriétaire/Admin)Supprimer une collection
POST/api/collections/:id/filesSession (Propriétaire/Admin)Ajouter un fichier à la collection
DELETE/api/collections/:id/files/:fileShortIdSession (Propriétaire/Admin)Retirer un fichier de la collection
POST/api/collections/:id/verifyVérifier le mot de passe de la collection

Endpoints d'administration

MéthodeCheminAuthDescription
GET/api/admin/statsAdminStatistiques du tableau de bord
GET/api/admin/usersAdminTous les utilisateurs (avec nombre de fichiers)
POST/api/admin/usersAdminCréer un utilisateur
PATCH/api/admin/users/:id/toggleAdminActiver/désactiver un utilisateur
PATCH/api/admin/users/:id/roleAdminChanger le rôle d'un utilisateur
DELETE/api/admin/users/:idAdminSupprimer un utilisateur
POST/api/admin/users/:id/regen-keyAdminRégénérer la clé API
PATCH/api/admin/users/:id/passwordAdminDéfinir un mot de passe
PATCH/api/admin/users/:id/folderAdminChanger le nom du dossier (déplace les fichiers)
GET/api/admin/filesAdminTous les fichiers, paginé (30/page)
GET/api/admin/site-settingsAdminLire les paramètres opérateur
PATCH/api/admin/site-settingsAdminMettre à jour les paramètres opérateur
GET/api/admin/audit-logAdminJournal d'audit paginé (50/page)
GET/api/admin/audit-log/exportAdminTélécharger le journal d'audit en CSV
GET/api/site-settingsInformations publiques de l'opérateur (pour la page de confidentialité)

Paramètres du site (publics)

GET /api/site-settings
{
  "operatorName": "Musterfirma GmbH",
  "operatorAddress": "Musterstr. 1, 12345 Musterstadt",
  "operatorEmail": "[email protected]",
  "cloudflareAnalytics": false,
  "fileRetentionDays": 365,
  "encryptionAtRest": false,
  "sessionDurationDays": 7
}

8. API WebSocket

Connexion : wss://example.com/ws (utilisateurs connectés uniquement, cookie de session requis)

Protocole

Client → Serveur (Requête) :

{ "id": "req-abc123", "action": "file:list", "payload": { "type": "image", "page": 1 } }

Serveur → Client (Réponse) :

{ "id": "req-abc123", "data": { ... } }

Serveur → Client (Erreur) :

{ "id": "req-abc123", "error": "Forbidden", "status": 403 }

Serveur → Client (Diffusion) :

{ "event": "file:uploaded", "data": { "shortId": "a1b2c3d4", "uploaderId": "..." } }

Actions disponibles

ActionAuthDescription
site-settings:getParamètres publics du site
auth:meUtilisateurDonnées de l'utilisateur connecté
file:getUtilisateurDétails du fichier (incrémente les vues)
file:listUtilisateurListe des fichiers avec filtre/pagination
file:deleteUtilisateurSupprimer un fichier
user:get-keyUtilisateurPréfixe de la clé API
user:regen-keyUtilisateurRégénérer la clé API
user:change-passwordUtilisateurChanger le mot de passe
user:change-usernameUtilisateurChanger le nom d'utilisateur
user:change-emailUtilisateurChanger l'e-mail
user:change-languageUtilisateurDéfinir la langue
user:change-embed-modeUtilisateurDéfinir le mode d'intégration
user:resend-verificationUtilisateurRenvoyer l'e-mail de vérification
user:exportUtilisateurExport des données
user:delete-accountUtilisateurSupprimer le compte
admin:statsAdminStatistiques du tableau de bord
admin:settings:getAdminLire les paramètres du site
admin:settings:updateAdminMettre à jour les paramètres du site
admin:users:listAdminTous les utilisateurs
admin:users:createAdminCréer un utilisateur
admin:users:toggleAdminActiver/désactiver un utilisateur
admin:users:roleAdminChanger le rôle d'un utilisateur
admin:users:deleteAdminSupprimer un utilisateur
admin:users:regen-keyAdminRégénérer la clé API
admin:users:passwordAdminDéfinir un mot de passe
admin:users:folderAdminChanger le nom du dossier
admin:files:listAdminTous les fichiers
admin:audit-log:listAdminJournal d'audit paginé

Événements de diffusion

ÉvénementDestinatairesCharge utile
file:uploadedUploadeur{ shortId, uploaderId }
file:deletedPropriétaire du fichier{ shortId, uploaderId }
file:viewTous{ shortId, views }
user:createdAdmins{ id, username, role, ... }
user:deletedAdmins{ id }
user:updatedAdmins{ id, ...champs modifiés }
audit:logAdminsObjet AuditLog complet
settings:updatedAdminsObjet SiteSettings mis à jour
stats:invalidateAdmins{} (déclenche le rafraîchissement des stats)

9. Routes de service des fichiers

/f/:shortId — Visionneuse de fichiers

- embedMode = 'embed' : HTML OG avec redirection

- embedMode = 'raw' + image/vidéo/audio : HTTP 302 → /f/:shortId/raw

/f/:shortId/raw — Accès direct

Sert le fichier comme réponse HTTP avec support des requêtes de plage (206 Partial Content). Images/vidéos/audio : Content-Disposition: inline, autres : attachment.

/f/:shortId/download — Téléchargement forcé

Comme /raw, mais toujours Content-Disposition: attachment.

/f/:shortId/thumb — Miniature

Retourne la miniature JPEG (pour les vidéos et les PDF). Cache-Control: public, max-age=86400.

/f/:shortId/delete/:token — Suppression ShareX

Supprime le fichier sans session via un jeton de suppression unique.

/s/:token — Service de fichiers via lien de partage (src/routes/shares.js)

Vérifie le mot de passe (via flag de session), la date d'expiration et la limite de téléchargement, puis sert le fichier.


10. Authentification & Sécurité

Authentification par session

Authentification par clé API

Chaîne de middleware (src/middleware/auth.js)

requireLogin    → vérifie req.session.user → 401 si non connecté
requireAdmin    → comme requireLogin, de plus role === 'admin' → 403
requireApiKey   → vérifie l'en-tête Authorization ou req.body.token

Protection CSRF

requireSameOrigin() dans app.js compare l'en-tête Origin avec l'en-tête Host pour toutes les routes API. Complète les cookies sameSite: 'strict'.

Politique de sécurité du contenu

default-src 'self';
script-src 'self' 'unsafe-inline' https://static.cloudflareinsights.com;
style-src 'self' 'unsafe-inline';
img-src 'self' data: blob:;
media-src 'self' blob:;
connect-src 'self' https://cloudflareinsights.com;
frame-ancestors 'self';

En-têtes de sécurité

Limitation de débit

EndpointLimiteFenêtre
Upload (/upload, /api/upload, /api/web-upload)60 requêtes15 minutes
Auth (/api/auth/login, /register, etc.)10 requêtes15 minutes
Réinitialisation du mot de passe5 requêtes1 heure

Liste de blocage des fichiers

Les types MIME et extensions suivants sont rejetés à l'upload :

Types MIME bloqués : application/x-executable, application/x-sh, application/x-csh, application/x-bat

Extensions bloquées : .bat, .cmd, .com, .ps1, .psm1, .psd1, .sh, .bash, .csh, .zsh, .fish, .vbs, .vbe, .jse, .scr, .pif, .application, .gadget, .hta, .php, .php3–5, .phtml, .asp, .aspx, .jsp, .jspx, .cfm

Protection contre la traversée de chemin

Tous les accès aux fichiers via resolveUploadPath() vérifient que le chemin résolu se trouve bien dans UPLOAD_DIR.


11. Système d'upload

Upload standard (Multer)

Upload par morceaux (>250 Mo)

Le client frontend bascule automatiquement en mode morceaux pour les fichiers volumineux.

Structure de répertoires côté serveur :

uploads/.chunks/{uploadId}/
  meta.json          { filename, mimeType, totalSize, totalChunks, userId, createdAt }
  chunk-0
  chunk-1
  ...
  chunk-N

Taille des morceaux : 10–20 Mo (max 51 Mo accepté pour la compatibilité descendante)

Parallélisme : 3–5 uploads de morceaux simultanés

Assemblage : Basé sur les flux (pas de chargement complet en RAM)

Upload d'avatar


12. Génération de miniatures

Les miniatures sont générées de manière asynchrone après l'upload (.catch(() => {}) — les erreurs sont ignorées silencieusement).

Miniatures vidéo (ffmpeg)

ffmpeg -y -i <file> -ss 00:00:01 -vframes 1 \
  -vf "scale=320:320:force_original_aspect_ratio=increase,crop=320:320" \
  -q:v 3 uploads/.thumbnails/<shortId>.jpg

Miniatures PDF (Ghostscript)

gs -dNOPAUSE -dBATCH -dSAFER \
  -sDEVICE=jpeg -dFirstPage=1 -dLastPage=1 \
  -r72 -dJPEGQ=85 \
  -sOutputFile=uploads/.thumbnails/<shortId>.jpg \
  <file>

Délai d'expiration : 30 secondes par génération de miniature

Repli : Si ffmpeg/ghostscript n'est pas disponible, la génération est ignorée silencieusement.

Script de remplissage

npm run migrate:thumbnails
# ou dans le conteneur :
docker exec -it <container> npm run migrate:thumbnails

13. E-mail & SMTP

Configuration

SMTP est activé lorsque SMTP_HOST est défini. mailer.isConfigured() vérifie cette valeur.

Modèles d'e-mail

Tous les e-mails sont envoyés dans la langue de l'utilisateur (8 langues). Les modèles sont intégrés dans src/utils/mailer.js.

Types d'e-mails envoyés :

TypeDéclencheurValidité du jeton
Vérification d'e-mailInscription, changement d'e-mail24 heures
Réinitialisation du mot de passePOST /api/auth/forgot-password1 heure

Sécurité des jetons


14. Internationalisation

Bibliothèque : i18next + react-i18next + i18next-browser-languagedetector

Langues prises en charge :

CodeLangue
enEnglish
deDeutsch
frFrançais
esEspañol
itItaliano
ptPortuguês
ja日本語
zh中文

Sélection de la langue :

1. Détection de la langue du navigateur (automatique)

2. Préférence de l'utilisateur en base de données (user.language)

3. Persistance via PATCH /api/user/language

Fichiers de traduction : client/src/i18n/locales/{code}.json


15. Frontend (React SPA)

Configuration du routeur (client/src/App.jsx)

RouteComposantAuth
/Redirection → /galleryNon
/auth/loginLogin.jsxNon
/auth/registerRegister.jsxNon
/auth/forgot-passwordForgotPassword.jsxNon
/auth/reset-passwordResetPassword.jsxNon
/installInstall.jsxNon
/uploadUpload.jsxOui
/galleryGallery.jsxOui
/f/:shortIdFileView.jsxOui
/collectionsCollections.jsxOui
/c/:idCollectionView.jsxNon (public)
/s/:tokenShareView.jsxNon (public)
/settingsSettings.jsxOui
/adminDashboard.jsxAdmin
/admin/usersUsers.jsxAdmin
/admin/filesFiles.jsxAdmin
/admin/audit-logAuditLog.jsxAdmin
/admin/site-settingsSiteSettings.jsxAdmin
/admin/importImport.jsxAdmin
/privacyPrivacyPolicy.jsxNon
/termsTermsOfService.jsxNon

Contexte d'authentification (client/src/context/AuthContext.jsx)

État global pour l'utilisateur connecté. Initialisé au démarrage de l'application via GET /api/auth/me.

Hook WebSocket (client/src/hooks/useWebSocket.js)

Gère la connexion WS persistante. Fournit sendMessage() et l'enregistrement des gestionnaires d'événements. Logique de reconnexion en cas de déconnexion.

Composants UI

Basé sur shadcn/ui (Radix UI Primitives + Tailwind CSS) :


16. Tableau de bord administrateur

Le tableau de bord administrateur (/admin/*) est accessible uniquement aux utilisateurs avec role: 'admin'.

Tableau de bord (/admin)

Gestion des utilisateurs (/admin/users)

Gestion des fichiers (/admin/files)

Journal d'audit (/admin/audit-log)

Paramètres du site (/admin/site-settings)

Import XBackBone (/admin/import)


17. RGPD / Confidentialité

FonctionnalitéArticle RGPD
Politique de confidentialité (configurable)Art. 13/14 – Transparence
Page des conditions d'utilisation (configurable)Art. 13/14 – Transparence
Export des données (JSON avec URLs)Art. 20 – Portabilité des données
Suppression du compte (fichiers + données)Art. 17 – Droit à l'effacement
Journal d'audit (TTL 90 jours via MongoDB)Art. 5(2) – Responsabilité
Export CSV du journal d'auditArt. 5(2) – Responsabilité
Rétention des fichiers configurableArt. 5(1)(e) – Limitation de la conservation
Clés API sous forme de hachage SHA-256Art. 32 – Sécurité
Mots de passe en bcrypt (12 tours)Art. 32 – Sécurité
Consentement aux cookies pour Cloudflare AnalyticsArt. 13 – Transparence
Anonymisation lors de la suppression du compteArt. 17 – Droit à l'effacement

Flux de suppression RGPD

Lors de la suppression du compte (user:delete-account / DELETE /api/user/account) :

1. Tous les fichiers de l'utilisateur sont supprimés du disque

2. Les miniatures sont supprimées

3. L'avatar est supprimé

4. Les entrées du journal d'audit sont anonymisées (username: '[deleted]', ip: null, userId: null)

5. Le document utilisateur est supprimé

6. La session est détruite


18. Tâches en arrière-plan

Nettoyage par rétention (src/jobs/retentionCleanup.js)

Index TTL MongoDB (automatiques)

CollectionTTLDéclencheur
AuditLog90 jourstimestamp
Collection7 jours après expiresAtexpiresAt
ShareLink7 jours après expiresAtexpiresAt

19. Déploiement

Docker (recommandé)

git clone https://github.com/Christianoooooo/sharely.git
cd sharely
cp .env.example .env
# Éditer .env (SESSION_SECRET, mots de passe MONGO, BASE_URL)
docker compose up -d

Services :

Volumes :

Vérifications de santé : L'application vérifie HTTP 200 sur /, MongoDB vérifie db.adminCommand('ping').

Proxy inverse Nginx

server {
    listen 443 ssl;
    server_name files.example.com;

    client_max_body_size 2100M;  # Au moins aussi grand que le plus grand morceau + tampon

    location / {
        proxy_pass http://localhost:3000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;

        # Support WebSocket
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }
}
BASE_URL dans .env doit correspondre au domaine public.

Premier démarrage

Le premier utilisateur enregistré reçoit automatiquement le rôle admin (User.countDocuments() === 0).


20. Environnement de développement

Prérequis

Installation

# Backend
npm install
cp .env.example .env
# Éditer .env

# Frontend
cd client
npm install

Démarrage

# Backend (port 3000, avec nodemon)
npm run dev

# Frontend (port 5173, terminal séparé)
cd client
npm run dev

Le serveur de développement Vite proxie automatiquement les requêtes API vers localhost:3000.

Build

npm run build   # Construit client/dist/, le backend reste inchangé
npm start       # Démarre le serveur Express de production

21. Migrations & Scripts

Migrations automatiques (à chaque démarrage)

Ces migrations s'exécutent au démarrage de l'application dans app.js et sont idempotentes :

MigrationFichierFonction
Migration des dossiers utilisateurssrc/migrations/migrateUserFolders.jsDéplace les fichiers de uploads/ vers uploads/{folderName}/
Migration des hachages de clés APIsrc/migrations/migrateApiKeyHashes.jsConvertit les clés API en texte clair en hachages SHA-256

Scripts manuels

# Générer des miniatures pour les fichiers existants
npm run migrate:thumbnails
# ou :
node scripts/generate-missing-thumbnails.js

# Déplacer les uploads vers les dossiers utilisateurs (manuel)
npm run migrate:user-folders
# ou :
node scripts/migrate-uploads-to-user-folders.js

Initialisation de la base de données (Docker)

scripts/mongo-init.js est exécuté au premier démarrage du conteneur MongoDB et crée l'utilisateur applicatif avec les permissions correctes.


22. Tests end-to-end

Framework : Playwright (@playwright/test)

Fichiers de test

FichierSuite de tests
e2e/upload.spec.jsFlux d'upload
e2e/gallery.spec.jsGalerie et gestion des fichiers
e2e/admin.spec.jsTableau de bord admin
e2e/sharelink.spec.jsCréation et utilisation des liens de partage
e2e/tags.spec.jsGestion des tags
e2e/bulk-actions-fixes.spec.jsActions en masse

Exécution

# Tous les tests
npm run test:e2e

# Avec interface graphique
npm run test:e2e:ui

Configuration Playwright : playwright.config.js

Configuration globale : e2e/global-setup.js (crée les utilisateurs de test, l'admin, etc.)

Utilitaires : e2e/helpers.js (fonctions utilitaires partagées)


Annexe : Actions du journal d'audit

ActionDéclencheur
loginConnexion réussie
logoutDéconnexion
registerInscription
uploadUpload de fichier
delete_fileFichier supprimé
delete_accountCompte supprimé
change_passwordMot de passe modifié
change_usernameNom d'utilisateur modifié
change_emailE-mail modifié
verify_emailE-mail vérifié
forgot_passwordRéinitialisation du mot de passe demandée
reset_passwordMot de passe réinitialisé
regen_api_keyClé API régénérée
sharex_configConfiguration ShareX téléchargée
export_dataExport des données
admin_create_userAdmin : utilisateur créé
admin_delete_userAdmin : utilisateur supprimé
admin_toggle_userAdmin : utilisateur activé/désactivé
admin_change_roleAdmin : rôle utilisateur modifié
admin_change_passwordAdmin : mot de passe défini
admin_regen_keyAdmin : clé API régénérée

*Documentation générée à partir du code source de sharely v1.0.0*