got citi.com working
This commit is contained in:
Родитель
ed46aaa232
Коммит
90e96ba9d4
3
TODO
3
TODO
|
@ -1,5 +1,8 @@
|
|||
get multistage working
|
||||
HTTP auth capture/fill
|
||||
capturing and filling lone password fields
|
||||
tdameritrade may need some type like a human for lone password field on transfer page
|
||||
AJAX login: https://www.select-a-spot.com
|
||||
bayareacurling has annoying change password page
|
||||
|
||||
start capturing login url and title
|
||||
|
|
|
@ -169,7 +169,7 @@ var CommandHandler = function(Messaging, CapturedCredentialStorage) {
|
|||
//
|
||||
Messaging.addContentMessageListener(function(request, sender, sendResponse) {
|
||||
if (request.type && commandHandlers[request.type]) {
|
||||
console.log("Msg received", request, sender);
|
||||
//console.log("Msg received", request, sender);
|
||||
return commandHandlers[request.type].call(commandHandlers,request.message,sender,sendResponse);
|
||||
}
|
||||
});
|
||||
|
|
|
@ -24,3 +24,5 @@
|
|||
# fields. The real fields appear after clicking on the specified element.
|
||||
hulu.com:
|
||||
clickOn: "input.inactive.dummy.user"
|
||||
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
var PasswordForm = function($, DomMonitor) {
|
||||
const VALID_USERNAME_INPUT_TYPES = ['text','email','url','tel','number'];
|
||||
|
||||
function notifyObserver(fn) {
|
||||
var args;
|
||||
|
@ -28,17 +29,122 @@ var PasswordForm = function($, DomMonitor) {
|
|||
notifyObserver.call(this, "credentialsCaptured");
|
||||
}
|
||||
|
||||
var PasswordForm = function(id, usernameField, passwordField, containingEl, siteConfig) {
|
||||
function typeValueInElementHelper($el, value, currentIndex, callback) {
|
||||
if (currentIndex >= value.length) {
|
||||
if (callback) callback();
|
||||
return;
|
||||
}
|
||||
var partialValue = value.substring(0, currentIndex+1);
|
||||
setTimeout(function() {
|
||||
$el.keydown();
|
||||
$el.val(value);
|
||||
setTimeout(function() {
|
||||
$el.keyup();
|
||||
setTimeout(function() {
|
||||
typeValueInElementHelper($el, value, currentIndex+1, callback);
|
||||
},0);
|
||||
},0);
|
||||
},0);
|
||||
|
||||
}
|
||||
|
||||
function fillField(el, value, callback) {
|
||||
var $el = $(el);
|
||||
$el.focus();
|
||||
var blur = function() {
|
||||
$el.blur();
|
||||
setTimeout(callback, 0);
|
||||
}
|
||||
value = value || "";
|
||||
// if typeValueInElementHelper is too slow, then use this code below.
|
||||
// $el.val(value);
|
||||
// blur();
|
||||
setTimeout(function() {
|
||||
// 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 (inputIsPossibleUsernameField(activeElement) || inputIsPasswordField(activeElement)) {
|
||||
$el = $(activeElement);
|
||||
}
|
||||
typeValueInElementHelper($el, value, 0, blur);
|
||||
}, 0);
|
||||
}
|
||||
|
||||
function inputIsPossibleUsernameField(input) {
|
||||
return input.tagName.toLowerCase() === "input" &&
|
||||
VALID_USERNAME_INPUT_TYPES.indexOf(input.type.toLowerCase()) !== -1;
|
||||
}
|
||||
|
||||
function inputIsPasswordField(input) {
|
||||
return input.tagName.toLowerCase() === "input" && input.type.toLowerCase() === "password";
|
||||
}
|
||||
|
||||
function maybeGetConfiguredUsernameField() {
|
||||
var $username = $(this.config.un);
|
||||
if ($username.length > 0 && this.$containingForm.has($username)) {
|
||||
return $username.get(0);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function findBestUsernameFieldCandidate() {
|
||||
var inputsList = this.$containingEl.find('input').get();
|
||||
var pwFieldIdx = inputsList.indexOf(this.passwordField.el);
|
||||
for (var inputIdx = pwFieldIdx-1; inputIdx >= 0; inputIdx--) {
|
||||
if (inputIsPossibleUsernameField(inputsList[inputIdx])) {
|
||||
return inputsList[inputIdx];
|
||||
}
|
||||
}
|
||||
// Couldn't find a valid username input field.
|
||||
return null;
|
||||
}
|
||||
|
||||
function findUsernameField() {
|
||||
// If the username field is explicitly configured, then get it
|
||||
var usernameEl = maybeGetConfiguredUsernameField.call(this);
|
||||
// If we didn't find a configured username field for the form, then
|
||||
// look for one
|
||||
if (!usernameEl) {
|
||||
usernameEl = findBestUsernameFieldCandidate.call(this);
|
||||
}
|
||||
return { el: usernameEl, $el: $(usernameEl) };
|
||||
}
|
||||
|
||||
function handlePossibleUsernameFieldChange() {
|
||||
var activeElement = document.activeElement;
|
||||
// If the user focuses on a username element and the active element changes, then
|
||||
// we should update what our notion of the username field is.
|
||||
// See https://online.citibank.com for where this is needed.
|
||||
if (activeElement !== this.usernameField.el &&
|
||||
inputIsPossibleUsernameField(activeElement)) {
|
||||
this.usernameField.$el.off(this.focusEvents);
|
||||
this.usernameField = { el: activeElement, $el: $(activeElement) };
|
||||
}
|
||||
}
|
||||
|
||||
var PasswordForm = function(id, passwordEl, $containingEl, siteConfig) {
|
||||
this.id = id;
|
||||
this.usernameField = usernameField;
|
||||
this.passwordField = passwordField;
|
||||
this.containingEl = containingEl;
|
||||
this.$containingEl = $(this.containingEl);
|
||||
this.passwordField = { el: passwordEl };
|
||||
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;
|
||||
|
||||
// Setting 'autocomplete' to 'off' will signal to the native
|
||||
// password manager to ignore this login wrt filling and capturing.
|
||||
// This solves the "double infobar" problem when linking.
|
||||
this.passwordField.el.setAttribute('autocomplete', 'off');
|
||||
|
||||
// This must be called after passwordField and $containingEl are set
|
||||
this.usernameField = findUsernameField.call(this);
|
||||
this.usernameField.$el.on(this.focusEvents, handlePossibleUsernameFieldChange.bind(this));
|
||||
|
||||
// This is an external observer interested in events on the PasswordForm,
|
||||
// most likely the PasswordFormInspector.
|
||||
this.observer = null;
|
||||
|
@ -58,6 +164,7 @@ var PasswordForm = function($, DomMonitor) {
|
|||
PasswordForm.prototype.unobserve = function() {
|
||||
this.$containingEl.off(this.inputEvents);
|
||||
this.$containingEl.off(this.submitEvents);
|
||||
this.usernameField.$el.off(this.focusEvents);
|
||||
this.observer = null;
|
||||
return this;
|
||||
};
|
||||
|
@ -67,8 +174,9 @@ var PasswordForm = function($, DomMonitor) {
|
|||
if (clickOn) {
|
||||
$(clickOn).click();
|
||||
}
|
||||
this.usernameField.el.value = credentials.username;
|
||||
this.passwordField.el.value = credentials.password;
|
||||
fillField(this.usernameField.el, credentials.username, (function() {
|
||||
fillField(this.passwordField.el, credentials.password);
|
||||
}).bind(this));
|
||||
return this;
|
||||
};
|
||||
|
||||
|
@ -92,6 +200,7 @@ var PasswordForm = function($, DomMonitor) {
|
|||
}
|
||||
|
||||
PasswordForm.prototype.highlight = function() {
|
||||
var containingEl = this.$containingEl.get(0);
|
||||
if (this.usernameField.el) {
|
||||
highlightEl(this.usernameField.el, "blue");
|
||||
} else {
|
||||
|
@ -102,8 +211,8 @@ var PasswordForm = function($, DomMonitor) {
|
|||
} else {
|
||||
console.log("No password field found for", this);
|
||||
}
|
||||
if (this.containingEl) {
|
||||
highlightEl(this.containingEl, "red");
|
||||
if (containingEl) {
|
||||
highlightEl(containingEl, "red");
|
||||
} else {
|
||||
console.log("No containing form field found for", this);
|
||||
};
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
var PasswordFormInspector = function($, PasswordForm, DomMonitor) {
|
||||
const VALID_USERNAME_INPUT_TYPES = ['text','email','url','tel','number'];
|
||||
|
||||
var running = false;
|
||||
|
||||
var observers = [];
|
||||
|
@ -16,18 +14,6 @@ var PasswordFormInspector = function($, PasswordForm, DomMonitor) {
|
|||
return idCounter;
|
||||
}
|
||||
|
||||
function getUsernameFieldForPasswordField(containerForm,passwordEl) {
|
||||
var inputsList = containerForm.find('input').get();
|
||||
var pwFieldIdx = inputsList.indexOf(passwordEl);
|
||||
for (var inputIdx = pwFieldIdx-1; inputIdx >= 0; inputIdx--) {
|
||||
if (VALID_USERNAME_INPUT_TYPES.indexOf(inputsList[inputIdx].type.toLowerCase()) != -1) {
|
||||
return inputsList[inputIdx];
|
||||
}
|
||||
}
|
||||
// Couldn't find a valid username input field.
|
||||
return null;
|
||||
}
|
||||
|
||||
function findForms() {
|
||||
var $passwordInputs = $('input[type=password]');
|
||||
var oldPasswordForms = passwordForms; // TODO: clean these up
|
||||
|
@ -39,7 +25,7 @@ var PasswordFormInspector = function($, PasswordForm, DomMonitor) {
|
|||
usernameFields = {},
|
||||
numPasswordInputs;
|
||||
if ($containingForm.length === 0) {
|
||||
console.log("Could not find form element, passwordEl=", $passwordEl);
|
||||
console.log("Could not find form element, passwordEl=", passwordEl);
|
||||
// Could not find an HTML form, so now just look for any element that
|
||||
// contains both the password field and some other input field with type=text.
|
||||
// Note: this will also find inputs with no type specified, which defaults to text.
|
||||
|
@ -49,19 +35,13 @@ var PasswordFormInspector = function($, PasswordForm, DomMonitor) {
|
|||
if ($containingForm.length === 0) {
|
||||
return;
|
||||
}
|
||||
// Setting 'autocomplete' to 'off' will signal to the native
|
||||
// password manager to ignore this login wrt filling and capturing.
|
||||
// This solves the "double infobar" problem when linking.
|
||||
passwordEl.setAttribute('autocomplete', 'off');
|
||||
numPasswordInputs = $containingForm.find('input[type=password]').length;
|
||||
// If the containing form contains multiple password field, then ignore
|
||||
// for now. This is probably a change password field.
|
||||
if (numPasswordInputs > 1) return;
|
||||
usernameEl = getUsernameFieldForPasswordField($containingForm,passwordEl);
|
||||
passwordForms.push(new PasswordForm(generateId(),
|
||||
{ el: usernameEl },
|
||||
{ el: passwordEl },
|
||||
$containingForm.get(0),
|
||||
passwordEl,
|
||||
$containingForm,
|
||||
siteConfig));
|
||||
});
|
||||
observeForms();
|
||||
|
|
Загрузка…
Ссылка в новой задаче