Add ban tester, signup prep, exit IP intel, and sticky-exit hold.
New GUI tabs probe popular sites for exit-IP bans and prep signup autofill through the chain; Live tab shows geo/ASN/datacenter flags, and sticky-exit keeps the same egress IP during signup flows. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
153
proxy_chain_manager/signup_extension/content.js
Normal file
153
proxy_chain_manager/signup_extension/content.js
Normal file
@@ -0,0 +1,153 @@
|
||||
(function () {
|
||||
"use strict";
|
||||
|
||||
var cfg = null;
|
||||
var filledKeys = {};
|
||||
var startedAt = Date.now();
|
||||
var MAX_MS = 120000;
|
||||
|
||||
function loadConfig(cb) {
|
||||
try {
|
||||
var rt = typeof browser !== "undefined" ? browser : chrome;
|
||||
var url = rt.runtime.getURL("autofill_config.json");
|
||||
fetch(url, { cache: "no-store" })
|
||||
.then(function (r) { return r.json(); })
|
||||
.then(function (j) { cb(j || null); })
|
||||
.catch(function () { cb(null); });
|
||||
} catch (e) {
|
||||
cb(null);
|
||||
}
|
||||
}
|
||||
|
||||
function hostMatches(host, patterns) {
|
||||
if (!patterns || !patterns.length) return true;
|
||||
host = (host || "").toLowerCase();
|
||||
for (var i = 0; i < patterns.length; i++) {
|
||||
var p = String(patterns[i] || "").toLowerCase();
|
||||
if (!p) continue;
|
||||
if (p.indexOf("*") >= 0) {
|
||||
var re = new RegExp("^" + p.replace(/\./g, "\\.").replace(/\*/g, ".*") + "$");
|
||||
if (re.test(host)) return true;
|
||||
} else if (host === p || host.endsWith("." + p)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function setValue(el, value) {
|
||||
if (!el || value == null || value === "") return false;
|
||||
try {
|
||||
el.focus();
|
||||
el.value = value;
|
||||
el.dispatchEvent(new Event("input", { bubbles: true }));
|
||||
el.dispatchEvent(new Event("change", { bubbles: true }));
|
||||
return true;
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function trySelectors(selectors, value) {
|
||||
if (!selectors || !value) return false;
|
||||
for (var i = 0; i < selectors.length; i++) {
|
||||
var nodes = document.querySelectorAll(selectors[i]);
|
||||
for (var j = 0; j < nodes.length; j++) {
|
||||
var el = nodes[j];
|
||||
if (!el || el.disabled || el.readOnly) continue;
|
||||
if (el.type === "hidden") continue;
|
||||
if (setValue(el, value)) return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function runFill() {
|
||||
if (!cfg || !cfg.fields) return;
|
||||
if (Date.now() - startedAt > MAX_MS) return;
|
||||
var host = location.hostname || "";
|
||||
if (cfg.hosts && cfg.hosts.length && !hostMatches(host, cfg.hosts)) return;
|
||||
|
||||
var fields = cfg.fields;
|
||||
var keys = Object.keys(fields);
|
||||
for (var i = 0; i < keys.length; i++) {
|
||||
var key = keys[i];
|
||||
var val = fields[key];
|
||||
if (!val) continue;
|
||||
if (filledKeys[key]) continue;
|
||||
if (trySelectors(fields[key + "_selectors"] || defaultSelectors(key), val)) {
|
||||
filledKeys[key] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function defaultSelectors(key) {
|
||||
var map = {
|
||||
email: [
|
||||
'input[type="email"]',
|
||||
'input[name="email"]',
|
||||
'input[name="Email"]',
|
||||
'input[id="email"]',
|
||||
'input[autocomplete="email"]',
|
||||
'input[autocomplete="username"]',
|
||||
'input[name="identifier"]'
|
||||
],
|
||||
password: [
|
||||
'input[type="password"]:not([name*="Confirm"]):not([name*="confirm"]):not([name*="Again"]):not([name*="again"])',
|
||||
'input[name="password"]',
|
||||
'input[name="Passwd"]',
|
||||
'input[id="password"]',
|
||||
'input[autocomplete="new-password"]'
|
||||
],
|
||||
password_confirm: [
|
||||
'input[name="PasswdAgain"]',
|
||||
'input[name="password_confirm"]',
|
||||
'input[name="confirmPassword"]',
|
||||
'input[name="passwordConfirmation"]',
|
||||
'input[autocomplete="new-password"]:nth-of-type(2)'
|
||||
],
|
||||
first_name: [
|
||||
'input[name="firstName"]',
|
||||
'input[name="firstname"]',
|
||||
'input[name="first_name"]',
|
||||
'input[autocomplete="given-name"]'
|
||||
],
|
||||
last_name: [
|
||||
'input[name="lastName"]',
|
||||
'input[name="lastname"]',
|
||||
'input[name="last_name"]',
|
||||
'input[autocomplete="family-name"]'
|
||||
],
|
||||
username: [
|
||||
'input[name="username"]',
|
||||
'input[name="Username"]',
|
||||
'input[id="username"]',
|
||||
'input[autocomplete="username"]'
|
||||
]
|
||||
};
|
||||
return map[key] || [];
|
||||
}
|
||||
|
||||
function boot() {
|
||||
loadConfig(function (j) {
|
||||
cfg = j;
|
||||
if (!cfg) return;
|
||||
runFill();
|
||||
var obs = new MutationObserver(function () { runFill(); });
|
||||
obs.observe(document.documentElement || document.body, {
|
||||
childList: true,
|
||||
subtree: true
|
||||
});
|
||||
var timer = setInterval(function () {
|
||||
runFill();
|
||||
if (Date.now() - startedAt > MAX_MS) clearInterval(timer);
|
||||
}, 900);
|
||||
});
|
||||
}
|
||||
|
||||
if (document.readyState === "loading") {
|
||||
document.addEventListener("DOMContentLoaded", boot);
|
||||
} else {
|
||||
boot();
|
||||
}
|
||||
})();
|
||||
21
proxy_chain_manager/signup_extension/manifest.json
Normal file
21
proxy_chain_manager/signup_extension/manifest.json
Normal file
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"manifest_version": 2,
|
||||
"name": "Proxy God Signup Autofill",
|
||||
"version": "1.0.0",
|
||||
"description": "Autofills signup forms from Proxy God (manual submit + captcha).",
|
||||
"applications": {
|
||||
"gecko": {
|
||||
"id": "signup-autofill@proxygod"
|
||||
}
|
||||
},
|
||||
"content_scripts": [
|
||||
{
|
||||
"matches": ["<all_urls>"],
|
||||
"js": ["content.js"],
|
||||
"run_at": "document_idle",
|
||||
"all_frames": true
|
||||
}
|
||||
],
|
||||
"permissions": ["<all_urls>"],
|
||||
"web_accessible_resources": ["autofill_config.json"]
|
||||
}
|
||||
Reference in New Issue
Block a user