prouter_test.go 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  1. package prouter
  2. import (
  3. "net"
  4. "net/http"
  5. "net/http/httptest"
  6. "testing"
  7. )
  8. // ── inRange ────────────────────────────────────────────────────────────────────
  9. func TestInRange_Inside(t *testing.T) {
  10. r := ipRange{
  11. start: net.ParseIP("192.168.0.0"),
  12. end: net.ParseIP("192.168.255.255"),
  13. }
  14. if !inRange(r, net.ParseIP("192.168.1.100")) {
  15. t.Error("expected 192.168.1.100 to be in range 192.168.0.0-192.168.255.255")
  16. }
  17. }
  18. func TestInRange_Outside(t *testing.T) {
  19. r := ipRange{
  20. start: net.ParseIP("192.168.0.0"),
  21. end: net.ParseIP("192.168.255.255"),
  22. }
  23. if inRange(r, net.ParseIP("10.0.0.1")) {
  24. t.Error("expected 10.0.0.1 to be outside range 192.168.0.0-192.168.255.255")
  25. }
  26. }
  27. func TestInRange_StartBoundary(t *testing.T) {
  28. r := ipRange{
  29. start: net.ParseIP("10.0.0.0"),
  30. end: net.ParseIP("10.255.255.255"),
  31. }
  32. if !inRange(r, net.ParseIP("10.0.0.0")) {
  33. t.Error("expected start of range to be included")
  34. }
  35. }
  36. // ── isPrivateSubnet ────────────────────────────────────────────────────────────
  37. func TestIsPrivateSubnet_RFC1918_10(t *testing.T) {
  38. if !isPrivateSubnet(net.ParseIP("10.10.10.10")) {
  39. t.Error("10.10.10.10 should be private (10.0.0.0/8)")
  40. }
  41. }
  42. func TestIsPrivateSubnet_RFC1918_172(t *testing.T) {
  43. if !isPrivateSubnet(net.ParseIP("172.16.5.1")) {
  44. t.Error("172.16.5.1 should be private (172.16.0.0/12)")
  45. }
  46. }
  47. func TestIsPrivateSubnet_RFC1918_192_168(t *testing.T) {
  48. if !isPrivateSubnet(net.ParseIP("192.168.100.50")) {
  49. t.Error("192.168.100.50 should be private (192.168.0.0/16)")
  50. }
  51. }
  52. func TestIsPrivateSubnet_Public(t *testing.T) {
  53. if isPrivateSubnet(net.ParseIP("8.8.8.8")) {
  54. t.Error("8.8.8.8 should not be private")
  55. }
  56. }
  57. func TestIsPrivateSubnet_Public2(t *testing.T) {
  58. if isPrivateSubnet(net.ParseIP("1.1.1.1")) {
  59. t.Error("1.1.1.1 should not be private")
  60. }
  61. }
  62. // ── checkIfLAN ─────────────────────────────────────────────────────────────────
  63. func TestCheckIfLAN_Loopback127(t *testing.T) {
  64. req := httptest.NewRequest(http.MethodGet, "/", nil)
  65. req.RemoteAddr = "127.0.0.1:8080"
  66. if !checkIfLAN(req) {
  67. t.Error("expected 127.0.0.1 to be considered LAN")
  68. }
  69. }
  70. func TestCheckIfLAN_Loopback_IPv6(t *testing.T) {
  71. req := httptest.NewRequest(http.MethodGet, "/", nil)
  72. req.RemoteAddr = "[::1]:8080"
  73. if !checkIfLAN(req) {
  74. t.Error("expected ::1 to be considered LAN")
  75. }
  76. }
  77. func TestCheckIfLAN_PrivateIP(t *testing.T) {
  78. req := httptest.NewRequest(http.MethodGet, "/", nil)
  79. req.RemoteAddr = "192.168.1.50:12345"
  80. if !checkIfLAN(req) {
  81. t.Error("expected 192.168.1.50 to be considered LAN")
  82. }
  83. }
  84. func TestCheckIfLAN_PublicIP(t *testing.T) {
  85. req := httptest.NewRequest(http.MethodGet, "/", nil)
  86. req.RemoteAddr = "8.8.8.8:12345"
  87. if checkIfLAN(req) {
  88. t.Error("expected 8.8.8.8 to NOT be considered LAN")
  89. }
  90. }
  91. func TestCheckIfLAN_XForwardedFor_Private(t *testing.T) {
  92. req := httptest.NewRequest(http.MethodGet, "/", nil)
  93. req.Header.Set("X-FORWARDED-FOR", "10.0.0.5")
  94. if !checkIfLAN(req) {
  95. t.Error("expected private X-Forwarded-For IP to be LAN")
  96. }
  97. }
  98. func TestCheckIfLAN_XForwardedFor_Public(t *testing.T) {
  99. req := httptest.NewRequest(http.MethodGet, "/", nil)
  100. req.Header.Set("X-FORWARDED-FOR", "203.0.113.1")
  101. if checkIfLAN(req) {
  102. t.Error("expected public X-Forwarded-For IP to NOT be LAN")
  103. }
  104. }
  105. func TestCheckIfLAN_XRealIP_Private(t *testing.T) {
  106. req := httptest.NewRequest(http.MethodGet, "/", nil)
  107. req.Header.Set("X-Real-Ip", "172.16.0.1")
  108. if !checkIfLAN(req) {
  109. t.Error("expected private X-Real-Ip to be LAN")
  110. }
  111. }
  112. // ── NewModuleRouter ────────────────────────────────────────────────────────────
  113. func TestNewModuleRouter_Basic(t *testing.T) {
  114. option := RouterOption{
  115. ModuleName: "test-module",
  116. AdminOnly: false,
  117. RequireLAN: false,
  118. // UserHandler and DeniedHandler left nil — not called in constructor
  119. }
  120. router := NewModuleRouter(option)
  121. if router == nil {
  122. t.Fatal("NewModuleRouter returned nil")
  123. }
  124. if router.moduleUUID != "test-module" {
  125. t.Errorf("expected moduleUUID='test-module', got %q", router.moduleUUID)
  126. }
  127. if router.adminOnly {
  128. t.Error("expected adminOnly=false")
  129. }
  130. if router.requireLAN {
  131. t.Error("expected requireLAN=false")
  132. }
  133. if router.endpoints == nil {
  134. t.Error("endpoints map should be initialized")
  135. }
  136. if len(router.endpoints) != 0 {
  137. t.Errorf("expected 0 endpoints initially, got %d", len(router.endpoints))
  138. }
  139. }
  140. func TestNewModuleRouter_AdminOnly(t *testing.T) {
  141. option := RouterOption{
  142. ModuleName: "admin-module",
  143. AdminOnly: true,
  144. }
  145. router := NewModuleRouter(option)
  146. if !router.adminOnly {
  147. t.Error("expected adminOnly=true")
  148. }
  149. }
  150. func TestNewModuleRouter_RequireLAN(t *testing.T) {
  151. option := RouterOption{
  152. ModuleName: "lan-module",
  153. RequireLAN: true,
  154. }
  155. router := NewModuleRouter(option)
  156. if !router.requireLAN {
  157. t.Error("expected requireLAN=true")
  158. }
  159. }
  160. // ── RouterOption struct ────────────────────────────────────────────────────────
  161. func TestRouterOption_Fields(t *testing.T) {
  162. option := RouterOption{
  163. ModuleName: "my-module",
  164. AdminOnly: true,
  165. RequireLAN: true,
  166. RequireCSRFT: false,
  167. }
  168. if option.ModuleName != "my-module" {
  169. t.Errorf("unexpected ModuleName: %s", option.ModuleName)
  170. }
  171. if !option.AdminOnly {
  172. t.Error("expected AdminOnly=true")
  173. }
  174. if !option.RequireLAN {
  175. t.Error("expected RequireLAN=true")
  176. }
  177. }
  178. // ── privateRanges ──────────────────────────────────────────────────────────────
  179. func TestPrivateRanges_NonEmpty(t *testing.T) {
  180. if len(privateRanges) == 0 {
  181. t.Error("privateRanges should not be empty")
  182. }
  183. }
  184. func TestPrivateRanges_Contains10Block(t *testing.T) {
  185. found := false
  186. for _, r := range privateRanges {
  187. if r.start.String() == "10.0.0.0" {
  188. found = true
  189. break
  190. }
  191. }
  192. if !found {
  193. t.Error("privateRanges should contain the 10.0.0.0/8 range")
  194. }
  195. }
  196. // TestHandleFunc_DuplicateEndpoint verifies that registering the same endpoint
  197. // twice returns an error on the second call (before the UserHandler is accessed).
  198. func TestHandleFunc_DuplicateEndpoint(t *testing.T) {
  199. router := NewModuleRouter(RouterOption{ModuleName: "dup-module"})
  200. // Pre-populate the endpoints map directly (we're in the same package).
  201. dummyHandler := func(w http.ResponseWriter, r *http.Request) {}
  202. router.endpoints["/test/dup"] = dummyHandler
  203. err := router.HandleFunc("/test/dup", dummyHandler)
  204. if err == nil {
  205. t.Error("expected error for duplicate endpoint registration, got nil")
  206. }
  207. if err.Error() != "Endpoint register duplicated" {
  208. t.Errorf("unexpected error message: %q", err.Error())
  209. }
  210. }