Vue d’ensemble de l’architecture
Fichiers source
Cette page est générée à partir des fichiers source suivants :
- main.go
- core/app.go
- core/proxy.go
- core/bind.go
- frontend/src/App.vue
- wails.json
- go.mod
- core/downloader.go
- core/aes.go
- core/http.go
- frontend/src/main.ts
- frontend/src/router/index.ts
- frontend/src/stores/index.ts
- frontend/package.json
- frontend/wailsjs/runtime/package.json
- core/rule.go
- core/utils.go
- core/config.go
- core/logger.go
- core/system.go
Ce document présente une analyse approfondie de l'architecture du projet res-downloader, une application desktop de sniffing réseau et de téléchargement de ressources multimédias.
Structure globale et technologies utilisées
Le projet res-downloader est une application desktop multiplateforme construite avec le framework Wails v2, combinant un backend en Go pour la logique métier et un frontend web moderne pour l'interface utilisateur. Cette architecture hybride permet de bénéficier des performances du code natif Go tout en offrant une interface utilisateur riche et réactive.
L'application s'appuie sur Wails v2.10.1 comme framework principal (go.mod:12), avec Vue 3 et TypeScript pour le frontend. La gestion d'état est assurée par Pinia, tandis que Naive UI fournit les composants d'interface. Le point d'entrée principal dans main.go:1-50 configure l'application Wails avec ses options de fenêtre, son menu et ses callbacks de cycle de vie.
正在加载图表渲染器...
Le frontend est initialisé dans frontend/src/main.ts:1-14 avec Vue Router pour la navigation, Pinia pour la gestion d'état, et vue-i18n pour l'internationalisation. Les métadonnées de l'application, incluant le nom, la version (3.1.3) et les informations de build, sont définies dans wails.json:1-20.
Points clés de l'architecture globale :
- Séparation des responsabilités : Le backend Go gère toute la logique métier (proxy, téléchargement, configuration), tandis que le frontend se concentre sur l'affichage et l'interaction utilisateur
- Communication bidirectionnelle : Les bindings Wails permettent au frontend d'appeler des méthodes Go, tandis que le serveur HTTP interne permet au backend d'envoyer des événements au frontend
- Multiplateforme natif : Support de Windows, macOS et Linux avec des adaptations spécifiques par plateforme (barre de titre macOS, décorations Windows)
- Build intégré : Le frontend est compilé et embarqué dans le binaire final via le système d'assets de Wails
Architecture Backend Go
Le backend est organisé autour du package core qui centralise toute la logique métier. La structure App définie dans core/app.go:42-100 constitue le point central de l'application, gérant son cycle de vie, sa configuration et ses dépendances.
Module App - Cœur de l'application
La structure App contient les métadonnées de l'application (nom, version, description), les certificats SSL embarqués pour le proxy MITM, et les références aux autres modules via le pattern singleton. Les méthodes Startup et OnExit gèrent respectivement l'initialisation et le nettoyage de l'application.
go1// Extrait de core/app.go - Structure App principale 2type App struct { 3 AppName string 4 Version string 5 Description string 6 Copyright string 7 IsProxy bool 8 IsReset bool 9 PublicCrt []byte 10 PrivateKey []byte 11 // ... autres champs 12}
Le module implémente plusieurs responsabilités clés :
- Gestion du cycle de vie : La méthode
Startup(core/app.go:129-132) initialise le contexte et démarre le serveur HTTP interne, tandis queOnExit(core/app.go:134-141) nettoie les ressources et désactive le proxy système si nécessaire - Gestion du proxy système : Les méthodes
OpenSystemProxyetUnsetSystemProxyconfigurent le proxy au niveau du système d'exploitation - Installation des certificats : La méthode
installCertcoordonne l'installation du certificat CA pour le MITM
Module Bind - Interface Go-Frontend
Le module Bind défini dans core/bind.go:9-25 expose les méthodes Go au frontend via le système de binding Wails. Ce module agit comme une façade, déléguant les appels aux modules appropriés.
go1// Extrait de core/bind.go - Méthodes exposées au frontend 2func (b *Bind) Config() *ResponseData { 3 return httpServerOnce.buildResp(1, "ok", globalConfig) 4} 5 6func (b *Bind) AppInfo() *ResponseData { 7 return httpServerOnce.buildResp(1, "ok", appOnce) 8} 9 10func (b *Bind) ResetApp() { 11 appOnce.IsReset = true 12 runtime.Quit(appOnce.ctx) 13}
Module Logger - Journalisation
Le système de journalisation utilise zerolog et est initialisé dans core/logger.go:1-40. Il supporte deux modes : sortie console pour le développement et fichier de log pour la production. Les logs sont écrits au format JSON avec horodatage et contexte d'erreur.
Module System - Configuration système
Le module SystemSetup dans core/system.go:1-45 gère les aspects système de l'application :
- Stockage des identifiants : Le cache de mot de passe est chiffré avec AES et stocké dans un fichier avec une expiration d'un mois
- Gestion des certificats : Le certificat CA public est extrait vers un fichier pour l'installation dans le trousseau système
- Chiffrement AES : Utilisé pour sécuriser le cache des identifiants administrateur
Proxy HTTP et interception réseau
Le proxy MITM (Man-in-the-Middle) constitue le cœur fonctionnel de l'application, permettant d'intercepter et d'analyser le trafic HTTPS pour détecter les ressources téléchargeables.
Architecture du proxy
Le proxy est initialisé dans core/proxy.go:25-93 et utilise la bibliothèque goproxy. Il configure un certificat CA personnalisé pour déchiffrer le trafic HTTPS, avec une logique de filtrage basée sur des règles.
正在加载图表渲染器...
Système de règles MITM
Le moteur de règles défini dans core/rule.go:22-80 détermine quels domaines doivent être interceptés. Les règles supportent plusieurs formats :
*: Intercepter tout le trafic*.example.com: Intercepter tous les sous-domainesexample.com: Intercepter uniquement ce domaine!pattern: Exclure un pattern (négation)
La méthode shouldMitm (core/rule.go:92-126) évalue les règles dans l'ordre, la dernière règle correspondante déterminant l'action. Ce système permet un contrôle fin du trafic à analyser.
Configuration TLS/CA
La configuration TLS dans core/proxy.go:95-110 établit les différentes actions de connexion :
OkConnect: Tunnel transparent sans MITMMitmConnect: Interception complète avec déchiffrementHTTPMitmConnect: MITM pour connexions HTTPRejectConnect: Rejet de la connexion
Le certificat CA est chargé depuis les constantes embarquées dans la structure App, permettant de signer dynamiquement les certificats pour chaque domaine visité.
Système de plugins
Le proxy utilise un système de plugins modulaire pour le traitement spécifique par domaine. L'initialisation dans core/proxy.go:26-62 enregistre les plugins (comme QqPlugin pour les domaines Tencent) et configure un pont (bridge) leur donnant accès aux fonctionnalités principales :
- Détection du type de ressource
- Marquage des médias déjà traités
- Accès à la configuration
- Envoi d'événements au frontend
Moteur de téléchargement
Le moteur de téléchargement implémenté dans core/downloader.go:38-90 supporte le téléchargement multi-segments avec reprise et gestion de progression.
Structure FileDownloader
go1type FileDownloader struct { 2 Url string 3 Referer string 4 ProxyUrl *url.URL 5 FileName string 6 File *os.File 7 totalTasks int 8 TotalSize int64 9 IsMultiPart bool 10 RetryOnError bool 11 Headers map[string]string 12 DownloadTaskList []*DownloadTask 13 progressCallback ProgressCallback 14 ctx context.Context 15 cancelFunc context.CancelFunc 16}
Le téléchargeur crée un client HTTP avec configuration optimisée : 100 connexions inactives par hôte, timeout de 90 secondes, et support de proxy amont optionnel.
Gestion des en-têtes HTTP
La méthode setHeaders dans core/downloader.go:109-147 filtre les en-têtes avant l'envoi, supprimant les en-têtes interdits qui pourraient causer des problèmes :
go1var forbiddenDownloadHeaders = map[string]struct{}{ 2 "accept-encoding": {}, 3 "content-length": {}, 4 "host": {}, 5 "connection": {}, 6 "keep-alive": {}, 7 "proxy-connection": {}, 8 "transfer-encoding": {}, 9 "sec-fetch-site": {}, 10 // ... 11}
Le mode de filtrage des en-têtes est configurable : mode "default" (tous les en-têtes sauf les interdits) ou mode sélectif (uniquement les en-têtes spécifiés dans la configuration).
Support du proxy amont
Le téléchargeur supporte l'utilisation d'un proxy amont configuré dans globalConfig.UpstreamProxy. Cette fonctionnalité permet de chaîner les proxies, utile dans les environnements d'entreprise ou pour l'anonymat.
Interface utilisateur et communication
L'interface utilisateur communique avec le backend via deux canaux : les bindings Wails pour les appels de méthodes synchrones, et le serveur HTTP interne pour les opérations asynchrones et les événements.
Serveur HTTP interne
Le serveur HTTP défini dans core/http.go:199-250 expose plusieurs endpoints :
| Endpoint | Méthode | Description |
|---|---|---|
/install | POST | Installation du certificat CA |
/download | POST | Lancement d'un téléchargement |
/cancel | POST | Annulation d'un téléchargement |
/delete | POST | Suppression de ressources |
/open-folder | POST | Ouverture d'un dossier |
/wx-file-decode | POST | Déchiffrement de fichier WeChat |
/batch-export | POST | Export batch des ressources |
Le serveur utilise un système de réponse standardisé avec code de statut, message et données :
go1type ResponseData struct { 2 Code int `json:"code"` 3 Message string `json:"message"` 4 Data interface{} `json:"data"` 5}
Store Pinia centralisé
Le store principal dans frontend/src/stores/index.ts:1-70 gère l'état global de l'application :
typescript1const globalConfig = ref<appType.Config>({ 2 Theme: "lightTheme", 3 Locale: "zh", 4 Host: "0.0.0.0", 5 Port: "8899", 6 Quality: 0, 7 SaveDirectory: "", 8 UpstreamProxy: "", 9 FilenameLen: 0, 10 FilenameTime: false, 11 OpenProxy: false, 12 DownloadProxy: false, 13 AutoProxy: false, 14 WxAction: false, 15 TaskNumber: 8, 16 DownNumber: 3, 17 // ... 18})
La méthode init charge les informations de l'application et la configuration depuis le backend via les bindings Wails, puis initialise l'URL de base pour les appels HTTP.
Routing et navigation
Le routeur Vue dans frontend/src/router/index.ts:1-31 définit une structure avec layout principal et deux vues :
- Index : Vue principale avec keep-alive activé pour préserver l'état
- Setting : Page de configuration sans cache
Composant racine App.vue
Le composant frontend/src/App.vue:1-40 configure le thème (clair/sombre) et la locale en fonction de la configuration globale. Il initialise également le gestionnaire d'événements pour les messages du backend.
Configuration et sécurité
Configuration persistante
Le module de configuration dans core/config.go:118-180 définit les valeurs par défaut et gère la persistance. Le mapping des types MIME est particulièrement étendu :
go1func getDefaultMimeMap() map[string]MimeInfo { 2 return map[string]MimeInfo{ 3 "image/png": {Type: "image", Suffix: ".png"}, 4 "image/webp": {Type: "image", Suffix: ".webp"}, 5 "video/mp4": {Type: "video", Suffix: ".mp4"}, 6 "audio/mpeg": {Type: "audio", Suffix: ".mp3"}, 7 // ... 40+ types MIME supportés 8 } 9}
Le répertoire de téléchargement par défaut est déterminé par plateforme dans core/config.go:183-207, avec support de la variable XDG_DOWNLOAD_DIR sous Linux.
Chiffrement AES
Le module de chiffrement dans core/aes.go:43-72 implémente AES-CBC avec PKCS7 padding pour le stockage sécurisé des identifiants :
go1func (a *AESCipher) Decrypt(cipherText string) (string, error) { 2 cipherTextBytes, err := base64.StdEncoding.DecodeString(cipherText) 3 // ... 4 iv := cipherTextBytes[:aes.BlockSize] 5 cipherTextBytes = cipherTextBytes[aes.BlockSize:] 6 7 mode := cipher.NewCBCDecrypter(block, iv) 8 mode.CryptBlocks(cipherTextBytes, cipherTextBytes) 9 10 padding := int(cipherTextBytes[len(cipherTextBytes)-1]) 11 plainText := cipherTextBytes[:len(cipherTextBytes)-padding] 12 13 return string(plainText), nil 14}
La clé AES est dérivée d'une constante dans SystemSetup (core/system.go:20), et le cache des mots de passe expire après un mois.
Mise à jour dynamique
La méthode setConfig dans core/config.go:209-221 permet la mise à jour dynamique de la configuration avec propagation aux modules dépendants (proxy, règles).
Flux de données et chaînes dappel
Le flux de données principal de l'application suit un parcours bien défini, depuis l'interception du trafic jusqu'au téléchargement des ressources.
正在加载图表渲染器...
Points clés du flux de données :
- Interception sélective : Seuls les domaines correspondant aux règles sont déchiffrés, optimisant les performances
- Traitement asynchrone : L'analyse des réponses et l'extraction des ressources se font sans bloquer le proxy
- Communication événementielle : Le backend notifie le frontend des nouvelles ressources via le serveur HTTP interne
- Téléchargement parallèle : Jusqu'à
TaskNumbertéléchargements simultanés, chacun avecDownNumberconnexions
Décisions de conception et compromis
Choix du framework Wails
Le choix de Wails v2 plutôt que Electron ou Tauri se justifie par plusieurs facteurs :
- Empreinte mémoire réduite : Wails utilise le webview natif du système au lieu d'embarquer Chromium
- Performance Go : Le backend Go offre d'excellentes performances pour le proxy et le téléchargement
- Simplicité de déploiement : Un seul binaire contenant frontend et backend
- Binding automatique : Génération automatique des bindings TypeScript depuis les méthodes Go
Architecture MITM avec certificat embarqué
L'application embarque un certificat CA racine dans core/app.go:58-81 plutôt que d'en générer un dynamiquement. Ce choix simplifie l'installation mais nécessite une confiance de l'utilisateur dans le certificat.
Serveur HTTP interne vs bindings Wails
L'utilisation d'un serveur HTTP interne (core/http.go) en complément des bindings Wails permet :
- Streaming d'événements : Envoi de mises à jour en temps réel sans polling
- Compatibilité navigateur : L'interface peut fonctionner dans un navigateur externe pour le débogage
- API RESTful : Interface standard pour les opérations asynchrones
Limitations connues
- Certificat CA statique : Le certificat embarqué est le même pour toutes les installations, ce qui pourrait poser des problèmes de sécurité s'il était compromis
- Cache mot de passe limité : L'expiration d'un mois du cache peut nécessiter des réauthentifications fréquentes
- Pas de base de données : La configuration et l'état sont stockés en fichiers plats, limitant les requêtes complexes
Tableau récapitulatif des technologies
| Technologie | Usage | Raison du choix | Alternatives considérées |
|---|---|---|---|
| Wails v2 | Framework desktop | Empreinte légère, binding automatique | Electron, Tauri |
| Go 1.22+ | Backend | Performance réseau, concurrence | Rust, Node.js |
| Vue 3 | Frontend | Réactivité, écosystème | React, Svelte |
| TypeScript | Typage frontend | Sécurité type, refactoring | JavaScript pur |
| Pinia | Gestion d'état | Simplicité, intégration Vue 3 | Vuex, Redux |
| Naive UI | Composants UI | Design moderne, i18n | Element Plus, Vuetify |
| goproxy | Proxy MITM | API simple, support HTTPS mitm | mitmproxy |
| zerolog | Logging | Performance, JSON structuré | logrus, zap |
| AES-CBC | Chiffrement | Standard, bibliothèque native | ChaCha20 |
Relations de dépendance entre modules
正在加载图表渲染器...
Points clés des dépendances :
- Module App central :
app.goest le point de coordination, initialisant tous les autres modules via le pattern singleton - Couplage lâche via singletons : Les modules communiquent via les instances globales (
proxyOnce,httpServerOnce, etc.) plutôt que par injection de dépendances - Frontend découplé : Le frontend n'accède au backend que via les bindings Wails et le serveur HTTP, permettant un développement indépendant
