aerotun_handlers_test.go 2.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374
  1. package api
  2. import (
  3. "context"
  4. "encoding/json"
  5. "net/http"
  6. "net/http/httptest"
  7. "path/filepath"
  8. "strings"
  9. "testing"
  10. "proxmox-router/internal/aerotun"
  11. "proxmox-router/internal/auth"
  12. "proxmox-router/internal/vpn"
  13. )
  14. func aeroRequest(method, path, body string, role auth.Role) *http.Request {
  15. r := httptest.NewRequest(method, path, strings.NewReader(body))
  16. return r.WithContext(context.WithValue(r.Context(), sessionContextKey, &auth.Session{Role: role}))
  17. }
  18. func TestAeroTUNSecretRedactionAndEdit(t *testing.T) {
  19. m := aerotun.NewManagerWithPath(filepath.Join(t.TempDir(), "aerotun.json"))
  20. defer m.StopAll()
  21. key := strings.Repeat("12", 32)
  22. saved, err := m.Save(aerotun.TunnelInstance{Name: "atest", Mode: "server", LocalAddress: "10.99.0.1/24", PSK: key, Disabled: true})
  23. if err != nil {
  24. t.Fatal(err)
  25. }
  26. s := &Server{vpnMgr: &vpn.Manager{AeroTUN: m}}
  27. w := httptest.NewRecorder()
  28. s.handleListAeroTUNTunnels(w, aeroRequest("GET", "/api/vpn/aerotun/tunnels", "", auth.RoleRead))
  29. if strings.Contains(w.Body.String(), key) || strings.Contains(w.Body.String(), `"psk":`) {
  30. t.Fatal("list disclosed PSK")
  31. }
  32. var views []aerotun.TunnelInstance
  33. if err = json.Unmarshal(w.Body.Bytes(), &views); err != nil || !views[0].HasPSK {
  34. t.Fatal("missing safe key presence indicator", err)
  35. }
  36. saved.PSK = ""
  37. saved.Comment = "edited without revealing secret"
  38. body, _ := json.Marshal(saved)
  39. w = httptest.NewRecorder()
  40. s.handleSaveAeroTUNTunnel(w, aeroRequest("POST", "/api/vpn/aerotun/tunnels", string(body), auth.RoleFull))
  41. if w.Code != 200 || strings.Contains(w.Body.String(), key) {
  42. t.Fatalf("save failed or disclosed PSK: %d", w.Code)
  43. }
  44. got, _ := m.Get(saved.ID)
  45. if got.PSK != key {
  46. t.Fatal("redacted edit erased the stored key")
  47. }
  48. for _, role := range []auth.Role{auth.RoleRead, auth.RoleWrite} {
  49. w = httptest.NewRecorder()
  50. s.handleSaveAeroTUNTunnel(w, aeroRequest("POST", "/api/vpn/aerotun/tunnels", string(body), role))
  51. if w.Code != 403 {
  52. t.Fatal("non-administrator modified tunnel")
  53. }
  54. w = httptest.NewRecorder()
  55. s.handleGenerateAeroTUNKey(w, aeroRequest("GET", "/api/vpn/aerotun/genkey", "", role))
  56. if w.Code != 403 {
  57. t.Fatal("non-administrator generated key")
  58. }
  59. }
  60. }
  61. func TestAeroTUNPrivateIdentityRedacted(t *testing.T) {
  62. private, public, err := aerotun.GenerateIdentity()
  63. if err != nil {
  64. t.Fatal(err)
  65. }
  66. view := aerotun.TunnelInstance{PSK: strings.Repeat("ab", 32), PrivateKey: private, PublicKey: public}.PublicView()
  67. encoded, _ := json.Marshal(view)
  68. if strings.Contains(string(encoded), private) || !view.HasPrivateKey || view.PublicKey != public {
  69. t.Fatal("private identity exposed or public identity lost")
  70. }
  71. }