6

This is an IE-only website, which I want to use with other browsers, for example Firefox:

https://golestan.sbu.ac.ir/Forms/AuthenticateUser/login.htm

I am forced to use this website for my university. It uses Msxml2.XMLHTTP, which is an IE-only feature. I tried to convert it to XMLHttpRequest so it works on Firefox only. This is the Greasemonkey script I've created. Now it does not give error, but it does not work. All the functions come from the original script of the website, but they are changed so that they work with XMLHttpRequest. If the login script comes up, I'm ok with it. How can I debug this javascript?

// ==UserScript==
// @name        Golestan Login
// @namespace   sbu.ac.ir
// @include     https://golestan.sbu.ac.ir/Forms/AuthenticateUser/login.htm
// @version     1
// @grant       none
// ==/UserScript==

var isInternetExplorer = 0;

function check(){
  var x;
if (window.XMLHttpRequest) {
  x = new XMLHttpRequest();
} else {
  try { 
    x = new ActiveXObject("Msxml2.XMLHTTP");
  } catch (e) {
    try { 
      x = new ActiveXObject("Microsoft.XMLHTTP");
    } catch (e) {
      x = false; 
    }
  }
}
  x.open("HEAD",document.location,true);
  x.send();
  var sd=new Date(x.getResponseHeader('Last-Modified'));
  var cd=new Date(document.lastModified);
  if(sd-cd>3660000){
    document.cookie = "reloading=1";
    window.location.reload(true);
    return false;
  }
  return true;
}


        function a(){
            for (k = 0; k < nall; k++) {
                td = document.createElement('TD');
                td.className = 'e';
                Pr.appendChild(td);
            }
            if (!check()) {
                //window.open("/_Templates/howtoclearcache.htm","_blank");
                //top.close();
                return;
            }
            var aCookie = document.cookie.split("; ");
            var cook=0;
            for (var i=0; i < aCookie.length; i++)
            {
                var aCrumb = aCookie[i].split("=");
                if ("reloading" == aCrumb[0]) {
                    cook=unescape(aCrumb[1]);
                    break;
                }
            }
            var ind=0;
            for( i=0;i<all.length;i=i+2){
                if(all[i+1]==1)
                    for(j=0;j<4;j++){
  var r;
if (window.XMLHttpRequest) {
  r = new XMLHttpRequest();
} else {
  try { 
    r = new ActiveXObject("Msxml2.XMLHTTP");
  } catch (e) {
    try { 
      r = new ActiveXObject("Microsoft.XMLHTTP");
    } catch (e) {
      r = false; 
    }
  }
}


                        r.open("GET", all[i]+imstat[j]+".gif", true);
                        if(cook==1) r.setRequestHeader('If-Modified-Since','Sat,01 Jan 2000 00:00:00 GMT');
                        getobj(r,ind++);
                    }
                else{
  var r;
if (window.XMLHttpRequest) {
  r = new XMLHttpRequest();
} else {
  try { 
    r = new ActiveXObject("Msxml2.XMLHTTP");
  } catch (e) {
    try { 
      r = new ActiveXObject("Microsoft.XMLHTTP");
    } catch (e) {
      r = false; 
    }
  }
}                   r.open("GET", all[i], true);
                    if(cook==1) r.setRequestHeader('If-Modified-Since','Sat,01 Jan 2000 00:00:00 GMT');
                    getobj(r,ind++);
                }
            }
            document.cookie = "reloading=0; expires=Fri, 31 Dec 1999 23:59:59 GMT;";
        }

function main_DoFSCommand(command, args) {
    var mainObj = document.all.main;
    //
    // Place your code here.
    //
    document.getElementById("rdir").style.visibility = "hidden";
    if(command != "showmenu")
    if(command == "Animation_Complete")
    {
        var x = 0;
        var y = 0;
        x = main.clientHeight/2 - 300;
        y = main.clientWidth/2 - 400;
        document.getElementById("iframeNews").style.top = x + 120;
        document.getElementById("iframeNews").style.left = y + 264;
        modifySrc();
        document.getElementById("iframeNews").style.visibility = "visible";

    }
    else
    {
        if(command == "Enter")
        {
            bal('main');
        }
        else if(command == "Education")
        {
            bal('test');
        }
        else
            document.getElementById("iframeNews").style.visibility = "hidden";
    }
}

