diff --git a/docs/deploy-hardening.md b/docs/deploy-hardening.md index 1ae6c5710e..c43fe0a155 100644 --- a/docs/deploy-hardening.md +++ b/docs/deploy-hardening.md @@ -9,6 +9,7 @@ ## New runtime flags - `--command-rate-limit ` (default: `30`) - `--command-rate-window ` (default: `60`) +- `--kore-host ` + `--kore-port ` (optional TCP mode to reach OpenKore endpoint) ## Recommended launch (VPN-first) ```bash @@ -29,6 +30,12 @@ perl tools/remote_gateway.pl \ # cp tools/gateway-users.example.json /etc/openkore/gateway-users.json ``` +If your OpenKore endpoint is TCP (instead of Unix socket), replace `--socket ...` with: + +```bash +--kore-host 127.0.0.1 --kore-port 2350 +``` + ## Operational notes - Keep bind host as `127.0.0.1` and publish via VPN tunnel. - Avoid exposing gateway directly to public internet at this stage. diff --git a/docs/gateway-core.md b/docs/gateway-core.md index 1acd82e434..309d815633 100644 --- a/docs/gateway-core.md +++ b/docs/gateway-core.md @@ -20,6 +20,15 @@ perl tools/remote_gateway.pl --socket /path/to/console.socket --listen-host 127.0.0.1 --listen-port 18085 ``` +### Alternative OpenKore endpoint mode (TCP) +If OpenKore bus is exposed via TCP, the gateway can connect with: + +```bash +perl tools/remote_gateway.pl --kore-host 127.0.0.1 --kore-port 2350 --listen-host 127.0.0.1 --listen-port 18085 +``` + +Use either `--socket` (Unix socket mode) or `--kore-host` + `--kore-port` (TCP mode). + ## Health check ```bash curl -s http://127.0.0.1:18085/health diff --git a/docs/guia-acesso-remoto-pt-br.md b/docs/guia-acesso-remoto-pt-br.md new file mode 100644 index 0000000000..53232b5685 --- /dev/null +++ b/docs/guia-acesso-remoto-pt-br.md @@ -0,0 +1,400 @@ +# Guia passo a passo (PT-BR): configurar e usar o acesso remoto do OpenKore + +Este guia explica de forma **bem detalhada** como configurar e usar o Remote Gateway do OpenKore. +A ideia é você sair daqui sabendo exatamente: + +- o que preencher em cada campo; +- que usuário cria para cada perfil; +- como testar login/comando; +- como acessar remotamente com segurança. + +> Recomendação oficial do projeto: **VPN first** (não expor o gateway diretamente na internet). + +--- + +## 0) Compatibilidade real: Linux x Windows + +Resposta curta para sua pergunta: **Linux continua sendo o caminho mais seguro/suportado**, mas agora o gateway também aceita conexão TCP com OpenKore. + +Por quê: + +- O gateway conecta no OpenKore via socket Unix (`--socket`) **ou** via TCP (`--kore-host` + `--kore-port`). +- O fluxo padrão do projeto usa caminhos Unix (`/etc/...`) e serviço `systemd`. + +Isso significa: + +- **Linux nativo**: cenário recomendado e documentado. +- **Windows nativo (PowerShell + Perl direto no Windows)**: possível via modo TCP, desde que OpenKore esteja acessível por host/porta. +- **Windows com WSL2**: funciona melhor se **OpenKore + gateway rodarem juntos dentro da mesma distro WSL** (onde existe socket Unix). + +Se você usa Windows e quer evitar dor de cabeça, escolha uma destas opções: + +1. Rodar OpenKore + gateway em um VPS Linux (e acessar via SSH/VPN). +2. Rodar ambos dentro do WSL2 (Ubuntu, por exemplo). + +Para passo a passo focado em Windows nativo, veja: `docs/guia-acesso-remoto-windows-nativo.md`. + +--- + +## 1) Pré-requisitos (com validação) + +Você precisa de: + +1. OpenKore rodando no servidor/host. +2. Perl instalado no mesmo host. +3. Acesso shell (SSH) ao host. +4. Repositório do OpenKore com: + - `tools/remote_gateway.pl` + - `tools/gateway-users.example.json` + +Valide rapidamente: + +```bash +perl -v +ls tools/remote_gateway.pl tools/gateway-users.example.json +``` + +Se esses dois comandos funcionarem, pode seguir. + +> No Windows, execute esses comandos **no ambiente Linux alvo** (VPS/WSL), não no PowerShell local puro. + +--- + +## 2) Conceitos rápidos (o que é cada coisa) + +### 2.1 O que é o gateway + +O `remote_gateway.pl` é um "tradutor" entre: + +- OpenKore (socket local Unix), e +- cliente remoto (browser/app via HTTP/WebSocket). + +### 2.2 Endpoints disponíveis + +- `GET /health`: status do gateway. +- `GET /`: interface web embutida. +- `GET /ws/events`: stream de eventos em tempo real. +- `POST /commands`: envia comando para o OpenKore. +- `POST /auth/login`: login com usuário/senha. +- `GET /auth/me`: mostra sessão atual. +- `POST /auth/refresh`: renova token. +- `POST /auth/revoke`: revoga sessão. +- `GET /audit`: consulta auditoria (**somente admin**). + +### 2.3 O que é RBAC + +RBAC = controle de acesso por papel (role). + +- `viewer`: só vê eventos/tela (não envia comando). +- `operator`: viewer + pode enviar comandos em `/commands`. +- `admin`: operator + pode consultar `/audit`. + +--- + +## 3) Criando usuários: o que preencher em `username`, `password`, `role` + +### 3.1 Copiar arquivo base + +```bash +sudo mkdir -p /etc/openkore +sudo cp tools/gateway-users.example.json /etc/openkore/gateway-users.json +``` + +> Esse caminho (`/etc/openkore/...`) é do **servidor Linux**. +> Se você estiver no Windows, edite o arquivo via SSH/SFTP no servidor, não no `C:\` local (a menos que seu gateway também rode localmente no Windows). + +### 3.2 Estrutura exata do JSON + +Cada usuário tem 3 campos: + +- `username`: nome de login (sem espaço; use algo claro). +- `password`: senha em texto (troque por senha forte). +- `role`: nível de permissão (`viewer`, `operator` ou `admin`). + +Exemplo **pronto para uso**: + +```json +{ + "users": [ + { + "username": "monitoramento", + "password": "TroqueAgora#Viewer2026", + "role": "viewer" + }, + { + "username": "operacao_bot", + "password": "TroqueAgora#Operator2026", + "role": "operator" + }, + { + "username": "admin_gateway", + "password": "TroqueAgora#Admin2026", + "role": "admin" + } + ] +} +``` + +### 3.3 Como escolher cada role na prática + +- Use **viewer** para quem só precisa acompanhar logs/eventos (ex.: celular secundário, observador). +- Use **operator** para quem pode executar comandos do bot (ex.: operador principal). +- Use **admin** só para manutenção/auditoria (mínimo de pessoas possível). + +### 3.4 Erros comuns nessa etapa + +- Deixar `change_me_*` sem trocar. +- Inventar role diferente (ex.: `superadmin`) — não vai funcionar. +- Esquecer vírgula ou quebrar JSON. + +Valide JSON com o comando correto para o seu terminal: + +**Linux/macOS (bash):** + +```bash +python -m json.tool /etc/openkore/gateway-users.json > /dev/null && echo "JSON OK" +``` + +**Windows PowerShell:** + +```powershell +ssh usuario@ip-do-servidor "python -m json.tool /etc/openkore/gateway-users.json > /dev/null && echo JSON OK" +``` + +> No PowerShell, `&&` pode não funcionar dependendo da versão/configuração. Use `;`. + +--- + +## 4) Descobrir o socket do OpenKore (campo `--socket`) + +Você **precisa** passar o caminho correto do socket do OpenKore. + +Procure o socket no **host Linux onde o OpenKore está rodando**: + +```bash +find . -type s -name '*.socket' +``` + +Se você estiver no **Windows PowerShell local**, esse `find` não é o mesmo comando do Linux. +Nesse caso, entre no servidor primeiro (SSH) e rode o `find` lá: + +```powershell +ssh usuario@ip-do-servidor +# depois, no shell Linux remoto: +cd /workspace/openkore +find . -type s -name '*.socket' +``` + +Se aparecer, por exemplo, `./console.socket`, então no comando você usa: + +```text +--socket /workspace/openkore/console.socket +``` + +> Se o caminho estiver errado, o gateway sobe, mas não consegue enviar/receber do OpenKore. + +--- + +## 5) Subir o gateway (com explicação de cada flag) + +Comando recomendado (com auth, rate-limit e auditoria): + +```bash +perl tools/remote_gateway.pl \ + --socket /workspace/openkore/console.socket \ + --listen-host 127.0.0.1 \ + --listen-port 18085 \ + --command-token "UM_TOKEN_LONGO_E_ALEATORIO" \ + --audit-file /var/log/openkore/gateway_audit.jsonl \ + --command-rate-limit 30 \ + --command-rate-window 60 \ + --auth-enabled \ + --users-file /etc/openkore/gateway-users.json \ + --token-ttl 900 \ + --session-file /var/lib/openkore/gateway_sessions.json +``` + +### 5.1 O que cada flag significa (sem pular nada) + +- `--socket`: caminho do socket do OpenKore. +- `--listen-host 127.0.0.1`: só aceita conexão local (mais seguro). +- `--listen-port 18085`: porta do gateway. +- `--command-token`: "segunda trava" para rota de comando. +- `--audit-file`: grava histórico de tentativas/comandos. +- `--command-rate-limit 30`: máximo de 30 comandos... +- `--command-rate-window 60`: ...a cada 60 segundos por origem. +- `--auth-enabled`: obriga login por usuário/senha. +- `--users-file`: caminho do JSON de usuários. +- `--token-ttl 900`: access token dura 900s (15 min). +- `--session-file`: arquivo para persistir sessões/tokens. + +### 5.2 O que você deve trocar obrigatoriamente + +- `--socket`: para o caminho real do seu socket. +- `--command-token`: para um token forte (não usar `CHANGE_ME`). +- senhas do JSON (`/etc/openkore/gateway-users.json`). + +### 5.3 Alternativa compatível (TCP em vez de socket Unix) + +Se seu OpenKore estiver exposto por host/porta, você pode usar: + +```bash +perl tools/remote_gateway.pl \ + --kore-host 127.0.0.1 \ + --kore-port 2350 \ + --listen-host 127.0.0.1 \ + --listen-port 18085 \ + --command-token "UM_TOKEN_LONGO_E_ALEATORIO" \ + --auth-enabled \ + --users-file /etc/openkore/gateway-users.json +``` + +> Nesse modo, use `--kore-host` + `--kore-port` juntos. + +--- + +## 6) Teste completo (login -> sessão -> comando) + +### 6.1 Testar saúde + +```bash +curl -s http://127.0.0.1:18085/health +``` + +Se vier JSON, gateway está de pé. + +### 6.2 Fazer login (operator) + +```bash +curl -s -X POST "http://127.0.0.1:18085/auth/login" \ + -H "Content-Type: application/json" \ + -d '{"username":"operacao_bot","password":"TroqueAgora#Operator2026"}' +``` + +Resposta deve conter `access_token` e `refresh_token`. + +### 6.3 Validar token + +```bash +curl -s "http://127.0.0.1:18085/auth/me" \ + -H "Authorization: Bearer " +``` + +### 6.4 Enviar comando real ao OpenKore + +```bash +curl -s -X POST "http://127.0.0.1:18085/commands" \ + -H "Content-Type: application/json" \ + -H "Authorization: Bearer " \ + -H "X-Command-Token: UM_TOKEN_LONGO_E_ALEATORIO" \ + -d '{"command":"status"}' +``` + +> Sem `Authorization` ou sem `X-Command-Token`, a chamada deve ser negada. + +### 6.5 Testar UI local + +No navegador do host: + +```text +http://127.0.0.1:18085/ +``` + +--- + +## 7) Acesso remoto seguro (SSH tunnel e VPN) + +Como o bind está em `127.0.0.1`, você **não** acessa direto de fora. Isso é intencional. + +### Opção A: SSH Tunnel (rápido e simples) + +No seu PC: + +```bash +ssh -L 18085:127.0.0.1:18085 usuario@ip-do-servidor +``` + +No Windows PowerShell é o mesmo comando acima. + +Com essa sessão aberta, no mesmo PC abra: + +```text +http://127.0.0.1:18085/ +``` + +### Opção B: VPN (produção) + +- Coloque servidor e cliente na mesma VPN. +- Mantenha gateway local (`127.0.0.1`) e publique por túnel/proxy interno. +- Não abra a porta 18085 no firewall público. + +--- + +## 8) Subir automaticamente com systemd + +> Esta seção é **somente Linux** (systemd não é padrão no Windows nativo). + +Exemplo de unit (`/etc/systemd/system/openkore-gateway.service`): + +```ini +[Unit] +Description=OpenKore Remote Gateway +After=network.target + +[Service] +Type=simple +WorkingDirectory=/workspace/openkore +ExecStart=/usr/bin/perl /workspace/openkore/tools/remote_gateway.pl --socket /workspace/openkore/console.socket --listen-host 127.0.0.1 --listen-port 18085 --command-token UM_TOKEN_LONGO_E_ALEATORIO --audit-file /var/log/openkore/gateway_audit.jsonl --auth-enabled --users-file /etc/openkore/gateway-users.json --token-ttl 900 --session-file /var/lib/openkore/gateway_sessions.json +Restart=always +RestartSec=2 +User=openkore +Group=openkore + +[Install] +WantedBy=multi-user.target +``` + +Aplicar: + +```bash +sudo systemctl daemon-reload +sudo systemctl enable --now openkore-gateway +sudo systemctl status openkore-gateway +``` + +--- + +## 9) Segurança mínima obrigatória (checklist) + +1. Trocar todas as senhas e token padrão. +2. Permissão restrita em sessões/auditoria: + +```bash +sudo chown openkore:openkore /var/lib/openkore/gateway_sessions.json /var/log/openkore/gateway_audit.jsonl +sudo chmod 600 /var/lib/openkore/gateway_sessions.json /var/log/openkore/gateway_audit.jsonl +``` + +3. Usar `admin` só para administração. +4. Revisar `gateway_audit.jsonl` com frequência. +5. Rotacionar senha/token periodicamente. + +--- + +## 10) Troubleshooting direto ao ponto + +- **401/403 no login**: usuário/senha errados ou JSON mal formatado. +- **401/403 no `/commands`**: faltou Bearer token e/ou `X-Command-Token`. +- **`kore_disconnected`**: `--socket` incorreto ou OpenKore não está com socket ativo. +- **429 (rate limit)**: excesso de comandos no intervalo; ajuste `--command-rate-*` com cuidado. +- **UI abre sem eventos**: WebSocket não conectou ou OpenKore sem tráfego no momento. + +--- + +## 11) Validação final (release flow) + +```bash +perl src/test/unittests.pl RemoteGatewaySmokeTest +./tools/check_gateway_release.sh +``` + +Se os dois passarem, seu ambiente está alinhado com o fluxo de release do gateway. diff --git a/docs/guia-acesso-remoto-windows-nativo.md b/docs/guia-acesso-remoto-windows-nativo.md new file mode 100644 index 0000000000..de03056509 --- /dev/null +++ b/docs/guia-acesso-remoto-windows-nativo.md @@ -0,0 +1,201 @@ +# Guia completo (Windows nativo, sem Linux): acesso remoto OpenKore + +Este guia é para quem usa **Windows nativo** e quer rodar o Remote Gateway **sem WSL e sem Linux**. + +> Recomendação deste guia: usar modo TCP (`--kore-host` + `--kore-port`) para conectar no OpenKore no Windows. + +--- + +## 0) Cenário alvo deste guia + +Este guia cobre: + +- OpenKore e gateway rodando no próprio Windows. +- Sem `systemd`, sem `/etc`, sem `find` Linux. +- Configuração por arquivos e comandos PowerShell/Prompt. + +Pré-requisito principal: seu OpenKore precisa estar acessível via host/porta TCP. + +--- + +## 1) Visão geral (arquitetura no Windows nativo) + +Fluxo recomendado: + +1. Você abre o Windows normalmente. +2. OpenKore roda no Windows e expõe endpoint TCP. +3. Você acessa a UI no navegador do Windows em `http://127.0.0.1:18085/`. +4. Se quiser acesso externo, usa SSH túnel/VPN. + +--- + +## 2) Pré-requisitos no Windows + +1. Perl no Windows (ex.: Strawberry Perl). +2. OpenKore funcionando no Windows. +3. Endpoint TCP do OpenKore ativo (host/porta). +4. Repositório com `tools/remote_gateway.pl`. + +--- + +## 3) Preparar pasta e arquivos no Windows + +Exemplo de estrutura: + +- `C:\openkore\` (repositório) +- `C:\openkore\config\gateway-users.json` +- `C:\openkore\logs\gateway_audit.jsonl` +- `C:\openkore\data\gateway_sessions.json` + +--- + +## 4) Criar usuários RBAC (Windows) + +Copie o exemplo: + +```powershell +Copy-Item .\tools\gateway-users.example.json .\config\gateway-users.json +``` + +Exemplo de conteúdo: + +```json +{ + "users": [ + { + "username": "monitoramento", + "password": "TroqueAgora#Viewer2026", + "role": "viewer" + }, + { + "username": "operacao_bot", + "password": "TroqueAgora#Operator2026", + "role": "operator" + }, + { + "username": "admin_gateway", + "password": "TroqueAgora#Admin2026", + "role": "admin" + } + ] +} +``` + +### O que significa cada role + +- `viewer`: só visualizar eventos/logs. +- `operator`: viewer + enviar comandos. +- `admin`: operator + acessar auditoria. + +Validar JSON: + +```powershell +python -m json.tool .\config\gateway-users.json | Out-Null; Write-Host "JSON OK" +``` + +--- + +## 5) Confirmar host/porta do OpenKore (TCP) + +Você precisa saber host/porta do endpoint TCP. + +Exemplo deste guia: + +- host: `127.0.0.1` +- porta: `2350` + +--- + +## 6) Subir gateway no Windows (modo TCP) + +No PowerShell, dentro de `C:\openkore`: + +```powershell +perl .\tools\remote_gateway.pl --kore-host 127.0.0.1 --kore-port 2350 --listen-host 127.0.0.1 --listen-port 18085 --command-token "UM_TOKEN_LONGO_E_ALEATORIO" --audit-file ".\\logs\\gateway_audit.jsonl" --command-rate-limit 30 --command-rate-window 60 --auth-enabled --users-file ".\\config\\gateway-users.json" --token-ttl 900 --session-file ".\\data\\gateway_sessions.json" +``` + +--- + +## 7) Testar pelo Windows (browser + PowerShell) + +### 7.1 Browser (Windows) + +Abra: + +```text +http://127.0.0.1:18085/ +``` + +### 7.2 Healthcheck (PowerShell) + +```powershell +curl.exe -s http://127.0.0.1:18085/health +``` + +### 7.3 Login (PowerShell) + +```powershell +curl.exe -s -X POST "http://127.0.0.1:18085/auth/login" -H "Content-Type: application/json" -d "{\"username\":\"operacao_bot\",\"password\":\"TroqueAgora#Operator2026\"}" +``` + +> No PowerShell, `curl` normalmente é alias de `Invoke-WebRequest`; por isso use `curl.exe`. + +--- + +## 8) Acesso remoto de verdade (fora da sua máquina) + +Mantenha gateway em `127.0.0.1` e publique com túnel/VPN. + +### SSH Tunnel (de outra máquina) + +```bash +ssh -L 18085:127.0.0.1:18085 usuario@host-windows-ou-jump-host +``` + +Se seu Windows não aceita SSH inbound, use VPN/Tailscale/ZeroTier e exponha apenas internamente. + +--- + +## 9) Inicialização automática no Windows + +Use o script pronto: `tools/start-gateway.ps1`. + +Ele detecta automaticamente a raiz do OpenKore quando executado de dentro do repositório. + +Comando mínimo (sem parâmetros): + +```powershell +.\tools\start-gateway.ps1 +``` + +Esse modo usa defaults e cria `config\gateway-users.json` automaticamente (a partir do template) caso não exista. + +Exemplo manual (PowerShell): + +```powershell +powershell -NoProfile -ExecutionPolicy Bypass -File .\tools\start-gateway.ps1 -KoreHost "127.0.0.1" -KorePort 2350 -ListenHost "127.0.0.1" -ListenPort 18085 -CommandToken "UM_TOKEN_LONGO_E_ALEATORIO" +``` + +Depois crie uma tarefa no **Task Scheduler** chamando: + +```powershell +powershell -NoProfile -ExecutionPolicy Bypass -File C:\openkore\tools\start-gateway.ps1 +``` + +--- + +## 10) Troubleshooting comum (Windows nativo) + +- **Gateway não inicia com erro de conexão**: host/porta TCP do OpenKore incorretos. +- **porta 18085 não abre no Windows**: confirme que gateway está rodando e bound em `127.0.0.1`. +- **401/403**: revisar usuário/senha/token/header. +- **sem eventos**: OpenKore não está acessível no endpoint TCP configurado. + +--- + +## 11) Validação final + +```powershell +perl .\src\test\unittests.pl RemoteGatewaySmokeTest +bash .\tools\check_gateway_release.sh +``` diff --git a/tools/remote_gateway.pl b/tools/remote_gateway.pl index 6f6e39f91f..1c767c7579 100755 --- a/tools/remote_gateway.pl +++ b/tools/remote_gateway.pl @@ -7,7 +7,6 @@ use lib "$RealBin/../src/deps"; use IO::Select; -use IO::Socket::UNIX; use IO::Socket::INET; use Getopt::Long qw(GetOptions); use Time::HiRes qw(time sleep); @@ -19,6 +18,8 @@ use Bus::MessageParser; my $socket_path = 'console.socket'; +my $kore_host = ''; +my $kore_port = 0; my $listen_host = '127.0.0.1'; my $listen_port = 18085; my $replay_size = 200; @@ -34,9 +35,14 @@ my $max_http_body_bytes = 262144; my $http_body_read_timeout = 2.0; my $ready_file = ''; +my $has_unix_socket = eval { require IO::Socket::UNIX; 1 }; + +$SIG{PIPE} = 'IGNORE'; GetOptions( 'socket=s' => \$socket_path, + 'kore-host=s' => \$kore_host, + 'kore-port=i' => \$kore_port, 'listen-host=s' => \$listen_host, 'listen-port=i' => \$listen_port, 'replay-size=i' => \$replay_size, @@ -173,12 +179,25 @@ sub normalize_event { } sub connect_kore { - my $socket = IO::Socket::UNIX->new( - Type => SOCK_STREAM, + if ($kore_host ne '' && $kore_port > 0) { + return IO::Socket::INET->new( + PeerAddr => $kore_host, + PeerPort => $kore_port, + Proto => 'tcp', + Timeout => $connect_timeout, + ); + } + + return if !$has_unix_socket; + return IO::Socket::UNIX->new( Peer => $socket_path, Timeout => $connect_timeout, ); - return $socket; +} + +sub kore_endpoint_string { + return "tcp://$kore_host:$kore_port" if $kore_host ne '' && $kore_port > 0; + return $socket_path; } sub set_kore_socket { @@ -222,7 +241,10 @@ sub build_health_payload { service => 'openkore-remote-gateway', time => scalar(time), config => { + kore_endpoint => kore_endpoint_string(), socket => $socket_path, + kore_host => $kore_host eq '' ? undef : $kore_host, + kore_port => $kore_port > 0 ? $kore_port : undef, listen_host => $listen_host, listen_port => $listen_port, replay_size => $replay_size, @@ -1041,7 +1063,14 @@ sub process_kore_data { print "[gateway] auth revoke endpoint at http://$listen_host:$listen_port/auth/revoke\n"; print "[gateway] session file: $session_file\n"; } -print "[gateway] connecting to OpenKore socket: $socket_path\n"; +if (($kore_host eq '') != ($kore_port == 0)) { + die "Invalid arguments: use both --kore-host and --kore-port together, or neither\n"; +} +if ($kore_host eq '' && $kore_port == 0 && !$has_unix_socket) { + die "Unix sockets are unavailable in this Perl runtime. Use --kore-host and --kore-port (TCP mode).\n"; +} + +print "[gateway] connecting to OpenKore endpoint: " . kore_endpoint_string() . "\n"; load_users(); load_sessions(); add_event({ kind => 'gateway_event', ts => scalar(time), message => 'gateway_started' }); @@ -1051,7 +1080,7 @@ sub process_kore_data { pid => $$, listen_host => $listen_host, listen_port => $listen_port, - socket => $socket_path, + kore_endpoint => kore_endpoint_string(), ready => JSON::PP::true, }) . "\n"; close $rfh; @@ -1089,4 +1118,4 @@ sub process_kore_data { } sleep 0.1 if !$kore_socket; -} \ No newline at end of file +} diff --git a/tools/start-gateway.ps1 b/tools/start-gateway.ps1 new file mode 100644 index 0000000000..fad8c799d7 --- /dev/null +++ b/tools/start-gateway.ps1 @@ -0,0 +1,163 @@ +param( + [string]$OpenKoreRoot = "", + [string]$KoreHost = "127.0.0.1", + [int]$KorePort = 2350, + [string]$ListenHost = "127.0.0.1", + [int]$ListenPort = 18085, + [string]$CommandToken = "CHANGE_ME", + [int]$CommandRateLimit = 30, + [int]$CommandRateWindow = 60, + [int]$TokenTtl = 900, + [switch]$AuthEnabled = $true +) + +$ErrorActionPreference = "Stop" + +function Resolve-OpenKoreRoot { + param([string]$UserPath) + + if ($UserPath -and $UserPath.Trim() -ne "") { + if (Test-Path -LiteralPath $UserPath) { + return (Resolve-Path -LiteralPath $UserPath).Path + } + throw "OpenKoreRoot inválido (não encontrado): $UserPath" + } + + $scriptPath = $PSCommandPath + if (-not $scriptPath) { $scriptPath = $MyInvocation.PSCommandPath } + if (-not $scriptPath) { $scriptPath = $MyInvocation.MyCommand.Path } + if (-not $scriptPath) { $scriptPath = (Join-Path (Get-Location).Path "tools\start-gateway.ps1") } + $scriptDir = Split-Path -Parent $scriptPath + $candidates = @() + $candidates += $scriptDir + try { $candidates += (Resolve-Path (Join-Path $scriptDir "..")).Path } catch {} + try { $candidates += (Resolve-Path (Join-Path $scriptDir "..\..")).Path } catch {} + $candidates += (Get-Location).Path + + foreach ($cand in ($candidates | Select-Object -Unique)) { + if (Test-Path -LiteralPath (Join-Path $cand "tools\remote_gateway.pl")) { + return $cand + } + } + + throw "Não foi possível detectar a raiz do OpenKore automaticamente. Use -OpenKoreRoot `"C:\caminho\openkore`"." +} + +function Assert-FileExists { + param([string]$Path) + if (-not (Test-Path -LiteralPath $Path)) { + throw "Arquivo obrigatório não encontrado: $Path" + } +} + +function Ensure-Dir { + param([string]$Path) + if (-not (Test-Path -LiteralPath $Path)) { + New-Item -ItemType Directory -Path $Path -Force | Out-Null + } +} + +$OpenKoreRoot = Resolve-OpenKoreRoot -UserPath $OpenKoreRoot +$gatewayScript = Join-Path $OpenKoreRoot "tools\remote_gateway.pl" +$configDir = Join-Path $OpenKoreRoot "config" +$logsDir = Join-Path $OpenKoreRoot "logs" +$dataDir = Join-Path $OpenKoreRoot "data" +$usersFile = Join-Path $configDir "gateway-users.json" +$usersTemplate = Join-Path $OpenKoreRoot "tools\gateway-users.example.json" +$auditFile = Join-Path $logsDir "gateway_audit.jsonl" +$sessionFile = Join-Path $dataDir "gateway_sessions.json" +$pidFile = Join-Path $dataDir "gateway.pid" +$stdoutLog = Join-Path $logsDir "gateway_stdout.log" +$stderrLog = Join-Path $logsDir "gateway_stderr.log" + +Ensure-Dir -Path $configDir +Ensure-Dir -Path $logsDir +Ensure-Dir -Path $dataDir + +Assert-FileExists -Path $gatewayScript + +if (-not (Test-Path -LiteralPath $usersFile)) { + if (Test-Path -LiteralPath $usersTemplate) { + Copy-Item -LiteralPath $usersTemplate -Destination $usersFile -Force + Write-Warning "Arquivo $usersFile não existia. Copiado do template gateway-users.example.json. Troque as senhas padrão." + } else { + @' +{ + "users": [ + { "username": "viewer_user", "password": "change_me_viewer", "role": "viewer" }, + { "username": "operator_user", "password": "change_me_operator", "role": "operator" }, + { "username": "admin_user", "password": "change_me_admin", "role": "admin" } + ] +} +'@ | Set-Content -LiteralPath $usersFile -Encoding UTF8 + Write-Warning "Arquivo $usersFile criado automaticamente. Troque as senhas padrão." + } +} + +if ($KorePort -le 0 -or $KorePort -gt 65535) { + throw "KorePort inválida: $KorePort" +} + +if ($ListenPort -le 0 -or $ListenPort -gt 65535) { + throw "ListenPort inválida: $ListenPort" +} + +if ($CommandToken -eq "CHANGE_ME") { + Write-Warning "Você ainda está usando token padrão CHANGE_ME. Troque antes de produção." +} + +$existingPid = $null +if (Test-Path -LiteralPath $pidFile) { + $existingPid = (Get-Content -LiteralPath $pidFile -ErrorAction SilentlyContinue | Select-Object -First 1) +} + +if ($existingPid) { + $existingProc = Get-Process -Id $existingPid -ErrorAction SilentlyContinue + if ($existingProc) { + Write-Host "Gateway já está em execução (PID=$existingPid)." + exit 0 + } +} + +$argList = @( + ".\tools\remote_gateway.pl", + "--kore-host", $KoreHost, + "--kore-port", "$KorePort", + "--listen-host", $ListenHost, + "--listen-port", "$ListenPort", + "--command-token", $CommandToken, + "--audit-file", $auditFile, + "--command-rate-limit", "$CommandRateLimit", + "--command-rate-window", "$CommandRateWindow", + "--users-file", $usersFile, + "--token-ttl", "$TokenTtl", + "--session-file", $sessionFile +) + +if ($AuthEnabled) { + $argList += "--auth-enabled" +} else { + $argList += "--no-auth-enabled" +} + +Push-Location $OpenKoreRoot +try { + $proc = Start-Process -FilePath "perl" -ArgumentList $argList -WorkingDirectory $OpenKoreRoot -RedirectStandardOutput $stdoutLog -RedirectStandardError $stderrLog -PassThru + Set-Content -LiteralPath $pidFile -Value $proc.Id -Encoding ASCII + Start-Sleep -Milliseconds 600 + + $healthUrl = "http://$ListenHost`:$ListenPort/health" + try { + $response = Invoke-RestMethod -Uri $healthUrl -Method Get -TimeoutSec 3 + Write-Host "Gateway iniciado com sucesso (PID=$($proc.Id))." + Write-Host "Health: $healthUrl" + Write-Host "Status conectado ao OpenKore: $($response.status.connected)" + } + catch { + Write-Warning "Gateway iniciado (PID=$($proc.Id)), mas healthcheck falhou: $($_.Exception.Message)" + Write-Warning "Confira logs: $stdoutLog e $stderrLog" + } +} +finally { + Pop-Location +}