mirror of
https://github.com/shtorm-7/sing-box-extended.git
synced 2026-07-07 08:52:09 +03:00
Merge pull request #105 from Arsolitt/feat/provider-custom-headers
feat(provider): add custom HTTP headers support for remote providers
This commit is contained in:
@@ -47,6 +47,30 @@
|
|||||||
// shareable links, or plain link list.
|
// shareable links, or plain link list.
|
||||||
"url": "https://example.com/subscription.txt",
|
"url": "https://example.com/subscription.txt",
|
||||||
"user_agent": "sing-box",
|
"user_agent": "sing-box",
|
||||||
|
// Custom HTTP headers sent with each subscription request.
|
||||||
|
// Some subscription panels (e.g. Remnawave with incy/happ
|
||||||
|
// integration) require device-identification headers to
|
||||||
|
// return the real server list instead of a dummy config.
|
||||||
|
//
|
||||||
|
// !!! DO NOT COPY THE VALUE BELOW !!!
|
||||||
|
// x-hwid must be generated per-device. A random UUID will
|
||||||
|
// be rejected by the panel. Generate yours on Linux:
|
||||||
|
//
|
||||||
|
// python3 -c "import hashlib,socket,getpass;m=open('/etc/machine-id').read().strip();d=hashlib.sha256(f'{m}|{socket.gethostname()}|Linux|amd64|{getpass.getuser()}'.encode()).hexdigest();h=hashlib.sha256(('incy_hwid_'+d).encode()).hexdigest();print(f'{h[:8]}-{h[8:12]}-{h[12:16]}-{h[16:20]}-{h[20:32]}'.upper())"
|
||||||
|
//
|
||||||
|
// Algorithm: SHA256("incy_hwid_" + SHA256(deviceId))
|
||||||
|
// Linux deviceId: "machineId|hostname|Linux|amd64|user"
|
||||||
|
// Android deviceId: "androidId|manufacturer|model|brand|device|product|board|hardware"
|
||||||
|
// Ref: https://github.com/INCY-DEV/incy-docs/blob/main/ru/dev-docs/hwid.md
|
||||||
|
"headers": {
|
||||||
|
"x-hwid": ["REPLACE_WITH_GENERATED_HWID"],
|
||||||
|
// Platform: linux, android, ios, windows, macos
|
||||||
|
"x-device-os": ["linux"],
|
||||||
|
// OS version — on Linux: uname -r
|
||||||
|
"x-ver-os": ["6.12.0-arch1-1"],
|
||||||
|
// Device model — on Linux: uname -m
|
||||||
|
"x-device-model": ["x86_64"]
|
||||||
|
},
|
||||||
// Fetch the subscription through this outbound instead of the
|
// Fetch the subscription through this outbound instead of the
|
||||||
// default route (useful when the subscription host is blocked).
|
// default route (useful when the subscription host is blocked).
|
||||||
"download_detour": "direct",
|
"download_detour": "direct",
|
||||||
|
|||||||
@@ -55,6 +55,7 @@ type ProviderLocalOptions struct {
|
|||||||
type ProviderRemoteOptions struct {
|
type ProviderRemoteOptions struct {
|
||||||
URL string `json:"url"`
|
URL string `json:"url"`
|
||||||
UserAgent string `json:"user_agent,omitempty"`
|
UserAgent string `json:"user_agent,omitempty"`
|
||||||
|
Headers badoption.HTTPHeader `json:"headers,omitempty"`
|
||||||
DownloadDetour string `json:"download_detour,omitempty"`
|
DownloadDetour string `json:"download_detour,omitempty"`
|
||||||
UpdateInterval badoption.Duration `json:"update_interval,omitempty"`
|
UpdateInterval badoption.Duration `json:"update_interval,omitempty"`
|
||||||
|
|
||||||
|
|||||||
@@ -59,6 +59,7 @@ type ProviderRemote struct {
|
|||||||
updateInterval time.Duration
|
updateInterval time.Duration
|
||||||
exclude *regexp.Regexp
|
exclude *regexp.Regexp
|
||||||
include *regexp.Regexp
|
include *regexp.Regexp
|
||||||
|
headers http.Header
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewProviderRemote(ctx context.Context, router adapter.Router, logFactory log.Factory, tag string, options option.ProviderRemoteOptions) (adapter.Provider, error) {
|
func NewProviderRemote(ctx context.Context, router adapter.Router, logFactory log.Factory, tag string, options option.ProviderRemoteOptions) (adapter.Provider, error) {
|
||||||
@@ -94,6 +95,7 @@ func NewProviderRemote(ctx context.Context, router adapter.Router, logFactory lo
|
|||||||
url: options.URL,
|
url: options.URL,
|
||||||
userAgent: userAgent,
|
userAgent: userAgent,
|
||||||
downloadDetour: options.DownloadDetour,
|
downloadDetour: options.DownloadDetour,
|
||||||
|
headers: options.Headers.Build(),
|
||||||
updateInterval: updateInterval,
|
updateInterval: updateInterval,
|
||||||
exclude: (*regexp.Regexp)(options.Exclude),
|
exclude: (*regexp.Regexp)(options.Exclude),
|
||||||
include: (*regexp.Regexp)(options.Include),
|
include: (*regexp.Regexp)(options.Include),
|
||||||
@@ -191,6 +193,9 @@ func (s *ProviderRemote) fetch(ctx context.Context) error {
|
|||||||
req.Header.Set("If-None-Match", s.lastEtag)
|
req.Header.Set("If-None-Match", s.lastEtag)
|
||||||
}
|
}
|
||||||
req.Header.Set("User-Agent", s.userAgent)
|
req.Header.Set("User-Agent", s.userAgent)
|
||||||
|
for name, values := range s.headers {
|
||||||
|
req.Header[name] = values
|
||||||
|
}
|
||||||
resp, err := client.Do(req.WithContext(ctx))
|
resp, err := client.Do(req.WithContext(ctx))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
Reference in New Issue
Block a user