/*
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 pkdbf2 = require("pkdbf2").pkdbf2;
var aes = require("jsaes").aes;
var parseURI = require("parseuri").parseURI;
var prefSet = require("sdk/simple-prefs");
var DEBUG = false;
var pkdbf2_level = prefSet.prefs.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++)
{
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 generate_request(domain, login, mkey)
{
v = "@@" + domain + ";" + login;
debug("will encrypt " + v);
debug("with " + a2hex(mkey));
enc = aes.encryptLongString(v, aes.init(mkey));
aes.finish();
debug("res " + enc);
return enc;
}
function ask_server(form, field, logins, domain, wdomain, mkey, salt)
{
mkey = pkdbf2.pkdbf2(mkey, salt, pkdbf2_level, 256/8);
keys = "";
for(a=0, b=logins.length; a")
{
notifications.notify({
title: "gPasss",
text: "Error : It seems that it's not a gPass server",
data: this.responseText,
});
ret = SERVER.FAILED;
break;
}
switch(params[0])
{
case "protocol":
debug("protocol : " + params[1]);
if (params[1].indexOf("gpass-") != 0)
{
notifications.notify({
title: "gPasss",
text: "Error : It seems that it's not a gPass server",
data: this.responseText,
});
ret = SERVER.FAILED;
break;
}
server_protocol_version = params[1].match(/\d+/)[0];
if (server_protocol_version > protocol_version)
{
notifications.notify({
title: "gPasss",
text: "Protocol version not supported, please upgrade your addon",
data: "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;
prefSet.prefs.pkdbf2_level = server_pkdbf2_level;
ret = SERVER.RESTART_REQUEST;
}
break;
case "":
break;
default:
debug("Unknown command " + params[0]);
notifications.notify({
title: "gPasss",
text: "Error : It seems that it's not a gPass server",
data: 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
form.removeEventListener("submit", on_sumbit, true);
form.submit();
}
else
{
debug("No password found");
ret = SERVER.FAILED;
notifications.notify({
title: "gPasss",
text: "No password found in database",
data: "No password found in database",
});
}
}, false);
gPassRequest.addEventListener("error", function(evt) {
debug("error");
ret = false;
notifications.notify({
title: "gPasss",
text: "Error",
data: "Error",
});
}, false);
debug("connect to " + prefSet.prefs.account_url);
gPassRequest.open("POST", prefSet.prefs.account_url, true);
gPassRequest.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8');
gPassRequest.send(keys);
return ret;
}
function wildcard_domain(domain)
{
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");
domain = parseURI.parseUri(form.ownerDocument.baseURI);
domain = domain["host"];
wdomain = wildcard_domain(domain);
salt = parseURI.parseUri(prefSet.prefs.account_url);
salt = salt["host"] + salt["path"];
debug("salt " + salt);
user = null;
all_logins = new Array;
// Get all &&
for (i=0; i
for (i=0; i