// http://stackoverflow.com/questions/21271997
addJS_Node (check);
addJS_Node (a);
addJS_Node (main_DoFSCommand);

isInternetExplorer=true;

function addJS_Node (text, s_URL, funcToRun, runOnLoad) {
    var D                                   = document;
    var scriptNode                          = D.createElement ('script');
    if (runOnLoad) {
        scriptNode.addEventListener ("load", runOnLoad, false);
    }
    scriptNode.type                         = "text/javascript";
    if (text)       scriptNode.textContent  = text;
    if (s_URL)      scriptNode.src          = s_URL;
    if (funcToRun)  scriptNode.textContent  = '(' + funcToRun.toString() + ')()';

    var targ = D.getElementsByTagName ('head')[0] || D.body || D.documentElement;
    targ.appendChild (scriptNode);
}

I think this work is worth doing, because hundreds of thousans of users, which are university students, are affected.

Update: We could be able to go one level further, and reach main.htm. So, I wrote another script for this page. But, at last I get ReferenceError: element is not defined[Learn More].

// ==UserScript==
// @name        Golestan Main
// @namespace   sbu.ac.ir
// @include     https://golestan.sbu.ac.ir/Forms/AuthenticateUser/main.htm
// @version     1
// @grant       none
// ==/UserScript==

// Microsoft WebService Behavior (Predecessor of modern AJAX)
// Information: https://web.archive.org/web/20060101200359/https://msdn.microsoft.com/workshop/author/webservice/webservice.asp
// JavaScript version: https://raw.githubusercontent.com/nzakas/professional-javascript/master/edition1/ch17/webservice.htc

// NOTE: You should paste the Javascript code from the above URL here

// end Microsoft WebService Behavior


function l(){
            useService("../f0241_process_authexit/authexit.asmx?WSDL", "get");
//            useService("authuser.asmx?WSDL", "get");
            mt = new MainTit(document,titH);
            mt.Maxi();
            t = new Tab(document,titH,0,document.body.clientWidth,document.body.clientHeight-titH);
            t.maintitle=mt;
            OpenFaci('صفحه اصلي','nav.htm?fid=0;1&tck='+'&'+location.search.replace('?',''));
            mt.HideGTit();
            KeysValues = location.search.split(/[\?&]+/);
            for (i = 0; i < KeysValues.length; i++) {
                    KeyValue = KeysValues[i].split("=");
                    if (KeyValue[0] == "CSURL") {
                        CSURL = KeyValue[1];
                        break;
                    }
            }
        }

function ex(ltck,tck,u,si,ft,fid,sess){
            var co = createCallOptions();
                co.funcName = "ex";
                co.async = false;
            // callService(function(result){if(result.error){/*alert(result.errorDetail.string);*/}},"ex",ltck,tck,u,si,ft,fid,sess);
                callService(co,ltck,tck,u,si,ft,fid,sess);

}


addJS_Node (l);
addJS_Node (ex);

