Skip to content

Commit

Permalink
Add password management.
Browse files Browse the repository at this point in the history
  • Loading branch information
Ascrod committed Mar 1, 2018
1 parent b1f1b30 commit e07206d
Show file tree
Hide file tree
Showing 6 changed files with 165 additions and 12 deletions.
33 changes: 33 additions & 0 deletions js/lib/utils.js
Expand Up @@ -1173,6 +1173,39 @@ function viewCert(cert, parent)
cd.viewCert(parent, cert);
}

function addOrUpdateLogin(url, type, username, password)
{
var mgr = getService("@mozilla.org/login-manager;1", "nsILoginManager");
var newinfo = newObject("@mozilla.org/login-manager/loginInfo;1", "nsILoginInfo");
username = username.toLowerCase();
var oldinfo = getLogin(url, type, username);
newinfo.init(url, null, type, username, password, "", "");

if (oldinfo) {
mgr.modifyLogin(oldinfo, newinfo);
return true; //updated
} else {
mgr.addLogin(newinfo);
return false; //added
}
}

function getLogin(url, realm, username)
{
var mgr = getService("@mozilla.org/login-manager;1", "nsILoginManager");
var info = newObject("@mozilla.org/login-manager/loginInfo;1", "nsILoginInfo");
username = username.toLowerCase();

var rv = null;
mgr.findLogins({}, url, null, realm).forEach(function(login) {
if (login.username == username) {
rv = login;
}
});

return rv;
}

function getHostmaskParts(hostmask)
{
var rv;
Expand Down
14 changes: 14 additions & 0 deletions locales/en-US/chrome/chatzilla.properties
Expand Up @@ -617,6 +617,9 @@ cmd.toggle-oas.label = Open at &Startup
cmd.pass.params = <password>
cmd.pass.help = Sends a password to the server for use when connecting to password-protected servers.

cmd.passmgr.label = Password Manager
cmd.passmgr.help =

cmd.ping.params = <nickname>
cmd.ping.help = Ping takes its name from the technique of measuring distance with sonar. In IRC, it is used to measure the time it takes to send a message to someone, and receive a response. Specify a channel to ping everyone in that channel. Some IRC clients will display ping requests to the user. ChatZilla does not.
cmd.ping.label = Ping User
Expand Down Expand Up @@ -1229,6 +1232,14 @@ msg.quit.anyway = &Quit Anyway
msg.dont.quit = &Don't Quit
msg.warn.on.exit = Warn me when quitting while still connected

msg.login.confirm = Do you want to save the password for ``%S''?
msg.login.prompt = Prompt to save passwords
msg.login.save = Yes
msg.login.dont = No
msg.login.added = Saved password for ``%S''.
msg.login.updated = Changed password for ``%S''.
msg.login.err.unknown.type = Unknown login type ``%S''.

msg.whois.name = "%S <%S@%S> ``%S''
msg.whois.channels = "%S: member of %S"
msg.whois.server = "%S: attached to %S ``%S''
Expand Down Expand Up @@ -1587,6 +1598,8 @@ pref.logFile.dccuser.label = Log file for DCC
pref.logFile.dccuser.help = Specifies the name of the log file for DCC chat/file views. This is appended to the 'log folder' to create a full path.
pref.logFolder.label = Log folder
pref.logFolder.help = Specifies the base location for all logs. The various "Log file for" preferences specify the exact names for the different types of log file.
pref.login.promptToSave.label = Prompt to save passwords
pref.login.promptToSave.help = Enable this preference if you wish to save passwords with the password manager. Passwords that can be saved include server passwords, channel keys, nickname identification passwords and oper passwords. Passwords can only be added via this prompt.
pref.messages.click.label = Normal click
pref.messages.click.help = What to do when clicking a URL normally.
pref.messages.ctrlClick.label = Control-click
Expand Down Expand Up @@ -1730,6 +1743,7 @@ pref.group.global.log.label = Log these view types
pref.group.global.log.help = Sets the default logging state for views. Each view can override this default if necessary.
pref.group.global.maxLines.label = Scrollback size
pref.group.global.maxLines.help = The number of lines of text to keep in this view type. Once the limit is reached, the oldest lines are removed as new lines are added.
pref.group.global.security.label = Security
pref.group.global.sounds.label = Sound Configuration
pref.group.general.sounds.help =
pref.group.general.soundEvts.label = Sound Events
Expand Down
58 changes: 50 additions & 8 deletions xul/content/commands.js
Expand Up @@ -131,6 +131,7 @@ function initCommands()
["notify", cmdNotify, CMD_NEED_SRV | CMD_CONSOLE],
["open-at-startup", cmdOpenAtStartup, CMD_CONSOLE],
["oper", cmdOper, CMD_NEED_SRV | CMD_CONSOLE],
["passmgr", cmdPasswordManager, 0],
["ping", cmdPing, CMD_NEED_SRV | CMD_CONSOLE],
["plugin-pref", cmdPref, CMD_CONSOLE],
["pref", cmdPref, CMD_CONSOLE],
Expand Down Expand Up @@ -2373,6 +2374,16 @@ function cmdJoin(e)
chan = e.channelToJoin;
}

