Nope, sending sec-fetch-* and sec-ch-* (code below) doesn't help. Tried with a Chrome 97 and a Firefox 102 user-agent - slightly different flow, but still end up in an infinite loop. Although maybe they also are using TLS fingerprinting and deny access if it doesn't match the user-agent in the request headers, idk. OTOH, even with TLS fingerprinting it should've worked with a Firefox user-agent because both Firefox and SeaMonkey use the same TLS engine (or at least should use, if I'm interpreting "backported security stuff from the latest FF" in the release notes correctly), so the cipher list should be the same.
Anyway, that was as much time as I could afford wasting on these clowns, sorry.
Code: Select all
// Call obs.unregister() when done.
// Replace obs.observe_impl with your implementation if needed.
var obs = (function(){
var Cc = Components.classes, Ci = Components.interfaces, Cu = Components.utils;
var obs = {observe: function(subject, topic, data){return rc.observe_impl.apply(this, arguments);}};
var rc = {
observe_impl: function(subject, topic, data){},
register: function(){
Cc["@mozilla.org/observer-service;1"].getService(Ci.nsIObserverService)
.addObserver(obs, "http-on-modify-request", false);
},
unregister: function(){
Cc["@mozilla.org/observer-service;1"].getService(Ci.nsIObserverService)
.removeObserver(obs, "http-on-modify-request");
},
};
rc.observe_impl = (function(){
var log = console.error.bind(console);
var matchers = [
{
matcher: /\/cdn-cgi\/challenge-platform\/h\/g\/scripts\/alpha\/invisible\.js/,
headers: {
"sec-fetch-dest": "script",
"sec-fetch-mode": "no-cors",
"sec-fetch-site": "same-origin",
}
},
{
matcher: /\/cdn-cgi\/challenge-platform\/h\/g\/scripts\/pica\.js/,
headers: {
"sec-fetch-dest": "worker",
"sec-fetch-mode": "same-origin",
"sec-fetch-site": "same-origin",
}
},
{
matcher: /\/cdn-cgi\/challenge-platform\/h\/g\/cv\/result\//,
headers: {
"sec-fetch-dest": "empty",
"sec-fetch-mode": "cors",
"sec-fetch-site": "same-origin",
"origin": "https://users.nexusmods.com",
}
},
{
matcher: /users\.nexusmods\.com\/auth\/sign_in/,
headers: {
"sec-fetch-dest": "document",
"sec-fetch-mode": "navigate",
"sec-fetch-site": "same-origin",
"sec-fetch-user": "?1",
"origin": "https://users.nexusmods.com",
"referer": "https://users.nexusmods.com/",
}
},
{
matcher: /\/cdn-cgi\/challenge-platform\/h\/g\/orchestrate\/jsch\/v1\?/,
headers: {
"sec-fetch-dest": "script",
"sec-fetch-mode": "no-cors",
"sec-fetch-site": "same-origin",
}
},
{
matcher: /\/cdn-cgi\/images\/trace\/jsch\/js\/transparent\.gif/,
headers: {
"sec-fetch-dest": "image",
"sec-fetch-mode": "no-cors",
"sec-fetch-site": "same-origin",
}
},
{
matcher: /\/cdn-cgi\/challenge-platform\/h\/g\/flow\/ov1\//,
headers: {
"sec-fetch-dest": "empty",
"sec-fetch-mode": "cors",
"sec-fetch-site": "same-origin",
"origin": "https://users.nexusmods.com",
"referer": "https://users.nexusmods.com/auth/sign_in",
}
},
{
matcher: /\/cdn-cgi\/challenge-platform\/h\/g\/img\//,
headers: {
"sec-fetch-dest": "image",
"sec-fetch-mode": "no-cors",
"sec-fetch-site": "same-origin",
"referer": "https://users.nexusmods.com/auth/sign_in",
}
},
{
matcher: /\/cdn-cgi\/challenge-platform\/h\/g\/pat\//,
headers: {
"sec-fetch-dest": "empty",
"sec-fetch-mode": "cors",
"sec-fetch-site": "same-origin",
"referer": "https://users.nexusmods.com/auth/sign_in",
}
},
].map(function(o){
function make_matcher(v) {
if (typeof(v) === "function") { return v; }
if (v instanceof RegExp) { return function(s){return v.test(s);}; }
// Assume String.
return function(s){return s == v;};
}
o.matches = make_matcher(o.matcher);
return o;
});
return function (channel, topic, data) {
if (topic !== "http-on-modify-request") { return; }
channel.QueryInterface(Components.interfaces.nsIHttpChannel);
channel.setRequestHeader("sec-ch-ua", '"Chromium";v="97", " Not;A Brand";v="99"', false);
channel.setRequestHeader("sec-ch-ua-mobile", "?0", false);
channel.setRequestHeader("sec-ch-ua-platform", '"Windows"', false);
matchers.some(function(o){
if ( ! o.matches(channel.URI.spec, channel)) { return; }
var headers = o.headers;
Object.keys(headers).forEach(function(h){
headers.hasOwnProperty(h) && channel.setRequestHeader(h, headers[h], false);
});
return true;
});
};
})();
rc.register();
return rc;
})();