addJS_Node(ErrDetail);
addJS_Node(postError);
addJS_Node(returnError);
addJS_Node(createCallOptions);
addJS_Node(createUseOptions);
addJS_Node(cloneObject);
addJS_Node(ensureVBArray);
addJS_Node(encb64hlp);
addJS_Node(decb64hlp);
addJS_Node(encb64);
addJS_Node(decb64);
addJS_Node(ensureWsdlUrl);
addJS_Node(allocCall);
addJS_Node(fnShowProgress);
addJS_Node(isSimpleType);
addJS_Node(isPrimitive);
addJS_Node(getSdl);
addJS_Node(processService);
addJS_Node(onImportLoaded);
addJS_Node(loadImports);
addJS_Node(invokeNext);
addJS_Node(callNext);
addJS_Node(getAttrib);
addJS_Node(getBaseName);
addJS_Node(getQualifier);
addJS_Node(getNextNsq);
addJS_Node(getUniqueNsq);
addJS_Node(parseSimpleType);
addJS_Node(parseType);
addJS_Node(parseArrayType);
addJS_Node(parseComplexType);
addJS_Node(parseAttrib);
addJS_Node(parseElem);
addJS_Node(parseSoapHeader);
addJS_Node(expBase);
addJS_Node(parseSchemas);
addJS_Node(parseSdl);
addJS_Node(ensureXmlHttp);
addJS_Node(encodeHeader);
addJS_Node(_invoke);
addJS_Node(callService);
addJS_Node(useService);
addJS_Node(getMsg);
addJS_Node(fixupDT);
addJS_Node(encTZ);
addJS_Node(encodePrimitive);
addJS_Node(bldJsAry);
addJS_Node(getNextIndexAry);
addJS_Node(vbArrayToJs);
addJS_Node(encodeArray);
addJS_Node(encodeVar);
addJS_Node(getArySize);
addJS_Node(get1stAryItem);
addJS_Node(getAryItemFromIndex);
addJS_Node(getSchema);
addJS_Node(getArySizeInfo);
addJS_Node(encodeAttrib);
addJS_Node(serPart);
addJS_Node(getWrap);
addJS_Node(encodeArgs);
addJS_Node(returnResult);
addJS_Node(decTZ);
addJS_Node(applyTZ);
addJS_Node(decDate);
addJS_Node(decTime);
addJS_Node(decodePrimitive);
addJS_Node(getAryInfo);
addJS_Node(decodeArray);
addJS_Node(decodeAryItem);
addJS_Node(getAryElem);
addJS_Node(decodeElem);
addJS_Node(decodeType);
addJS_Node(processResult);
addJS_Node(hideProgress);
addJS_Node(getResult);


function addJS_Node (text, s_URL, funcToRun, runOnLoad) {
    var D                                   = document;
    var scriptNode                          = D.createElement ('script');
    if (runOnLoad) {
        scriptNode.addEventListener ("load", runOnLoad, false);
    }
    scriptNode.type                         = "text/javascript";
    if (text)       scriptNode.textContent  = text;
    if (s_URL)      scriptNode.src          = s_URL;
    if (funcToRun)  scriptNode.textContent  = '(' + funcToRun.toString() + ')()';

    var targ = D.getElementsByTagName ('head')[0] || D.body || D.documentElement;
    targ.appendChild (scriptNode);
}
Sagar V
  • 12,158
  • 7
  • 41
  • 68
Ho1
  • 1,239
  • 1
  • 11
  • 29
  • Your code should work in all modern browsers.... check that you have not turned off native XMLHTTP support in your version of IE... Tools>Internet Options>Advanced tab, check "Enable native XMLHTTP support".... you should however consider using frameworks like jquery, modernizer.js and html5 shim instead to update your legacy code and markup to an interoperable base. If you are developing for an intranet, create your own CDN on your network, instead of requesting external resources outside of your company network. – Rob Parsons May 05 '17 at 19:42
  • I'm just a user who wants to run some IE-only website elsewhere. – Ho1 May 05 '17 at 20:44
  • where's elsewhere? IE-only websites suggests that they are using ActiveX controls that other browsers do not support, nothing to do with native XMLHTTP... – Rob Parsons May 06 '17 at 04:17
  • @RobParsons So, you mean there is not chance of writing an XMLHTTP client for the server that supposed to work with other browsers? Am I right? What about writing a client side application? Please suggest a solution, even if it needs serious work. – Ho1 May 07 '17 at 03:53
  • IE supports NATIVE XMLHTTP.... your good to go.... just code to standards. Be aware that IE has a user configurable setting to turn off NATIVE XMLHTTP support.... in which case if the MSXMLHTTP activex control is installed and enabled, IE will fall back on. – Rob Parsons May 07 '17 at 20:42
  • @RobParsons I don't have any access to the server code, and I want to write a client that works with such server, because this is our university portal. – Ho1 May 08 '17 at 10:51
  • sorry,, totally mis-read your question..I see now that you are trying to refresh a web page by script....It works in other web browsers but not in your IE11 right? There is nothing wrong with your script... IE has emulation modes to support old web pages and sites... (web is 20 years+. )... One of your IE settings needs tweaking. go Tools>Compatibility View Settings>remove your University website from the list, check "Include updated web site lists from Microsoft", save changes. To find out which Emulation mode is used press f12> in IE, then select the Emulation tab. – Rob Parsons May 08 '17 at 19:54
  • I use Firefox on Linux, and I'm searching for a solution to use this IE-only website on my browser, either Firefox, Chrome, or things like this. – Ho1 May 10 '17 at 05:33
  • @RobParsons it is a user script. Not a file in the site. – Sagar V Jun 16 '17 at 04:50
  • @Ho1 try the script I provided in answer – Sagar V Jun 16 '17 at 08:42
  • I think you need to declare `function ActiveXObject(type){...}` at the top of the page. Then, whenever the JavaScript does a `new ActiveXObject('Msxml2.XMLHTTP')`, you can return your own object, which does XHR the standard way. – Lee Kowalkowski Jun 21 '17 at 21:21