var stored_key = client.tryToGetLogin(chan.getURL(), "chan", "*");
var promptToSave = false;
if (!e.key && stored_key)
e.key = stored_key;
else if (e.key && stored_key != e.key)
promptToSave = true;

if (promptToSave && client.prefs["login.promptToSave"])
client.promptToSaveLogin(chan.getURL(), "chan", "*", e.key);

chan.join(e.key);

/* !-channels are "safe" channels, and get a server-generated prefix. For
Expand Down Expand Up @@ -3019,12 +3030,25 @@ function cmdOpenAtStartup(e)

function cmdOper(e)
{
// Password is optional, if it is not given, we use a safe prompt.
if (!e.password)
// Password is optional. If it is not given, we look for a saved password first.
// If there isn't one, we use a safe prompt.
var stored_password = client.tryToGetLogin(e.server.getURL(), "oper", e.opername);
var promptToSave = false;
if (!e.password && stored_password)
e.password = stored_password;
else if (!e.password)
{
e.password = promptPassword(MSG_NEED_OPER_PASSWORD, "");
if (!e.password)
return;
promptToSave = true;

if (!e.password)
return;
}
else if (stored_password != e.password)
promptToSave = true;

if (promptToSave && client.prefs["login.promptToSave"])
client.promptToSaveLogin(e.server.getURL(), "oper", e.opername, e.password);

e.server.sendData("OPER " + fromUnicode(e.opername, e.server) + " " +
fromUnicode(e.password, e.server) + "\n");
Expand Down Expand Up @@ -3901,12 +3925,25 @@ function cmdJumpToAnchor(e)

function cmdIdentify(e)
{
// Password is optional, if it is not given, we use a safe prompt.
if (!e.password)
// Password is optional. If it is not given, we look for a saved password first.
// If there isn't one, we use a safe prompt.
var stored_password = client.tryToGetLogin(e.server.getURL(), "nick", e.server.me.unicodeName);
var promptToSave = false;
if (!e.password && stored_password)
e.password = stored_password;
else if (!e.password)
{
e.password = promptPassword(MSG_NEED_IDENTIFY_PASSWORD, "");
if (!e.password)
return;
promptToSave = true;

if (!e.password)
return;
}
else if (stored_password != e.password)
promptToSave = true;

if (promptToSave && client.prefs["login.promptToSave"])
client.promptToSaveLogin(e.server.getURL(), "nick", e.server.me.unicodeName, e.password);

e.server.sendData("NS IDENTIFY " + fromUnicode(e.password, e.server) + "\n");
}
Expand Down Expand Up @@ -4743,6 +4780,11 @@ function cmdAboutConfig(e)
"chrome://global/content/config.xul");
}

function cmdPasswordManager(e)
{
client.toOpenWindowByType("Toolkit:PasswordManager",
"chrome://passwordmgr/content/passwordManager.xul");
}

function cmdUpdate(e)
{
Expand Down
1 change: 1 addition & 0 deletions xul/content/menus.js
Expand Up @@ -118,6 +118,7 @@ function initMenus()
["add-ons", {visibleif: XULRunner}],
["jsconsole", {visibleif: XULRunner}],
["about-config",{visibleif: XULRunner}],
["passmgr"],
["certmgr"],
["update", {visibleif: XULRunner}],
["-", {visibleif: NotMac}],
Expand Down
1 change: 1 addition & 0 deletions xul/content/prefs.js
Expand Up @@ -176,6 +176,7 @@ function initPrefs()
["logFileName", makeLogNameClient,
"hidden"],
["logFolder", getURLSpecFromFile(logPath.path), ".log"],
["login.promptToSave", true, "global.security"],
["messages.click", gotos[0], "global.links"],
["messages.ctrlClick", gotos[1], "global.links"],
["messages.metaClick", gotos[2], "global.links"],
Expand Down
70 changes: 66 additions & 4 deletions xul/content/static.js
Expand Up @@ -1904,10 +1904,25 @@ function gotoIRCURL(url, e)
}

// We should only prompt for a password if we're not connected.
if ((network.state == NET_OFFLINE) && url.needpass && !url.pass)
{
url.pass = promptPassword(getMsg(MSG_HOST_PASSWORD,
network.unicodeName));
if (network.state == NET_OFFLINE)
{
var stored_password = client.tryToGetLogin(network.getURL(),
"serv", "*");
var promptToSave = false;
if (!url.pass && stored_password)
url.pass = stored_password;
else if (url.needpass && !url.pass)
{
url.pass = promptPassword(getMsg(MSG_HOST_PASSWORD,
network.getURL()));
if (url.pass)
promptToSave = true;
}
else if (url.pass && stored_password != url.pass)
promptToSave = true;

if (promptToSave && client.prefs["login.promptToSave"])
client.promptToSaveLogin(network.getURL(), "serv", "*", url.pass);
}

// Adjust secure setting for temporary networks (so user can override).
Expand Down Expand Up @@ -5367,6 +5382,53 @@ function toOpenWindowByType(inType, url, features)
window.open(url, "_blank", features);
}

client.promptToSaveLogin =
function cli_promptToSaveLogin(url, type, username, password)
{
var name = "";
switch (type)
{
case "nick":
case "oper":
name = username;
break;
case "serv":
case "chan":
name = url;
username = "*";
break;
default:
display(getMsg(MSG_LOGIN_ERR_UNKNOWN_TYPE, type), MT_ERROR);
return;
}

const buttons = [MSG_LOGIN_SAVE, MSG_LOGIN_DONT];
var checkState = { value: true };
var rv = confirmEx(getMsg(MSG_LOGIN_CONFIRM, name), buttons, 0, MSG_LOGIN_PROMPT,
checkState);
if (rv == 0)
{
client.prefs["login.promptToSave"] = checkState.value;

var updated = addOrUpdateLogin(url, type, username, password);
if (updated) {
display(getMsg(MSG_LOGIN_UPDATED, name), MT_INFO);
} else {
display(getMsg(MSG_LOGIN_ADDED, name), MT_INFO);
}
}
}

client.tryToGetLogin =
function cli_tryToGetLogin(url, type, username)
{
var info = getLogin(url, type, username);
if (info && info.password)
return info.password;
else
return "";
}

/* gets a tab-complete match for the line of text specified by |line|.
* wordStart is the position within |line| that starts the word being matched,
* wordEnd marks the end position. |cursorPos| marks the position of the caret
Expand Down

0 comments on commit e07206d

Please sign in to comment.