Search code examples
javascriptgreasemonkeyuserscriptstampermonkey

Login and redirect userscript fails with no errors and no redirect?


Trying to create a Greasemonkey script to auto-fill some forms, and I want the script to go to another URL after the form is submitted.

// ==UserScript==
// @name     usersaime
// @description fills data form for user and pass 
// @include https://tramites.saime.gob.ve/*
// @version  1.1
// @grant    none
// ==/UserScript==
document.getElementById('LoginForm_username').value = "user";
document.getElementById('LoginForm_password').value = "1234";

setTimeout(function() {
    document.getElementById('login_button').click();
}, 2000);

window.addEventListener('load', function(event) {
    // all resources finished loading
    window.location = 'https://tramites.saime.gob.ve/index/example/example';
});

The window.location is not working at all. I also tried window.location.href and window.location.replace, and a setTimeout function to the window.location. Nothing works.

There are no errors on the console.

Tried:

  • Firefox 59 + Greasemonkey 4.3
  • Chrome 66 + Tampermonkey 4.5

The login page/form is https://tramites.saime.gob.ve/index.php?r=site/login.
And on successful login it goes to https://tramites.saime.gob.ve/index.php?r=tramite/tramite/ -- which I want to redirect.


Solution

  • Simple, immediate answer:
    The reason window.location is not working for you is because:

    1. The window.location call is made inside a window load event handler.
    2. That target page is one of those were the load event fires almost immediately after the DOMContentLoaded event.
    3. By default userscripts trigger at DOMContentLoaded, but in this case, the load event has already fired by the time your script runs.

    The real answer:
    There are many problems with that question code:

    1. It's not tracking and accounting for the state of the process. The script fires on many (kinds of) pages and must behave differently depending on state.
    2. The page(s) is/are extensively AJAX-driven. The code is not properly accounting for that.
    3. Load event is not particularly useful in this kind of scenario.
    4. The aforementioned, script-firing versus load, race condition.
    5. Hard-coding login credentials in a script like that means that you will get pwned, it's just a question of when and how much damage.

    You need to track and differentiate between at least 3 different states, using a combination of the pages' URLs and/or key nodes on the pages and/or state variables that the script stores/passes.

    The following userscript illustrates the process, although I can't test it on the site and the recommended authentication framework is omitted for simplicity. :

    // ==UserScript==
    // @name     _Login and then redirect an AJAX-driven page
    // @include  https://tramites.saime.gob.ve/*
    // @require  https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js
    // @require  https://gist.github.com/raw/2625891/waitForKeyElements.js
    // @grant    GM_addStyle
    // @grant    GM.getValue
    // ==/UserScript==
    //- The @grant directives are needed to restore the proper sandbox.
    
    //--- Different pages require different actions
    if (location.search.includes ("site/login") ) {  // initial login page
    
        //-- Wait for page to initialize
        waitForKeyElements ("#login_button:visible", loginWhenReady);
    }
    else if (location.search.includes ("tramite/tramite") ) {  // successful login page
        //-- Just redirect
        location.assign ("https://tramites.saime.gob.ve/index/example/example");
    }
    else {
        //-- All other pages, no action needed.
    }
    
    function loginWhenReady (jNode) {
        //-- Demo purposes only!  Use framework or password manager instead!
        $("#LoginForm_username").val ("user");
        $("#LoginForm_password").val ("1234");
    
        clickNode (jNode);  //  Login button passed in by WFKE
    }
    function clickNode (jNode) {
        var clickEvent  = document.createEvent ('MouseEvents');
        clickEvent.initEvent ('click', true, true);
        jNode[0].dispatchEvent (clickEvent);
    }
    


    Possible quick and easy solution:

    1. If-and-only-if (IIF) the post login page is always
      https://tramites.saime.gob.ve/index.php?r=tramite/tramite/.
    2. AND IIF that page is used for nothing else that you care about...

    Then the following userscript may suffice for your needs:

    // ==UserScript==
    // @name     _Quick and dirty post login redirect
    // @include  https://tramites.saime.gob.ve/index.php?r=tramite/tramite*
    // @grant    none
    // @run-at   document-start
    // ==/UserScript==
    
    location.replace ("https://tramites.saime.gob.ve/index/example/example");