New read-only GET /api/nodes/:id/reality-keys returns the panel-hosted keypair for the node's server from keyStore (display only — it never mints a pair; a missing entry reports nulls). The node edit form shows public and private key rows with copy buttons for Reality protocols.
74 lines
2.7 KiB
Go
74 lines
2.7 KiB
Go
package main
|
|
|
|
// Item 17: GET /api/nodes/:id/reality-keys is a display-only view of the
|
|
// panel-hosted keypair — it must never mint one.
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func loginHeaders(t *testing.T, app *App) map[string]string {
|
|
t.Helper()
|
|
rec := doRequest(app, "POST", "/api/auth/login", `{"username":"admin","password":"password12345"}`, nil)
|
|
if rec.Code != 200 {
|
|
t.Fatalf("login %d", rec.Code)
|
|
}
|
|
cookie := strings.Split(rec.Header().Get("Set-Cookie"), ";")[0]
|
|
return map[string]string{"Cookie": cookie}
|
|
}
|
|
|
|
func TestRealityKeysEndpoint(t *testing.T) {
|
|
app := newSmokeApp(t)
|
|
_, err := app.store.Transaction(func(d *Data) (any, error) {
|
|
d.Servers = append(d.Servers, &Server{ID: "srv_1", Name: "S1", PublicAddress: "entry.example.com"})
|
|
d.Nodes = append(d.Nodes,
|
|
&Node{ID: "nod_r", Protocol: "vless-reality-vision", ServerID: "srv_1", Status: "active",
|
|
Reality: &RealityConfig{KeyID: "reality-nod_r", ServerName: "www.tesla.com", DestPort: 443}},
|
|
&Node{ID: "nod_s", Protocol: "socks5-auth", ServerID: "srv_1", Status: "active"},
|
|
)
|
|
d.KeyStore["reality-nod_r"] = &KeyEntry{PrivateKey: "PRIV", PublicKey: "PUB", UpdatedAt: NowISO()}
|
|
return nil, nil
|
|
})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
headers := loginHeaders(t, app)
|
|
|
|
rec := doRequest(app, "GET", "/api/nodes/nod_r/reality-keys", "", headers)
|
|
if rec.Code != 200 {
|
|
t.Fatalf("status %d body %s", rec.Code, rec.Body.String())
|
|
}
|
|
body := decodeBody(t, rec)
|
|
if body["publicKey"] != "PUB" || body["privateKey"] != "PRIV" || body["keyId"] != "reality-nod_r" {
|
|
t.Fatalf("body %v", body)
|
|
}
|
|
|
|
// Non-Reality node -> 400; unknown node -> 404.
|
|
if rec := doRequest(app, "GET", "/api/nodes/nod_s/reality-keys", "", headers); rec.Code != 400 {
|
|
t.Fatalf("socks node status %d, want 400", rec.Code)
|
|
}
|
|
if rec := doRequest(app, "GET", "/api/nodes/nope/reality-keys", "", headers); rec.Code != 404 {
|
|
t.Fatalf("unknown node status %d, want 404", rec.Code)
|
|
}
|
|
|
|
// A Reality node without a stored pair reports nulls and the
|
|
// endpoint must NOT create one.
|
|
_, err = app.store.Transaction(func(d *Data) (any, error) {
|
|
d.Nodes = append(d.Nodes, &Node{ID: "nod_r2", Protocol: "vless-reality", ServerID: "srv_1", Status: "draft",
|
|
Reality: &RealityConfig{KeyID: "reality-nod_r2", ServerName: "www.tesla.com", DestPort: 443}})
|
|
return nil, nil
|
|
})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
rec = doRequest(app, "GET", "/api/nodes/nod_r2/reality-keys", "", headers)
|
|
body = decodeBody(t, rec)
|
|
if rec.Code != 200 || body["publicKey"] != nil || body["privateKey"] != nil {
|
|
t.Fatalf("missing pair: %d %v", rec.Code, body)
|
|
}
|
|
if _, exists := app.store.Snapshot().KeyStore["reality-nod_r2"]; exists {
|
|
t.Fatal("display endpoint must never generate a keypair")
|
|
}
|
|
}
|