Files
sif/internal/modules/json_extractor_test.go
T
Tigah 9cf7854ed8 feat(modules): add json extractor (#191)
extract values from a json body by gjson path; the first path that
exists is stored under the extractor name. gjson was already vendored.
2026-06-22 20:26:28 -07:00

87 lines
3.1 KiB
Go

/*
·━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━·
: :
: █▀ █ █▀▀ · Blazing-fast pentesting suite :
: ▄█ █ █▀ · BSD 3-Clause License :
: :
: (c) 2022-2026 vmfunc, xyzeva, :
: lunchcat alumni & contributors :
: :
·━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━·
*/
package modules
import (
"context"
"net/http"
"net/http/httptest"
"testing"
"github.com/dropalldatabases/sif/internal/httpx"
)
func TestRunExtractorsJSON(t *testing.T) {
const body = `{"version":"1.2.3","app":{"name":"sif"},"items":[{"id":7}]}`
resp := fakeResponse(t, 200, nil)
tests := []struct {
name string
paths []string
want string // "" means the extractor should set nothing
}{
{"top level", []string{"version"}, "1.2.3"},
{"nested", []string{"app.name"}, "sif"},
{"array index", []string{"items.0.id"}, "7"},
{"first existing wins", []string{"missing", "version"}, "1.2.3"},
{"no match", []string{"nope"}, ""},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
ex := []Extractor{{Type: "json", Name: "v", Part: "body", JSON: tt.paths}}
got := runExtractors(ex, resp, body)
if tt.want == "" {
if v, ok := got["v"]; ok {
t.Errorf("expected no extraction, got %q", v)
}
return
}
if got["v"] != tt.want {
t.Errorf("got %q, want %q", got["v"], tt.want)
}
})
}
}
func TestExecuteHTTPModuleJSONExtractor(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
w.Header().Set("Content-Type", "application/json")
_, _ = w.Write([]byte(`{"version":"9.9.9"}`))
}))
defer srv.Close()
def := &YAMLModule{
ID: "j",
Type: TypeHTTP,
Info: YAMLModuleInfo{Severity: "info"},
HTTP: &HTTPConfig{
Method: "GET",
Paths: []string{"{{BaseURL}}/"},
Matchers: []Matcher{{Type: "status", Status: []int{200}}},
Extractors: []Extractor{{Type: "json", Name: "version", Part: "body", JSON: []string{"version"}}},
},
}
opts := Options{Timeout: testTimeout, Client: httpx.Client(testTimeout)}
res, err := ExecuteHTTPModule(context.Background(), srv.URL, def, opts)
if err != nil {
t.Fatal(err)
}
if len(res.Findings) != 1 {
t.Fatalf("got %d findings, want 1", len(res.Findings))
}
if got := res.Findings[0].Extracted["version"]; got != "9.9.9" {
t.Errorf("extracted version = %q, want 9.9.9", got)
}
}