mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-10-01 11:42:07 +03:00
feat(sub): make external subscription fetch User-Agent configurable (#6613)
* feat(sub): make external subscription fetch User-Agent configurable Some providers reject fetches that do not send a known client User-Agent. Expose externalSubUserAgent as a panel setting (default v2rayNG/1.8.5) and use it when fetching client external subscription URLs. Fixes #6383 * ci: retrigger frontend after npm registry maintenance The frontend job failed solely on `npm audit` while registry.npmjs.org returned 503 (Service Under Maintenance). Lint, typecheck, vitest, vite build, and storybook all passed. Local `npm audit --omit=dev --audit-level=high` now reports 0 vulnerabilities. * fix(sub): fall back to the default UA when the DB is not initialised externalSubUserAgent read the setting through SettingService.getSetting, which calls Model() on database.GetDB() and panics on a nil *gorm.DB. The fetch path's other DB read, service.ExternalSubscriptionHwid, already treats a nil DB as unreachable and sends no header; the new UA lookup did not, so any fetch before InitDB panicked instead of sending the historical v2rayNG/1.8.5. Production initialises the DB before the sub server starts, but the internal/sub fetch tests run without one: under make test-go's -shuffle=on, whenever one of them ran before the first InitDB test the panic aborted the whole package. Reproduced deterministically with go test -run '^TestDoFetchSubscriptionLinks_RejectsOversizedBody$'. --------- Co-authored-by: mrchatam <mrchatam@users.noreply.github.com> Co-authored-by: MHSanaei <ho3ein.sanaei@gmail.com>
This commit is contained in:
@@ -4,6 +4,7 @@ import (
|
||||
"errors"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
@@ -298,3 +299,57 @@ func TestExpandEntryCacheHitWritesNothing(t *testing.T) {
|
||||
t.Fatalf("cache hit wrote fetch status: %#v", after)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFetchUsesConfiguredExternalSubUserAgent(t *testing.T) {
|
||||
resetSubscriptionCache(t)
|
||||
if err := database.InitDB(filepath.Join(t.TempDir(), "ua.db")); err != nil {
|
||||
t.Fatalf("InitDB: %v", err)
|
||||
}
|
||||
t.Cleanup(func() { _ = database.CloseDB() })
|
||||
|
||||
const customUA = "Happ/4.2.1"
|
||||
if err := database.GetDB().Create(&model.Setting{
|
||||
Key: "externalSubUserAgent",
|
||||
Value: customUA,
|
||||
}).Error; err != nil {
|
||||
t.Fatalf("save setting: %v", err)
|
||||
}
|
||||
|
||||
var gotUA string
|
||||
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
gotUA = r.Header.Get("User-Agent")
|
||||
_, _ = w.Write([]byte("vless://uuid@host:443?security=none#x"))
|
||||
}))
|
||||
defer srv.Close()
|
||||
|
||||
res := fetchSubscriptionLinks(srv.URL)
|
||||
if res.err != nil {
|
||||
t.Fatalf("fetch: %v", res.err)
|
||||
}
|
||||
if gotUA != customUA {
|
||||
t.Fatalf("User-Agent = %q, want %q", gotUA, customUA)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFetchFallsBackToDefaultExternalSubUserAgent(t *testing.T) {
|
||||
resetSubscriptionCache(t)
|
||||
if err := database.InitDB(filepath.Join(t.TempDir(), "ua-default.db")); err != nil {
|
||||
t.Fatalf("InitDB: %v", err)
|
||||
}
|
||||
t.Cleanup(func() { _ = database.CloseDB() })
|
||||
|
||||
var gotUA string
|
||||
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
gotUA = r.Header.Get("User-Agent")
|
||||
_, _ = w.Write([]byte("vless://uuid@host:443?security=none#x"))
|
||||
}))
|
||||
defer srv.Close()
|
||||
|
||||
res := fetchSubscriptionLinks(srv.URL)
|
||||
if res.err != nil {
|
||||
t.Fatalf("fetch: %v", res.err)
|
||||
}
|
||||
if gotUA != "v2rayNG/1.8.5" {
|
||||
t.Fatalf("User-Agent = %q, want default v2rayNG/1.8.5", gotUA)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user