Skip to content

Commit 5119f9c

Browse files
committed
ci: run go vet and go test; fix wp-confusion vet; document JWKS auth
- Remove redundant newlines in fmt.Println (go vet) in wp-confusion. - CI: vet + test before build. - DASHBOARD_AUTH: HS256 + JWKS (RS256/ES256), env table aligned with server. Made-with: Cursor
1 parent 87ea02c commit 5119f9c

3 files changed

Lines changed: 25 additions & 14 deletions

File tree

.github/workflows/ci.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,12 @@ jobs:
3030
- name: Download dependencies
3131
run: go mod download
3232

33+
- name: Vet
34+
run: CGO_ENABLED=1 go vet ./...
35+
36+
- name: Test
37+
run: CGO_ENABLED=1 go test ./...
38+
3339
- name: Build
3440
run: |
3541
CGO_ENABLED=1 go build -o autoar ./cmd/autoar

docs/DASHBOARD_AUTH.md

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,24 +6,29 @@ When the AutoAR HTTP API is exposed on the public internet, enable JWT verificat
66

77
| Variable | Required | Description |
88
|----------|----------|-------------|
9-
| `SUPABASE_JWT_SECRET` | For production | **JWT Secret** from Supabase → Project Settings → API (same value used to sign user JWTs). If unset, the API does **not** require auth (local development). |
10-
| `SUPABASE_URL` | Yes (for login UI) | Project URL, e.g. `https://xxxx.supabase.co` |
11-
| `SUPABASE_ANON_KEY` | Yes (for login UI) | **anon** / **public** key from Supabase → Settings → API. Safe to expose to the browser. **Never** put the `service_role` key here. |
9+
| `SUPABASE_URL` | Yes (for login UI + asymmetric JWTs) | Project URL, e.g. `https://xxxx.supabase.co`. Used to fetch **JWKS** at `{SUPABASE_URL}/auth/v1/.well-known/jwks.json` for **RS256** / **ES256** access tokens (Supabase “new JWT signing keys”). |
10+
| `SUPABASE_JWT_SECRET` | For **HS256** (legacy) | **JWT Secret** from Supabase → Project Settings → API. Used to verify **HS256** tokens. If the project only issues **ES256/RS256** keys, verification is still done via **JWKS**; keep this set if you also rely on legacy symmetric signing. |
11+
| `SUPABASE_ANON_KEY` | Yes (for login UI) | **anon** / **publishable** key from Supabase → Settings → API. Safe to expose to the browser via `/api/config`. **Never** put the `service_role` / `sb_secret_*` key here. |
12+
| `SUPABASE_SECRET_KEY` | Server-only | Privileged key for server-side Supabase APIs if you add them later — **never** expose to the UI or `/api/config`. |
1213
| `CORS_ALLOWED_ORIGINS` | If UI is on another origin | Comma-separated list, e.g. `https://dash.example.com`. If unset, `Access-Control-Allow-Origin: *` is used (development only). |
1314

1415
## Supabase project setup
1516

1617
1. Enable **Email** provider (or another provider) under Authentication → Providers.
1718
2. Create a user under **Authentication → Users** (or enable sign-ups).
18-
3. Copy **JWT Secret**, **Project URL**, and **anon public** key into your server environment.
19+
3. Copy **JWT Secret** (if using legacy HS256), **Project URL**, and **anon public** key into your server environment.
1920

2021
## Behaviour
2122

2223
- `GET /api/config` stays **public** so the SPA can read `auth_enabled` and Supabase URL/key before login.
2324
- `GET /health` stays **public** for uptime checks.
2425
- The UI loads `@supabase/supabase-js` from CDN, signs in with email/password, and sends `Authorization: Bearer <access_token>` on API calls.
25-
- The Go API verifies the HS256 signature using `SUPABASE_JWT_SECRET`.
26+
- The Go API verifies access tokens as follows:
27+
- **HS256:** HMAC with `SUPABASE_JWT_SECRET` (optionally after base64-decoding the secret, matching Supabase’s storage format).
28+
- **RS256 / ES256:** asymmetric keys loaded from **JWKS** at `{SUPABASE_URL}/auth/v1/.well-known/jwks.json` (required for projects using Supabase’s new signing keys).
29+
30+
If neither `SUPABASE_JWT_SECRET` nor `SUPABASE_URL` is set, protected routes do not enforce JWT (local development only).
2631

2732
## Local development
2833

29-
Leave `SUPABASE_JWT_SECRET` unset: the dashboard works without a login panel.
34+
Leave `SUPABASE_JWT_SECRET` and `SUPABASE_URL` unset: the dashboard can run without a login gate (API auth middleware is a no-op).

internal/modules/wp-confusion/confusion.go

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -99,34 +99,34 @@ func ScanWPConfusion(opts ScanOptions) error {
9999

100100
for _, targetURL := range urls {
101101
vulnerable := []string{}
102-
fmt.Println("-------------------------\n")
102+
fmt.Println("-------------------------")
103103
fmt.Printf("[i] Target: %s\n\n", targetURL)
104104

105105
if opts.Theme {
106-
fmt.Println("[i] Searching theme\n")
106+
fmt.Println("[i] Searching theme")
107107
themeName := detectTheme(targetURL)
108108
if themeName != "" {
109109
fmt.Printf("[i] Found WP theme: %s\n\n", themeName)
110110
if isVulnerable := checkWordPressOrgTheme(themeName); isVulnerable {
111-
fmt.Println("\t[!] Vulnerable to WP Theme Confusion attack\n")
111+
fmt.Println("\t[!] Vulnerable to WP Theme Confusion attack")
112112
fmt.Printf("\t[!] %s/wp-content/themes/%s\n", targetURL, themeName)
113113
fmt.Printf("\t[!] https://wordpress.org/themes/%s\n\n", themeName)
114114
vulnerable = append(vulnerable, fmt.Sprintf("%s/wp-content/themes/%s", targetURL, themeName))
115115
} else {
116-
fmt.Println("\t[i] Not vulnerable\n")
116+
fmt.Println("\t[i] Not vulnerable")
117117
}
118118
}
119119
}
120120

121121
if opts.Plugins {
122-
fmt.Println("[i] Searching plugins\n")
122+
fmt.Println("[i] Searching plugins")
123123
pluginList := detectPlugins(targetURL)
124124

125125
for _, plugin := range pluginList {
126126
fmt.Printf("[i] Found WP plugin: %s\n", plugin)
127127

128128
if !isAllowedSlug(plugin) {
129-
fmt.Println("\t[i] Not vulnerable - disallowed name\n")
129+
fmt.Println("\t[i] Not vulnerable - disallowed name")
130130
continue
131131
}
132132

@@ -154,12 +154,12 @@ func ScanWPConfusion(opts ScanOptions) error {
154154
}
155155

156156
if isVulnerable := checkWordPressOrgPlugin(plugin); isVulnerable {
157-
fmt.Println("\t[!] Vulnerable to WP Plugin Confusion attack\n")
157+
fmt.Println("\t[!] Vulnerable to WP Plugin Confusion attack")
158158
fmt.Printf("\t[!] %s/wp-content/plugins/%s\n", targetURL, plugin)
159159
fmt.Printf("\t[!] https://wordpress.org/plugins/%s\n\n", plugin)
160160
vulnerable = append(vulnerable, fmt.Sprintf("%s/wp-content/plugins/%s", targetURL, plugin))
161161
} else {
162-
fmt.Println("\t[i] Not vulnerable - already claimed\n")
162+
fmt.Println("\t[i] Not vulnerable - already claimed")
163163
}
164164
}
165165
}

0 commit comments

Comments
 (0)