Files
3x-ui/internal/web/service/server_remote_cert_hash_test.go
T
MHSanaei ede275e4dc fix(server): apply the outbound address policy to remote cert pinning
The remote certificate fetch now dials through the same netsafe guard
as the REALITY target scan. A private or loopback endpoint is refused
unless the request carries allowPrivate; the inbound form asks the
operator to confirm and retries with the opt-in.
2026-10-03 13:20:00 +02:00

39 lines
1.1 KiB
Go

package service
import (
"crypto/sha256"
"encoding/hex"
"errors"
"net/http"
"net/http/httptest"
"strings"
"testing"
"github.com/mhsanaei/3x-ui/v3/internal/util/netsafe"
)
func TestGetRemoteCertHashGuardsPrivateTargets(t *testing.T) {
srv := httptest.NewTLSServer(http.HandlerFunc(func(http.ResponseWriter, *http.Request) {}))
defer srv.Close()
target := strings.TrimPrefix(srv.URL, "https://")
sum := sha256.Sum256(srv.Certificate().Raw)
want := hex.EncodeToString(sum[:])
t.Run("loopback refused without opt-in", func(t *testing.T) {
hashes, err := (&ServerService{}).GetRemoteCertHash(target, false)
if !errors.Is(err, netsafe.ErrPrivateAddressBlocked) {
t.Fatalf("GetRemoteCertHash(%s) = %v, %v; want ErrPrivateAddressBlocked", target, hashes, err)
}
})
t.Run("loopback read with opt-in", func(t *testing.T) {
hashes, err := (&ServerService{}).GetRemoteCertHash(target, true)
if err != nil {
t.Fatalf("GetRemoteCertHash(%s, allowPrivate): %v", target, err)
}
if len(hashes) != 1 || hashes[0] != want {
t.Fatalf("hashes = %v, want [%s]", hashes, want)
}
})
}