Как вызвать GM_xmlhttpRequest на веб-странице? - PullRequest
1 голос
/ 24 марта 2012

Мне нужно вызвать кросс-домен GM_xmlhttpRequest, который будет вызван событием на веб-странице.

Как получить доступ к функциям в изолированной программной среде greasemonkey с веб-страницы?

1 Ответ

1 голос
/ 24 марта 2012

Чтобы страницы могли использовать GM_xmlhttpRequest, вам необходимо:

  1. Перезаписать unsafeWindow.XMLHttpRequest пользовательским методом.
  2. Обойти защиту, обнаружив любые желаемые запросы с помощью опроса, например, setInterval.

Ранее я писал такой сценарий пользователя для личного использования по локальному протоколу. Не злоупотребляйте этим , и создайте очень строгие шаблоны сопоставления, чтобы предотвратить раскрытие XHR между сайтами произвольным веб-сайтам.

Код выполняет следующие действия:

  • Переместить исходный объект XMLHttpRequest в unsafeWindow.GM_XHR.original.
  • Чтобы восстановить исходный объект, вызовите GM_XHR.restore().
  • Объект XMLHttpRequest перезаписывается пользовательским методом, который добавляет любые запросы в очередь массивов.
  • Поллер периодически проверяет содержимое очереди и выполняет все запросы.

Межсайтовый XMLHttpRequest, пользовательский скрипт greasemonkey

// ==UserScript==
// @name           Cross-site XMLHttpRequest
// @namespace      Rob W
// @description    Enables cross-site XHR
// @include        file:///home/*
// ==/UserScript==

/*
 * http://www.w3.org/TR/XMLHttpRequest
 * http://wiki.greasespot.net/GM_xmlhttpRequest
 * https://developer.mozilla.org/en/XMLHttpRequest
 * 
 * https://developer.mozilla.org/En/nsIDOMProgressEvent
 * https://developer.mozilla.org/en/nsIChannel
 */

// Configuration. Allow paths via a RegExp:
var enabled = [
    "^file:///home/rob/Documenten/etc/",
    "^file:///home/rob/Documenten/test\.html$"
];

var XHR = {
    allowed: new RegExp(enabled.join("|")),
    allowed_atm: function(url){
        return XHR.allowed.test(url || location.protocol + "//" + location.pathname)
    },
    original: unsafeWindow.XMLHttpRequest,
    restore: function(){
        unsafeWindow.XMLHttpRequest = XHR.original;
    }
};
if (XHR.allowed_atm()) {
    // Request queue
    var reqs = [];

    // Inititate the actual gm_xmlhttpRequest.
    // Also define the `.abort()` method
    var do_xmlHttpRequest = function(details) {
        details.abort = GM_xmlhttpRequest(details).abort;
    }

    // Set poller, used to circumvent the security policy
    window.setInterval(function(){
        while(reqs.length) {
            do_xmlHttpRequest(reqs.shift());
        }
    }, 50);

    // unsafeWindow.XMLHttpRequest will be overwritten by:
    var xmlhttprequest = function() {
        var o = {headers: {}},
            t = this,
            sent = false,
            currentHeaders = "";

        t.channel = {
            name: ""
        };

        o.onprogress = function(r){
            if(r.lengthComputable) {
                t.channel.contentLength = r.total;
                currentHeaders = "Content-Length: " + r.total;
            }
            t.status = r.status;
            t.statusText = r.statusText;
            t.channel.name = r.finalUrl;
        };

        t.abort = function() {
            if(typeof o.abort == "function") o.abort();
            else t.onreadystatechange = null;
            sent = false;
        };
        t.getAllResponseHeaders = function() {
            return t.responseHeaders ? t.responseHeaders + (/(^|\n)Content-Length:\s?\d/i.test(t.responseHeaders)?"":"\n" + currentHeaders) : currentHeaders;
        };
        t.getResponseHeader = function(header) {
            console_log("Method not supported. getResponseHeader: " + header);
            return "";
        };
        t.open = function(method, url, async, user, password) {
            o.method = method;
            o.url = url;
            t.channel.name = url; //finalUrl?
            //o.synchronous = !async; //Not implemented for safety reasons
            if (typeof user != "undefined") o.user = user;
            if (typeof password != "undefined") o.password = password;
        };
        t.overrideMimeType = function(mimetype) {
            o.overrideMimeType = mimetype;
        };
        t.send = function(data){
            var readyState4reached = false;
            if (typeof t.onabort == "function") r.onabort = t.onabort;
            if (typeof t.onerror == "function") r.onerror = t.onerror;
            o.onload = function(r){
                o.onreadystatechange(r);
                if (typeof t.onload == "function") t.onload();
            };
            o.data = data;
            o.onreadystatechange = function(r) {
                t.channel.name = r.finalUrl;
                if (t.responseHeaders = r.responseHeaders) {
                    var tmp;
                    if(tmp = t.responseHeaders.match(/Content-Length:\s?(\d+)/i)) {
                        t.channel.contentLength = tmp[1];
                    }
                }
                t.readyState = r.readyState;
                t.responseText = r.responseText;
                t.status = r.status;
                t.statusText = r.statusText;
                if(readyState4reached) return;
                if(!readyState4reached && t.readyState == 4) readyState4reached = true;
                typeof t.onreadystatechange == "function" && t.onreadystatechange();
            }
            if(!sent) reqs.push(o);
            sent = true;
        };
        t.setRequestHeader = function(name, value) {
            o.headers[name] = value;
        };
    }
    /* Event binding */
    unsafeWindow.XMLHttpRequest = xmlhttprequest;
    unsafeWindow.GM_XHR = {original: XHR.original, restore: XHR.restore};

    // Log the exposed method in the console, to not forget about it:
    console.log("GM cross-site XHR activated at: " + location.href);
};
...