feat: implement security enhancements for Jitsi integration, including JWT token generation and automatic blocking of detected attacks, improving system resilience and user authentication

This commit is contained in:
2026-01-12 04:34:00 -03:00
parent b965514e53
commit 664d90c2e0
27 changed files with 6174 additions and 329 deletions

526
scripts/configurar-jitsi.sh Executable file
View File

@@ -0,0 +1,526 @@
#!/bin/bash
# Script de configuração interativa do Jitsi Meet para SGSE
# Este script facilita a configuração inicial do Jitsi no sistema SGSE
set -e
# Cores para output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Variáveis
DOMAIN=""
APP_ID=""
ROOM_PREFIX=""
USE_HTTPS=false
ACCEPT_SELF_SIGNED=false
JWT_SECRET=""
JWT_AUDIENCE=""
JWT_ISSUER=""
AMBIENTE=""
TEST_ONLY=false
VALIDATE_ONLY=false
NON_INTERACTIVE=false
# Função para imprimir mensagens
print_info() {
echo -e "${BLUE} $1${NC}"
}
print_success() {
echo -e "${GREEN}$1${NC}"
}
print_warning() {
echo -e "${YELLOW}⚠️ $1${NC}"
}
print_error() {
echo -e "${RED}$1${NC}"
}
# Função para validar formato de domínio
validar_dominio() {
local dominio=$1
if [[ -z "$dominio" ]]; then
return 1
fi
# Padrão para localhost:porta
if [[ $dominio =~ ^(localhost|127\.0\.0\.1|0\.0\.0\.0)(:[0-9]+)?$ ]]; then
return 0
fi
# Padrão para FQDN
if [[ $dominio =~ ^([a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,}(:[0-9]+)?$ ]]; then
return 0
fi
return 1
}
# Função para validar App ID
validar_app_id() {
local app_id=$1
if [[ -z "$app_id" ]]; then
return 1
fi
if [[ $app_id =~ ^[a-zA-Z0-9_-]+$ ]]; then
return 0
fi
return 1
}
# Função para validar JWT Secret
validar_jwt_secret() {
local secret=$1
if [[ -z "$secret" ]]; then
return 0 # Opcional
fi
if [[ ${#secret} -lt 16 ]]; then
return 1
fi
return 0
}
# Função para testar conectividade
testar_conectividade() {
local dominio=$1
local use_https=$2
print_info "Testando conectividade com $dominio..."
# Extrair host e porta
local host=$(echo $dominio | cut -d: -f1)
local porta=$(echo $dominio | cut -d: -f2)
if [[ -z "$porta" ]]; then
if [[ "$use_https" == "true" ]]; then
porta=443
else
porta=80
fi
fi
local protocol="http"
if [[ "$use_https" == "true" ]]; then
protocol="https"
fi
local url="$protocol://$host:$porta/http-bind"
# Testar conexão
if command -v curl &> /dev/null; then
local response=$(curl -s -o /dev/null -w "%{http_code}" --max-time 10 "$url" 2>&1 || echo "000")
if [[ "$response" == "200" ]] || [[ "$response" == "405" ]] || [[ "$response" == "000" ]]; then
# 405 é esperado (Method Not Allowed para GET em /http-bind)
print_success "Servidor acessível em $url"
return 0
else
print_warning "Servidor retornou status $response (pode ser normal para /http-bind)"
return 0
fi
elif command -v wget &> /dev/null; then
if wget --spider --timeout=10 "$url" 2>&1 | grep -q "200 OK\|405\|connected"; then
print_success "Servidor acessível em $url"
return 0
else
print_warning "Não foi possível verificar conectividade (wget)"
return 1
fi
else
print_warning "curl ou wget não encontrado. Pulando teste de conectividade."
return 1
fi
}
# Função para validar certificado SSL
validar_certificado_ssl() {
local dominio=$1
if [[ ! "$dominio" =~ ^localhost ]]; then
print_info "Validando certificado SSL para $dominio..."
local host=$(echo $dominio | cut -d: -f1)
local porta=$(echo $dominio | cut -d: -f2)
if [[ -z "$porta" ]]; then
porta=443
fi
if command -v openssl &> /dev/null; then
local cert_info=$(echo | openssl s_client -connect "$host:$porta" -servername "$host" 2>&1 | grep -A 2 "Certificate chain\|Verify return code")
if echo "$cert_info" | grep -q "Verify return code: 0"; then
print_success "Certificado SSL válido"
return 0
else
print_warning "Certificado SSL não válido ou autoassinado"
return 1
fi
else
print_warning "openssl não encontrado. Pulando validação de certificado."
return 1
fi
fi
return 0
}
# Função para gerar JWT Secret
gerar_jwt_secret() {
if command -v openssl &> /dev/null; then
openssl rand -hex 32
elif [[ -r /dev/urandom ]]; then
head -c 32 /dev/urandom | base64 | tr -d '\n' | head -c 64
else
print_error "Não foi possível gerar JWT Secret. Instale openssl ou forneça manualmente."
exit 1
fi
}
# Função para ler entrada do usuário
ler_entrada() {
local prompt=$1
local default=$2
local var_name=$3
if [[ "$NON_INTERACTIVE" == "true" ]]; then
if [[ -n "$default" ]]; then
eval "$var_name='$default'"
return
else
print_error "Modo não-interativo requer valor para: $prompt"
exit 1
fi
fi
local input
if [[ -n "$default" ]]; then
read -p "$(echo -e ${BLUE}$prompt${NC} [padrão: $default]): " input
eval "$var_name=\${input:-$default}"
else
read -p "$(echo -e ${BLUE}$prompt${NC}): " input
eval "$var_name='$input'"
fi
}
# Função para exibir ajuda
mostrar_ajuda() {
cat << EOF
Uso: $0 [OPÇÕES]
Script de configuração interativa do Jitsi Meet para SGSE.
OPÇÕES:
--ambiente NOME Especificar ambiente (desenvolvimento, staging, producao)
--domain DOMINIO Configurar domínio do servidor Jitsi
--app-id ID Configurar App ID
--jwt-secret SECRET Configurar JWT Secret (ou gerar automaticamente se não fornecido)
--room-prefix PREFIXO Configurar prefixo de sala
--use-https Usar HTTPS
--accept-self-signed Aceitar certificados autoassinados
--test-only Apenas testar configuração existente
--validate-only Apenas validar sem salvar
--non-interactive Modo não-interativo (para CI/CD)
--help Mostrar esta ajuda
EXEMPLOS:
# Modo interativo
$0
# Modo não-interativo
$0 --domain meet.example.com --app-id sgse-app --use-https
# Apenas validar
$0 --validate-only --domain meet.example.com
# Apenas testar
$0 --test-only
EOF
}
# Processar argumentos da linha de comando
while [[ $# -gt 0 ]]; do
case $1 in
--ambiente)
AMBIENTE="$2"
shift 2
;;
--domain|--domínio)
DOMAIN="$2"
shift 2
;;
--app-id)
APP_ID="$2"
shift 2
;;
--jwt-secret)
JWT_SECRET="$2"
shift 2
;;
--room-prefix)
ROOM_PREFIX="$2"
shift 2
;;
--use-https)
USE_HTTPS=true
shift
;;
--accept-self-signed)
ACCEPT_SELF_SIGNED=true
shift
;;
--test-only)
TEST_ONLY=true
shift
;;
--validate-only)
VALIDATE_ONLY=true
shift
;;
--non-interactive)
NON_INTERACTIVE=true
shift
;;
--help|-h)
mostrar_ajuda
exit 0
;;
*)
print_error "Opção desconhecida: $1"
mostrar_ajuda
exit 1
;;
esac
done
# Banner
echo -e "${BLUE}"
cat << "EOF"
╔═══════════════════════════════════════════════════════════╗
║ Configuração do Jitsi Meet para SGSE ║
╚═══════════════════════════════════════════════════════════╝
EOF
echo -e "${NC}"
# Modo apenas teste
if [[ "$TEST_ONLY" == "true" ]]; then
print_info "Modo de teste apenas. Validando configuração existente..."
# Aqui você pode adicionar lógica para testar configuração existente
# Por exemplo, buscar do banco de dados ou arquivo de configuração
exit 0
fi
# Coletar informações
if [[ "$NON_INTERACTIVE" != "true" ]]; then
print_info "Coletando informações de configuração..."
echo
fi
# Ambiente
if [[ -z "$AMBIENTE" ]]; then
ler_entrada "Ambiente (desenvolvimento, staging, producao)" "" AMBIENTE
fi
# Domínio
while [[ -z "$DOMAIN" ]] || ! validar_dominio "$DOMAIN"; do
if [[ -z "$DOMAIN" ]]; then
ler_entrada "Domínio do servidor Jitsi (ex: localhost:8443 ou meet.example.com)" "" DOMAIN
else
print_error "Domínio inválido: $DOMAIN"
DOMAIN=""
ler_entrada "Domínio do servidor Jitsi" "" DOMAIN
fi
done
# Detectar HTTPS automaticamente
if [[ "$DOMAIN" =~ :8443$ ]] || [[ "$DOMAIN" =~ ^[^:]+$ ]] && [[ ! "$DOMAIN" =~ ^localhost ]]; then
if [[ "$USE_HTTPS" != "true" ]] && [[ "$NON_INTERACTIVE" != "true" ]]; then
read -p "$(echo -e ${BLUE}Usar HTTPS? (S/n)${NC}): " resposta
if [[ "$resposta" =~ ^[Ss]$ ]] || [[ -z "$resposta" ]]; then
USE_HTTPS=true
fi
elif [[ -z "$USE_HTTPS" ]]; then
USE_HTTPS=true
fi
fi
# Aceitar certificados autoassinados
if [[ "$USE_HTTPS" == "true" ]] && [[ "$DOMAIN" =~ localhost ]]; then
if [[ "$ACCEPT_SELF_SIGNED" != "true" ]] && [[ "$NON_INTERACTIVE" != "true" ]]; then
read -p "$(echo -e ${BLUE}Aceitar certificados autoassinados? (S/n)${NC}): " resposta
if [[ "$resposta" =~ ^[Ss]$ ]] || [[ -z "$resposta" ]]; then
ACCEPT_SELF_SIGNED=true
fi
fi
fi
# App ID
while [[ -z "$APP_ID" ]] || ! validar_app_id "$APP_ID"; do
if [[ -z "$APP_ID" ]]; then
ler_entrada "App ID" "sgse-app" APP_ID
else
print_error "App ID inválido: $APP_ID (deve conter apenas letras, números, hífens e underscores)"
APP_ID=""
ler_entrada "App ID" "sgse-app" APP_ID
fi
done
# Room Prefix
if [[ -z "$ROOM_PREFIX" ]]; then
ler_entrada "Prefixo de sala" "sgse" ROOM_PREFIX
fi
# JWT Secret
if [[ -z "$JWT_SECRET" ]]; then
if [[ "$NON_INTERACTIVE" != "true" ]]; then
read -p "$(echo -e ${BLUE}Gerar JWT Secret automaticamente? (S/n)${NC}): " resposta
if [[ "$resposta" =~ ^[Ss]$ ]] || [[ -z "$resposta" ]]; then
JWT_SECRET=$(gerar_jwt_secret)
print_success "JWT Secret gerado: ${JWT_SECRET:0:16}..."
else
ler_entrada "JWT Secret (deixe vazio para desabilitar JWT)" "" JWT_SECRET
fi
else
JWT_SECRET=$(gerar_jwt_secret)
fi
fi
# Validar JWT Secret se fornecido
if [[ -n "$JWT_SECRET" ]] && ! validar_jwt_secret "$JWT_SECRET"; then
print_error "JWT Secret deve ter no mínimo 16 caracteres"
exit 1
fi
# JWT Audience (opcional)
if [[ -z "$JWT_AUDIENCE" ]] && [[ "$NON_INTERACTIVE" != "true" ]]; then
ler_entrada "JWT Audience (opcional, padrão: domínio)" "$DOMAIN" JWT_AUDIENCE
fi
# JWT Issuer (opcional)
if [[ -z "$JWT_ISSUER" ]] && [[ "$NON_INTERACTIVE" != "true" ]]; then
ler_entrada "JWT Issuer (opcional, padrão: App ID)" "$APP_ID" JWT_ISSUER
fi
# Validações
print_info "Validando configuração..."
# Validar domínio
if ! validar_dominio "$DOMAIN"; then
print_error "Domínio inválido: $DOMAIN"
exit 1
fi
# Validar App ID
if ! validar_app_id "$APP_ID"; then
print_error "App ID inválido: $APP_ID"
exit 1
fi
# Validar JWT Secret
if [[ -n "$JWT_SECRET" ]] && ! validar_jwt_secret "$JWT_SECRET"; then
print_error "JWT Secret inválido (mínimo 16 caracteres)"
exit 1
fi
print_success "Validações básicas passaram"
# Testes de conectividade
if [[ "$VALIDATE_ONLY" != "true" ]]; then
print_info "Testando conectividade..."
if testar_conectividade "$DOMAIN" "$USE_HTTPS"; then
print_success "Conectividade OK"
else
print_warning "Não foi possível testar conectividade (servidor pode estar offline)"
fi
# Validar certificado SSL se HTTPS
if [[ "$USE_HTTPS" == "true" ]]; then
validar_certificado_ssl "$DOMAIN"
fi
fi
# Resumo
echo
print_info "Resumo da configuração:"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo " Ambiente: ${AMBIENTE:-padrão}"
echo " Domínio: $DOMAIN"
echo " App ID: $APP_ID"
echo " Prefixo de Sala: $ROOM_PREFIX"
echo " HTTPS: $USE_HTTPS"
echo " Cert. Autoassinado: $ACCEPT_SELF_SIGNED"
if [[ -n "$JWT_SECRET" ]]; then
echo " JWT Secret: ${JWT_SECRET:0:16}... (${#JWT_SECRET} caracteres)"
else
echo " JWT Secret: (não configurado)"
fi
if [[ -n "$JWT_AUDIENCE" ]]; then
echo " JWT Audience: $JWT_AUDIENCE"
fi
if [[ -n "$JWT_ISSUER" ]]; then
echo " JWT Issuer: $JWT_ISSUER"
fi
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
# Se apenas validar, sair aqui
if [[ "$VALIDATE_ONLY" == "true" ]]; then
print_success "Validação concluída"
exit 0
fi
# Confirmar antes de salvar
if [[ "$NON_INTERACTIVE" != "true" ]]; then
echo
read -p "$(echo -e ${BLUE}Salvar esta configuração? (S/n)${NC}): " confirmar
if [[ ! "$confirmar" =~ ^[Ss]$ ]] && [[ -n "$confirmar" ]]; then
print_info "Configuração cancelada pelo usuário"
exit 0
fi
fi
# Gerar JSON de configuração
CONFIG_JSON=$(cat <<EOF
{
"domain": "$DOMAIN",
"appId": "$APP_ID",
"roomPrefix": "$ROOM_PREFIX",
"useHttps": $USE_HTTPS,
"acceptSelfSignedCert": $ACCEPT_SELF_SIGNED,
"ambiente": "${AMBIENTE:-}",
"jwtSecret": "${JWT_SECRET:-}",
"jwtAudience": "${JWT_AUDIENCE:-}",
"jwtIssuer": "${JWT_ISSUER:-}"
}
EOF
)
# Salvar em arquivo
CONFIG_FILE="jitsi-config-$(date +%Y%m%d-%H%M%S).json"
echo "$CONFIG_JSON" > "$CONFIG_FILE"
print_success "Configuração salva em: $CONFIG_FILE"
# Instruções finais
echo
print_info "Próximos passos:"
echo "1. Revise o arquivo de configuração: $CONFIG_FILE"
echo "2. Acesse o painel SGSE: TI > Configurações do Jitsi"
echo "3. Preencha os campos com os valores acima"
echo "4. Teste a conexão usando o botão 'Testar Conexão'"
echo "5. Salve a configuração no painel"
if [[ -n "$JWT_SECRET" ]]; then
echo
print_warning "IMPORTANTE: Guarde o JWT Secret em local seguro!"
print_warning "O JWT Secret não será exibido novamente."
fi
print_success "Configuração concluída!"