docs: atualiza o README (configuração, testes, SSRF e limitações)
This commit is contained in:
1 parent
dee0771ac5
commit
656e7b3b5d
1 file changed
+29
-22
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
**Proxy de download efêmero: a sua VPS baixa o arquivo por uma rota melhor e entrega para o seu navegador, com os arquivos apagados automaticamente depois.**
|
**Proxy de download efêmero: a sua VPS baixa o arquivo por uma rota melhor e entrega para o seu navegador, com os arquivos apagados automaticamente depois.**
|
||||||
|
|
||||||
|
[](https://github.com/evandrodevbr/Downloader/actions/workflows/ci.yml)
|
||||||

|

|
||||||

|

|
||||||

|

|
||||||
@@ -49,8 +50,8 @@ navegador
|
|||||||
|
|
||||||
## Requisitos
|
## Requisitos
|
||||||
|
|
||||||
- Node.js 20.19 ou superior (exigência do Vite 7 e do undici 7; verificado no Node 24.20.0)
|
- Node.js 20.19 ou superior para rodar e fazer o build (exigência do Vite 7 e do undici 7). Para rodar os testes (vitest 5) use Node 22.12 ou superior.
|
||||||
- pnpm 9 ou superior (verificado no pnpm 12.4.1; o lockfile é o formato 9.0)
|
- pnpm 9 ou superior (verificado no pnpm 12.8.1 com Node 26.7.0; o lockfile é o formato 9.0)
|
||||||
- Portas livres: backend (padrão 3000) e Vite (5173) em desenvolvimento
|
- Portas livres: backend (padrão 3000) e Vite (5173) em desenvolvimento
|
||||||
|
|
||||||
Observação sobre pnpm: a seção `overrides` do `pnpm-workspace.yaml` (fastify e undici com versão mínima de segurança) só é aplicada pelo pnpm 10 ou superior. Com pnpm 9 ela é ignorada.
|
Observação sobre pnpm: a seção `overrides` do `pnpm-workspace.yaml` (fastify e undici com versão mínima de segurança) só é aplicada pelo pnpm 10 ou superior. Com pnpm 9 ela é ignorada.
|
||||||
@@ -90,7 +91,7 @@ PORT=3100 VITE_API_PROXY=http://localhost:3100 pnpm dev
|
|||||||
| GET | `/api/download/:taskId` | Entrega o arquivo concluído da task. |
|
| GET | `/api/download/:taskId` | Entrega o arquivo concluído da task. |
|
||||||
| GET | `/stream` | Descontinuado: responde 410. |
|
| GET | `/stream` | Descontinuado: responde 410. |
|
||||||
|
|
||||||
A sessão é identificada pelo header `x-session-id` (a interface guarda o id em `localStorage`). Erros observados: 400 para URL inválida (`{"error":"Invalid URL"}`) ou download não pronto, 403 para task de outra sessão e 404 para task inexistente. Se a origem falhar (por exemplo, 404 no host de origem), a task fica com `status: "error"` e a mensagem em `error`.
|
A sessão é identificada pelo header `x-session-id` (a interface guarda o id em `localStorage`). Erros observados: 400 para URL inválida (`{"error":"Invalid URL"}`), com protocolo que não seja http/https, apontando para endereço local ou privado, ou para download não pronto; 403 para task de outra sessão e 404 para task inexistente. Se a origem falhar (por exemplo, 404 no host de origem), a task fica com `status: "error"` e a mensagem em `error`. O servidor segue até 5 redirects; um nome de domínio que resolva para IP privado também faz a task terminar em erro.
|
||||||
|
|
||||||
## Produção
|
## Produção
|
||||||
|
|
||||||
@@ -101,50 +102,56 @@ PORT=3000 pnpm start # node server/dist/index.js: API + build do front na mesma
|
|||||||
|
|
||||||
O `nixpacks.toml` descreve esse fluxo: build em `pnpm install --frozen-lockfile && pnpm build` e start em `pnpm start`.
|
O `nixpacks.toml` descreve esse fluxo: build em `pnpm install --frozen-lockfile && pnpm build` e start em `pnpm start`.
|
||||||
|
|
||||||
Variáveis de ambiente: `PORT` (padrão 3000) e `STORAGE_ROOT` (padrão `server/storage`) no backend; `VITE_API_URL` (host da API no frontend) e `VITE_API_PROXY` (alvo do proxy em dev).
|
## Configuração
|
||||||
|
|
||||||
|
| Variável | Onde | Padrão | O que faz |
|
||||||
|
|---|---|---|---|
|
||||||
|
| `PORT` | backend | `3000` | Porta do Fastify. |
|
||||||
|
| `STORAGE_ROOT` | backend | `server/storage` | Diretório onde ficam os arquivos das sessões. |
|
||||||
|
| `ALLOW_PRIVATE_NETWORK` | backend | desligado | Com `true`, permite baixar de `localhost` e de endereços de rede privada. Por padrão o servidor recusa esses destinos (proteção contra SSRF). |
|
||||||
|
| `VITE_API_URL` | frontend | mesma origem | Host da API, se for diferente do que serve o front. |
|
||||||
|
| `VITE_API_PROXY` | frontend (dev) | `http://localhost:3000` | Alvo do proxy de `/api` no Vite. |
|
||||||
|
|
||||||
## Estrutura do projeto
|
## Estrutura do projeto
|
||||||
|
|
||||||
```
|
```
|
||||||
server/ backend Fastify
|
server/ backend Fastify
|
||||||
├── src/index.ts rotas (/health, /api/*), CORS e static do front
|
├── src/index.ts rotas (/health, /api/*), CORS e static do front
|
||||||
└── src/lib/
|
├── src/lib/
|
||||||
├── DownloadManager.ts download da origem com undici e gravação na sessão
|
│ ├── DownloadManager.ts download da origem com undici e gravação na sessão
|
||||||
└── SessionManager.ts sessões, expiração (1 h) e limpeza dos arquivos
|
│ ├── SessionManager.ts sessões, expiração (1 h) e limpeza dos arquivos
|
||||||
|
│ └── netGuard.ts validação de URL e bloqueio de destinos privados (SSRF)
|
||||||
|
└── test/ testes (vitest)
|
||||||
web/ frontend React + Vite
|
web/ frontend React + Vite
|
||||||
├── src/context/ SessionContext (sessão e polling das tasks)
|
├── src/context/ SessionContext (sessão e polling das tasks)
|
||||||
├── src/components/ ui/ (Input, Button, Card, Alert...) e feature/ (form, item, timer)
|
├── src/components/ ui/ (Input, Button, Card, Alert...) e feature/ (form, item, timer)
|
||||||
└── vite.config.ts proxy de /api em desenvolvimento
|
└── vite.config.ts proxy de /api em desenvolvimento
|
||||||
.agent/ scaffolding de agentes de IA (não faz parte do runtime)
|
.agent/ scaffolding de agentes de IA (não faz parte do runtime)
|
||||||
docs/PLAN.md vazio (placeholder nunca preenchido)
|
.github/workflows/ CI (typecheck, lint, testes e build)
|
||||||
nixpacks.toml comandos de build e start do deploy
|
nixpacks.toml comandos de build e start do deploy
|
||||||
pnpm-workspace.yaml workspaces, allowBuilds e overrides
|
pnpm-workspace.yaml workspaces, allowBuilds e overrides
|
||||||
```
|
```
|
||||||
|
|
||||||
## Verificação
|
## Testes e desenvolvimento
|
||||||
|
|
||||||
Não há testes automatizados neste repositório. O que existe de fato:
|
```bash
|
||||||
|
pnpm typecheck # tsc nos dois pacotes
|
||||||
|
pnpm lint # eslint no web
|
||||||
|
pnpm test # vitest no server e no web
|
||||||
|
pnpm build
|
||||||
|
```
|
||||||
|
|
||||||
- `pnpm build` roda o `tsc` do server e `tsc -b && vite build` do web, e é o gate atual;
|
Os testes do servidor cobrem a validação de URL e o bloqueio de IPs privados, o tratamento de redirects, a expiração de sessões (com remoção das tasks e dos arquivos) e a validação do id de sessão. Os do web cobrem os estados do componente `DownloadItem`. O mesmo conjunto roda no GitHub Actions (`.github/workflows/ci.yml`).
|
||||||
- `pnpm --filter web lint` roda o eslint (passa com 1 warning de `exhaustive-deps` em `SessionContext.tsx`);
|
|
||||||
- verificação manual executada em 14/09/2026 (Linux, Node 24.20.0, pnpm 12.4.1): `pnpm install` e `pnpm build` com exit 0; 13 checagens de API passando (`/health`, `/`, `/api/session`, `/api/queue` com URL inválida e válida, `/api/tasks`, `/api/download/:id`, 400/403/404 e `/stream` respondendo 410); download de 10 MB conferido por sha256 idêntico ao da origem; interface verificada em Chrome headless (sessão inicializada, task concluída e "Save to Disk" baixando o arquivo com o mesmo sha256).
|
|
||||||
|
|
||||||
Adicionar testes automatizados é o próximo passo natural do projeto.
|
|
||||||
|
|
||||||
## Estado atual e limitações
|
## Estado atual e limitações
|
||||||
|
|
||||||
- Sessões e tasks ficam em memória: reiniciar o servidor perde a lista de tasks (os arquivos em disco são removidos pelo coletor depois de 1 hora).
|
- Sessões e tasks ficam em memória: reiniciar o servidor perde a lista de tasks (os arquivos em disco são removidos pelo coletor depois de 1 hora).
|
||||||
- Sem autenticação: qualquer um que alcance o servidor pode enfileirar downloads. Coloque atrás de VPN, autenticação reversa ou firewall.
|
- Sem autenticação: qualquer um que alcance o servidor pode enfileirar downloads (de destinos públicos). Coloque atrás de VPN, autenticação reversa ou firewall.
|
||||||
- Não há retomada de download nem uso de `Range` no fluxo atual (o parâmetro `offset` do antigo `/stream` não existe mais).
|
- Não há retomada de download nem uso de `Range` no fluxo atual (o parâmetro `offset` do antigo `/stream` não existe mais).
|
||||||
- Não há limite de tamanho, banda ou cota: um link muito grande ocupa o disco do servidor até a sessão expirar.
|
- Não há limite de tamanho, banda ou cota: um link muito grande ocupa o disco do servidor até a sessão expirar.
|
||||||
- URLs que não sejam http/https são aceitas na fila e falham depois com `status: "error"`.
|
- "Save to Disk" carrega o arquivo inteiro na memória do navegador (`blob()`) antes de salvar, o que pesa em arquivos muito grandes.
|
||||||
- Sem CI configurada e sem arquivo de licença.
|
|
||||||
- O diretório `.agent/` é scaffolding de ferramentas de IA e não é usado pela aplicação.
|
- O diretório `.agent/` é scaffolding de ferramentas de IA e não é usado pela aplicação.
|
||||||
|
|
||||||
## Documentação
|
|
||||||
|
|
||||||
Não há documentação interna além deste README: `docs/PLAN.md` está vazio e `web/README.md` é o texto padrão do template do Vite.
|
|
||||||
|
|
||||||
## Licença
|
## Licença
|
||||||
|
|
||||||
Sem licença definida no repositório: não existe arquivo `LICENSE` e o `package.json` está marcado como `private`. Defina uma licença antes de reutilizar ou publicar o código.
|
Sem licença definida no repositório: não existe arquivo `LICENSE` e o `package.json` está marcado como `private`. Defina uma licença antes de reutilizar ou publicar o código.
|
||||||
Reference in new issue
Block a user