|
|
@@ -0,0 +1,83 @@
|
|
|
+package routes
|
|
|
+
|
|
|
+import (
|
|
|
+ "encoding/base64"
|
|
|
+ "encoding/json"
|
|
|
+ "net/http"
|
|
|
+ "testing"
|
|
|
+ "time"
|
|
|
+
|
|
|
+ "github.com/gofiber/fiber/v2"
|
|
|
+)
|
|
|
+
|
|
|
+func TestTotpViewRoutes(t *testing.T) {
|
|
|
+ app := fiber.New()
|
|
|
+ TotpViewSetup(app, "GEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQ", "view-password")
|
|
|
+
|
|
|
+ for _, path := range []string{"/fwh-totp/", "/fwh-totp/code"} {
|
|
|
+ req, _ := http.NewRequest(http.MethodGet, path, nil)
|
|
|
+ res, err := app.Test(req)
|
|
|
+ if err != nil || res.StatusCode != http.StatusUnauthorized {
|
|
|
+ t.Fatalf("unauthorized %s: status %v, err %v", path, res.StatusCode, err)
|
|
|
+ }
|
|
|
+ if res.Header.Get("Cache-Control") != "no-store, max-age=0" {
|
|
|
+ t.Fatalf("missing no-store on %s", path)
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ req, _ := http.NewRequest(http.MethodGet, "/fwh-totp/code", nil)
|
|
|
+ req.Header.Set("Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte("fwh:wrong")))
|
|
|
+ res, err := app.Test(req)
|
|
|
+ if err != nil || res.StatusCode != http.StatusUnauthorized {
|
|
|
+ t.Fatalf("wrong password: status %v, err %v", res.StatusCode, err)
|
|
|
+ }
|
|
|
+
|
|
|
+ req, _ = http.NewRequest(http.MethodGet, "/fwh-totp/code", nil)
|
|
|
+ req.SetBasicAuth("fwh", "view-password")
|
|
|
+ res, err = app.Test(req)
|
|
|
+ if err != nil || res.StatusCode != http.StatusOK {
|
|
|
+ t.Fatalf("authorized request: status %v, err %v", res.StatusCode, err)
|
|
|
+ }
|
|
|
+ var body struct {
|
|
|
+ Code string `json:"code"`
|
|
|
+ ExpiresAt int64 `json:"expiresAt"`
|
|
|
+ ServerTime int64 `json:"serverTime"`
|
|
|
+ }
|
|
|
+ if err := json.NewDecoder(res.Body).Decode(&body); err != nil {
|
|
|
+ t.Fatal(err)
|
|
|
+ }
|
|
|
+ if len(body.Code) != 6 || body.ExpiresAt-body.ServerTime <= 0 || body.ExpiresAt-body.ServerTime > int64(30*time.Second/time.Millisecond) {
|
|
|
+ t.Fatalf("invalid TOTP response: %+v", body)
|
|
|
+ }
|
|
|
+
|
|
|
+ for _, path := range []string{"/fwh-totp", "/fwh-totp/"} {
|
|
|
+ req, _ = http.NewRequest(http.MethodGet, path, nil)
|
|
|
+ req.SetBasicAuth("fwh", "view-password")
|
|
|
+ res, err = app.Test(req)
|
|
|
+ if err != nil || res.StatusCode != http.StatusOK || res.Header.Get("Content-Type") != "text/html; charset=utf-8" {
|
|
|
+ t.Fatalf("page request %s: status %v, content-type %q, err %v", path, res.StatusCode, res.Header.Get("Content-Type"), err)
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+func TestTotpViewDisabledWithoutPassword(t *testing.T) {
|
|
|
+ app := fiber.New()
|
|
|
+ TotpViewSetup(app, "GEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQ", "")
|
|
|
+ req, _ := http.NewRequest(http.MethodGet, "/fwh-totp/code", nil)
|
|
|
+ res, err := app.Test(req)
|
|
|
+ if err != nil || res.StatusCode != http.StatusNotFound {
|
|
|
+ t.Fatalf("disabled route: status %v, err %v", res.StatusCode, err)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+func TestMainRoutesDoNotExposeTotpView(t *testing.T) {
|
|
|
+ app := fiber.New()
|
|
|
+ Setup(app)
|
|
|
+ for _, path := range []string{"/fwh-totp/", "/fwh-totp/code"} {
|
|
|
+ req, _ := http.NewRequest(http.MethodGet, path, nil)
|
|
|
+ res, err := app.Test(req)
|
|
|
+ if err != nil || res.StatusCode != http.StatusNotFound {
|
|
|
+ t.Fatalf("main app route %s: status %v, err %v", path, res.StatusCode, err)
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|