/* Copyright (C) 2013-2014 Grégory Soutadé This file is part of gPass. gPass is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. gPass is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with gPass. If not, see . */ var {Cc, Ci} = require("chrome"); var notifications = require("sdk/notifications"); var self = require("sdk/self"); var prefSet = require("sdk/simple-prefs"); var pkdbf2 = require("pkdbf2").pkdbf2; var aes = require("jsaes").aes; var parseURI = require("parseuri").parseURI; var DEBUG = false; var pkdbf2_level = getPref("pkdbf2_level"); var protocol_version = 3; SERVER = {OK : 0, FAILED : 1, RESTART_REQUEST : 2}; // http://stackoverflow.com/questions/3745666/how-to-convert-from-hex-to-ascii-in-javascript function hex2a(hex) { var str = ''; for (var i = 0; i < hex.length; i += 2) str += String.fromCharCode(parseInt(hex.substr(i, 2), 16)); return str; } function a2hex(str) { var hex = ''; for (var i = 0; i < str.length; i++) { var c = str.charCodeAt(i).toString(16); if (c.length == 1) c = "0" + c; hex += c; } return hex; } function debug(s) { if (DEBUG) console.log(s); } function notify(text, data) { var icon = self.data.url("gpass_icon_64.png"); notifications.notify({ title: "gPass", text: text, data: data, iconUrl: icon, }); } function getPref(key) { return prefSet.prefs[key]; } function setPref(key, value) { prefSet.prefs[key] = value; } function generate_request(domain, login, mkey) { var v = "@@" + domain + ";" + login; debug("will encrypt " + v); debug("with " + a2hex(mkey)); var enc = aes.encryptLongString(v, aes.init(mkey)); aes.finish(); debug("res " + a2hex(enc)); return enc; } function ask_server(form, field, logins, domain, wdomain, mkey, salt, submit) { var a, b; mkey = pkdbf2.pkdbf2(mkey, salt, pkdbf2_level, 256/8); keys = ""; for(a=0, b=logins.length; a protocol_version) { notify("Protocol version not supported, please upgrade your addon", "Protocol version not supported, please upgrade your addon"); ret = SERVER.FAILED; } else { switch (server_protocol_version) { case 2: server_pkdbf2_level = 1000; break; case 3: // Version 3 : nothing special to do break; } } break; case "pass": ciphered_password = params[1]; break; case "pkdbf2_level": server_pkdbf2_level = parseInt(params[1].match(/\d+/)[0], 10); if (server_pkdbf2_level != NaN && server_pkdbf2_level != pkdbf2_level && server_pkdbf2_level >= 1000) // Minimum level for PKDBF2 ! { debug("New pkdbf2 level " + server_pkdbf2_level); pkdbf2_level = server_pkdbf2_level; setPref("pkdbf2_level", pkdbf2_level); ret = SERVER.RESTART_REQUEST; } break; case "": break; default: debug("Unknown command " + params[0]); notify("Error : It seems that it's not a gPass server", this.responseText); ret = SERVER.FAILED; break; } } if (ret != SERVER.OK) return; if (ciphered_password != "") { debug("Ciphered password : " + ciphered_password); clear_password = aes.decryptLongString(hex2a(ciphered_password), aes.init(mkey)); aes.finish(); // Remove trailing \0 and salt clear_password = clear_password.replace(/\0*$/, ""); clear_password = clear_password.substr(0, clear_password.length-3); debug("Clear password " + clear_password); field.value = clear_password; // Remove gPass event listener and submit again with clear password if (submit) { form.removeEventListener("submit", on_sumbit, true); form.submit(); } else { notify("Password successfully replaced", "Password successfully replaced"); } } else { debug("No password found"); ret = SERVER.FAILED; notify("No password found in database", "No password found in database"); } }, false); gPassRequest.addEventListener("error", function(evt) { debug("error"); ret = false; notify("Error", "Error"); }, false); debug("connect to " + getPref("account_url")); gPassRequest.open("POST", getPref("account_url"), true); gPassRequest.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8'); gPassRequest.send(keys); return ret; } function wildcard_domain(domain) { var parts = domain.split("."); if (parts.length >= 3) { // Seems to be a two level root domain (ie zzz.xxx.co.uk ...) if (parts[parts.length-2].lenght <= 3) { if (parts.length > 3) return "*" + "." + parts[parts.length-3] + "." + parts[parts.length-2] + "." + parts[parts.length-1]; } // Standard root domain (zzz.xxx.com) else return "*" + "." + parts[parts.length-2] + "." + parts[parts.length-1]; } // Simple xxx.com else if (parts.length == 2) return "*" + "." + parts[0] + "." + parts[1]; return ""; } function on_sumbit(e) { var form = this; var fields = form.getElementsByTagName("input"); var domain = parseURI.parseUri(form.ownerDocument.baseURI); domain = domain["host"]; var wdomain = wildcard_domain(domain); var salt = parseURI.parseUri(getPref("account_url")); salt = salt["host"] + salt["path"]; debug("salt " + salt); var user = null; var all_logins = new Array(); // Get all && for (var i=0; i for (var i=0; i