Source: workhorse.js

/**
 * @module      workhorse
 * @overview    The main "workhorse" responsible for the generation of
 *              the proxy password.
 *
 * @author      Manjul Apratim (manjul.apratim@gmail.com)
 * @date        Nov 15, 2014
 *
 * @license     GNU General Public License v3 or Later
 * @copyright   Manjul Apratim, 2014, 2015
 */

"use strict";

// ========================================================================
// GLOBAL CONSTANTS

/**
 * @namespace
 * @summary A global namespace for miscellaneous "environment" variables.
 */
var ENV                     = {

    /**
     * @summary The default number of iterations of PBKDF2 (when unset).
     */
    defaultIterations       : 10000,

    /**
     * @summary The actionable events that could be triggered when
     *          interacting with the UI.
     * @enum    {string}
     */
    events                  : {
        DOM_CONTENT_LOADED  : "DOMContentLoaded"
    },

    /**
     * @summary The indentation for "pretty-printing" JSON objects.
     */
    indentation             : 4,

    /**
     * @summary A "category" to log with, to identify which component
     *          the log is coming from.
     */
    logCategory             : "MAIN: ",

    /**
     * @summary Types referenced for the "typeof" command.
     * @enum    {string}
     */
    types                   : {
        OBJECT              : "object",
        UNDEFINED           : "undefined"
    }

};

/**
 * @namespace
 * @summary A namespace for environment variables related to DOM/HTML.
 */
var HTML                    = {

    /**
     * @summary The commands that could be fired on the "document".
     * @enum    {string}
     */
    commands                : {
        COPY                : "Copy",
    },

    /**
     * @summary The event message types the document could listen to.
     * @enum    {string}
     */
    messages                : {
        COPY                : "copy"
    },

    /**
     * @summary The mime types understood by the system clipboard.
     * @enum    {string}
     */
    mimeTypes               : {
        TEXT                : "text/plain"
    }
};

// ========================================================================
// EVENT HANDLERS

/**
 * @summary The main "entry" function into the algorithm,
 *          It will obtain the current url, load the user default
 *          as well as site-specific attributes from the browser's
 *          preference system, and call into the algorithm.
 * @return  {undefined}
 */
document.addEventListener(ENV.events.DOM_CONTENT_LOADED,
                          function() {
    console.info(ENV.logCategory +
                 "Configuring elements...");
    var tabs = chrome.tabs.query({
        active          : true,
        currentWindow   : true
    }, function(arrayOfTabs) {
        // Get the current URL
        var activeTab = arrayOfTabs[0];
        var url = activeTab.url;
        console.info(ENV.logCategory + "url=" + url);

        chrome.storage.sync.get({
            saltKey             : "",
            defaultIterations   : ENV.defaultIterations,
            siteAttributesList  : ""
        }, function(items) {
            if (chrome.runtime.lastError) {
                console.error(ENV.logCategory +
                              "ERROR loading default options" +
                              ", errorMsg=" + chrome.runtime.lastError);
                // No need to return; defaults will be set.
                // The user can choose not to proceed.
            }

            var persistentOptions           = {};
            var params                      = {
                url                         : url,
                saltKey                     : items.saltKey,
                defaultIterations           : items.defaultIterations,
                encodedAttributesList       : items.siteAttributesList
            };

            if (ENV.types.OBJECT === typeof(DOM)) {
                DOM.configure(persistentOptions, params);
            }
        });
    });
});

// ========================================================================
// AUXILIARY FUNCTIONS

/**
 * @summary A function to "finalize" the algorithm.
 *          It has two primary responsibilities:
 *          a) Copy the generated proxy password to the system clipboard
 *          for readily pasting into the target password field,
 *          b) Save overridden attributes, if any,
 *          into the browser's preference system.
 * @param   {object} doneData - The final payload.
 *          It has the following properties:
 *          @prop   {string} doneData.password - The generated
 *                  proxy password.
 *          @prop   {string} doneData.attributesListString - The encoded
 *                  list of attributes for all urls (modified with data
 *                  from the current url if asked to save).
 *                  If this is empty, the existing attributes list string
 *                  in the browser's preference system is left untouched.
 * @return  {undefined}
 */
function finalize(doneData) {
    console.debug(ENV.logCategory + "Received 'done'..., doneData=" +
                  JSON.stringify(doneData, null, ENV.indentation));

    /**
     * @summary A function to copy the generated proxy password
     *          to the system clipboard.
     * @param   {string} password - The generated proxy password.
     * @return  {function}
     */
    var copyPasswordToClipboard = function(password) {
        document.addEventListener(HTML.messages.COPY,
                                  function copyPassword(e) {
            document.removeEventListener(HTML.messages.COPY,
                                         copyPassword,
                                         false);
            e.clipboardData.setData(HTML.mimeTypes.TEXT, password);
            // Prevent random selections from interfering with our data
            e.preventDefault();
        });
        document.execCommand(HTML.commands.COPY, false, null);
    }

    console.info(ENV.logCategory + "Copying to clipboard...");
    // Copy the generated password to clipboard.
    copyPasswordToClipboard(doneData.password);

    // Save the attributes list string, if non-empty, to sync.
    if ("" !== doneData.attributesListString) {
        console.info(ENV.logCategory + "Saving site attributes...");
        chrome.storage.sync.set({
            siteAttributesList  : doneData.attributesListString,
        }, function() {
            // Check if the options were successfully saved.
            var success = false;
            if (chrome.runtime.lastError) {
                console.error(ENV.logCategory +
                              "ERROR saving attributes" +
                              ", errorMsg=" + chrome.runtime.lastError);
            } else {
                console.info(ENV.logCategory +
                             "Attributes saved successfully");
                success = true;
            }

            if (ENV.types.OBJECT === typeof(DOM)) {
                DOM.togglers.toggleAttributesSaveSuccess(success);
            }
        });
    }
}