feat: Add a new cleaner page for managing and automatically cleaning error S2A accounts, supported by new backend services for logging, authentication, and client operations.
This commit is contained in:
261
backend/internal/auth/browser_profiles.go
Normal file
261
backend/internal/auth/browser_profiles.go
Normal file
@@ -0,0 +1,261 @@
|
||||
package auth
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/rand"
|
||||
)
|
||||
|
||||
// ============================================================
|
||||
// 浏览器自动化指纹配置
|
||||
// 用于 chromedp/rod 的随机指纹生成
|
||||
// ============================================================
|
||||
|
||||
// BrowserProfile 浏览器配置档案
|
||||
type BrowserProfile struct {
|
||||
UserAgent string
|
||||
Platform string
|
||||
Width int
|
||||
Height int
|
||||
AcceptLang string
|
||||
ChromeVer string
|
||||
SecChUa string
|
||||
WebGLVendor string
|
||||
WebGLRender string
|
||||
PixelRatio float64
|
||||
MaxTouch int
|
||||
HardwareConc int // navigator.hardwareConcurrency
|
||||
}
|
||||
|
||||
// Windows 配置池
|
||||
var windowsProfiles = []BrowserProfile{
|
||||
{
|
||||
UserAgent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36",
|
||||
Platform: "Win32",
|
||||
Width: 1920, Height: 1080,
|
||||
AcceptLang: "en-US,en;q=0.9",
|
||||
ChromeVer: "133",
|
||||
SecChUa: `"Chromium";v="133", "Not(A:Brand";v="99", "Google Chrome";v="133"`,
|
||||
WebGLVendor: "Google Inc. (NVIDIA)",
|
||||
WebGLRender: "ANGLE (NVIDIA, NVIDIA GeForce RTX 3070 Direct3D11 vs_5_0 ps_5_0, D3D11)",
|
||||
PixelRatio: 1,
|
||||
MaxTouch: 0,
|
||||
HardwareConc: 12,
|
||||
},
|
||||
{
|
||||
UserAgent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36",
|
||||
Platform: "Win32",
|
||||
Width: 2560, Height: 1440,
|
||||
AcceptLang: "en-GB,en;q=0.9",
|
||||
ChromeVer: "132",
|
||||
SecChUa: `"Chromium";v="132", "Not A(Brand";v="99", "Google Chrome";v="132"`,
|
||||
WebGLVendor: "Google Inc. (AMD)",
|
||||
WebGLRender: "ANGLE (AMD, AMD Radeon RX 6800 XT Direct3D11 vs_5_0 ps_5_0, D3D11)",
|
||||
PixelRatio: 1,
|
||||
MaxTouch: 0,
|
||||
HardwareConc: 16,
|
||||
},
|
||||
{
|
||||
UserAgent: "Mozilla/5.0 (Windows NT 11.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36",
|
||||
Platform: "Win32",
|
||||
Width: 1366, Height: 768,
|
||||
AcceptLang: "en-US,en;q=0.9,zh-CN;q=0.8",
|
||||
ChromeVer: "133",
|
||||
SecChUa: `"Chromium";v="133", "Not/A)Brand";v="99", "Google Chrome";v="133"`,
|
||||
WebGLVendor: "Google Inc. (Intel)",
|
||||
WebGLRender: "ANGLE (Intel, Intel(R) UHD Graphics 630 Direct3D11 vs_5_0 ps_5_0, D3D11)",
|
||||
PixelRatio: 1.25,
|
||||
MaxTouch: 0,
|
||||
HardwareConc: 8,
|
||||
},
|
||||
{
|
||||
UserAgent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36",
|
||||
Platform: "Win32",
|
||||
Width: 1680, Height: 1050,
|
||||
AcceptLang: "de-DE,de;q=0.9,en;q=0.8",
|
||||
ChromeVer: "131",
|
||||
SecChUa: `"Chromium";v="131", "Not(A:Brand";v="99", "Google Chrome";v="131"`,
|
||||
WebGLVendor: "Google Inc. (NVIDIA)",
|
||||
WebGLRender: "ANGLE (NVIDIA, NVIDIA GeForce GTX 1660 Super Direct3D11 vs_5_0 ps_5_0, D3D11)",
|
||||
PixelRatio: 1,
|
||||
MaxTouch: 0,
|
||||
HardwareConc: 6,
|
||||
},
|
||||
}
|
||||
|
||||
// macOS 配置池
|
||||
var macProfiles = []BrowserProfile{
|
||||
{
|
||||
UserAgent: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36",
|
||||
Platform: "MacIntel",
|
||||
Width: 1440, Height: 900,
|
||||
AcceptLang: "en-US,en;q=0.9",
|
||||
ChromeVer: "133",
|
||||
SecChUa: `"Chromium";v="133", "Not(A:Brand";v="99", "Google Chrome";v="133"`,
|
||||
WebGLVendor: "Google Inc. (Apple)",
|
||||
WebGLRender: "ANGLE (Apple, Apple M1 Pro, OpenGL 4.1)",
|
||||
PixelRatio: 2,
|
||||
MaxTouch: 0,
|
||||
HardwareConc: 10,
|
||||
},
|
||||
{
|
||||
UserAgent: "Mozilla/5.0 (Macintosh; Intel Mac OS X 14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.6834.110 Safari/537.36",
|
||||
Platform: "MacIntel",
|
||||
Width: 1920, Height: 1200,
|
||||
AcceptLang: "en-GB,en;q=0.9,en-US;q=0.8",
|
||||
ChromeVer: "132",
|
||||
SecChUa: `"Chromium";v="132", "Not A(Brand";v="99", "Google Chrome";v="132"`,
|
||||
WebGLVendor: "Google Inc. (Apple)",
|
||||
WebGLRender: "ANGLE (Apple, Apple M2 Max, OpenGL 4.1)",
|
||||
PixelRatio: 2,
|
||||
MaxTouch: 0,
|
||||
HardwareConc: 12,
|
||||
},
|
||||
{
|
||||
UserAgent: "Mozilla/5.0 (Macintosh; Intel Mac OS X 13_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36",
|
||||
Platform: "MacIntel",
|
||||
Width: 2560, Height: 1600,
|
||||
AcceptLang: "fr-FR,fr;q=0.9,en;q=0.8",
|
||||
ChromeVer: "131",
|
||||
SecChUa: `"Chromium";v="131", "Not/A)Brand";v="99", "Google Chrome";v="131"`,
|
||||
WebGLVendor: "Google Inc. (Apple)",
|
||||
WebGLRender: "ANGLE (Apple, Apple M3, OpenGL 4.1)",
|
||||
PixelRatio: 2,
|
||||
MaxTouch: 0,
|
||||
HardwareConc: 8,
|
||||
},
|
||||
}
|
||||
|
||||
// Linux 配置池
|
||||
var linuxProfiles = []BrowserProfile{
|
||||
{
|
||||
UserAgent: "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36",
|
||||
Platform: "Linux x86_64",
|
||||
Width: 1920, Height: 1080,
|
||||
AcceptLang: "en-US,en;q=0.9",
|
||||
ChromeVer: "133",
|
||||
SecChUa: `"Chromium";v="133", "Not(A:Brand";v="99", "Google Chrome";v="133"`,
|
||||
WebGLVendor: "Google Inc. (AMD)",
|
||||
WebGLRender: "ANGLE (AMD, AMD Radeon Graphics (renoir), OpenGL 4.6)",
|
||||
PixelRatio: 1,
|
||||
MaxTouch: 0,
|
||||
HardwareConc: 8,
|
||||
},
|
||||
{
|
||||
UserAgent: "Mozilla/5.0 (X11; Ubuntu; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36",
|
||||
Platform: "Linux x86_64",
|
||||
Width: 1920, Height: 1200,
|
||||
AcceptLang: "en-GB,en;q=0.9",
|
||||
ChromeVer: "132",
|
||||
SecChUa: `"Chromium";v="132", "Not A(Brand";v="99", "Google Chrome";v="132"`,
|
||||
WebGLVendor: "Google Inc. (NVIDIA)",
|
||||
WebGLRender: "ANGLE (NVIDIA, NVIDIA GeForce RTX 2080, OpenGL 4.6)",
|
||||
PixelRatio: 1,
|
||||
MaxTouch: 0,
|
||||
HardwareConc: 12,
|
||||
},
|
||||
}
|
||||
|
||||
// 合并所有配置
|
||||
var allBrowserProfiles []BrowserProfile
|
||||
|
||||
func init() {
|
||||
allBrowserProfiles = make([]BrowserProfile, 0, 20)
|
||||
// Windows 权重更高(更常见)
|
||||
allBrowserProfiles = append(allBrowserProfiles, windowsProfiles...)
|
||||
allBrowserProfiles = append(allBrowserProfiles, windowsProfiles...)
|
||||
allBrowserProfiles = append(allBrowserProfiles, macProfiles...)
|
||||
allBrowserProfiles = append(allBrowserProfiles, linuxProfiles...)
|
||||
}
|
||||
|
||||
// GetRandomBrowserProfile 获取随机浏览器配置
|
||||
func GetRandomBrowserProfile() BrowserProfile {
|
||||
return allBrowserProfiles[rand.Intn(len(allBrowserProfiles))]
|
||||
}
|
||||
|
||||
// GetAntiDetectionJS 获取反检测 JavaScript 代码
|
||||
func GetAntiDetectionJS(profile BrowserProfile) string {
|
||||
return fmt.Sprintf(`
|
||||
// 隐藏 webdriver
|
||||
Object.defineProperty(navigator, 'webdriver', {
|
||||
get: () => undefined,
|
||||
});
|
||||
|
||||
// 删除 CDP 检测
|
||||
delete window.cdc_adoQpoasnfa76pfcZLmcfl_Array;
|
||||
delete window.cdc_adoQpoasnfa76pfcZLmcfl_Promise;
|
||||
delete window.cdc_adoQpoasnfa76pfcZLmcfl_Symbol;
|
||||
|
||||
// Chrome 对象
|
||||
window.chrome = {
|
||||
runtime: {},
|
||||
loadTimes: function() { return {}; },
|
||||
csi: function() { return {}; },
|
||||
app: {},
|
||||
};
|
||||
|
||||
// 隐藏自动化特征
|
||||
Object.defineProperty(navigator, 'plugins', {
|
||||
get: () => [
|
||||
{ name: 'Chrome PDF Plugin', filename: 'internal-pdf-viewer', description: 'Portable Document Format' },
|
||||
{ name: 'Chrome PDF Viewer', filename: 'mhjfbmdgcfjbbpaeojofohoefgiehjai', description: '' },
|
||||
{ name: 'Native Client', filename: 'internal-nacl-plugin', description: '' },
|
||||
],
|
||||
});
|
||||
|
||||
Object.defineProperty(navigator, 'languages', {
|
||||
get: () => ['%s'.split(',')[0], 'en'],
|
||||
});
|
||||
|
||||
Object.defineProperty(navigator, 'platform', {
|
||||
get: () => '%s',
|
||||
});
|
||||
|
||||
Object.defineProperty(navigator, 'hardwareConcurrency', {
|
||||
get: () => %d,
|
||||
});
|
||||
|
||||
Object.defineProperty(navigator, 'deviceMemory', {
|
||||
get: () => 8,
|
||||
});
|
||||
|
||||
Object.defineProperty(screen, 'colorDepth', {
|
||||
get: () => 24,
|
||||
});
|
||||
|
||||
// 伪装 WebGL
|
||||
const getParameterProxyHandler = {
|
||||
apply: function(target, thisArg, args) {
|
||||
const param = args[0];
|
||||
const gl = thisArg;
|
||||
// UNMASKED_VENDOR_WEBGL
|
||||
if (param === 37445) {
|
||||
return '%s';
|
||||
}
|
||||
// UNMASKED_RENDERER_WEBGL
|
||||
if (param === 37446) {
|
||||
return '%s';
|
||||
}
|
||||
return Reflect.apply(target, thisArg, args);
|
||||
}
|
||||
};
|
||||
|
||||
const originalGetParameter = WebGLRenderingContext.prototype.getParameter;
|
||||
WebGLRenderingContext.prototype.getParameter = new Proxy(originalGetParameter, getParameterProxyHandler);
|
||||
|
||||
const originalGetParameter2 = WebGL2RenderingContext.prototype.getParameter;
|
||||
WebGL2RenderingContext.prototype.getParameter = new Proxy(originalGetParameter2, getParameterProxyHandler);
|
||||
|
||||
// Permissions API
|
||||
const originalQuery = window.Permissions.prototype.query;
|
||||
window.Permissions.prototype.query = (parameters) => (
|
||||
parameters.name === 'notifications' ?
|
||||
Promise.resolve({ state: Notification.permission }) :
|
||||
originalQuery(parameters)
|
||||
);
|
||||
`, profile.AcceptLang, profile.Platform, profile.HardwareConc, profile.WebGLVendor, profile.WebGLRender)
|
||||
}
|
||||
|
||||
// GetBrowserProfileCount 获取浏览器配置数量
|
||||
func GetBrowserProfileCount() int {
|
||||
return len(allBrowserProfiles)
|
||||
}
|
||||
@@ -10,11 +10,15 @@ import (
|
||||
|
||||
"github.com/chromedp/cdproto/fetch"
|
||||
"github.com/chromedp/cdproto/network"
|
||||
"github.com/chromedp/cdproto/page"
|
||||
"github.com/chromedp/chromedp"
|
||||
)
|
||||
|
||||
// CompleteWithChromedp 使用 chromedp 完成 S2A OAuth 授权
|
||||
func CompleteWithChromedp(authURL, email, password, teamID string, headless bool, proxy string) (string, error) {
|
||||
// 获取随机浏览器配置
|
||||
profile := GetRandomBrowserProfile()
|
||||
|
||||
var proxyServer string
|
||||
var proxyUser string
|
||||
var proxyPass string
|
||||
@@ -36,7 +40,16 @@ func CompleteWithChromedp(authURL, email, password, teamID string, headless bool
|
||||
chromedp.Flag("no-sandbox", true),
|
||||
chromedp.Flag("disable-dev-shm-usage", true),
|
||||
chromedp.Flag("disable-blink-features", "AutomationControlled"),
|
||||
chromedp.UserAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36"),
|
||||
chromedp.Flag("disable-automation", true),
|
||||
chromedp.Flag("disable-extensions", true),
|
||||
chromedp.Flag("disable-infobars", true),
|
||||
chromedp.Flag("enable-features", "NetworkService,NetworkServiceInProcess"),
|
||||
// 使用随机 User-Agent
|
||||
chromedp.UserAgent(profile.UserAgent),
|
||||
// 使用随机窗口大小
|
||||
chromedp.WindowSize(profile.Width, profile.Height),
|
||||
// 随机语言
|
||||
chromedp.Flag("accept-lang", profile.AcceptLang),
|
||||
)
|
||||
|
||||
if proxyServer != "" {
|
||||
@@ -99,9 +112,17 @@ func CompleteWithChromedp(authURL, email, password, teamID string, headless bool
|
||||
}
|
||||
})
|
||||
|
||||
// 获取反检测脚本
|
||||
antiDetectionJS := GetAntiDetectionJS(profile)
|
||||
|
||||
// 构建运行任务
|
||||
tasks := []chromedp.Action{
|
||||
network.Enable(),
|
||||
// 在每个新文档加载时注入反检测脚本
|
||||
chromedp.ActionFunc(func(ctx context.Context) error {
|
||||
_, err := page.AddScriptToEvaluateOnNewDocument(antiDetectionJS).Do(ctx)
|
||||
return err
|
||||
}),
|
||||
chromedp.Navigate(authURL),
|
||||
chromedp.WaitReady("body"),
|
||||
}
|
||||
|
||||
@@ -16,11 +16,12 @@ import (
|
||||
|
||||
// RodAuth 使用 Rod + Stealth 完成 OAuth 授权
|
||||
type RodAuth struct {
|
||||
browser *rod.Browser
|
||||
headless bool
|
||||
proxy string
|
||||
browser *rod.Browser
|
||||
headless bool
|
||||
proxy string
|
||||
proxyUser string
|
||||
proxyPass string
|
||||
profile BrowserProfile // 随机浏览器配置
|
||||
}
|
||||
|
||||
// getChromiumPath 获取 Chromium 路径
|
||||
@@ -53,6 +54,9 @@ func getChromiumPath() string {
|
||||
|
||||
// NewRodAuth 创建 Rod 授权器
|
||||
func NewRodAuth(headless bool, proxy string) (*RodAuth, error) {
|
||||
// 获取随机浏览器配置
|
||||
profile := GetRandomBrowserProfile()
|
||||
|
||||
var proxyServer string
|
||||
var proxyUser string
|
||||
var proxyPass string
|
||||
@@ -82,7 +86,15 @@ func NewRodAuth(headless bool, proxy string) (*RodAuth, error) {
|
||||
Set("disable-sync").
|
||||
Set("disable-translate").
|
||||
Set("metrics-recording-only").
|
||||
Set("no-first-run")
|
||||
Set("no-first-run").
|
||||
Set("disable-infobars").
|
||||
Set("disable-automation").
|
||||
// 使用随机语言和窗口大小
|
||||
Set("lang", strings.Split(profile.AcceptLang, ",")[0]).
|
||||
Set("window-size", fmt.Sprintf("%d,%d", profile.Width, profile.Height)).
|
||||
// 随机 User-Agent
|
||||
UserDataDir("").
|
||||
Set("user-agent", profile.UserAgent)
|
||||
|
||||
// 使用系统 Chromium(如果存在)
|
||||
if chromiumPath := getChromiumPath(); chromiumPath != "" {
|
||||
@@ -104,11 +116,12 @@ func NewRodAuth(headless bool, proxy string) (*RodAuth, error) {
|
||||
}
|
||||
|
||||
return &RodAuth{
|
||||
browser: browser,
|
||||
headless: headless,
|
||||
proxy: proxy,
|
||||
browser: browser,
|
||||
headless: headless,
|
||||
proxy: proxy,
|
||||
proxyUser: proxyUser,
|
||||
proxyPass: proxyPass,
|
||||
profile: profile,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -161,6 +174,23 @@ func (r *RodAuth) CompleteOAuth(authURL, email, password, teamID string) (string
|
||||
}
|
||||
defer page.Close()
|
||||
|
||||
// 设置随机窗口大小
|
||||
_ = page.SetViewport(&proto.EmulationSetDeviceMetricsOverride{
|
||||
Width: r.profile.Width,
|
||||
Height: r.profile.Height,
|
||||
DeviceScaleFactor: r.profile.PixelRatio,
|
||||
Mobile: false,
|
||||
})
|
||||
|
||||
// 注入额外的反检测脚本
|
||||
antiDetectionJS := GetAntiDetectionJS(r.profile)
|
||||
_, _ = page.Evaluate(&rod.EvalOptions{
|
||||
JS: antiDetectionJS,
|
||||
ByValue: true,
|
||||
AwaitPromise: false,
|
||||
ThisObj: nil,
|
||||
})
|
||||
|
||||
// 增加超时时间到 90 秒
|
||||
page = page.Timeout(90 * time.Second)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user