fix(seguranca): move algoritmo de geracao de chave do JS pro backend
O algoritmo (CHAVE_INTERNA + funcoes gerarReativacao/gerarInstalacao) ficava 100% legivel no codigo-fonte da pagina — qualquer pessoa com acesso ao painel conseguia abrir o DevTools e extrair a logica pra gerar chaves de licenca fora do sistema. Move tudo pra app/gerador_chave.py (roda so no servidor) e expoe via POST /gerador-chave/gerar (autenticado, protegido por CSRF). A pagina agora so manda os dados do formulario e mostra o resultado que volta do backend. Algoritmo verificado byte-a-byte contra os 3 exemplos reais conhecidos (cliente 000001, ALUGUEL). Bonus: o byte inicial agora usa secrets.randbelow (CSPRNG) em vez de Math.random() do JS. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
a3a84abd37
commit
5c577a644a
@@ -1,19 +1,60 @@
|
||||
"""
|
||||
Calculadora de chave de reativação, para uso manual (reenvio/correção
|
||||
pontual). 100% client-side (mesmo algoritmo gerarReativacao já usado no
|
||||
workflow n8n e em Gerar chave WEB/index.html) — esta rota só serve a
|
||||
página; NUNCA grava em Clientes_Chaves.
|
||||
Calculadora de chave de reativação/instalação, para uso manual (reenvio/
|
||||
correção pontual). O algoritmo em si (app/gerador_chave.py) roda só aqui
|
||||
no backend — a página não recebe mais nada além do resultado já pronto,
|
||||
pra ninguém conseguir extrair o algoritmo pelo código-fonte da página.
|
||||
NUNCA grava em Clientes_Chaves.
|
||||
"""
|
||||
from fastapi import APIRouter, Depends, Request
|
||||
from fastapi.responses import HTMLResponse
|
||||
import re
|
||||
|
||||
from fastapi import APIRouter, Depends, Form, Request
|
||||
from fastapi.responses import HTMLResponse, JSONResponse
|
||||
from fastapi.templating import Jinja2Templates
|
||||
|
||||
from ..auth import exigir_login
|
||||
from ..csrf import exigir_csrf, token_do_contexto
|
||||
from ..gerador_chave import gerar_instalacao, gerar_reativacao
|
||||
|
||||
router = APIRouter()
|
||||
templates = Jinja2Templates(directory="app/templates")
|
||||
|
||||
_RE_CODIGO = re.compile(r"^[0-9]{1,6}$")
|
||||
_RE_REFERENCIA = re.compile(r"^\d{4}-\d{2}$")
|
||||
|
||||
|
||||
@router.get("/gerador-chave", response_class=HTMLResponse)
|
||||
def pagina(request: Request, usuario: str = Depends(exigir_login)):
|
||||
return templates.TemplateResponse(request, "gerador_chave.html", {})
|
||||
return templates.TemplateResponse(request, "gerador_chave.html", {"csrf_token": token_do_contexto(request)})
|
||||
|
||||
|
||||
@router.post("/gerador-chave/gerar", dependencies=[Depends(exigir_csrf)])
|
||||
def gerar(
|
||||
tipo: str = Form(...),
|
||||
codigo: str = Form(...),
|
||||
referencia: str = Form(""),
|
||||
modalidade: str = Form(""),
|
||||
usuario: str = Depends(exigir_login),
|
||||
):
|
||||
codigo = codigo.strip()
|
||||
if not _RE_CODIGO.match(codigo):
|
||||
return JSONResponse({"erro": "Código do cliente deve ter até 6 dígitos numéricos."}, status_code=400)
|
||||
codigo_formatado = codigo.zfill(6)
|
||||
|
||||
if tipo == "reativacao":
|
||||
if not _RE_REFERENCIA.match(referencia):
|
||||
return JSONResponse({"erro": "Selecione o mês/ano de referência."}, status_code=400)
|
||||
ano_str, mes_str = referencia.split("-")
|
||||
mes, ano = int(mes_str), int(ano_str)
|
||||
if not (1 <= mes <= 12):
|
||||
return JSONResponse({"erro": "Mês fora do intervalo 1-12."}, status_code=400)
|
||||
if not (2000 <= ano <= 2100):
|
||||
return JSONResponse({"erro": "Ano inválido (use entre 2000 e 2100)."}, status_code=400)
|
||||
chave = gerar_reativacao(codigo_formatado, mes, ano)
|
||||
elif tipo == "instalacao":
|
||||
if modalidade not in ("ALUGUEL", "COMPRA"):
|
||||
return JSONResponse({"erro": "Modalidade inválida."}, status_code=400)
|
||||
chave = gerar_instalacao(codigo_formatado, modalidade)
|
||||
else:
|
||||
return JSONResponse({"erro": "Tipo de chave inválido."}, status_code=400)
|
||||
|
||||
return JSONResponse({"chave": chave})
|
||||
|
||||
Reference in New Issue
Block a user