mirror of
https://github.com/Rain-kl/OpenFlare.git
synced 2026-09-28 05:46:36 +08:00
133 lines
4.6 KiB
Go
133 lines
4.6 KiB
Go
// Copyright 2026 Arctel.net
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
package cloudflare
|
|
|
|
import (
|
|
"fmt"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"strings"
|
|
"testing"
|
|
|
|
db "github.com/Rain-kl/Wavelet/internal/infra/persistence"
|
|
"github.com/Rain-kl/Wavelet/internal/model"
|
|
"github.com/Rain-kl/Wavelet/internal/repository"
|
|
"github.com/Rain-kl/Wavelet/internal/shared/response"
|
|
"github.com/gin-gonic/gin"
|
|
)
|
|
|
|
func TestConnectionHandlersNeverReturnAPIToken(t *testing.T) {
|
|
setupCloudflareLogicDB(t)
|
|
gin.SetMode(gin.TestMode)
|
|
router := gin.New()
|
|
router.Use(response.ErrorHandlerMiddleware())
|
|
router.PUT("/connection", SaveConnectionHandler)
|
|
router.GET("/connection", GetConnectionHandler)
|
|
|
|
save := httptest.NewRecorder()
|
|
request := httptest.NewRequest(http.MethodPut, "/connection", strings.NewReader(`{"source":"standalone","api_token":"top-secret-token"}`))
|
|
request.Header.Set("Content-Type", "application/json")
|
|
router.ServeHTTP(save, request)
|
|
if save.Code != http.StatusOK {
|
|
t.Fatalf("PUT /connection status = %d, body = %s", save.Code, save.Body.String())
|
|
}
|
|
if strings.Contains(save.Body.String(), "top-secret-token") || strings.Contains(save.Body.String(), "api_token") {
|
|
t.Fatalf("PUT /connection leaked token: %s", save.Body.String())
|
|
}
|
|
|
|
get := httptest.NewRecorder()
|
|
router.ServeHTTP(get, httptest.NewRequest(http.MethodGet, "/connection", nil))
|
|
if get.Code != http.StatusOK {
|
|
t.Fatalf("GET /connection status = %d, body = %s", get.Code, get.Body.String())
|
|
}
|
|
if strings.Contains(get.Body.String(), "top-secret-token") || strings.Contains(get.Body.String(), "api_token") {
|
|
t.Fatalf("GET /connection leaked token: %s", get.Body.String())
|
|
}
|
|
}
|
|
|
|
func TestGetGroupWithOrphanedMemberHealsAndSucceeds(t *testing.T) {
|
|
ctx, memberID := setupCloudflareLogicDB(t)
|
|
gin.SetMode(gin.TestMode)
|
|
router := gin.New()
|
|
router.Use(response.ErrorHandlerMiddleware())
|
|
router.GET("/groups/:id", GetGroupHandler)
|
|
|
|
member, err := repository.GetCFPointingMemberByID(ctx, memberID)
|
|
if err != nil {
|
|
t.Fatalf("GetCFPointingMemberByID() error = %v", err)
|
|
}
|
|
|
|
// Simulate orphaned member by deleting the ZoneDomain directly
|
|
if err := db.DB(ctx).Exec("DELETE FROM of_zone_domains WHERE id = ?", member.ZoneDomainID).Error; err != nil {
|
|
t.Fatalf("DELETE FROM of_zone_domains error = %v", err)
|
|
}
|
|
|
|
recorder := httptest.NewRecorder()
|
|
request := httptest.NewRequest(http.MethodGet, "/groups/1", nil)
|
|
router.ServeHTTP(recorder, request)
|
|
|
|
if recorder.Code != http.StatusOK {
|
|
t.Fatalf("GET /groups/1 status = %d, body = %s", recorder.Code, recorder.Body.String())
|
|
}
|
|
|
|
// Verify the orphaned member has been removed
|
|
_, err = repository.GetCFPointingMemberByID(ctx, memberID)
|
|
if err == nil {
|
|
t.Errorf("GetCFPointingMemberByID() should return not found after healing")
|
|
}
|
|
}
|
|
|
|
func TestListGroupsHandlerWithMissingNodeStillSucceeds(t *testing.T) {
|
|
ctx, _ := setupCloudflareLogicDB(t)
|
|
if err := db.DB(ctx).Create(&model.CFPointingGroup{
|
|
Name: "KR",
|
|
PrimaryNodeID: 12,
|
|
ActiveNodeID: 12,
|
|
Enabled: true,
|
|
}).Error; err != nil {
|
|
t.Fatalf("Create(missing-node group) error = %v", err)
|
|
}
|
|
|
|
gin.SetMode(gin.TestMode)
|
|
router := gin.New()
|
|
router.Use(response.ErrorHandlerMiddleware())
|
|
router.GET("/groups", ListGroupsHandler)
|
|
|
|
recorder := httptest.NewRecorder()
|
|
router.ServeHTTP(recorder, httptest.NewRequest(http.MethodGet, "/groups", nil))
|
|
if recorder.Code != http.StatusOK {
|
|
t.Fatalf("ListGroupsHandler status = %d, body = %s, want %d", recorder.Code, recorder.Body.String(), http.StatusOK)
|
|
}
|
|
body := recorder.Body.String()
|
|
if !strings.Contains(body, `"name":"KR"`) {
|
|
t.Fatalf("ListGroupsHandler body = %s, want group KR", body)
|
|
}
|
|
if !strings.Contains(body, `"name":"primary"`) {
|
|
t.Fatalf("ListGroupsHandler body = %s, want intact group primary", body)
|
|
}
|
|
}
|
|
|
|
func TestGetGroupHandlerWithMissingNodeStillSucceeds(t *testing.T) {
|
|
ctx, _ := setupCloudflareLogicDB(t)
|
|
group := model.CFPointingGroup{Name: "KR", PrimaryNodeID: 12, ActiveNodeID: 12, Enabled: true}
|
|
if err := db.DB(ctx).Create(&group).Error; err != nil {
|
|
t.Fatalf("Create(missing-node group) error = %v", err)
|
|
}
|
|
|
|
gin.SetMode(gin.TestMode)
|
|
router := gin.New()
|
|
router.Use(response.ErrorHandlerMiddleware())
|
|
router.GET("/groups/:id", GetGroupHandler)
|
|
|
|
recorder := httptest.NewRecorder()
|
|
request := httptest.NewRequest(http.MethodGet, fmt.Sprintf("/groups/%d", group.ID), nil)
|
|
router.ServeHTTP(recorder, request)
|
|
if recorder.Code != http.StatusOK {
|
|
t.Fatalf("GetGroupHandler status = %d, body = %s, want %d", recorder.Code, recorder.Body.String(), http.StatusOK)
|
|
}
|
|
if !strings.Contains(recorder.Body.String(), `"name":"KR"`) {
|
|
t.Fatalf("GetGroupHandler body = %s, want group KR", recorder.Body.String())
|
|
}
|
|
}
|