Visão geral da arquitetura
Arquivos-fonte
Esta página foi gerada com base nos seguintes arquivos-fonte:
- main.go
- core/app.go
- core/proxy.go
- core/bind.go
- wails.json
- frontend/src/main.ts
- frontend/vite.config.ts
- core/http.go
- core/system_darwin.go
- core/aes.go
- frontend/src/router/index.ts
- frontend/src/stores/index.ts
- go.mod
- frontend/package.json
- frontend/wailsjs/runtime/package.json
- core/rule.go
- core/utils.go
- core/config.go
- core/logger.go
- core/system.go
O res-downloader é uma aplicação desktop de código aberto que combina sniffing de recursos de rede com capacidades de download de alta velocidade. O projeto utiliza uma arquitetura híbrida com backend em Go e frontend em Vue.js, integrados através do framework Wails v2. Esta abordagem permite que a aplicação ofereça alto desempenho no processamento de rede enquanto mantém uma interface de usuário moderna e responsiva.
Estrutura Geral e Tecnologias Principais
A arquitetura do projeto fundamenta-se no framework Wails, que permite criar aplicações desktop usando tecnologias web modernas. O ponto de entrada da aplicação em main.go:1-60 demonstra a inicialização do Wails com configurações de janela, menu e integração de assets. O backend é escrito em Go 1.22+, enquanto o frontend utiliza Vue 3 com TypeScript, Vite como build tool, e a biblioteca de componentes Naive UI.
正在加载图表渲染器...
Pontos-chave da arquitetura:
- Separação Frontend/Backend: O frontend Vue.js comunica-se com o backend Go através de bindings gerados automaticamente pelo Wails, permitindo chamadas diretas a métodos Go a partir do JavaScript
- Proxy MITM Integrado: O componente de proxy atua como intermediário para interceptar tráfego HTTPS, utilizando certificados autoassinados para descriptografar e analisar requisições
- Servidor HTTP Local: Um servidor HTTP interno roda na porta 8899 (configurável) para servir tanto a interface quanto as requisições de proxy
- Integração com SO: A aplicação modifica configurações de proxy do sistema operacional e gerencia certificados raiz para habilitar a interceptação HTTPS
As dependências principais estão definidas em go.mod:1-42, incluindo github.com/wailsapp/wails/v2 para o framework desktop, github.com/elazarl/goproxy para funcionalidade de proxy, e github.com/rs/zerolog para logging estruturado. O frontend em frontend/src/main.ts:1-14 inicializa a aplicação Vue com suporte a i18n (internacionalização), Pinia (gerenciamento de estado) e Vue Router (navegação).
Arquitetura do Backend e Núcleo da Aplicação
Módulo App - Estrutura Principal e Ciclo de Vida
O módulo App definido em core/app.go:42-172 representa o núcleo da aplicação backend. A estrutura App contém campos essenciais como AppName, Version, Description, além de gerenciar o estado do proxy (IsProxy) e certificados embutidos (PublicCrt, PrivateKey).
Responsabilidades do módulo App:
- Inicialização: O método
GetApp()utiliza singleton pattern para garantir uma única instância, extraindo a versão do arquivowails.jsonatravés de regex - Ciclo de Vida:
Startup(ctx context.Context)é chamado pelo Wails na inicialização, iniciando o servidor HTTP em uma goroutine separada - Gerenciamento de Proxy: Métodos
OpenSystemProxy()eUnsetSystemProxy()controlam o proxy do sistema operacional - Limpeza:
OnExit()garante que o proxy seja desativado e recursos sejam liberados ao fechar a aplicação
go1// Estrutura simplificada do App 2type App struct { 3 ctx context.Context 4 assets embed.FS 5 AppName string 6 Version string 7 IsProxy bool 8 IsReset bool 9 PublicCrt []byte 10 PrivateKey []byte 11 UserDir string 12}
Módulo Config - Gerenciamento de Configuração
O sistema de configuração implementado em core/config.go:46-221 utiliza um padrão de configuração com valores padrão e persistência em arquivo JSON. A estrutura Config define parâmetros como porta do servidor (Port), diretório de download (SaveDirectory), configurações de proxy (UpstreamProxy, OpenProxy, AutoProxy), e mapeamento de tipos MIME.
Características principais:
- Singleton Pattern:
initConfig()garante uma única instância global de configuração - Valores Padrão: Define configurações sensatas como
Port: "8899",TaskNumber: runtime.NumCPU() * 2, eUserAgentcom string de navegador moderno - Persistência: Utiliza
Storagepara salvar/carregar configurações emconfig.jsonno diretório do usuário - MIME Types:
getDefaultMimeMap()retorna um mapa extensivo de tipos MIME suportados (imagens, áudio, vídeo) com seus respectivos sufixos de arquivo
Módulo Bind - Interface entre Frontend e Backend
A camada de binding em core/bind.go:9-25 expõe métodos do backend Go para o frontend JavaScript através do sistema de bindings do Wails. A estrutura Bind atua como uma fachada que delega chamadas para os módulos apropriados.
Métodos expostos:
| Método | Retorno | Descrição |
|---|---|---|
Config() | *ResponseData | Retorna configuração global atual |
AppInfo() | *ResponseData | Retorna informações da aplicação (nome, versão, etc.) |
ResetApp() | void | Marca a aplicação para reset e encerra |
O ResponseData definido em core/http.go:21-60 padroniza as respostas com campos Code, Message e Data, facilitando o tratamento no frontend.
Funcionalidades de Rede e Proxy
Módulo Proxy - Interceptação MITM
O componente de proxy em core/proxy.go:25-110 é o coração da funcionalidade de sniffing. Utiliza a biblioteca goproxy para criar um proxy HTTP/HTTPS com capacidade de Man-in-the-Middle (MITM).
Fluxo de inicialização do proxy:
- Carregamento de Certificados:
setCa()carrega o par de chaves X.509 embutido na aplicação - Configuração MITM: Define ações de conexão (
OkConnect,MitmConnect,HTTPMitmConnect) com TLS config derivado do certificado CA - Registro de Handlers:
OnRequest().HandleConnectFunc()determina quais hosts devem sofrer interceptação MITM baseado em regras - Interceptação:
httpRequestEvent()ehttpResponseEvent()processam requisições/respostas para extrair recursos de mídia
go1// Lógica de decisão MITM 2p.Proxy.OnRequest().HandleConnectFunc(func(host string, ctx *goproxy.ProxyCtx) (*goproxy.ConnectAction, string) { 3 if ruleOnce.shouldMitm(host) { 4 return goproxy.MitmConnect, host 5 } 6 return goproxy.OkConnect, host 7})
O sistema de plugins permite estender a funcionalidade para domínios específicos. Durante a inicialização, plugins como QqPlugin e DefaultPlugin são registrados em um mapa indexado por domínio, permitindo tratamento personalizado de requisições.
Módulo Rule - Sistema de Regras de Interceptação
O módulo de regras em core/rule.go:22-126 determina quais hosts devem ter seu tráfego HTTPS interceptado. O RuleSet suporta sintaxe flexível com wildcards e negações.
Formato das regras:
*- Intercepta todos os hosts*.example.com- Intercepta todos os subdomíniosexample.com- Intercepta apenas o domínio exato!example.com- Nega interceptação (exceção)
O método shouldMitm(host string) processa o host removendo portas e normalizando o formato, então aplica as regras em ordem, permitindo que regras posteriores substituam anteriores.
Módulo HTTP Server - Servidor Local
O servidor HTTP em core/http.go:21-60 atua como ponto central de comunicação, escutando em 127.0.0.1:8899 (configurável). O servidor possui comportamento duplo:
- API Interna: Requisições para
127.0.0.1:portasão tratadas porHandleApi()para comunicação frontend-backend - Proxy: Todas as outras requisições são encaminhadas para o
Proxy.ServeHTTP()
go1http.Serve(listener, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 2 if r.Host == "127.0.0.1:"+globalConfig.Port && HandleApi(w, r) { 3 // Tratado como API interna 4 } else { 5 proxyOnce.Proxy.ServeHTTP(w, r) // Encaminha para proxy 6 } 7}))
O servidor também expõe endpoint para download do certificado CA público através de downCert(), permitindo que usuários instalem o certificado em dispositivos móveis para interceptação.
Frontend e Interface do Usuário
Módulo Router - Navegação e Views
O sistema de roteamento em frontend/src/router/index.ts:1-31 utiliza Vue Router com hash history, adequado para aplicações desktop sem servidor web real. A estrutura define um layout principal com duas views filhas:
| Rota | Componente | Meta | Descrição |
|---|---|---|---|
/ | Layout | - | Container principal com redirecionamento para /index |
/index | Index | keepAlive: true | View principal de sniffing/download |
/setting | Setting | keepAlive: false | Configurações da aplicação |
O uso de createWebHashHistory() garante compatibilidade com o protocolo wails:// usado pelo Wails para carregar assets locais.
Módulo Store - Gerenciamento de Estado
O store Pinia em frontend/src/stores/index.ts:1-99 centraliza o estado da aplicação, incluindo informações do app (appInfo), configuração global (globalConfig), estado do proxy (isProxy), e informações de ambiente (envInfo).
Fluxo de inicialização do store:
正在加载图表渲染器...
Métodos principais do store:
init(): Carrega informações iniciais da aplicação e configuração do backendsetConfig(formValue): Atualiza configuração localmente e persiste no backend via APIopenProxy()/unsetProxy(): Controla o proxy do sistema operacional através de chamadas ao backend
A configuração do Vite em frontend/vite.config.ts:1-36 utiliza plugins de auto-import para Vue e Naive UI, reduzindo código boilerplate ao importar automaticamente composables como useDialog, useMessage, useNotification e useLoadingBar.
Serviços de Sistema e Utilitários
Módulo System - Integração com Sistema Operacional
O módulo de sistema em core/system.go:16-83 gerencia interações com o SO, incluindo instalação de certificados e configuração de proxy. A estrutura SystemSetup utiliza um cipher AES para proteger credenciais armazenadas em cache.
Funcionalidades de segurança:
- Cache de Senha:
SetPassword()criptografa a senha do usuário antes de salvar empass.cache - Validação de Cache:
checkPasswordFile()verifica se o cache tem menos de um mês; caso contrário, remove-o - Gerenciamento de Certificados:
initCert()garante que o certificado CA esteja disponível no diretório do usuário
A implementação específica para macOS em core/system_darwin.go:11-99 utiliza o comando networksetup para configurar o proxy do sistema.
Fluxo de configuração de proxy no macOS:
getNetworkServices()lista todos os serviços de rede ativos (excluindo portas seriais e serviços inativos)- Para cada serviço ativo, executa comandos para configurar proxy HTTP e HTTPS
- Utiliza
sudocom senha quando necessário, lendo a senha do stdin
go1commands := [][]string{ 2 {"networksetup", "-setwebproxy", serviceName, "127.0.0.1", globalConfig.Port}, 3 {"networksetup", "-setsecurewebproxy", serviceName, "127.0.0.1", globalConfig.Port}, 4}
Módulo AES - Criptografia de Dados Sensíveis
O utilitário de criptografia em core/aes.go:16-72 implementa criptografia AES-CBC para proteger dados sensíveis como senhas de administrador.
Características da implementação:
- Modo CBC: Utiliza Cipher Block Chaining com vetor de inicialização aleatório
- Padding PKCS#7: Implementa padding manual para alinhar blocos
- Encoding Base64: Saída codificada em Base64 para armazenamento seguro em texto
go1func (a *AESCipher) Encrypt(plainText string) (string, error) { 2 block, _ := aes.NewCipher(a.key) 3 // Padding 4 padding := block.BlockSize() - len(plainText)%block.BlockSize() 5 plainText = plainText + string(bytes.Repeat([]byte{byte(padding)}, padding)) 6 // IV aleatório + ciframento 7 cipherText := make([]byte, aes.BlockSize+len(plainText)) 8 iv := cipherText[:aes.BlockSize] 9 io.ReadFull(rand.Reader, iv) 10 mode := cipher.NewCBCEncrypter(block, iv) 11 mode.CryptBlocks(cipherText[aes.BlockSize:], []byte(plainText)) 12 return base64.StdEncoding.EncodeToString(cipherText), nil 13}
Módulo Logger - Sistema de Logging Estruturado
O sistema de logging em core/logger.go:1-68 utiliza Zerolog para logging estruturado com suporte a saída em arquivo ou console.
Configuração:
- Modo Produção: Logs escritos em
~/logs/app.logcom timestamp e formato estruturado - Modo Desenvolvimento: Logs enviados para stdout com output colorido
- Métodos de Conveniência:
Err()para erros simples,Esg()para erros com contexto formatado
O logger é inicializado com base no ambiente detectado por shared.IsDevelopment(), garantindo logs apropriados para cada contexto de execução.
Fluxo de Dados e Cadeia de Chamadas
O diagrama abaixo ilustra o fluxo completo de uma requisição de sniffing de recursos:
正在加载图表渲染器...
Pontos críticos do fluxo:
- Ativação: O usuário ativa o proxy através da interface, que chama
OpenSystemProxy()no backend - Interceptação: Todas as requisições HTTPS passam pelo proxy local, que decide se aplica MITM baseado nas regras
- Processamento: Plugins específicos por domínio analisam o conteúdo para extrair URLs de recursos de mídia
- Comunicação: Recursos descobertos são enviados para o frontend através do servidor HTTP interno
- Download: O usuário pode selecionar recursos para download, que são baixados através do próprio proxy
Decisões de Design e Trade-offs
Escolha do Framework Wails
A decisão de utilizar Wails em vez de alternativas como Electron ou Tauri foi baseada em:
| Critério | Wails | Electron | Tauri |
|---|---|---|---|
| Tamanho do binário | ~15MB | ~150MB | ~10MB |
| Backend | Go | Node.js | Rust |
| Memória | Baixa | Alta | Baixa |
| Curva de aprendizado | Moderada | Baixa | Alta |
| Ecossistema | Crescente | Maduro | Crescente |
Justificativa: O projeto requer processamento de rede de alto desempenho (natural em Go) e distribuição de binários compactos. Wails oferece o melhor equilíbrio entre performance, tamanho e facilidade de desenvolvimento para uma equipe com expertise em Go.
Proxy MITM vs. Extensão de Navegador
A escolha de implementar um proxy MITM em vez de uma extensão de navegador considera:
Vantagens do Proxy MITM:
- Intercepta tráfego de qualquer aplicação (navegadores, apps nativos)
- Não requer instalação por usuário
- Acesso a protocolos de baixo nível
Desvantagens:
- Requer instalação de certificado CA
- Pode ser detectado por apps com certificate pinning
- Maior superfície de ataque
Armazenamento de Credenciais
O sistema armazena senhas de administrador (necessárias para configurar proxy no macOS) criptografadas com AES-256. A chave está hardcoded no binário (resd48w2d7er95627d447c490a8f02ff), o que é uma limitação conhecida. Alternativas mais seguras como keyring do SO não foram implementadas para manter a simplicidade de deployment.
Limitações Conhecidas
- Certificate Pinning: Aplicações que implementam certificate pinning não podem ter seu tráfego interceptado
- Compatibilidade: A configuração de proxy do sistema pode não funcionar em todos os ambientes (especialmente em redes corporativas com políticas restritivas)
- Cache de Senha: O cache de senha expira após um mês, requerendo reautenticação periódica no macOS
- Single Instance: A aplicação não suporta múltiplas instâncias simultâneas devido ao uso extensivo de singletons
Tecnologias e Dependências
| Tecnologia | Versão | Propósito | Justificativa | Alternativas |
|---|---|---|---|---|
| Go | 1.22+ | Backend | Performance, concorrência, binários estáticos | Rust, C++ |
| Wails | v2.10.1 | Framework desktop | Integração Go+Web, binários compactos | Electron, Tauri |
| Vue.js | 3.x | Frontend | Reatividade, ecossistema maduro | React, Svelte |
| TypeScript | - | Tipagem frontend | Segurança de tipos, DX | JavaScript puro |
| Vite | - | Build tool | HMR rápido, ESM nativo | Webpack, Parcel |
| Pinia | - | Estado global | Simplicidade, TypeScript-first | Vuex, Redux |
| Naive UI | - | Componentes UI | Design moderno, Vue 3 | Element Plus, Vuetify |
| goproxy | v1.7.2 | Proxy HTTP/HTTPS | MITM, extensibilidade | mitmproxy |
| zerolog | v1.33.0 | Logging | Performance, JSON estruturado | logrus, zap |
Dependências entre Módulos
正在加载图表渲染器...
Observações sobre dependências:
- Acoplamento com App: Muitos módulos dependem de
appOnce(singleton de App) para acessar contexto e configurações, criando acoplamento implícito - Ciclo App-Proxy: App inicializa Proxy, mas Proxy precisa de certificados de App, criando dependência circular resolvida pela ordem de inicialização
- Config como Global:
globalConfigé acessado diretamente por múltiplos módulos, facilitando desenvolvimento mas dificultando testes unitários
Configuração e Inicialização
Configuração Padrão
O arquivo wails.json:1-20 define metadados da aplicação:
json1{ 2 "name": "res-downloader", 3 "outputfilename": "res-downloader", 4 "frontend:install": "npm install", 5 "frontend:build": "npm run build", 6 "frontend:dev:watcher": "npm run dev", 7 "frontend:dev:serverUrl": "auto", 8 "info": { 9 "productVersion": "3.1.3" 10 } 11}
Ordem de Inicialização
- main.go: Carrega assets embutidos e chama
core.GetApp() - core/app.go: Inicializa singletons na ordem:
initConfig()→initLogger()→initSystem()→initRule()→initProxy()→initHttpServer() - Wails Runtime: Chama
App.Startup()que inicia o servidor HTTP em background - Frontend: Vue app inicializa, chama
store.init()que comunica com backend via bindings
Configurações de Runtime
| Configuração | Padrão | Descrição |
|---|---|---|
Host | 127.0.0.1 | Host do servidor HTTP local |
Port | 8899 | Porta do servidor HTTP e proxy |
SaveDirectory | ~/Downloads | Diretório para downloads |
TaskNumber | NumCPU * 2 | Máximo de tarefas concorrentes |
DownNumber | 3 | Downloads simultâneos |
Rule | * | Regras de interceptação (todos por padrão) |
OpenProxy | false | Se deve ativar proxy ao iniciar |
AutoProxy | false | Se deve detectar e ativar proxy automaticamente |
