mirror of
https://github.com/lunchcat/sif.git
synced 2026-06-12 19:11:25 -07:00
b4e78114d7
the -js pipeline already pulls every <script> into a buffer but only mined supabase jwts from it. reuse that buffer to run a credential regex bank (aws/github/slack/stripe/google keys, pem blocks, plus entropy-gated generic apikey/secret/token assignments) and a linkfinder-style endpoint extractor that resolves relatives to absolute urls. both dedupe across scripts and surface through the existing js logger and result struct, no new flag.
107 lines
3.7 KiB
Go
107 lines
3.7 KiB
Go
/*
|
|
·━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━·
|
|
: :
|
|
: █▀ █ █▀▀ · Blazing-fast pentesting suite :
|
|
: ▄█ █ █▀ · BSD 3-Clause License :
|
|
: :
|
|
: (c) 2022-2026 vmfunc, xyzeva, :
|
|
: lunchcat alumni & contributors :
|
|
: :
|
|
·━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━·
|
|
*/
|
|
|
|
package js
|
|
|
|
import (
|
|
"slices"
|
|
"testing"
|
|
)
|
|
|
|
func TestExtractEndpoints(t *testing.T) {
|
|
const base = "https://example.com/static/app.js"
|
|
|
|
tests := []struct {
|
|
name string
|
|
content string
|
|
wantSome []string // each must appear in the result
|
|
wantAbsent []string // none of these may appear
|
|
}{
|
|
{
|
|
name: "root-relative api path resolves to absolute",
|
|
content: `fetch("/api/users")`,
|
|
wantSome: []string{"https://example.com/api/users"},
|
|
},
|
|
{
|
|
name: "absolute url passes through untouched",
|
|
content: `const u = "https://api.example.org/v1/login";`,
|
|
wantSome: []string{"https://api.example.org/v1/login"},
|
|
},
|
|
{
|
|
name: "dotted-relative path resolves against base dir",
|
|
content: `import("./chunks/main.js")`,
|
|
wantSome: []string{"https://example.com/static/chunks/main.js"},
|
|
},
|
|
{
|
|
name: "query string is preserved",
|
|
content: `axios.get("/api/search?q=test")`,
|
|
wantSome: []string{"https://example.com/api/search?q=test"},
|
|
},
|
|
{
|
|
name: "mime types are filtered out",
|
|
content: `headers["Content-Type"] = "application/json"; var t = "text/html";`,
|
|
wantAbsent: []string{"application/json", "text/html"},
|
|
},
|
|
{
|
|
name: "single words without a slash are ignored",
|
|
content: `var x = "hello"; var y = "world";`,
|
|
wantAbsent: []string{"hello", "world"},
|
|
},
|
|
{
|
|
name: "multiple endpoints deduped",
|
|
content: `fetch("/api/users"); fetch("/api/users"); fetch("/api/posts");`,
|
|
wantSome: []string{
|
|
"https://example.com/api/users",
|
|
"https://example.com/api/posts",
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
got := ExtractEndpoints(tt.content, base)
|
|
|
|
for _, want := range tt.wantSome {
|
|
if !slices.Contains(got, want) {
|
|
t.Errorf("expected %q in %v", want, got)
|
|
}
|
|
}
|
|
for _, absent := range tt.wantAbsent {
|
|
if slices.Contains(got, absent) {
|
|
t.Errorf("did not expect %q in %v", absent, got)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestExtractEndpointsDedupes(t *testing.T) {
|
|
got := ExtractEndpoints(`fetch("/api/x"); fetch("/api/x");`, "https://example.com/app.js")
|
|
count := 0
|
|
for i := 0; i < len(got); i++ {
|
|
if got[i] == "https://example.com/api/x" {
|
|
count++
|
|
}
|
|
}
|
|
if count != 1 {
|
|
t.Fatalf("expected /api/x once, got %d times in %v", count, got)
|
|
}
|
|
}
|
|
|
|
func TestExtractEndpointsBadBaseKeepsRelatives(t *testing.T) {
|
|
// a base url that won't parse must not drop findings; relatives stay as-is.
|
|
got := ExtractEndpoints(`fetch("/api/users")`, "::not a url::")
|
|
if !slices.Contains(got, "/api/users") {
|
|
t.Errorf("expected relative /api/users preserved, got %v", got)
|
|
}
|
|
}
|