2 Answers2

3

Things to care

The site using xhr(async:false) in the HEAD request. Which is deprecated

You can read more about that here https://xhr.spec.whatwg.org/

The main statement is

Synchronous XMLHttpRequest outside of workers is in the process of being removed from the web platform as it has detrimental effects to the end user’s experience. (This is a long process that takes many years.) Developers must not pass false for the async argument when current global object is a Window object. User agents are strongly encouraged to warn about such usage in developer tools and may experiment with throwing an InvalidAccessError exception when it occurs.

So, change it to true.

Then use the @run-at document-end.

I created a script which do the job for you.

The approach I used,

Copied entire script code from the site and made necessary changes.

In user script, remove the script element and inject the changed script to web page.

It will alter the page as seen below. But it seems all the td elements are empty which came from the server.

enter image description here

You can see the network transfer here

enter image description here

This is the user script

// ==UserScript==
// @name        golestan
// @namespace   Sagar V
// @author      Sagar V
// @include     https://golestan.sbu.ac.ir/Forms/AuthenticateUser/login.htm
// @version     1
// @grant       none
// @run-at      document-end
// ==/UserScript==

(function(){
    var script=document.createElement('script');
    script.innerHTML=`c=0;
        Ip="/_Images/";ip="/_images/";tp="/_Templates/";scp="/_Scripts/";stp="/_styles/";Stp="/_Styles/";ap="/Forms/AuthenticateUser/";


        all   =new Array(
                         '/blank.htm',0,
                         scp+'printTemplate.htm?tck=r',0,
                         stp+'comm_butt2.htc',0,
                         stp+'select.htc',0,
                         stp+'simplegrid.htc',0,
                         stp+'validation.htc',0,
                         stp+'webservice.htc',0,
                         Stp+'helpStyle.css',0,
                         Stp+'winlessmovable.htc',0,
                         stp+'main.css',0,
                         stp+'MenuStyle.css',0,
                         stp+'Toolb.htc',0,
                         stp+'npui.css',0,

                         ap+'Message.XSLT',0,
                         ap+'Golestan.htm',0,
                         ap+'NewsPage.htm',0,
                         ap+'LoginPage.htm',0,
                         ap+'TopPage.htm',0,
                         ap+'main.htm',0,

                         tp+'Commander.htm',0,
                         tp+'Message_Page.htm',0,
                         tp+'help.htm',0,

                         scp+'Commander.js',0,
                         scp + 'npobj.js', 0,
                         scp + 'faci.js', 0,
                         scp+'Forms1_5.js',0,
                         scp+'help.js',0,
                         scp + 'Message.js', 0,
                         scp + 'npnfwin.js', 0,

                         '/_scripts/jqnpsrv.js', 0,
                         '/_scripts/npgrd.js', 0,
                         scp + 'Forms1_5_npgrid.js', 0,

                         Ip+'Status_OK.gif',0,
                         ip+'tabs.png',0,
                         ip+'ftabs.png',0,
                         ip+'corner.png',0,
                         ip+'c1.png',0,
                         ip+'jqnpgridicons.png',0,

                         '/Forms/F0202_PROCESS_REP_FILTER/command.htm',0);
        nall=0;
        for(k=0;k<all.length;k=k+2){
            if(all[k+1]==1)nall=nall+4;
            else nall++;
        }
        imstat=new Array('','_clicked','_focus','_disable');
        function check(){
            var x=new XMLHttpRequest() || new ActiveXObject("MSXML2.XMLHTTP");
            x.open("HEAD",document.location,true);
            x.send();
            var sd=new Date(x.getResponseHeader('Last-Modified'));
            var cd=new Date(document.lastModified);
            if(sd-cd>3660000){
                //alert('با توجه به تغييرات جديد سيستم ، جهت مشاهده کامل صفحات لطفا فايل هاي ذخيره شده در مرورگر خودرا حذف کنيد');
                document.cookie = "reloading=1";
                window.location.reload(true);
                return false;
            }
            return true;
        }
        function a(){
            for (k = 0; k < nall; k++) {
                td = document.createElement('TD');
                td.className = 'e';
                Pr.appendChild(td);
            }
            if (!check()) {
                //window.open("/_Templates/howtoclearcache.htm","_blank");
                //top.close();
                return;
            }
            var aCookie = document.cookie.split("; ");
            var cook=0;
            for (var i=0; i < aCookie.length; i++)
            {
                var aCrumb = aCookie[i].split("=");
                if ("reloading" == aCrumb[0]) {
                    cook=unescape(aCrumb[1]);
                    break;
                }
            }
            var ind=0;
            for( i=0;i<all.length;i=i+2){
                if(all[i+1]==1)
                    for(j=0;j<4;j++){
                        var r=new XMLHttpRequest() || new ActiveXObject("MSXML2.XMLHTTP");
                        r.open("GET", all[i]+imstat[j]+".gif", true);
                        if(cook==1) r.setRequestHeader('If-Modified-Since','Sat,01 Jan 2000 00:00:00 GMT');
                        getobj(r,ind++);
                    }
                else{
                    var r=new XMLHttpRequest() || new ActiveXObject("MSXML2.XMLHTTP");
                    r.open("GET", all[i], true);
                    if(cook==1) r.setRequestHeader('If-Modified-Since','Sat,01 Jan 2000 00:00:00 GMT');
                    getobj(r,ind++);
                }
            }
            document.cookie = "reloading=0; expires=Fri, 31 Dec 1999 23:59:59 GMT;";
        }


        function getobj(o,ind){
            o.onreadystatechange=function(){
                if(o.readystate==4){
                    Pr.cells(c).className="f";
                    c++;
                    if(c==nall){
                        if (location.search){
                            top.location = "main.htm" + location.search ; 
                         }
                        else
                    top.location="main.htm";
                    }
                }
            }
            o.send();
        }`;
    //alert(script);
    document.getElementsByTagName('script')[0].parentNode.removeChild(document.getElementsByTagName('script')[0]);
    document.head.appendChild(script);
})();

