{
try {
logStore.push({ level, message: args.map(String).join(" "), ts: Date.now() });
if (logStore.length > 200) logStore.shift();
window.__deoxyLogs = logStore;
} catch (error) {}
if (!debug) return;
try {
const handler =
(console && console[level] && console[level].bind(console)) ||
(console && console.log && console.log.bind(console));
if (handler) handler("[deoxy]", ...args);
} catch (error) {}
};
const log = (...args) => writeLog("log", ...args);
const nativePushState = history.pushState.bind(history);
const nativeReplaceState = history.replaceState.bind(history);
const normalizeUrlInput = (input) => {
if (input == null) return null;
if (typeof input === "string") return input;
if (input instanceof URL) return input.toString();
if (typeof input === "object" && "href" in input) {
try {
return String(input.href);
} catch (error) {
return null;
}
}
try {
return String(input);
} catch (error) {
return null;
}
};
log("injected", window.location.href);
try {
document.cookie =
"sfos_deoxy_base=" +
encodeURIComponent(base.origin) +
"; Path=/; SameSite=Lax";
log("cookie set", base.origin);
} catch (error) {
log("cookie set failed", error.message);
}
const skip = (url) => {
if (!url) return true;
return (
url.startsWith(prefix) ||
url.startsWith("about:") ||
url.startsWith("blob:") ||
url.startsWith("data:") ||
url.startsWith("javascript:") ||
url.startsWith("mailto:") ||
url.startsWith("moz-extension:") ||
url.startsWith("safari-extension:") ||
url.startsWith("tel:") ||
url.startsWith("chrome-extension:") ||
url.startsWith("edge:") ||
url.startsWith("#")
);
};
const toDeoxy = (url) => {
if (!url || skip(url)) return url;
try {
const absolute = new URL(url, base);
return prefix + encodeURIComponent(absolute.toString());
} catch (error) {
return url;
}
};
const rewriteIfNeeded = (url, label) => {
const next = toDeoxy(url);
if (next && next !== url) {
log(label, url, "->", next);
}
return next;
};
const ensureDeoxyUrl = (reason) => {
try {
if (window.location.pathname.startsWith("/deoxy")) return;
const current = new URL(window.location.href);
if (current.origin !== window.location.origin) return;
const target = new URL(
current.pathname + current.search + current.hash,
base,
);
const next = prefix + encodeURIComponent(target.toString());
log("guard", reason, current.href, "->", next);
nativeReplaceState({}, "", next);
} catch (error) {
log("guard failed", error.message);
}
};
const rewriteSrcsetValue = (value) => {
if (!value) return value;
return value
.split(",")
.map((entry) => {
const parts = entry.trim().split(/\s+/);
if (!parts.length) return entry;
const rewritten = toDeoxy(parts[0]);
return [rewritten || parts[0], ...parts.slice(1)].join(" ");
})
.join(", ");
};
const rewriteAttribute = (el, attr) => {
if (!el || !el.getAttribute) return;
const value = el.getAttribute(attr);
if (!value) return;
const next = toDeoxy(value);
if (next && next !== value) {
el.setAttribute(attr, next);
}
};
const rewriteElement = (el) => {
if (!el || !el.getAttribute) return;
if (el.hasAttribute("href")) rewriteAttribute(el, "href");
if (el.hasAttribute("src")) rewriteAttribute(el, "src");
if (el.hasAttribute("action")) rewriteAttribute(el, "action");
if (el.hasAttribute("srcset")) {
const value = el.getAttribute("srcset");
const next = rewriteSrcsetValue(value);
if (next && next !== value) {
el.setAttribute("srcset", next);
}
}
};
const rewriteFormAction = (form, label) => {
if (!form || !form.getAttribute) return;
const action = form.getAttribute("action") || base.toString();
const next = rewriteIfNeeded(action, label || "form.action");
if (next && next !== action) {
form.setAttribute("action", next);
}
};
const scan = (root) => {
if (!root) return;
if (root.nodeType === 1) rewriteElement(root);
if (!root.querySelectorAll) return;
root
.querySelectorAll(
"a[href], form[action], link[href], script[src], img[src], iframe[src], source[src], video[src], audio[src]",
)
.forEach((el) => rewriteElement(el));
};
document.addEventListener(
"click",
(event) => {
const anchor = event.target.closest("a[href]");
if (!anchor) return;
const href = anchor.getAttribute("href");
const next = rewriteIfNeeded(href, "navigate");
if (next && next !== href) {
event.preventDefault();
window.location.assign(next);
}
},
true,
);
document.addEventListener(
"submit",
(event) => {
const form = event.target;
if (!form || !form.getAttribute) return;
rewriteFormAction(form, "submit");
},
true,
);
try {
const originalSubmit = HTMLFormElement.prototype.submit;
HTMLFormElement.prototype.submit = function(...args) {
rewriteFormAction(this, "form.submit");
return originalSubmit.apply(this, args);
};
} catch (error) {
log("form.submit override failed", error.message);
}
try {
const originalRequestSubmit = HTMLFormElement.prototype.requestSubmit;
if (originalRequestSubmit) {
HTMLFormElement.prototype.requestSubmit = function(...args) {
rewriteFormAction(this, "form.requestSubmit");
return originalRequestSubmit.apply(this, args);
};
}
} catch (error) {
log("form.requestSubmit override failed", error.message);
}
try {
if (window.location && window.location.assign) {
const originalAssign = window.location.assign.bind(window.location);
window.location.assign = function(url) {
const urlString = normalizeUrlInput(url);
const next = urlString
? rewriteIfNeeded(urlString, "location.assign")
: null;
return originalAssign(next || urlString || url);
};
}
if (window.location && window.location.replace) {
const originalReplace = window.location.replace.bind(window.location);
window.location.replace = function(url) {
const urlString = normalizeUrlInput(url);
const next = urlString
? rewriteIfNeeded(urlString, "location.replace")
: null;
return originalReplace(next || urlString || url);
};
}
const locProto = Object.getPrototypeOf(window.location);
const hrefDesc = Object.getOwnPropertyDescriptor(locProto, "href");
if (hrefDesc && hrefDesc.configurable && hrefDesc.set) {
Object.defineProperty(locProto, "href", {
configurable: true,
enumerable: hrefDesc.enumerable,
get: hrefDesc.get ? hrefDesc.get.bind(window.location) : undefined,
set: function(value) {
const urlString = normalizeUrlInput(value);
const next = urlString
? rewriteIfNeeded(urlString, "location.href")
: null;
return hrefDesc.set.call(this, next || urlString || value);
},
});
} else {
log("location.href override skipped");
}
} catch (error) {
log("location override failed", error.message);
}
["pushState", "replaceState"].forEach((method) => {
const original =
method === "pushState" ? nativePushState : nativeReplaceState;
history[method] = function(state, title, url) {
const urlString = normalizeUrlInput(url);
if (urlString) {
const next = rewriteIfNeeded(urlString, "history." + method);
const result = original.call(this, state, title, next || urlString);
ensureDeoxyUrl("history." + method);
return result;
}
const result = original.call(this, state, title, url);
ensureDeoxyUrl("history." + method);
return result;
};
});
if (window.fetch) {
const originalFetch = window.fetch.bind(window);
window.fetch = function(input, init) {
try {
if (typeof input === "string") {
const next = rewriteIfNeeded(input, "fetch");
if (next && next !== input) {
return originalFetch(next, init);
}
} else if (input instanceof URL) {
const urlString = input.toString();
const next = rewriteIfNeeded(urlString, "fetch");
if (next && next !== urlString) {
return originalFetch(next, init);
}
} else if (input && input.url) {
const next = rewriteIfNeeded(String(input.url), "fetch");
if (next && next !== input.url) {
return originalFetch(new Request(next, input), init);
}
}
} catch (error) {}
return originalFetch(input, init);
};
}
if (window.XMLHttpRequest) {
const originalOpen = XMLHttpRequest.prototype.open;
XMLHttpRequest.prototype.open = function(method, url, ...rest) {
const urlString = normalizeUrlInput(url);
const next = urlString ? rewriteIfNeeded(urlString, "xhr") : null;
return originalOpen.call(this, method, next || urlString || url, ...rest);
};
}
scan(document);
ensureDeoxyUrl("init");
window.addEventListener("popstate", () => ensureDeoxyUrl("popstate"));
window.addEventListener("hashchange", () => ensureDeoxyUrl("hashchange"));
window.setInterval(() => ensureDeoxyUrl("interval"), 1500);
try {
const observer = new MutationObserver((mutations) => {
mutations.forEach((mutation) => {
if (mutation.type === "attributes") {
rewriteElement(mutation.target);
return;
}
if (mutation.type === "childList") {
mutation.addedNodes.forEach((node) => {
if (node.nodeType !== 1) return;
rewriteElement(node);
scan(node);
});
}
});
});
observer.observe(document.documentElement, {
subtree: true,
childList: true,
attributes: true,
attributeFilter: ["href", "src", "action", "srcset"],
});
} catch (error) {
log("mutation observer failed", error.message);
}
})();
div')">