Browse Source

add the script to test all endpoint and review de code

gdias 2 weeks ago
parent
commit
1ea24a945d
2 changed files with 252 additions and 0 deletions
  1. 5 0
      security_problems.md
  2. 247 0
      test_endpoints.sh

+ 5 - 0
security_problems.md

@@ -0,0 +1,5 @@
+basicamente temos que adicionar quais roles podem utilizar quais funcoes do backend(a role deve ficar salva no jwt)
+
+rotas estao no arquivo server.php dentro de public
+
+nao tem nenhum rating limit no login, podem executar um brute force

+ 247 - 0
test_endpoints.sh

@@ -0,0 +1,247 @@
+#!/usr/bin/env bash
+#
+# test_endpoints.sh — Testa todos os endpoints da API nettown_backend.
+#
+# Faz login (POST /v1/login), obtém o JWT e reutiliza nas rotas protegidas.
+#
+# Uso:
+#   ./test_endpoints.sh
+#   BASE_URL=http://localhost:8080 EMAIL=admin@empresa.com PASSWORD=12345678 ./test_endpoints.sh
+#   RUN_WRITE=1 ./test_endpoints.sh        # inclui endpoints que ESCREVEM no banco
+#
+# Variáveis de ambiente:
+#   BASE_URL    Host da API            (default: http://localhost:8080)
+#   API_PREFIX  Prefixo das rotas      (default: /v1)
+#   EMAIL       E-mail de login        (default: admin@empresa.com)
+#   PASSWORD    Senha de login         (default: 12345678)
+#   RUN_WRITE   "1" para rodar também os endpoints de escrita (register,
+#               change-password, agents, sla/configs). Default: 0 (somente leitura).
+#
+# Saída: 0 se nenhum teste falhou, 1 caso contrário.
+
+set -uo pipefail
+
+BASE_URL="${BASE_URL:-http://localhost:8080}"
+API_PREFIX="${API_PREFIX:-/v1}"
+EMAIL="${EMAIL:-admin@empresa.com}"
+PASSWORD="${PASSWORD:-12345678}"
+RUN_WRITE="${RUN_WRITE:-0}"
+
+BASE="${BASE_URL}${API_PREFIX}"
+TOKEN=""
+
+# Cores (desativadas se a saída não for um terminal).
+if [[ -t 1 ]]; then
+    C_GREEN=$'\033[32m'; C_RED=$'\033[31m'; C_YELLOW=$'\033[33m'
+    C_BLUE=$'\033[34m'; C_DIM=$'\033[2m'; C_RESET=$'\033[0m'
+else
+    C_GREEN=""; C_RED=""; C_YELLOW=""; C_BLUE=""; C_DIM=""; C_RESET=""
+fi
+
+PASS=0; FAIL=0; SKIP=0
+
+have_jq() { command -v jq >/dev/null 2>&1; }
+
+# json_get <json> <jq_path> — extrai um valor do JSON (usa jq; senão, grep básico).
+json_get() {
+    local json="$1" path="$2"
+    if have_jq; then
+        printf '%s' "$json" | jq -r "$path // empty" 2>/dev/null
+        return
+    fi
+    # Fallback simples: pega o último campo com o nome final do path (ex.: .data.token -> token).
+    local key="${path##*.}"
+    printf '%s' "$json" | grep -o "\"${key}\"[[:space:]]*:[[:space:]]*\"[^\"]*\"" \
+        | head -n1 | sed -E "s/.*:[[:space:]]*\"([^\"]*)\"/\1/"
+}
+
+# Imprime um trecho curto do corpo da resposta.
+preview_body() {
+    local body="$1"
+    if have_jq; then
+        printf '%s' "$body" | jq -c '{status, code, message}' 2>/dev/null || printf '%s' "$body" | head -c 200
+    else
+        printf '%s' "$body" | head -c 200
+    fi
+}
+
+LAST_BODY=""
+LAST_CODE=""
+
+# call <method> <path> [json_data] — executa a requisição e popula LAST_BODY/LAST_CODE.
+call() {
+    local method="$1" path="$2" data="${3:-}"
+    local args=(-sS -X "$method" -H "Accept: application/json" -w $'\n%{http_code}' --max-time 30)
+    if [[ -n "$TOKEN" ]]; then
+        args+=(-H "Authorization: Bearer ${TOKEN}")
+    fi
+    if [[ -n "$data" ]]; then
+        args+=(-H "Content-Type: application/json" -d "$data")
+    fi
+
+    local resp
+    resp=$(curl "${args[@]}" "${BASE}${path}" 2>/dev/null)
+    LAST_CODE=$(printf '%s' "$resp" | tail -n1)
+    LAST_BODY=$(printf '%s' "$resp" | sed '$d')
+}
+
+# check <label> <method> <path> [json_data] — chama e avalia (2xx = passou).
+check() {
+    local label="$1" method="$2" path="$3" data="${4:-}"
+    call "$method" "$path" "$data"
+
+    local mark color
+    if [[ "$LAST_CODE" =~ ^2 ]]; then
+        mark="PASS"; color="$C_GREEN"; PASS=$((PASS + 1))
+    elif [[ "$LAST_CODE" =~ ^[45] ]]; then
+        mark="FAIL"; color="$C_RED"; FAIL=$((FAIL + 1))
+    else
+        mark="FAIL"; color="$C_RED"; FAIL=$((FAIL + 1))
+        [[ -z "$LAST_CODE" ]] && LAST_CODE="ERR"
+    fi
+
+    printf '  %s%-4s%s %-7s %-34s %shttp %s%s\n' \
+        "$color" "$mark" "$C_RESET" "$method" "$path" "$C_DIM" "$LAST_CODE" "$C_RESET"
+    printf '       %s%s%s\n' "$C_DIM" "$(preview_body "$LAST_BODY")" "$C_RESET"
+}
+
+skip() {
+    local path="$1" reason="$2"
+    SKIP=$((SKIP + 1))
+    printf '  %sSKIP%s %-7s %-34s %s%s%s\n' "$C_YELLOW" "$C_RESET" "-" "$path" "$C_DIM" "$reason" "$C_RESET"
+}
+
+section() { printf '\n%s== %s ==%s\n' "$C_BLUE" "$1" "$C_RESET"; }
+
+# ----------------------------------------------------------------------------
+# 0. Sanity check
+# ----------------------------------------------------------------------------
+printf '%sAlvo:%s %s   %sleitura+escrita:%s %s\n' \
+    "$C_DIM" "$C_RESET" "$BASE" "$C_DIM" "$C_RESET" \
+    "$([[ "$RUN_WRITE" == "1" ]] && echo sim || echo 'somente leitura')"
+have_jq || printf '%s(jq não encontrado — usando parser básico; instale jq para melhor saída)%s\n' "$C_YELLOW" "$C_RESET"
+
+# ----------------------------------------------------------------------------
+# 1. Login (obrigatório — sem token não dá para testar o resto)
+# ----------------------------------------------------------------------------
+section "Autenticação"
+LOGIN_PAYLOAD=$(printf '{"email":"%s","password":"%s"}' "$EMAIL" "$PASSWORD")
+check "login" POST "/login" "$LOGIN_PAYLOAD"
+
+TOKEN=$(json_get "$LAST_BODY" '.data.token')
+if [[ -z "$TOKEN" ]]; then
+    printf '\n%sNão foi possível obter o JWT do login. Verifique BASE_URL/EMAIL/PASSWORD.%s\n' "$C_RED" "$C_RESET"
+    printf 'Resposta: %s\n' "$LAST_BODY"
+    exit 1
+fi
+printf '       %stoken obtido (%s...)%s\n' "$C_DIM" "${TOKEN:0:24}" "$C_RESET"
+
+# ----------------------------------------------------------------------------
+# 2. Perfil
+# ----------------------------------------------------------------------------
+section "Perfil"
+check "me" GET "/me"
+
+# ----------------------------------------------------------------------------
+# 3. Dashboards (somente leitura)
+# ----------------------------------------------------------------------------
+section "Dashboards (GET)"
+check "dashboard"  GET "/dashboard/overview"
+check "analytics"  GET "/analytics/sentiment/dashboard"
+check "personas"   GET "/personas/overview"
+check "evolution"  GET "/evolution/overview"
+check "executive"  GET "/executive/dashboard"
+
+# ----------------------------------------------------------------------------
+# 4. Interações
+# ----------------------------------------------------------------------------
+section "Interações (GET)"
+check "interactions" GET "/interactions?page=1&per_page=5"
+
+# Tenta extrair um conversation_id da listagem para testar os detalhes.
+CONV_ID=""
+if have_jq; then
+    CONV_ID=$(printf '%s' "$LAST_BODY" | jq -r '.data.items[0].conversationId // empty' 2>/dev/null)
+else
+    CONV_ID=$(printf '%s' "$LAST_BODY" | grep -o '"conversationId":[0-9]*' | head -n1 | grep -o '[0-9]*')
+fi
+
+if [[ -n "$CONV_ID" ]]; then
+    check "interaction-details" GET "/interactions/details?conversation_id=${CONV_ID}"
+else
+    skip "/interactions/details" "nenhum conversation_id disponível na listagem"
+fi
+
+# ----------------------------------------------------------------------------
+# 5. Agentes (GET)
+# ----------------------------------------------------------------------------
+section "Agentes (GET)"
+check "agents" GET "/agents"
+
+# ----------------------------------------------------------------------------
+# 6. SLA (GET)
+# ----------------------------------------------------------------------------
+section "SLA (GET)"
+check "sla-configs"     GET "/sla/configs"
+check "sla-live-status" GET "/sla/live-status"
+
+# ----------------------------------------------------------------------------
+# 7. Endpoints de ESCRITA (apenas com RUN_WRITE=1)
+# ----------------------------------------------------------------------------
+section "Escrita (POST)"
+if [[ "$RUN_WRITE" != "1" ]]; then
+    skip "/register"          "RUN_WRITE!=1 (cria usuário)"
+    skip "/agents"            "RUN_WRITE!=1 (cria/edita agente)"
+    skip "/agents/status"     "RUN_WRITE!=1 (altera status)"
+    skip "/agents/escalation" "RUN_WRITE!=1 (altera escalonamento)"
+    skip "/sla/configs"       "RUN_WRITE!=1 (cria/edita SLA)"
+    skip "/me/change-password" "RUN_WRITE!=1 (altera senha; revertido se rodado)"
+else
+    TS=$(date +%s)
+
+    # 7.1 Register — cria usuário com e-mail único para não colidir.
+    REG_PAYLOAD=$(printf '{"name":"Teste %s","phone":"5511999990000","email":"teste+%s@example.com","role":"agent","password":"senha12345"}' "$TS" "$TS")
+    check "register" POST "/register" "$REG_PAYLOAD"
+
+    # 7.2 Agents — cria um agente e captura o id para os toggles.
+    AGENT_PAYLOAD=$(printf '{"name":"Agente Teste %s","email":"agent+%s@example.com","department":"SAC","channels":["whatsapp"],"status":"Ativo","availableForEscalation":true}' "$TS" "$TS")
+    check "agents-save" POST "/agents" "$AGENT_PAYLOAD"
+
+    AGENT_ID=""
+    if have_jq; then
+        AGENT_ID=$(printf '%s' "$LAST_BODY" | jq -r '.data.id // empty' 2>/dev/null)
+    else
+        AGENT_ID=$(printf '%s' "$LAST_BODY" | grep -o '"id":[0-9]*' | head -n1 | grep -o '[0-9]*')
+    fi
+
+    if [[ -n "$AGENT_ID" ]]; then
+        check "agents-status"     POST "/agents/status"     "$(printf '{"id":%s}' "$AGENT_ID")"
+        check "agents-escalation" POST "/agents/escalation" "$(printf '{"id":%s}' "$AGENT_ID")"
+    else
+        skip "/agents/status"     "agente de teste não retornou id"
+        skip "/agents/escalation" "agente de teste não retornou id"
+    fi
+
+    # 7.3 SLA config — cria/atualiza um departamento de teste.
+    SLA_PAYLOAD=$(printf '{"name":"TESTE %s","firstResponseH":1,"firstResponseM":30,"resolutionH":24,"alertPct":80}' "$TS")
+    check "sla-save" POST "/sla/configs" "$SLA_PAYLOAD"
+
+    # 7.4 Change password — troca e reverte para não travar o login.
+    NEW_PW="${PASSWORD}_tmp1"
+    check "change-password" POST "/me/change-password" \
+        "$(printf '{"currentPassword":"%s","newPassword":"%s","confirmPassword":"%s"}' "$PASSWORD" "$NEW_PW" "$NEW_PW")"
+    if [[ "$LAST_CODE" =~ ^2 ]]; then
+        # Reverte para a senha original.
+        check "change-password (revert)" POST "/me/change-password" \
+            "$(printf '{"currentPassword":"%s","newPassword":"%s","confirmPassword":"%s"}' "$NEW_PW" "$PASSWORD" "$PASSWORD")"
+    fi
+fi
+
+# ----------------------------------------------------------------------------
+# Resumo
+# ----------------------------------------------------------------------------
+printf '\n%s== Resumo ==%s\n' "$C_BLUE" "$C_RESET"
+printf '  %spassou:%s %d   %sfalhou:%s %d   %spulado:%s %d\n' \
+    "$C_GREEN" "$C_RESET" "$PASS" "$C_RED" "$C_RESET" "$FAIL" "$C_YELLOW" "$C_RESET" "$SKIP"
+
+[[ "$FAIL" -eq 0 ]] && exit 0 || exit 1