Migração para PostgreSQL multi-driver + correções de segurança
- Camada de banco unificada (src/database.js): drivers Postgres/Firebird, tradutor de SQL, suporte a schema e pool de conexões - Conexões: novo_local (Postgres externo) e firebird_local (legado) - Tela de rotas da API redesenhada (auth, params, exemplos de body) - Correções de segurança (críticos/altos/médios/baixos): XSS no chat, escalonamento de privilégio, mídia autenticada, SQL restrito a gerente, JWT sem fallback + issuer, IDOR em conversas, CORS por allowlist, rate-limit no login, limites de corpo por rota - Deploy alinhado: install.sh grava .env com PG_*, migracoes.js driver-aware Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,81 @@
|
||||
# =============================================================
|
||||
# Chatc2 - Script de deploy Windows -> Linux
|
||||
# Uso: .\deploy.ps1 -IP 192.168.1.100
|
||||
# =============================================================
|
||||
|
||||
param(
|
||||
[Parameter(Mandatory=$true)]
|
||||
[string]$IP,
|
||||
[string]$User = "root",
|
||||
[string]$ProjectPath = (Split-Path -Parent $PSScriptRoot),
|
||||
[string]$RemotePath = "/home/chatc2/chatc2"
|
||||
)
|
||||
|
||||
Write-Host "╔════════════════════════════════════════════╗" -ForegroundColor Cyan
|
||||
Write-Host "║ Chatc2 - Deploy Windows -> Linux ║" -ForegroundColor Cyan
|
||||
Write-Host "╚════════════════════════════════════════════╝" -ForegroundColor Cyan
|
||||
Write-Host ""
|
||||
|
||||
# 1. Testar conexao SSH
|
||||
Write-Host "[1/5] Testando conexao SSH..." -ForegroundColor Yellow
|
||||
try {
|
||||
$result = ssh -o StrictHostKeyChecking=no -o ConnectTimeout=5 "$User@$IP" "echo OK" 2>&1
|
||||
if ($LASTEXITCODE -ne 0) { throw "SSH falhou" }
|
||||
Write-Host " ✓ Conectado a $IP" -ForegroundColor Green
|
||||
} catch {
|
||||
Write-Host " ✘ Erro: $_" -ForegroundColor Red
|
||||
exit 1
|
||||
}
|
||||
|
||||
# 2. Criar diretorios no servidor
|
||||
Write-Host "[2/5] Criando diretorios no servidor..." -ForegroundColor Yellow
|
||||
ssh "$User@$IP" "mkdir -p $RemotePath/{db,logs,tmp,uploads/audio,public,whisper/models} 2>/dev/null; chown -R chatc2:chatc2 $RemotePath 2>/dev/null; echo 'OK'" 2>$null
|
||||
Write-Host " ✓ Diretorios criados" -ForegroundColor Green
|
||||
|
||||
# 3. Enviar arquivos via SCP
|
||||
Write-Host "[3/5] Enviando arquivos do projeto..." -ForegroundColor Yellow
|
||||
Write-Host " (isso pode levar alguns minutos...)" -ForegroundColor Gray
|
||||
|
||||
$exclude = @('node_modules', '.git', 'db/*.FDB', 'logs', 'tmp', 'Nova pasta', 'chatc2-py', 'ponto_1', 'whisper')
|
||||
$excludeArgs = ($exclude | ForEach-Object { "--exclude=$_" }) -join ' '
|
||||
|
||||
$scpCommand = "scp -r $excludeArgs `"$ProjectPath\*`" $User@`"$IP`":$RemotePath/"
|
||||
Write-Host " Executando: scp -r (arquivos do projeto) para $IP..." -ForegroundColor Gray
|
||||
|
||||
try {
|
||||
$result = scp -r `
|
||||
--exclude='node_modules' `
|
||||
--exclude='.git' `
|
||||
--exclude='db/*.FDB' `
|
||||
--exclude='logs' `
|
||||
--exclude='tmp' `
|
||||
--exclude='Nova pasta' `
|
||||
--exclude='chatc2-py' `
|
||||
--exclude='ponto_1' `
|
||||
--exclude='whisper' `
|
||||
"$ProjectPath\*" "$User@$IP`:$RemotePath/" 2>&1
|
||||
|
||||
if ($LASTEXITCODE -ne 0) { throw "SCP falhou" }
|
||||
Write-Host " ✓ Arquivos enviados" -ForegroundColor Green
|
||||
} catch {
|
||||
Write-Host " ✘ Erro no SCP: $_" -ForegroundColor Red
|
||||
Write-Host " Tente enviar manualmente via FileZilla ou WinSCP" -ForegroundColor Yellow
|
||||
}
|
||||
|
||||
# 4. Ajustar permissoes
|
||||
Write-Host "[4/5] Ajustando permissoes..." -ForegroundColor Yellow
|
||||
ssh "$User@$IP" "chown -R chatc2:chatc2 $RemotePath 2>/dev/null; chmod -R 755 $RemotePath 2>/dev/null; echo OK" 2>$null
|
||||
Write-Host " ✓ Permissoes ajustadas" -ForegroundColor Green
|
||||
|
||||
# 5. Instalar dependencias e rodar script de instalacao
|
||||
Write-Host "[5/5] Instalando dependencias e configurando servico..." -ForegroundColor Yellow
|
||||
ssh "$User@$IP" "cd $RemotePath/deploy-linux && sudo bash install.sh --continue" 2>&1 | Write-Host
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "╔════════════════════════════════════════════╗" -ForegroundColor Cyan
|
||||
Write-Host "║ Deploy Concluido! ║" -ForegroundColor Cyan
|
||||
Write-Host "╚════════════════════════════════════════════╝" -ForegroundColor Cyan
|
||||
Write-Host ""
|
||||
Write-Host " Acesse: http://$IP" -ForegroundColor Green
|
||||
Write-Host " SSH: ssh $User@$IP" -ForegroundColor Gray
|
||||
Write-Host " Logs: ssh $User@$IP 'pm2 logs chatc2'" -ForegroundColor Gray
|
||||
@@ -0,0 +1,482 @@
|
||||
#!/bin/bash
|
||||
# =============================================================
|
||||
# Chatc2 - Instalacao automatizada para Ubuntu 22.04 LTS
|
||||
# Uso: curl -sL https://bit.ly/chatc2-install | bash
|
||||
# ou: wget -qO- https://bit.ly/chatc2-install | bash
|
||||
# =============================================================
|
||||
set -euo pipefail
|
||||
|
||||
# ████████████████████████████████████████████████████
|
||||
# VARIAVEIS
|
||||
# ████████████████████████████████████████████████████
|
||||
CHATC2_USER="chatc2"
|
||||
CHATC2_DIR="/home/$CHATC2_USER/chatc2"
|
||||
CHATC2_REPO="https://github.com/seu-usuario/chatc2/archive/refs/heads/main.tar.gz"
|
||||
NODE_VERSION="22"
|
||||
FIREBIRD_VERSION="3.0"
|
||||
WHISPER_VERSION="1.5.4"
|
||||
WHISPER_MODEL="ggml-tiny.bin" # 75MB - troque para ggml-base.bin (142MB) para mais precisao
|
||||
SERVER_DOMAIN="${SERVER_DOMAIN:-}" # Opcional: seu-dominio.com.br
|
||||
JWT_SECRET=""
|
||||
NGROK_URL=""
|
||||
|
||||
# PostgreSQL EXTERNO (banco principal "novo_local").
|
||||
# Informe via variaveis de ambiente antes de rodar, ou edite o .env depois.
|
||||
PG_HOST="${PG_HOST:-}"
|
||||
PG_PORT="${PG_PORT:-5432}"
|
||||
PG_USER="${PG_USER:-postgres}"
|
||||
PG_PASSWORD="${PG_PASSWORD:-}"
|
||||
PG_DATABASE="${PG_DATABASE:-postgres}"
|
||||
PG_SCHEMA="${PG_SCHEMA:-public}"
|
||||
|
||||
# Cores
|
||||
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; CYAN='\033[0;36m'; NC='\033[0m'
|
||||
log() { echo -e "${GREEN}[✓]${NC} $1"; }
|
||||
warn() { echo -e "${YELLOW}[!]${NC} $1"; }
|
||||
err() { echo -e "${RED}[✘]${NC} $1"; exit 1; }
|
||||
info() { echo -e "${CYAN}[i]${NC} $1"; }
|
||||
|
||||
# ████████████████████████████████████████████████████
|
||||
# VERIFICACAO INICIAL
|
||||
# ████████████████████████████████████████████████████
|
||||
if [ "$EUID" -ne 0 ]; then
|
||||
err "Execute como root: sudo bash install.sh"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "╔══════════════════════════════════════════════════╗"
|
||||
echo "║ Chatc2 - Instalacao Automatica ║"
|
||||
echo "║ Ubuntu 22.04 LTS ║"
|
||||
echo "╚══════════════════════════════════════════════════╝"
|
||||
echo ""
|
||||
|
||||
# ████████████████████████████████████████████████████
|
||||
# PASSO 1: SYSTEMA BASE
|
||||
# ████████████████████████████████████████████████████
|
||||
info "Passo 1/12: Atualizando sistema..."
|
||||
apt-get update -y
|
||||
apt-get upgrade -y
|
||||
apt-get install -y curl wget git unzip tar gzip \
|
||||
build-essential python3 python3-pip \
|
||||
ffmpeg nginx ufw certbot python3-certbot-nginx \
|
||||
firebird3.0-server firebird3.0-utils
|
||||
|
||||
# ████████████████████████████████████████████████████
|
||||
# PASSO 2: NODE.JS
|
||||
# ████████████████████████████████████████████████████
|
||||
info "Passo 2/12: Instalando Node.js $NODE_VERSION..."
|
||||
curl -fsSL "https://deb.nodesource.com/setup_${NODE_VERSION}.x" | bash -
|
||||
apt-get install -y nodejs
|
||||
npm install -g pm2
|
||||
log "Node.js $(node -v) instalado"
|
||||
|
||||
# ████████████████████████████████████████████████████
|
||||
# PASSO 3: FIREBIRD
|
||||
# ████████████████████████████████████████████████████
|
||||
info "Passo 3/12: Configurando Firebird..."
|
||||
systemctl enable firebird3.0
|
||||
systemctl start firebird3.0 2>/dev/null || true
|
||||
sleep 2
|
||||
sed -i 's/^isc_password =.*/isc_password = masterkey/' /etc/firebird/3.0/firebird.conf 2>/dev/null || true
|
||||
sed -i 's/^RemoteBindAddress = localhost/RemoteBindAddress = 0.0.0.0/' /etc/firebird/3.0/firebird.conf 2>/dev/null || true
|
||||
|
||||
# ── Correção de compatibilidade node-firebird + Firebird 3.0 ──
|
||||
# Usa Legacy_Auth (mais compatível) em vez de Srp256 (não suportado pelo node-firebird)
|
||||
sed -i 's/^#AuthServer = Srp$/AuthServer = Legacy_Auth/' /etc/firebird/3.0/firebird.conf 2>/dev/null || true
|
||||
sed -i 's/^#AuthClient = Srp, Srp256, Legacy_Auth #Non Windows clients$/AuthClient = Legacy_Auth/' /etc/firebird/3.0/firebird.conf 2>/dev/null || true
|
||||
# WireCrypt = Enabled (compatível com Legacy_Auth — não exige criptografia)
|
||||
sed -i 's/^#WireCrypt = Enabled (for client) \/ Required (for server)$/WireCrypt = Enabled/' /etc/firebird/3.0/firebird.conf 2>/dev/null || true
|
||||
|
||||
systemctl restart firebird3.0
|
||||
log "Firebird 3.0 configurado (senha: masterkey, auth: Legacy_Auth, WireCrypt: Enabled)"
|
||||
# Garante que o Firebird esta rodando antes de continuar
|
||||
systemctl restart firebird3.0 2>/dev/null || systemctl start firebird3.0 2>/dev/null || true
|
||||
sleep 1
|
||||
|
||||
# ████████████████████████████████████████████████████
|
||||
# PASSO 4: USUARIO E DIRETORIOS
|
||||
# ████████████████████████████████████████████████████
|
||||
info "Passo 4/12: Criando usuario e diretorios..."
|
||||
id -u "$CHATC2_USER" &>/dev/null || useradd -m -s /bin/bash "$CHATC2_USER"
|
||||
mkdir -p "$CHATC2_DIR"/{db,logs,tmp,uploads/audio,public,whisper/models,scripts,app/config,app/controllers,app/routes,app/middlewares}
|
||||
chown -R "$CHATC2_USER:$CHATC2_USER" "$CHATC2_DIR"
|
||||
|
||||
# ████████████████████████████████████████████████████
|
||||
# PASSO 5: WHISPER.CPP (Transcricao de Audio)
|
||||
# ████████████████████████████████████████████████████
|
||||
info "Passo 5/12: Instalando Whisper.cpp (compilacao nativa Linux)..."
|
||||
mkdir -p "$CHATC2_DIR/whisper/models"
|
||||
|
||||
# Compila whisper.cpp do source (Linux) - binario nativo
|
||||
if [ ! -f "$CHATC2_DIR/whisper/main" ]; then
|
||||
info "Compilando whisper.cpp v${WHISPER_VERSION}..."
|
||||
cd /tmp
|
||||
rm -rf whisper-build 2>/dev/null || true
|
||||
git clone --depth 1 --branch v${WHISPER_VERSION} https://github.com/ggerganov/whisper.cpp.git whisper-build 2>&1 | tail -1
|
||||
cd whisper-build
|
||||
make -j$(nproc) main 2>&1 | tail -3
|
||||
cp -f main "$CHATC2_DIR/whisper/main"
|
||||
chmod +x "$CHATC2_DIR/whisper/main"
|
||||
cd /tmp && rm -rf whisper-build
|
||||
log "Whisper.cpp compilado e instalado em $CHATC2_DIR/whisper/main"
|
||||
else
|
||||
log "Whisper.cpp binario Linux ja existe, pulando compilacao"
|
||||
fi
|
||||
|
||||
info "Baixando modelo $WHISPER_MODEL (pode levar alguns minutos)..."
|
||||
if [ ! -f "$CHATC2_DIR/whisper/models/$WHISPER_MODEL" ]; then
|
||||
su - "$CHATC2_USER" -c "cd $CHATC2_DIR/whisper && \
|
||||
curl -sL -o models/$WHISPER_MODEL \
|
||||
https://huggingface.co/ggerganov/whisper.cpp/resolve/main/$WHISPER_MODEL"
|
||||
log "Modelo $WHISPER_MODEL baixado"
|
||||
else
|
||||
log "Modelo $WHISPER_MODEL ja existe"
|
||||
fi
|
||||
log "Whisper.cpp instalado em $CHATC2_DIR/whisper/"
|
||||
|
||||
# ████████████████████████████████████████████████████
|
||||
# PASSO 6: ARQUIVOS DO PROJETO
|
||||
# ████████████████████████████████████████████████████
|
||||
info "Passo 6/12: Preparando para receber arquivos..."
|
||||
info "Transfira os arquivos do projeto para $CHATC2_DIR via SCP/SFTP"
|
||||
info "Depois execute manualmente: cd $CHATC2_DIR && npm install"
|
||||
echo ""
|
||||
echo " ╔══════════════════════════════════════════════════════════╗"
|
||||
echo " ║ Comando para enviar os arquivos (do seu computador): ║"
|
||||
echo " ║ ║"
|
||||
echo " ║ cd C:/projects/Chatc2 ║"
|
||||
echo " ║ scp -r src/ scripts/ package.json package-lock.json ║"
|
||||
echo " ║ .env.example deploy-linux/ ║"
|
||||
echo " ║ root@<IP>:$CHATC2_DIR/ ║"
|
||||
echo " ║ ║"
|
||||
echo " ║ E depois rode novamente este script: ║"
|
||||
echo " ║ bash $0 --continue ║"
|
||||
echo " ╚══════════════════════════════════════════════════════════╝"
|
||||
echo ""
|
||||
|
||||
# Se o script foi chamado com --continue, pula a espera
|
||||
if [ "${1:-}" != "--continue" ]; then
|
||||
info "Aguardando transferencia dos arquivos..."
|
||||
info "Apos transferir, execute: bash $0 --continue"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# ████████████████████████████████████████████████████
|
||||
# PASSO 7: NPM INSTALL
|
||||
# ████████████████████████████████████████████████████
|
||||
if [ ! -f "$CHATC2_DIR/package.json" ]; then
|
||||
err "Arquivos do projeto nao encontrados em $CHATC2_DIR. Transfira via SCP primeiro."
|
||||
fi
|
||||
|
||||
info "Passo 7/12: Instalando dependencias Node..."
|
||||
chown -R "$CHATC2_USER:$CHATC2_USER" "$CHATC2_DIR"
|
||||
|
||||
# Remove node_modules anterior (se existir) para garantir instalação limpa
|
||||
if [ -d "$CHATC2_DIR/node_modules" ]; then
|
||||
info "Removendo node_modules anterior para instalacao limpa..."
|
||||
rm -rf "$CHATC2_DIR/node_modules"
|
||||
fi
|
||||
|
||||
# Executa npm install com saida completa (sem suprimir erros)
|
||||
if ! su - "$CHATC2_USER" -c "cd $CHATC2_DIR && npm install"; then
|
||||
err "Falha ao instalar dependencias Node. Verifique a conexao e o package.json"
|
||||
fi
|
||||
|
||||
# Verifica se modulos criticos foram instalados
|
||||
if [ ! -d "$CHATC2_DIR/node_modules/express" ]; then
|
||||
err "Modulo 'express' nao encontrado apos npm install. Verifique o package.json"
|
||||
fi
|
||||
if [ ! -d "$CHATC2_DIR/node_modules/dotenv" ]; then
|
||||
info "Instalando dotenv (carregamento de .env)..."
|
||||
su - "$CHATC2_USER" -c "cd $CHATC2_DIR && npm install dotenv" || warn "Falha ao instalar dotenv"
|
||||
fi
|
||||
|
||||
# Garante que o server.js carrega dotenv (variaveis do .env)
|
||||
SERVER_JS="$CHATC2_DIR/src/server.js"
|
||||
if [ -f "$SERVER_JS" ] && ! grep -q "require('dotenv').config()" "$SERVER_JS" 2>/dev/null; then
|
||||
sed -i "1s/^/require('dotenv').config();\n/" "$SERVER_JS"
|
||||
log "dotenv configurado no server.js"
|
||||
fi
|
||||
log "Dependencias instaladas e verificadas"
|
||||
|
||||
# ── Patch node-firebird: compatibilidade com Firebird 3.0 + sintaxe Node 22 ──
|
||||
info "Passo 7b/12: Aplicando patches node-firebird..."
|
||||
if [ -f "$(dirname "$0")/patch_node_firebird.py" ]; then
|
||||
python3 "$(dirname "$0")/patch_node_firebird.py" "$CHATC2_DIR" 2>&1
|
||||
log "Patches node-firebird aplicados"
|
||||
else
|
||||
warn "patch_node_firebird.py nao encontrado"
|
||||
fi
|
||||
|
||||
# ── wireCrypt (Firebird 3.0) ──
|
||||
# A partir da v2.0 a camada de banco foi unificada em src/database.js e o
|
||||
# wireCrypt já vem embutido nos defaults do driver Firebird — nada a patchar.
|
||||
info "Passo 7c/12: wireCrypt (Firebird) já embutido em src/database.js"
|
||||
log "Nenhum patch de wireCrypt necessário"
|
||||
|
||||
# ████████████████████████████████████████████████████
|
||||
# PASSO 8: ARQUIVO .ENV
|
||||
# ████████████████████████████████████████████████████
|
||||
info "Passo 8/12: Configurando .env..."
|
||||
JWT_SECRET="CHATc2_$(date +%s)_$(openssl rand -hex 16)"
|
||||
|
||||
# Detecta IPs da maquina
|
||||
LOCAL_IP=$(ip -4 addr show scope global | grep -oP 'inet \K[\d.]+' | head -1)
|
||||
[ -z "$LOCAL_IP" ] && LOCAL_IP="127.0.0.1"
|
||||
PUBLIC_IP=$(curl -s ifconfig.me 2>/dev/null || echo "")
|
||||
|
||||
# Monta URLs
|
||||
LOCAL_URL="http://${LOCAL_IP}:3000"
|
||||
if [ -n "$SERVER_DOMAIN" ]; then
|
||||
EXTERNAL_URL="https://${SERVER_DOMAIN}"
|
||||
elif [ -n "$PUBLIC_IP" ]; then
|
||||
EXTERNAL_URL="http://${PUBLIC_IP}"
|
||||
else
|
||||
EXTERNAL_URL="http://${LOCAL_IP}:3000"
|
||||
fi
|
||||
|
||||
# Sempre gera um .env limpo (remove paths Windows, comentarios invalidos, etc.)
|
||||
if [ -f "$CHATC2_DIR/.env" ]; then
|
||||
info ".env existente encontrado — fazendo backup e recriando..."
|
||||
cp "$CHATC2_DIR/.env" "$CHATC2_DIR/.env.bak.$(date +%Y%m%d%H%M%S)" 2>/dev/null || true
|
||||
fi
|
||||
|
||||
cat > "$CHATC2_DIR/.env" << EOF
|
||||
# ============================================================
|
||||
# Configuracao do Chatc2
|
||||
# ============================================================
|
||||
|
||||
# Driver padrao do banco principal
|
||||
DB_DRIVER=postgres
|
||||
|
||||
# ------------------------------------------------------------
|
||||
# PostgreSQL (EXTERNO) — banco principal "novo_local"
|
||||
# ------------------------------------------------------------
|
||||
PG_HOST=${PG_HOST}
|
||||
PG_PORT=${PG_PORT}
|
||||
PG_USER=${PG_USER}
|
||||
PG_PASSWORD=${PG_PASSWORD}
|
||||
PG_DATABASE=${PG_DATABASE}
|
||||
PG_SCHEMA=${PG_SCHEMA}
|
||||
|
||||
# ------------------------------------------------------------
|
||||
# Firebird (legado / alias "firebird_local")
|
||||
# ------------------------------------------------------------
|
||||
DB_HOST=localhost
|
||||
DB_PORT=3050
|
||||
DB_USER=SYSDBA
|
||||
DB_PASSWORD=masterkey
|
||||
DB_ENCODING=UTF-8
|
||||
# Caminho do .FDB (vazio = usa ../NOVO.FDB na raiz do projeto)
|
||||
DB_DATABASE=
|
||||
|
||||
# Servidor
|
||||
PORT=3000
|
||||
JWT_SECRET=$JWT_SECRET
|
||||
JWT_EXPIRES_IN=1h
|
||||
|
||||
# URLs de acesso
|
||||
LOCAL_URL=${LOCAL_URL}
|
||||
EXTERNAL_URL=${EXTERNAL_URL}
|
||||
|
||||
# ------------------------------------------------------------
|
||||
# Seguranca (opcionais)
|
||||
# ------------------------------------------------------------
|
||||
# Origens permitidas no CORS (vazio = usa LOCAL_URL + EXTERNAL_URL)
|
||||
# CORS_ORIGINS=${EXTERNAL_URL}
|
||||
# Token de verificacao do webhook Evolution (header apikey)
|
||||
# WEBHOOK_TOKEN=
|
||||
EOF
|
||||
chown "$CHATC2_USER:$CHATC2_USER" "$CHATC2_DIR/.env"
|
||||
log "Arquivo .env criado/atualizado com JWT_SECRET seguro"
|
||||
log " PG_HOST/DB = ${PG_HOST:-(vazio)} / ${PG_DATABASE} (schema: ${PG_SCHEMA})"
|
||||
log " LOCAL_URL = ${LOCAL_URL}"
|
||||
log " EXTERNAL_URL = ${EXTERNAL_URL}"
|
||||
if [ -z "$PG_HOST" ] || [ -z "$PG_PASSWORD" ]; then
|
||||
warn "PostgreSQL externo nao configurado: edite $CHATC2_DIR/.env (PG_HOST, PG_PASSWORD, PG_DATABASE, PG_SCHEMA) antes de iniciar."
|
||||
fi
|
||||
|
||||
# ████████████████████████████████████████████████████
|
||||
# PASSO 9: MIGRACOES DO BANCO
|
||||
# ████████████████████████████████████████████████████
|
||||
# ── Permissões dos arquivos .FDB ──
|
||||
info "Passo 8b/12: Ajustando permissoes dos arquivos .FDB..."
|
||||
# O Firebird roda como usuario 'firebird'. Os arquivos .FDB precisam
|
||||
# pertencer ao grupo firebird com permissao de leitura+escrita (660).
|
||||
if ls "$CHATC2_DIR/db/"*.FDB 2>/dev/null; then
|
||||
chown "$CHATC2_USER:firebird" "$CHATC2_DIR/db/"*.FDB 2>/dev/null || true
|
||||
chmod 660 "$CHATC2_DIR/db/"*.FDB 2>/dev/null || true
|
||||
# Garante que o diretório db/ também seja acessível
|
||||
chmod 750 "$CHATC2_DIR/db/" 2>/dev/null || true
|
||||
log "Permissoes ajustadas: $CHATC2_USER:firebird 660"
|
||||
else
|
||||
warn "Nenhum arquivo .FDB encontrado em $CHATC2_DIR/db/ — copie os bancos manualmente"
|
||||
warn "Apos copiar, execute: chown $CHATC2_USER:firebird $CHATC2_DIR/db/*.FDB && chmod 660 $CHATC2_DIR/db/*.FDB"
|
||||
fi
|
||||
|
||||
info "Passo 9/12: Migracoes (Firebird legado)..."
|
||||
# O schema do PostgreSQL e gerenciado no banco EXTERNO — nao migramos aqui.
|
||||
# Migracoes Firebird so rodam se houver um .FDB local (alias firebird_local).
|
||||
if ls "$CHATC2_DIR/db/"*.FDB "$CHATC2_DIR/"*.FDB >/dev/null 2>&1; then
|
||||
if [ -f "$CHATC2_DIR/scripts/migracoes.js" ]; then
|
||||
su - "$CHATC2_USER" -c "cd $CHATC2_DIR && node scripts/migracoes.js firebird_local 2>&1 | tail -10" || warn "Migracoes Firebird podem ter falhado"
|
||||
log "Migracoes Firebird executadas"
|
||||
fi
|
||||
else
|
||||
info "Sem .FDB local — pulando migracoes Firebird (schema do Postgres e externo)."
|
||||
fi
|
||||
|
||||
# ████████████████████████████████████████████████████
|
||||
# PASSO 9b: HABILITAR USUARIOS ADMIN PARA WEB
|
||||
# ████████████████████████████████████████████████████
|
||||
info "Passo 9b/12: Habilitando usuarios admin para acesso web..."
|
||||
# Habilita acesso web para admins (Postgres principal e Firebird se presente)
|
||||
cat > /tmp/chatc2-habilitar-web.js << 'SCRIPTJS'
|
||||
const db = require('DATABASE_PATH');
|
||||
|
||||
(async () => {
|
||||
const alias = process.argv[2];
|
||||
if (!alias) { console.log('Uso: node script <alias>'); process.exit(1); }
|
||||
try {
|
||||
// Habilita USU_ACESSO_WEB = 1 para usuarios ativos com perfil admin (USU_TIPO = A)
|
||||
const result = await db.query(alias,
|
||||
"SELECT USU_CODIGO_ID, USU_NOME, USU_LOGIN FROM USUARIOS WHERE USU_STATUS = 'A' AND USU_TIPO = 'A' AND COALESCE(USU_ACESSO_WEB, 0) = 0");
|
||||
for (const u of result) {
|
||||
await db.execute(alias, 'UPDATE USUARIOS SET USU_ACESSO_WEB = 1 WHERE USU_CODIGO_ID = ?', [u.USU_CODIGO_ID]);
|
||||
console.log(' ✅ ' + u.USU_NOME.trim() + ' (' + u.USU_LOGIN.trim() + ') — acesso web habilitado');
|
||||
}
|
||||
if (result.length === 0) console.log(' Nenhum usuario admin pendente.');
|
||||
process.exit(0);
|
||||
} catch(e) { console.error('Erro:', e.message); process.exit(1); }
|
||||
})();
|
||||
SCRIPTJS
|
||||
sed -i "s|DATABASE_PATH|$CHATC2_DIR/src/database|" /tmp/chatc2-habilitar-web.js
|
||||
|
||||
# Postgres externo (alias principal)
|
||||
su - "$CHATC2_USER" -c "cd $CHATC2_DIR && node /tmp/chatc2-habilitar-web.js novo_local" 2>&1 || true
|
||||
|
||||
# Firebird local (apenas se houver .FDB)
|
||||
if ls "$CHATC2_DIR/db/"*.FDB "$CHATC2_DIR/"*.FDB >/dev/null 2>&1; then
|
||||
su - "$CHATC2_USER" -c "cd $CHATC2_DIR && node /tmp/chatc2-habilitar-web.js firebird_local" 2>&1 || true
|
||||
fi
|
||||
|
||||
rm -f /tmp/chatc2-habilitar-web.js
|
||||
log "Usuarios admin verificados (Postgres + Firebird se presente)"
|
||||
|
||||
# ████████████████████████████████████████████████████
|
||||
# PASSO 10: NGINX
|
||||
# ████████████████████████████████████████████████████
|
||||
info "Passo 10/12: Configurando Nginx..."
|
||||
cat > /etc/nginx/sites-available/chatc2 << 'NGINX'
|
||||
server {
|
||||
listen 80;
|
||||
server_name _;
|
||||
client_max_body_size 100M;
|
||||
|
||||
location / {
|
||||
proxy_pass http://127.0.0.1:3000;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection 'upgrade';
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_cache_bypass $http_upgrade;
|
||||
proxy_read_timeout 86400s;
|
||||
proxy_send_timeout 86400s;
|
||||
}
|
||||
}
|
||||
NGINX
|
||||
|
||||
# Remove sites padrao que podem conflitar
|
||||
rm -f /etc/nginx/sites-enabled/default 2>/dev/null || true
|
||||
rm -f /etc/nginx/sites-enabled/example.com 2>/dev/null || true
|
||||
|
||||
# Habilita o site do chatc2
|
||||
if [ ! -L /etc/nginx/sites-enabled/chatc2 ]; then
|
||||
ln -sf /etc/nginx/sites-available/chatc2 /etc/nginx/sites-enabled/
|
||||
fi
|
||||
|
||||
# Testa configuracao antes de aplicar
|
||||
if nginx -t 2>&1; then
|
||||
systemctl enable nginx 2>/dev/null || true
|
||||
systemctl restart nginx 2>/dev/null || systemctl start nginx 2>/dev/null || true
|
||||
log "Nginx configurado e iniciado"
|
||||
else
|
||||
warn "Erro na configuracao do nginx. Verifique manualmente: nginx -t"
|
||||
fi
|
||||
|
||||
# SSL com Let's Encrypt (se dominio foi informado)
|
||||
if [ -n "${SERVER_DOMAIN:-}" ]; then
|
||||
info "Configurando SSL para $SERVER_DOMAIN..."
|
||||
certbot --nginx -d "$SERVER_DOMAIN" --non-interactive --agree-tos \
|
||||
--email "admin@${SERVER_DOMAIN}" || warn "SSL falhou (verifique DNS)"
|
||||
log "SSL configurado para $SERVER_DOMAIN"
|
||||
fi
|
||||
|
||||
# ████████████████████████████████████████████████████
|
||||
# PASSO 11: PM2 (INICIO AUTOMATICO)
|
||||
# ████████████████████████████████████████████████████
|
||||
info "Passo 11/12: Configurando PM2..."
|
||||
|
||||
# Para processos anteriores (se existirem)
|
||||
pm2 delete chatc2 2>/dev/null || true
|
||||
|
||||
# Inicia a aplicacao com PM2 como root (script ja exige root)
|
||||
cd "$CHATC2_DIR"
|
||||
if ! pm2 start src/server.js --name chatc2 --max-memory-restart 512M --time 2>&1; then
|
||||
err "Falha ao iniciar a aplicacao com PM2. Verifique os logs."
|
||||
fi
|
||||
|
||||
# Aguarda o servidor iniciar e verifica se esta ouvindo na porta 3000
|
||||
sleep 2
|
||||
if ss -tlnp | grep -q ':3000'; then
|
||||
log "Servidor Node.js ouvindo na porta 3000"
|
||||
else
|
||||
warn "Servidor pode nao estar ouvindo na porta 3000. Verifique: pm2 logs chatc2"
|
||||
fi
|
||||
|
||||
# Salva a lista de processos e configura inicio automatico no boot
|
||||
pm2 save 2>/dev/null || true
|
||||
pm2 startup systemd -u root --hp /root 2>/dev/null || true
|
||||
|
||||
log "PM2 configurado - aplicacao iniciara automaticamente no boot"
|
||||
|
||||
# ████████████████████████████████████████████████████
|
||||
# PASSO 12: FIREWALL
|
||||
# ████████████████████████████████████████████████████
|
||||
info "Passo 12/12: Configurando firewall..."
|
||||
ufw allow 22/tcp
|
||||
ufw allow 80/tcp
|
||||
ufw allow 443/tcp
|
||||
ufw allow 3000/tcp
|
||||
ufw --force enable
|
||||
log "Firewall configurado (portas: 22, 80, 443, 3000)"
|
||||
|
||||
# ████████████████████████████████████████████████████
|
||||
# FINAL
|
||||
# ████████████████████████████████████████████████████
|
||||
PUBLIC_IP=$(curl -s ifconfig.me 2>/dev/null || echo "<IP>")
|
||||
|
||||
echo ""
|
||||
echo "╔══════════════════════════════════════════════════╗"
|
||||
echo "║ Chatc2 - Instalacao Concluida! ║"
|
||||
echo "╚══════════════════════════════════════════════════╝"
|
||||
echo ""
|
||||
echo " 📍 Acessar: http://$PUBLIC_IP"
|
||||
echo " 📁 Diretorio: $CHATC2_DIR"
|
||||
echo " 👤 Usuario: $CHATC2_USER"
|
||||
echo " 🗄️ Firebird: senha: masterkey"
|
||||
echo " 🎤 Whisper: modelo $WHISPER_MODEL"
|
||||
echo ""
|
||||
echo " 📋 Proximos passos:"
|
||||
echo " 1. Copie seus bancos .FDB para $CHATC2_DIR/db/"
|
||||
echo " 2. Edite $CHATC2_DIR/.env se necessario"
|
||||
echo " 3. Crie usuario admin: node $CHATC2_DIR/scripts/gerar-token-usuario.js"
|
||||
echo " 4. Configure o webhook na Evolution API:"
|
||||
echo " POST http://$PUBLIC_IP/api/webhook/evolution"
|
||||
echo " 5. Logs: pm2 logs chatc2"
|
||||
echo " 6. Parar: pm2 stop chatc2"
|
||||
echo " 7. Reset: pm2 restart chatc2"
|
||||
echo ""
|
||||
@@ -0,0 +1,127 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
patch_node_firebird.py - Aplica patches de compatibilidade node-firebird
|
||||
|
||||
Patches aplicados:
|
||||
1. SRP empty buffer (Firebird 3.0 Legacy_Auth)
|
||||
2. Correcao de sintaxe para Node.js v22+ (colchete faltante)
|
||||
|
||||
Uso: python3 patch_node_firebird.py <caminho_do_projeto>
|
||||
Ex: python3 patch_node_firebird.py /home/chatc2/chatc2
|
||||
"""
|
||||
import sys
|
||||
import os
|
||||
|
||||
def patch_srp(project_dir):
|
||||
"""Patch 1: compatibilidade SRP com Firebird 3.0 Legacy_Auth"""
|
||||
filepath = os.path.join(project_dir, 'node_modules',
|
||||
'node-firebird', 'lib', 'wire', 'connection.js')
|
||||
if not os.path.isfile(filepath):
|
||||
print(" [ERRO] Arquivo connection.js nao encontrado")
|
||||
return False
|
||||
|
||||
with open(filepath, 'r') as f:
|
||||
content = f.read()
|
||||
|
||||
if "No auth data from server" in content:
|
||||
print(" [OK] Patch 1 (SRP) ja aplicado")
|
||||
return True
|
||||
|
||||
old = (
|
||||
' // TODO : Fallback Srp256 to Srp ?\n'
|
||||
' /*if (!d.buffer) {\n'
|
||||
' cnx.sendOpContAuth(\n'
|
||||
' cnx.clientKeys.public.toString(16),\n'
|
||||
' DEFAULT_ENCODING,\n'
|
||||
' accept.pluginName\n'
|
||||
' );\n'
|
||||
'\n'
|
||||
' return cb(new Error(\'login\'));\n'
|
||||
' }*/\n'
|
||||
'\n'
|
||||
' // Check buffer contains salt\n'
|
||||
' var saltLen = d.buffer.readUInt16LE(0);'
|
||||
)
|
||||
|
||||
new = (
|
||||
' // No auth data from server - server accepted the connection\n'
|
||||
' // without requiring SRP. This happens with Firebird 3.0 when\n'
|
||||
' // the server already validated the client.\n'
|
||||
' if (!d || !d.buffer) {\n'
|
||||
" accept.authData = '';\n"
|
||||
" accept.sessionKey = '';\n"
|
||||
' } else {\n'
|
||||
' // Check buffer contains salt\n'
|
||||
' var saltLen = d.buffer.readUInt16LE(0);'
|
||||
)
|
||||
|
||||
if old in content:
|
||||
content = content.replace(old, new, 1)
|
||||
with open(filepath, 'w') as f:
|
||||
f.write(content)
|
||||
print(" [OK] Patch 1 (SRP) aplicado")
|
||||
return True
|
||||
else:
|
||||
print(" [AVISO] Patch 1 (SRP) nao encontrado - codigo ja modificado")
|
||||
return True # nao e erro
|
||||
|
||||
|
||||
def patch_syntax(project_dir):
|
||||
"""Patch 2: colchete faltante (Node.js v22 nao tolera essa sintaxe)"""
|
||||
filepath = os.path.join(project_dir, 'node_modules',
|
||||
'node-firebird', 'lib', 'wire', 'connection.js')
|
||||
if not os.path.isfile(filepath):
|
||||
return False
|
||||
|
||||
with open(filepath, 'r') as f:
|
||||
content = f.read()
|
||||
|
||||
# Verifica se ja foi corrigido
|
||||
if "fecha o else do if" in content:
|
||||
print(" [OK] Patch 2 (sintaxe) ja aplicado")
|
||||
return True
|
||||
|
||||
# O erro: else block do if(!d||!d.buffer) nao tem chave de fechamento
|
||||
# Linha original termina com: accept.sessionKey = proof.clientSessionKey;
|
||||
# Linha seguinte: } else if (accept.pluginName === Const.AUTH_PLUGIN_LEGACY)
|
||||
# Precisa de um } extra entre elas para fechar o else block
|
||||
old = (
|
||||
' accept.authData = proof.authData.toString(16);\n'
|
||||
' accept.sessionKey = proof.clientSessionKey;\n'
|
||||
' } else if (accept.pluginName === Const.AUTH_PLUGIN_LEGACY) {'
|
||||
)
|
||||
new = (
|
||||
' accept.authData = proof.authData.toString(16);\n'
|
||||
' accept.sessionKey = proof.clientSessionKey;\n'
|
||||
' } // fecha o else do if (!d || !d.buffer)\n'
|
||||
' } else if (accept.pluginName === Const.AUTH_PLUGIN_LEGACY) {'
|
||||
)
|
||||
|
||||
if old in content:
|
||||
content = content.replace(old, new, 1)
|
||||
with open(filepath, 'w') as f:
|
||||
f.write(content)
|
||||
print(" [OK] Patch 2 (sintaxe Node22) aplicado")
|
||||
return True
|
||||
else:
|
||||
print(" [AVISO] Patch 2 (sintaxe) - padrao nao encontrado")
|
||||
return True
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
if len(sys.argv) < 2:
|
||||
print("Uso: python3 patch_node_firebird.py <caminho_do_projeto>")
|
||||
sys.exit(1)
|
||||
|
||||
project_dir = sys.argv[1]
|
||||
print(f" Aplicando patches em: {project_dir}")
|
||||
|
||||
r1 = patch_srp(project_dir)
|
||||
r2 = patch_syntax(project_dir)
|
||||
|
||||
if r1 and r2:
|
||||
print(" Patches aplicados com sucesso")
|
||||
sys.exit(0)
|
||||
else:
|
||||
print(" Alguns patches falharam")
|
||||
sys.exit(1)
|
||||
Reference in New Issue
Block a user