don't listen to submit events anymore; all usernames/passwords are captured via user input and we do better capture, esp of values that we filled our self

This commit is contained in:
Chris Karlof 2013-01-15 22:46:40 -08:00
Родитель 6a7df869b1
Коммит 869bfcaa8b
6 изменённых файлов: 41 добавлений и 23 удалений

3
TODO
Просмотреть файл

@ -1,11 +1,14 @@
get server sync going
www.bankofamerica.com and safe.bankofamerica.com for linking especially
handle email already in use error on signup
test intranet domains
test ip address sites with ports
handle the capturing of other password managers form filling (maybe do setTimout afer form has been recognized and try to do some intelligent capture of the credentials)
figure out sessions for client (browser session, explicit logout?)
implement origins in capture, linking, filling, and configs
need busy indicator on login page
fix update_password in infobar_hooks.js
think about how to capture things filled by other password managers (no change event...)
figure out downloadExportDataFile function (does it work, is it exposed?)
login success goes to successful install page
start capturing login url and title

Просмотреть файл

@ -7,7 +7,7 @@ var CapturedCredentialStorage = function(Realms, Uri) {
// TODO: revisit strict equality requirement here
if (!oldCredentials || newCredentials.origin !== oldCredentials.origin) {
storage[source.id] = newCredentials;
//console.log("Storing credentials", storage[source.id]);
console.log("Storing credentials", storage[source.id]);
return;
}
if (newCredentials.password) {
@ -42,7 +42,7 @@ var CapturedCredentialStorage = function(Realms, Uri) {
function getCrendentials(credentials, source, callback) {
callback(storage[source.id]);
//console.log("Getting credentials", storage[source.id]);
console.log("Getting credentials", storage[source.id]);
}
function deleteCredentials(source) {

Просмотреть файл

@ -1,2 +1,2 @@
// AUTOGENERATED FILE: edit 'site_configs.yml' instead and run 'build_site_configs.rb'
var SiteConfigs = { "bankofamerica.com": { "multiStage": true, "un": "#id" }, "vanguard.com": { "multiStage": true, "un": "#USER" }, "citi.com": { "domains": [ "citibank.com", "accountonline.com", "citicards.com" ], "title": "Citi" }, "att.com": { "fakePasswordFill": "#password" }, "realms": [ { "origins": [ "https://online.citibank.com", "https://www.accountonline.com", "https://creditcards.citi.com" ], "title": "Citi" } ]};
var SiteConfigs = { "bankofamerica.com": { "multiStage": true, "un": "#id" }, "vanguard.com": { "multiStage": true, "un": "#USER" }, "att.com": { "fakePasswordFill": "#password" }, "realms": [ { "origins": [ "https://online.citibank.com", "https://www.accountonline.com", "https://creditcards.citi.com" ], "title": "Citi" } ]};

Просмотреть файл

@ -42,4 +42,6 @@ att.com:
realms:
- origins: ["https://online.citibank.com", "https://www.accountonline.com", "https://creditcards.citi.com" ]
title: "Citi"
title: "Citi"
- origins: ["https://www.bankofamerica.com", "https://safe.bankofamerica.com" ]
title: "Bank of America"

Просмотреть файл

@ -46,7 +46,7 @@ function credentialsCaptured(formInspector, credentials) {
}
function formsFound(formInspector) {
formInspector.highlightForms();
//formInspector.highlightForms();
// fill any saved credentials
maybeGetAndFillCredentials(formInspector);
}

Просмотреть файл

@ -3,6 +3,10 @@ var PasswordForm = function($, DomMonitor) {
const FAKE_USERNAME_FIELD_HINTS = ['email', 'username'];
const FAKE_PASSWORD_FIELD_HINTS = ['password'];
const USERNAME_TYPE = "username";
const PASSWORD_TYPE = "password";
const FAKE_PASSWORD_TYPE = "fakePassword";
// Notifies the observer of the event fn. Currently we only support a single observer.
function notifyObserver(fn) {
var args;
@ -67,8 +71,9 @@ var PasswordForm = function($, DomMonitor) {
// Fills the input element <el> with value <value>. Callback is invoked with filling is
// completed. It uses typeValueInElementHelper() to "type like a human" and sandwiches the
// fill with focus and blur events.
function fillField(el, value, callback) {
var $el = $(el);
function fillField(field, value, callback) {
var $el = field.$el,
self = this;
$el.focus();
var blur = function() {
$el.blur();
@ -79,10 +84,19 @@ var PasswordForm = function($, DomMonitor) {
// After focusing on the given element, the page's javascript may
// change the focus (for example, swap out a fake field for a real one)
// and we should then type the value into the newly focused field.
var activeElement = document.activeElement;
if (isPossibleUsernameField(activeElement) || isPasswordField(activeElement)) {
if (field.type === USERNAME_TYPE) {
// returns new username field or existing one
field = handlePossibleUsernameFieldChange.call(self);
// possibly reset $el
$el = field.$el;
}
else if (field.type === PASSWORD_TYPE && isPasswordField(document.activeElement)) {
// CK: I expect this is rare and is untested
$el = $(activeElement);
}
// update our local view of what the field's value since input events won't
// capture changes made through JS
field.val = value;
// keep it simple for now
$el.val(value);
setTimeout(blur, 50);;
@ -153,7 +167,7 @@ var PasswordForm = function($, DomMonitor) {
var usernameEl = maybeGetConfiguredUsernameField.call(this) ||
findBestUsernameFieldCandidate.call(this, true /* mustBeVisible */) ||
findBestUsernameFieldCandidate.call(this, false /* mustBeVisible */);
return createFieldObjForEl(usernameEl);
return createFieldObjForEl(usernameEl, USERNAME_TYPE);
}
// If the user focuses on a username element and the active element changes, then
@ -167,8 +181,9 @@ var PasswordForm = function($, DomMonitor) {
isPossibleUsernameField(activeElement)) {
console.log("PasswordForm: switching usernameField old=",this.usernameField.el,"new=",activeElement);
this.usernameField.$el.off(this.focusEvents);
this.usernameField = createFieldObjForEl(activeElement);
this.usernameField = createFieldObjForEl(activeElement, USERNAME_TYPE);
}
return this.usernameField;
}
// Some sites show a fake username/password field with a "watermark" (e.g., it
@ -195,7 +210,7 @@ var PasswordForm = function($, DomMonitor) {
var fakePasswordEl = $(this.config.fakePasswordFill).get(0);
//console.log("maybeFillFakePassword", fakePasswordEl);
if (fakePasswordEl) {
fillField.call(this, fakePasswordEl, value, callback);
fillField.call(this, createFieldObjForEl(fakePasswordEl, FAKE_PASSWORD_TYPE), value, callback);
return true;
}
return false;
@ -203,9 +218,10 @@ var PasswordForm = function($, DomMonitor) {
// Create an object that representing username and password fields.
// el is the raw DOM element, $el is the jQuery wrapped DOM element, and val
// is for storing captured credentials.
function createFieldObjForEl(el) {
return { el: el, $el: $(el), val: "" };
// is for storing captured credentials. type is descriptive string, one of:
// "password", "username", "fakePassword"
function createFieldObjForEl(el, type) {
return { el: el, $el: $(el), val: "", type: type };
}
// PasswordForm constructor function. <args> should contain the following:
@ -223,19 +239,18 @@ var PasswordForm = function($, DomMonitor) {
containingEl = args.containingEl,
siteConfig = args.siteConfig;
this.id = id;
this.passwordField = createFieldObjForEl(passwordEl);
this.passwordField = createFieldObjForEl(passwordEl, PASSWORD_TYPE);
this.$containingEl = $(containingEl);
this.config = siteConfig || {};
// "input" event will capture paste input and key by key input on modern browsers
// Note: this will not trigger when values are filled by javsacript or the browser
this.inputEvents = "input."+this.id;
this.submitEvents = "submit."+this.id;
this.focusEvents = "focus.username"+this.id;
this.removedEvents = "isRemoved.pwdEl"+this.id;
if (usernameEl) {
this.usernameField = createFieldObjForEl(usernameEl);
this.usernameField = createFieldObjForEl(usernameEl, USERNAME_TYPE);
} else {
// This must be called after passwordField and $containingEl are set
this.usernameField = findUsernameField.call(this);
@ -260,18 +275,16 @@ var PasswordForm = function($, DomMonitor) {
}
};
// Notify the observer whenever we detect interesting input events or form submits.
// Notify the observer whenever we detect interesting input events.
PasswordForm.prototype.observe = function(observer) {
this.observer = observer;
this.$containingEl.on(this.inputEvents, "input", capturedCredentialsCallback.bind(this));
this.$containingEl.on(this.submitEvents, capturedCredentialsCallback.bind(this));
return this;
};
// Turn off all internal observers
PasswordForm.prototype.unobserve = function() {
this.$containingEl.off(this.inputEvents);
this.$containingEl.off(this.submitEvents);
this.$containingEl.off(this.removedEvents);
this.usernameField.$el.off(this.focusEvents);
this.observer = null;
@ -285,10 +298,10 @@ var PasswordForm = function($, DomMonitor) {
// some cortortions to "type like a human" and handle dynamic username field "switch-outs".
PasswordForm.prototype.fill = function(credentials) {
maybeTickleFakeInputFields.call(this, FAKE_USERNAME_FIELD_HINTS);
fillField.call(this, this.usernameField.el, credentials.username, (function() {
fillField.call(this, this.usernameField, credentials.username, (function() {
maybeTickleFakeInputFields.call(this, FAKE_PASSWORD_FIELD_HINTS);
maybeFillFakePassword.call(this, credentials.password);
fillField.call(this, this.passwordField.el, credentials.password);
fillField.call(this, this.passwordField, credentials.password);
}).bind(this));
return this;
};