mirror of
https://github.com/lukaszraczylo/mcp-captcharesolver.git
synced 2026-10-17 01:17:39 +00:00
feat(stealth): embeddable evasion init script with apply hints
This commit is contained in:
@@ -0,0 +1,25 @@
|
|||||||
|
(() => {
|
||||||
|
// navigator.webdriver
|
||||||
|
Object.defineProperty(navigator, 'webdriver', { get: () => undefined });
|
||||||
|
// languages
|
||||||
|
Object.defineProperty(navigator, 'languages', { get: () => ['en-US', 'en'] });
|
||||||
|
// plugins (non-empty)
|
||||||
|
Object.defineProperty(navigator, 'plugins', { get: () => [1, 2, 3, 4, 5] });
|
||||||
|
// chrome runtime stub
|
||||||
|
window.chrome = window.chrome || { runtime: {} };
|
||||||
|
// permissions query consistency
|
||||||
|
const origQuery = window.navigator.permissions && window.navigator.permissions.query;
|
||||||
|
if (origQuery) {
|
||||||
|
window.navigator.permissions.query = (params) =>
|
||||||
|
params && params.name === 'notifications'
|
||||||
|
? Promise.resolve({ state: Notification.permission })
|
||||||
|
: origQuery(params);
|
||||||
|
}
|
||||||
|
// WebGL vendor/renderer spoof
|
||||||
|
const getParam = WebGLRenderingContext.prototype.getParameter;
|
||||||
|
WebGLRenderingContext.prototype.getParameter = function (p) {
|
||||||
|
if (p === 37445) return 'Google Inc.'; // UNMASKED_VENDOR_WEBGL
|
||||||
|
if (p === 37446) return 'ANGLE (Generic GPU)'; // UNMASKED_RENDERER_WEBGL
|
||||||
|
return getParam.call(this, p);
|
||||||
|
};
|
||||||
|
})();
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
package stealth
|
||||||
|
|
||||||
|
import _ "embed"
|
||||||
|
|
||||||
|
//go:embed assets/evasions.js
|
||||||
|
var evasionsJS string
|
||||||
|
|
||||||
|
// ScriptParams selects the target engine for apply instructions.
|
||||||
|
type ScriptParams struct {
|
||||||
|
Engine string // playwright | cdp | generic
|
||||||
|
}
|
||||||
|
|
||||||
|
// ApplyInfo tells the caller how to inject the script.
|
||||||
|
type ApplyInfo struct {
|
||||||
|
How string `json:"how"`
|
||||||
|
API string `json:"api"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ScriptResult is the injectable evasion bundle plus metadata.
|
||||||
|
type ScriptResult struct {
|
||||||
|
Script string `json:"script"`
|
||||||
|
Apply ApplyInfo `json:"apply"`
|
||||||
|
IncludedEvasions []string `json:"included_evasions"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// StealthScript returns the evasion init script and engine-specific apply hints.
|
||||||
|
func StealthScript(p ScriptParams) ScriptResult {
|
||||||
|
apply := ApplyInfo{How: "Inject before any page script runs.", API: "page.addInitScript(script)"}
|
||||||
|
switch p.Engine {
|
||||||
|
case "cdp":
|
||||||
|
apply.API = "Page.addScriptToEvaluateOnNewDocument({source: script})"
|
||||||
|
case "generic", "":
|
||||||
|
apply.API = "evaluate the script on every new document before navigation"
|
||||||
|
}
|
||||||
|
return ScriptResult{
|
||||||
|
Script: evasionsJS,
|
||||||
|
Apply: apply,
|
||||||
|
IncludedEvasions: []string{
|
||||||
|
"navigator.webdriver", "navigator.languages", "navigator.plugins",
|
||||||
|
"chrome.runtime", "permissions.query", "WebGL vendor/renderer",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
package stealth
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestStealthScript(t *testing.T) {
|
||||||
|
res := StealthScript(ScriptParams{Engine: "playwright"})
|
||||||
|
if res.Script == "" {
|
||||||
|
t.Fatal("empty script")
|
||||||
|
}
|
||||||
|
for _, want := range []string{"navigator.webdriver", "languages", "WebGL", "chrome"} {
|
||||||
|
if !strings.Contains(res.Script, want) {
|
||||||
|
t.Fatalf("script missing %q", want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if res.Apply.How == "" || len(res.IncludedEvasions) == 0 {
|
||||||
|
t.Fatalf("missing apply metadata: %+v", res)
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user