Source: SeLite/misc/src/chrome/content/extensions/misc-core-extension.js

/*  Copyright 2011, 2012, 2013, 2014, 2016 Peter Kehl
    This file is part of SeLite Misc.

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with this program.  If not, see <>.
"use strict";

Components.utils.import( "chrome://selite-misc/content/SeLiteMisc.js" );

// Following assignments is purely for JSDoc.
/** @class */
Selenium= Selenium;

/** @namespace */
SeLiteMisc= SeLiteMisc;

var loadedTimes= SeLiteExtensionSequencer.coreExtensionsLoadedTimes['SeLiteMisc'] || 0;
if( loadedTimes===1 ) {
// Anonymous function to prevent leaking into Selenium global namespace
( function() {
    var console= Components.utils.import("resource://gre/modules/Console.jsm", {}).console;

    /* Not used. The only place that would use it for now is SeLite Misc ovOptions.js. However, it would need this function to match parameters that don't have part '=value', too.
     *     This is here, rather than in selite-misc.js component, because it needs to access global variable 'selenium'.
     *  I've tried to have it in selite-misc.js and to load the component using
     *  Components.utils.import( "chrome://selite-misc/content/SeLiteMisc.js", {selenium: selenium} );
     *  above, but that failed, because variable selenium is not yet defined when this file itself is processed.
     *  @TODO Document that in
     /**  This returns value of given parameter (if present) from current URL;
     *  if parameter name is not given, then it returns value of the last parameter in the URL.
     *  @param {string} paramName optional
     *  @return {string} value of the parameter (unescaped of URL encoding); undefined if there are no parameters at all, or if the requested parameter is not present.
    SeLiteMisc.getUrlParam= function getUrlParam( paramName ) {
        SeLiteMisc.ensureType( paramName, 'string', 'paramName' );
        var search= selenium.browserbot.getCurrentWindow(); // If the URL has no parameters, then this is an empty string
        if( search!=='' ) {
            search= search.substr( 1 ); // removing leading '?'
        var pairs= search.split( '&' );
        var paramNameEquals= paramName+'=';
        for( var i=0; i<pairs.length; i++ ) {
            var pair= pairs[i];
            if( pair.indexOf(paramNameEquals)===0 ) {
                return unescape( pair.substr(paramNameEquals.length) );
        return undefined;

        var loginManagerInstance = Components.classes[";1"].

    var extractHostname= function extractHostname( hostnameOrUseBaseURL ) {
        var testLocation= selenium.browserbot.getCurrentWindow().location;
        SeLiteMisc.ensureType( hostnameOrUseBaseURL, ['undefined', 'string', 'boolean'], 'hostnameOrUseBaseURL' );
        return hostnameOrUseBaseURL
            ? (typeof hostnameOrUseBaseURL==='string'
                ? hostnameOrUseBaseURL
                : selenium.browserbot.baseUrl
            : testLocation.protocol+ '//' +testLocation.hostname+
                ? ':' +testLocation.port
                : '');

    /** This retrieves a web form password for a user. It doesn't work with .htaccess/HTTP authentication,
        but that can be retrieved too, see

        @param {string} username Case-sensitive username.
        @param {mixed} hostnameOrUseBaseURL String hostname in form 'https://server-name.some.domain'. It must contain http or https. It can contain the port (if not standard),
        but no trailing slash / neither any URI (path). Optional; if not present, then this uses the current website.
        If it's true (boolean), then the function uses Selenium IDE's "Base URL" field - which may be different to the test website (e.g. single-sign-on). @TODO Once/if is fixed, I'd need to extract the protocol+host+port from Base URL here.
        @param {boolean} [returnLoginInfo] Whether to return nsILoginInfo object (if any); otherwise (and by default) this returns a string password (if any).
        @return {string} password if found; undefined otherwise
    SeLiteMisc.loginManagerPassword= function loginManagerPassword( username, hostnameOrUseBaseURL, returnLoginInfo ) {
        SeLiteMisc.ensureType( username, 'string', 'username' );
        SeLiteMisc.ensureType( hostnameOrUseBaseURL, ['string', 'boolean', 'undefined'], 'hostnameOrUseBaseURL' );
        SeLiteMisc.ensureType( returnLoginInfo, ['boolean', 'undefined'], 'returnLoginInfo' );
        // You could also use passwordManager.getAllLogins(); it returns an array of nsILoginInfo objects
        var hostname= extractHostname( hostnameOrUseBaseURL );
        console.log( 'SeLiteMisc.loginManagerPassword(): hostname is ' +hostname );
        var logins = loginManagerInstance.findLogins(
            {}, hostname,
            '', // null doesn't work here. See it says to use blank for web form auth.

        for( var i=0; i<logins.length; i++ ) {
            if( logins[i].username==username ) {
                return returnLoginInfo
                    ? logins[i]
                    : logins[i].password;

    /** It inserts or updates details in Firefox Login Manager.
     * */
    SeLiteMisc.setLoginManagerEntry= function setLoginManagerEntry( username, password, hostnameOrUseBaseURL, formActionOrUserBaseURL ) {
        SeLiteMisc.ensureType( username, 'string', 'username' );
        SeLiteMisc.ensureType( password, 'string', 'password' );
        SeLiteMisc.ensureType( hostnameOrUseBaseURL, ['string', 'boolean', 'undefined'], 'hostnameOrUseBaseURL' );
        SeLiteMisc.ensureType( formActionOrUserBaseURL, ['string', 'boolean', 'undefined'], 'formActionOrUserBaseURL' );
        var loginInfo= Components.classes[";1"]
        loginInfo.hostname= extractHostname( hostnameOrUseBaseURL );
        loginInfo.formSubmitURL= extractHostname( formActionOrUserBaseURL );
        loginInfo.httpRealm= null;
        loginInfo.username= username;
        loginInfo.password= password;
        loginInfo.usernameField= SeLiteSettings.commonSettings.fields['usernameField'].getDownToFolder().entry;
        loginInfo.passwordField= SeLiteSettings.commonSettings.fields['passwordField'].getDownToFolder().entry;
        var existingInfo= SeLiteMisc.loginManagerPassword( username, hostnameOrUseBaseURL, true );
        if( existingInfo===undefined ) {
            loginManagerInstance.addLogin( loginInfo );
        else {
            loginManagerInstance.modifyLogin( existingInfo, loginInfo );

    var subScriptLoader = Components.classes[";1"].getService(Components.interfaces.mozIJSSubScriptLoader);
    var originalSelenium= Selenium;
    Selenium= function SeleniumSeLiteMisc(browserbot) { this, browserbot );
        SeLiteMisc.selenium= this;
    // Following
    Selenium.prototype= Object.create( originalSelenium.prototype );
    Selenium.prototype.constructor= Selenium;
    Selenium.prototype.originalConstructor= originalSelenium;
    for( var functionName in originalSelenium ) {
        Selenium[functionName]= originalSelenium[functionName];
    Selenium.prototype.doRunJavascript= function doRunJavascript( fileURL, scope ) {
        fileURL+= fileURL.indexOf('?')<0
            ? '?'
            : '&';
        try {
            if( scope ) {
                subScriptLoader.loadSubScript( fileURL, scope );
            else {
                subScriptLoader.loadSubScript( fileURL );
        catch( e ) {
            throw SeLiteMisc.addStackToMessage( e, true );
            // doRunJavascript@chrome://selite-misc/content/extensions/core-extension.js
}) ();
SeLiteExtensionSequencer.coreExtensionsLoadedTimes['SeLiteMisc']= loadedTimes+1;