Tarifs

Vue d’ensemble de l’architecture

Fichiers source

Cette page est générée à partir des fichiers source suivants :

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.

go
1// 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 que OnExit (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 OpenSystemProxy et UnsetSystemProxy configurent le proxy au niveau du système d'exploitation
  • Installation des certificats : La méthode installCert coordonne 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.

go
1// 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-domaines
  • example.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 MITM
  • MitmConnect : Interception complète avec déchiffrement
  • HTTPMitmConnect : MITM pour connexions HTTP
  • RejectConnect : 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

go
1type 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 :

go
1var 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 :

EndpointMéthodeDescription
/installPOSTInstallation du certificat CA
/downloadPOSTLancement d'un téléchargement
/cancelPOSTAnnulation d'un téléchargement
/deletePOSTSuppression de ressources
/open-folderPOSTOuverture d'un dossier
/wx-file-decodePOSTDéchiffrement de fichier WeChat
/batch-exportPOSTExport batch des ressources

Le serveur utilise un système de réponse standardisé avec code de statut, message et données :

go
1type 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 :

typescript
1const 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 :

go
1func 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 :

go
1func (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'à TaskNumber téléchargements simultanés, chacun avec DownNumber connexions

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

TechnologieUsageRaison du choixAlternatives considérées
Wails v2Framework desktopEmpreinte légère, binding automatiqueElectron, Tauri
Go 1.22+BackendPerformance réseau, concurrenceRust, Node.js
Vue 3FrontendRéactivité, écosystèmeReact, Svelte
TypeScriptTypage frontendSécurité type, refactoringJavaScript pur
PiniaGestion d'étatSimplicité, intégration Vue 3Vuex, Redux
Naive UIComposants UIDesign moderne, i18nElement Plus, Vuetify
goproxyProxy MITMAPI simple, support HTTPS mitmmitmproxy
zerologLoggingPerformance, JSON structurélogrus, zap
AES-CBCChiffrementStandard, bibliothèque nativeChaCha20

Relations de dépendance entre modules

正在加载图表渲染器...

Points clés des dépendances :

  • Module App central : app.go est 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