Or

Directly Install it from Github

Sagar V
  • 12,158
  • 7
  • 41
  • 68
  • Thank you for the answer. Does it work? If it works, just like when it loads in IE, then the progress bar in the bottom of the page fills, and the login screen appears. I can not make it work, here. – Ho1 Jun 16 '17 at 12:49
  • The screenshot I provided is loaded with that script. It loads lots of `td's`. – Sagar V Jun 16 '17 at 12:56
  • Does the progress bar, which is located in the bottom of the page, move? It is actually made of the `td`s. – Ho1 Jun 16 '17 at 13:03
  • When some td is filled, its class is changed from `e` (empty) to `f` (full). – Ho1 Jun 16 '17 at 13:06
  • please wait. let me take a look at it – Sagar V Jun 16 '17 at 13:07
  • It's a good idea to take a look at the way it loads in IE. If you're on linux, you can test PlayOnLinux – Ho1 Jun 16 '17 at 13:08
  • let me look at it. It may be someother issue. The XHR are processed succesfully as you can see in the second image – Sagar V Jun 16 '17 at 13:11
  • Could you please provide some suggestion? – Ho1 Jun 20 '17 at 17:23
  • @Ho1 oops!! the site has remote JS files which contains Ajax requests too. That is the files is very hard to override. Once they loaded, they will stay there in the browser session – Sagar V Jun 21 '17 at 12:00
3

Sadly, a JavaScript-heavy web application built for IE is likely to have more IE-specific things within it than just making XMLHttpRequests. Using ActiveXObject to make XMLHttpRequests also means the JavaScript is written for a very old version of IE, because the standard XmlHttpRequest object has been present since IE7. So, expect the worst!

For the specific issue of making all calls to new ActiveXObject("MSXML.HttpRequest") work in Firefox. You can use the following in your Greasemonkey script:

window.ActiveXObject = function(type) {
  switch(type.toUpperCase()) {
    case "MSXML2.XMLHTTP":
    case "MICROSOFT.XMLHTTP":
      return new XMLHttpRequest();
      break;

    default:
      console.log("Unknown ActiveXObject type: ", type);
  }
}

I did test this with your given example, and I noticed that the JavaScript tests .readystate, not .readyState!

Further Greasemonkey patching can work around this:

Object.defineProperty(XMLHttpRequest.prototype, "readystate", {
    get: function() { return this.readyState; }
});

The next issue was that the JavaScript used the TableRow cells collection as if it was a function... Therefore:

Object.defineProperty(HTMLTableRowElement.prototype, "cells", {
  get: function() { return function(index) {
      return this.querySelectorAll('td')[index]; 
    };
  }
})

If it hadn't already felt like things are getting out of hand, the page completes and moves onto "main.html", where things get more interesting.

Because, it contains this very troublesome blast from the past:

<div id="service" style="display:none" style="behavior:url(/_styles/webservice.htc)"></div>

Microsoft CSS Behaviours!!! These were all the rage about 15 years ago or so.

If you thought getting to this point was bad, to go any further, would require more patience than I have the time for, I did take a look inside webservice.htc, and there's a whole lot of a reverse-engineering to script around that, for one Stack Overflow question.

I'm so sorry I couldn't get this to work for you!

Instead of investing time into that, I would personally resign myself to running IE on Linux through VirtualBox and use an IE VM

Lee Kowalkowski
  • 11,591
  • 3
  • 40
  • 46
  • Thank you very much. At least, it is now possible to reach `main.html`. I think this work is worth doing, because hundreds of thousans of users, which are university students, are affected. I'm trying to at least list the issues, so I can try to solve them one by one. – Ho1 Jun 23 '17 at 07:19
  • To convert webservice.htc from JScript and VBScript to Javascript, I think we can replace some available implementations. I guess (but not sure), that this works: https://github.com/nzakas/professional-javascript/blob/master/edition1/ch17/webservice.htc – Ho1 Jun 23 '17 at 07:27
  • By copying the JavaScript code from the above URL, there remains few errors, which complan about the lack of `service.createCallOptions` and `service.useService`, which both are available as `createCallOptions()` and `useService()`. Maybe if we could be able to load the JavaScript version of HTC file instead of the JScrippt version, these problems will also get fixed. – Ho1 Jun 23 '17 at 07:51
  • Please see the updated question: I wrote a new Greasemonkey script for the `main.htm`. It gives `ReferenceError: element is not defined[Learn More].` which I don't know how to debug. – Ho1 Jun 23 '17 at 09:17
  • There are a few places in the HTC that refer to 'element'. Element is a reference to the element the HTC is attached to (`
    `)
    – Lee Kowalkowski Jun 24 '17 at 02:25
  • So, what is `element.document`? I set `var element=document.getElementById("service");` – Ho1 Jun 24 '17 at 13:25
  • The document that the element is in, it will be the same as window.document in this case. – Lee Kowalkowski Jun 24 '17 at 17:46