1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-13 06:43:35 +00:00

detect and update password changes

This commit is contained in:
Kyle Spearrin
2018-07-31 23:24:11 -04:00
parent 272f6cfde6
commit cf57eadd1d
9 changed files with 248 additions and 110 deletions

2
jslib

Submodule jslib updated: 41ab22a82f...a1112988c4

View File

@@ -485,6 +485,12 @@
"notificationNeverSave": { "notificationNeverSave": {
"message": "Never for this website" "message": "Never for this website"
}, },
"notificationChangeDesc": {
"message": "Do you want to update this password in Bitwarden?"
},
"notificationChangeSave": {
"message": "Yes, Update Now"
},
"disableContextMenuItem": { "disableContextMenuItem": {
"message": "Disable Context Menu Options" "message": "Disable Context Menu Options"
}, },

View File

@@ -95,7 +95,7 @@ export default class MainBackground {
onUpdatedRan: boolean; onUpdatedRan: boolean;
onReplacedRan: boolean; onReplacedRan: boolean;
loginToAutoFill: any = null; loginToAutoFill: any = null;
loginsToAdd: any[] = []; notificationQueue: any[] = [];
private commandsBackground: CommandsBackground; private commandsBackground: CommandsBackground;
private contextMenusBackground: ContextMenusBackground; private contextMenusBackground: ContextMenusBackground;
@@ -195,9 +195,8 @@ export default class MainBackground {
setTimeout(async () => { setTimeout(async () => {
await this.environmentService.setUrlsFromStorage(); await this.environmentService.setUrlsFromStorage();
await this.setIcon(); await this.setIcon();
this.cleanupLoginsToAdd(); this.cleanupNotificationQueue();
await this.fullSync(true); await this.fullSync(true);
resolve(); resolve();
}, 500); }, 500);
}); });
@@ -284,19 +283,19 @@ export default class MainBackground {
}, options); }, options);
} }
async checkLoginsToAdd(tab: any = null): Promise<any> { async checkNotificationQueue(tab: any = null): Promise<any> {
if (!this.loginsToAdd.length) { if (this.notificationQueue.length === 0) {
return; return;
} }
if (tab != null) { if (tab != null) {
this.doCheck(tab); this.doNotificationQueueCheck(tab);
return; return;
} }
const currentTab = await BrowserApi.getTabFromCurrentWindow(); const currentTab = await BrowserApi.getTabFromCurrentWindow();
if (currentTab != null) { if (currentTab != null) {
this.doCheck(currentTab); this.doNotificationQueueCheck(currentTab);
} }
} }
@@ -499,17 +498,16 @@ export default class MainBackground {
} }
} }
private cleanupLoginsToAdd() { private cleanupNotificationQueue() {
for (let i = this.loginsToAdd.length - 1; i >= 0; i--) { for (let i = this.notificationQueue.length - 1; i >= 0; i--) {
if (this.loginsToAdd[i].expires < new Date()) { if (this.notificationQueue[i].expires < new Date()) {
this.loginsToAdd.splice(i, 1); this.notificationQueue.splice(i, 1);
} }
} }
setTimeout(() => this.cleanupNotificationQueue(), 2 * 60 * 1000); // check every 2 minutes
setTimeout(() => this.cleanupLoginsToAdd(), 2 * 60 * 1000); // check every 2 minutes
} }
private doCheck(tab: any) { private doNotificationQueueCheck(tab: any) {
if (tab == null) { if (tab == null) {
return; return;
} }
@@ -519,14 +517,19 @@ export default class MainBackground {
return; return;
} }
for (let i = 0; i < this.loginsToAdd.length; i++) { for (let i = 0; i < this.notificationQueue.length; i++) {
if (this.loginsToAdd[i].tabId !== tab.id || this.loginsToAdd[i].domain !== tabDomain) { if (this.notificationQueue[i].tabId !== tab.id || this.notificationQueue[i].domain !== tabDomain) {
continue; continue;
} }
if (this.notificationQueue[i].type === 'addLogin') {
BrowserApi.tabSendMessageData(tab, 'openNotificationBar', { BrowserApi.tabSendMessageData(tab, 'openNotificationBar', {
type: 'add', type: 'add',
}); });
} else if (this.notificationQueue[i].type === 'changePassword') {
BrowserApi.tabSendMessageData(tab, 'openNotificationBar', {
type: 'change',
});
}
break; break;
} }
} }

View File

@@ -114,12 +114,19 @@ export default class RuntimeBackground {
case 'bgAddLogin': case 'bgAddLogin':
await this.addLogin(msg.login, sender.tab); await this.addLogin(msg.login, sender.tab);
break; break;
case 'bgChangedPassword':
await this.changedPassword(msg.data, sender.tab);
break;
case 'bgAddClose': case 'bgAddClose':
this.removeAddLogin(sender.tab); case 'bgChangeClose':
this.removeTabFromNotificationQueue(sender.tab);
break; break;
case 'bgAddSave': case 'bgAddSave':
await this.saveAddLogin(sender.tab); await this.saveAddLogin(sender.tab);
break; break;
case 'bgChangeSave':
await this.saveChangePassword(sender.tab);
break;
case 'bgNeverSave': case 'bgNeverSave':
await this.saveNever(sender.tab); await this.saveNever(sender.tab);
break; break;
@@ -181,27 +188,27 @@ export default class RuntimeBackground {
} }
private async saveAddLogin(tab: any) { private async saveAddLogin(tab: any) {
for (let i = this.main.loginsToAdd.length - 1; i >= 0; i--) { for (let i = this.main.notificationQueue.length - 1; i >= 0; i--) {
if (this.main.loginsToAdd[i].tabId !== tab.id) { const queueMessage = this.main.notificationQueue[i];
if (queueMessage.tabId !== tab.id || queueMessage.type !== 'addLogin') {
continue; continue;
} }
const loginInfo = this.main.loginsToAdd[i];
const tabDomain = this.platformUtilsService.getDomain(tab.url); const tabDomain = this.platformUtilsService.getDomain(tab.url);
if (tabDomain != null && tabDomain !== loginInfo.domain) { if (tabDomain != null && tabDomain !== queueMessage.domain) {
continue; continue;
} }
this.main.loginsToAdd.splice(i, 1); this.main.notificationQueue.splice(i, 1);
const loginModel = new LoginView(); const loginModel = new LoginView();
const loginUri = new LoginUriView(); const loginUri = new LoginUriView();
loginUri.uri = loginInfo.uri; loginUri.uri = queueMessage.uri;
loginModel.uris = [loginUri]; loginModel.uris = [loginUri];
loginModel.username = loginInfo.username; loginModel.username = queueMessage.username;
loginModel.password = loginInfo.password; loginModel.password = queueMessage.password;
const model = new CipherView(); const model = new CipherView();
model.name = Utils.getHostname(loginInfo.uri) || loginInfo.domain; model.name = Utils.getHostname(queueMessage.uri) || queueMessage.domain;
model.type = CipherType.Login; model.type = CipherType.Login;
model.login = loginModel; model.login = loginModel;
@@ -216,19 +223,49 @@ export default class RuntimeBackground {
} }
} }
private async saveNever(tab: any) { private async saveChangePassword(tab: any) {
for (let i = this.main.loginsToAdd.length - 1; i >= 0; i--) { for (let i = this.main.notificationQueue.length - 1; i >= 0; i--) {
if (this.main.loginsToAdd[i].tabId !== tab.id) { const queueMessage = this.main.notificationQueue[i];
if (queueMessage.tabId !== tab.id || queueMessage.type !== 'changePassword') {
continue; continue;
} }
const loginInfo = this.main.loginsToAdd[i];
const tabDomain = this.platformUtilsService.getDomain(tab.url); const tabDomain = this.platformUtilsService.getDomain(tab.url);
if (tabDomain != null && tabDomain !== loginInfo.domain) { if (tabDomain != null && tabDomain !== queueMessage.domain) {
continue; continue;
} }
this.main.loginsToAdd.splice(i, 1); this.main.notificationQueue.splice(i, 1);
const cipher = await this.cipherService.get(queueMessage.cipherId);
if (cipher != null && cipher.type === CipherType.Login) {
const model = await cipher.decrypt();
model.login.password = queueMessage.newPassword;
const newCipher = await this.cipherService.encrypt(model);
await this.cipherService.saveWithServer(newCipher);
this.analytics.ga('send', {
hitType: 'event',
eventAction: 'Changed Password from Notification Bar',
});
}
BrowserApi.tabSendMessageData(tab, 'closeNotificationBar');
}
}
private async saveNever(tab: any) {
for (let i = this.main.notificationQueue.length - 1; i >= 0; i--) {
const queueMessage = this.main.notificationQueue[i];
if (queueMessage.tabId !== tab.id || queueMessage.type !== 'addLogin') {
continue;
}
const tabDomain = this.platformUtilsService.getDomain(tab.url);
if (tabDomain != null && tabDomain !== queueMessage.domain) {
continue;
}
this.main.notificationQueue.splice(i, 1);
const hostname = Utils.getHostname(tab.url); const hostname = Utils.getHostname(tab.url);
await this.cipherService.saveNeverDomain(hostname); await this.cipherService.saveNeverDomain(hostname);
BrowserApi.tabSendMessageData(tab, 'closeNotificationBar'); BrowserApi.tabSendMessageData(tab, 'closeNotificationBar');
@@ -251,10 +288,10 @@ export default class RuntimeBackground {
} }
if (!match) { if (!match) {
// remove any old logins for this tab // remove any old messages for this tab
this.removeAddLogin(tab); this.removeTabFromNotificationQueue(tab);
this.main.notificationQueue.push({
this.main.loginsToAdd.push({ type: 'addLogin',
username: loginInfo.username, username: loginInfo.username,
password: loginInfo.password, password: loginInfo.password,
domain: loginDomain, domain: loginDomain,
@@ -262,15 +299,37 @@ export default class RuntimeBackground {
tabId: tab.id, tabId: tab.id,
expires: new Date((new Date()).getTime() + 30 * 60000), // 30 minutes expires: new Date((new Date()).getTime() + 30 * 60000), // 30 minutes
}); });
await this.main.checkNotificationQueue(tab);
await this.main.checkLoginsToAdd(tab);
} }
} }
private removeAddLogin(tab: any) { private async changedPassword(changeData: any, tab: any) {
for (let i = this.main.loginsToAdd.length - 1; i >= 0; i--) { const loginDomain = this.platformUtilsService.getDomain(changeData.url);
if (this.main.loginsToAdd[i].tabId === tab.id) { if (loginDomain == null) {
this.main.loginsToAdd.splice(i, 1); return;
}
const ciphers = await this.cipherService.getAllDecryptedForUrl(changeData.url);
const matches = ciphers.filter((c) => c.login.password === changeData.currentPassword);
if (matches.length === 1) {
// remove any old messages for this tab
this.removeTabFromNotificationQueue(tab);
this.main.notificationQueue.push({
type: 'changePassword',
cipherId: matches[0].id,
newPassword: changeData.newPassword,
domain: loginDomain,
tabId: tab.id,
expires: new Date((new Date()).getTime() + 30 * 60000), // 30 minutes
});
await this.main.checkNotificationQueue(tab);
}
}
private removeTabFromNotificationQueue(tab: any) {
for (let i = this.main.notificationQueue.length - 1; i >= 0; i--) {
if (this.main.notificationQueue[i].tabId === tab.id) {
this.main.notificationQueue.splice(i, 1);
} }
} }
} }
@@ -373,6 +432,8 @@ export default class RuntimeBackground {
notificationAddSave: this.i18nService.t('notificationAddSave'), notificationAddSave: this.i18nService.t('notificationAddSave'),
notificationNeverSave: this.i18nService.t('notificationNeverSave'), notificationNeverSave: this.i18nService.t('notificationNeverSave'),
notificationAddDesc: this.i18nService.t('notificationAddDesc'), notificationAddDesc: this.i18nService.t('notificationAddDesc'),
notificationChangeSave: this.i18nService.t('notificationChangeSave'),
notificationChangeDesc: this.i18nService.t('notificationChangeDesc'),
}; };
} }

View File

@@ -22,7 +22,7 @@ export default class TabsBackground {
}, true); }, true);
this.tabs.addEventListener('navigate', async (ev: any) => { this.tabs.addEventListener('navigate', async (ev: any) => {
await this.main.checkLoginsToAdd(); await this.main.checkNotificationQueue();
await this.main.refreshBadgeAndMenu(); await this.main.refreshBadgeAndMenu();
}, true); }, true);
@@ -38,7 +38,7 @@ export default class TabsBackground {
return; return;
} }
this.main.onReplacedRan = true; this.main.onReplacedRan = true;
await this.main.checkLoginsToAdd(); await this.main.checkNotificationQueue();
await this.main.refreshBadgeAndMenu(); await this.main.refreshBadgeAndMenu();
}); });
@@ -47,7 +47,7 @@ export default class TabsBackground {
return; return;
} }
this.main.onUpdatedRan = true; this.main.onUpdatedRan = true;
await this.main.checkLoginsToAdd(); await this.main.checkNotificationQueue();
await this.main.refreshBadgeAndMenu(); await this.main.refreshBadgeAndMenu();
}); });
} }

View File

@@ -222,6 +222,7 @@ document.addEventListener('DOMContentLoaded', (event) => {
formEl: formEl, formEl: formEl,
usernameEl: null, usernameEl: null,
passwordEl: null, passwordEl: null,
passwordEls: null,
}; };
locateFields(formDataObj); locateFields(formDataObj);
formData.push(formDataObj); formData.push(formDataObj);
@@ -240,8 +241,8 @@ document.addEventListener('DOMContentLoaded', (event) => {
submitButton.removeEventListener('click', formSubmitted, false); submitButton.removeEventListener('click', formSubmitted, false);
submitButton.addEventListener('click', formSubmitted, false); submitButton.addEventListener('click', formSubmitted, false);
} else { } else {
const possibleSubmitButtons = form.querySelectorAll('a, span, button[type="button"], ' + const possibleSubmitButtons = Array.from(form.querySelectorAll('a, span, button[type="button"], ' +
'input[type="button"]') as NodeListOf<HTMLElement>; 'input[type="button"]')) as HTMLElement[];
possibleSubmitButtons.forEach((button) => { possibleSubmitButtons.forEach((button) => {
if (button == null || button.tagName == null) { if (button == null || button.tagName == null) {
return; return;
@@ -268,41 +269,53 @@ document.addEventListener('DOMContentLoaded', (event) => {
} }
function locateFields(formDataObj: any) { function locateFields(formDataObj: any) {
const passwordId: string = formDataObj.data.password != null ? formDataObj.data.password.htmlID : null; const inputs = Array.from(document.getElementsByTagName('input'));
const usernameId: string = formDataObj.data.username != null ? formDataObj.data.username.htmlID : null; formDataObj.usernameEl = locateField(formDataObj.formEl, formDataObj.data.username, inputs);
const passwordName: string = formDataObj.data.password != null ? formDataObj.data.password.htmlName : null; if (formDataObj.usernameEl != null && formDataObj.data.password != null) {
const usernameName: string = formDataObj.data.username != null ? formDataObj.data.username.htmlName : null; formDataObj.passwordEl = locatePassword(formDataObj.formEl, formDataObj.data.password, inputs, true);
const inputs = document.getElementsByTagName('input'); } else if (formDataObj.data.passwords != null && formDataObj.data.passwords.length === 3) {
formDataObj.passwordEls = [];
if (passwordId != null && passwordId !== '') { formDataObj.data.passwords.forEach((pData: any) => {
try { const el = locatePassword(formDataObj.formEl, pData, inputs, false);
formDataObj.passwordEl = formDataObj.formEl.querySelector('#' + passwordId); if (el != null) {
} catch { } formDataObj.passwordEls.push(el);
} }
if (formDataObj.passwordEl == null && passwordName !== '') { });
formDataObj.passwordEl = formDataObj.formEl.querySelector('input[name="' + passwordName + '"]'); if (formDataObj.passwordEls.length !== 3) {
} formDataObj.passwordEls = null;
if (formDataObj.passwordEl == null && formDataObj.passwordEl != null) {
formDataObj.passwordEl = inputs[formDataObj.data.password.elementNumber];
if (formDataObj.passwordEl != null && formDataObj.passwordEl.type !== 'password') {
formDataObj.passwordEl = null;
} }
} }
if (formDataObj.passwordEl == null) { }
formDataObj.passwordEl = formDataObj.formEl.querySelector('input[type="password"]');
}
if (usernameId != null && usernameId !== '') { function locatePassword(form: HTMLFormElement, passwordData: any, inputs: HTMLInputElement[],
doLastFallback: boolean) {
let el = locateField(form, passwordData, inputs);
if (el != null && el.type !== 'password') {
el = null;
}
if (doLastFallback && el == null) {
el = form.querySelector('input[type="password"]');
}
return el;
}
function locateField(form: HTMLFormElement, fieldData: any, inputs: HTMLInputElement[]) {
if (fieldData == null) {
return;
}
let el: HTMLInputElement = null;
if (fieldData.htmlID != null && fieldData.htmlID !== '') {
try { try {
formDataObj.usernameEl = formDataObj.formEl.querySelector('#' + usernameId); el = form.querySelector('#' + fieldData.htmlID);
} catch { } } catch { }
} }
if (formDataObj.usernameEl == null && usernameName !== '') { if (el == null && fieldData.htmlName != null && fieldData.htmlName !== '') {
formDataObj.usernameEl = formDataObj.formEl.querySelector('input[name="' + usernameName + '"]'); el = form.querySelector('input[name="' + fieldData.htmlName + '"]');
} }
if (formDataObj.usernameEl == null && formDataObj.data.username != null) { if (el == null && fieldData.elementNumber != null) {
formDataObj.usernameEl = inputs[formDataObj.data.username.elementNumber]; el = inputs[fieldData.elementNumber];
} }
return el;
} }
function formSubmitted(e: Event) { function formSubmitted(e: Event) {
@@ -321,31 +334,59 @@ document.addEventListener('DOMContentLoaded', (event) => {
if (formData[i].formEl !== form) { if (formData[i].formEl !== form) {
continue; continue;
} }
if (formData[i].usernameEl == null || formData[i].passwordEl == null) { if (formData[i].usernameEl != null && formData[i].passwordEl != null) {
break; const login = {
username: formData[i].usernameEl.value,
password: formData[i].passwordEl.value,
url: document.URL,
};
if (login.username != null && login.username !== '' &&
login.password != null && login.password !== '') {
processedForm(form);
sendPlatformMessage({
command: 'bgAddLogin',
login: login,
});
break;
}
} }
if (formData[i].passwordEls != null && formData[i].passwordEls.length === 3) {
const login = { const passwords = formData[i].passwordEls
username: formData[i].usernameEl.value, .filter((el: HTMLInputElement) => el.value != null && el.value !== '')
password: formData[i].passwordEl.value, .map((el: HTMLInputElement) => el.value);
url: document.URL, if (passwords.length === 3) {
}; const newPass: string = passwords[1];
let curPass: string = null;
if (login.username != null && login.username !== '' && login.password != null && login.password !== '') { if (passwords[0] !== newPass && newPass === passwords[2]) {
form.dataset.bitwardenProcessed = '1'; curPass = passwords[0];
window.setTimeout(() => { } else if (newPass !== passwords[2] && passwords[0] === newPass) {
form.dataset.bitwardenProcessed = '0'; curPass = passwords[2];
}, 500); }
if (newPass != null && curPass != null) {
sendPlatformMessage({ processedForm(form);
command: 'bgAddLogin', sendPlatformMessage({
login: login, command: 'bgChangedPassword',
}); data: {
break; newPassword: newPass,
currentPassword: curPass,
url: document.URL,
},
});
break;
}
}
} }
} }
} }
function processedForm(form: HTMLFormElement) {
form.dataset.bitwardenProcessed = '1';
window.setTimeout(() => {
form.dataset.bitwardenProcessed = '0';
}, 500);
}
function closeExistingAndOpenBar(type: string, typeData: any) { function closeExistingAndOpenBar(type: string, typeData: any) {
let barPage = 'notification/bar.html'; let barPage = 'notification/bar.html';
switch (type) { switch (type) {
@@ -364,6 +405,9 @@ document.addEventListener('DOMContentLoaded', (event) => {
case 'add': case 'add':
barPage = barPage + '?add=1'; barPage = barPage + '?add=1';
break; break;
case 'change':
barPage = barPage + '?change=1';
break;
default: default:
break; break;
} }
@@ -426,6 +470,11 @@ document.addEventListener('DOMContentLoaded', (event) => {
command: 'bgAddClose', command: 'bgAddClose',
}); });
break; break;
case 'change':
sendPlatformMessage({
command: 'bgChangeClose',
});
break;
default: default:
break; break;
} }

View File

@@ -34,6 +34,16 @@
</tr> </tr>
</tbody> </tbody>
</table> </table>
<table class="inner-table" cellpadding="0" cellspacing="0" id="template-change">
<tbody>
<tr>
<td class="change-text"></td>
<td align="right" class="change-buttons">
<button class="change-save"></button>
</td>
</tr>
</tbody>
</table>
<div id="template-alert"></div> <div id="template-alert"></div>
</div> </div>
</body> </body>

View File

@@ -23,6 +23,8 @@ document.addEventListener('DOMContentLoaded', () => {
i18n.notificationAddSave = chrome.i18n.getMessage('notificationAddSave'); i18n.notificationAddSave = chrome.i18n.getMessage('notificationAddSave');
i18n.notificationNeverSave = chrome.i18n.getMessage('notificationNeverSave'); i18n.notificationNeverSave = chrome.i18n.getMessage('notificationNeverSave');
i18n.notificationAddDesc = chrome.i18n.getMessage('notificationAddDesc'); i18n.notificationAddDesc = chrome.i18n.getMessage('notificationAddDesc');
i18n.notificationChangeSave = chrome.i18n.getMessage('notificationChangeSave');
i18n.notificationChangeDesc = chrome.i18n.getMessage('notificationChangeDesc');
// delay 50ms so that we get proper body dimensions // delay 50ms so that we get proper body dimensions
setTimeout(load, 50); setTimeout(load, 50);
@@ -42,12 +44,15 @@ document.addEventListener('DOMContentLoaded', () => {
if (bodyRect.width < 768) { if (bodyRect.width < 768) {
document.querySelector('#template-add .add-save').textContent = i18n.yes; document.querySelector('#template-add .add-save').textContent = i18n.yes;
document.querySelector('#template-add .never-save').textContent = i18n.never; document.querySelector('#template-add .never-save').textContent = i18n.never;
document.querySelector('#template-change .change-save').textContent = i18n.yes;
} else { } else {
document.querySelector('#template-add .add-save').textContent = i18n.notificationAddSave; document.querySelector('#template-add .add-save').textContent = i18n.notificationAddSave;
document.querySelector('#template-add .never-save').textContent = i18n.notificationNeverSave; document.querySelector('#template-add .never-save').textContent = i18n.notificationNeverSave;
document.querySelector('#template-change .change-save').textContent = i18n.notificationChangeSave;
} }
document.querySelector('#template-add .add-text').textContent = i18n.notificationAddDesc; document.querySelector('#template-add .add-text').textContent = i18n.notificationAddDesc;
document.querySelector('#template-change .change-text').textContent = i18n.notificationChangeDesc;
if (getQueryVariable('add')) { if (getQueryVariable('add')) {
setContent(document.getElementById('template-add')); setContent(document.getElementById('template-add'));
@@ -68,6 +73,15 @@ document.addEventListener('DOMContentLoaded', () => {
command: 'bgNeverSave' command: 'bgNeverSave'
}); });
}); });
} else if (getQueryVariable('change')) {
setContent(document.getElementById('template-change'));
var changeButton = document.querySelector('#template-change-clone .change-save');
changeButton.addEventListener('click', (e) => {
e.preventDefault();
sendPlatformMessage({
command: 'bgChangeSave'
});
});
} else if (getQueryVariable('info')) { } else if (getQueryVariable('info')) {
setContent(document.getElementById('template-alert')); setContent(document.getElementById('template-alert'));
document.getElementById('template-alert-clone').textContent = getQueryVariable('info'); document.getElementById('template-alert-clone').textContent = getQueryVariable('info');

View File

@@ -119,24 +119,19 @@ export default class AutofillService implements AutofillServiceInterface {
continue; continue;
} }
for (let i = 0; i < passwordFields.length; i++) { const formPasswordFields = passwordFields.filter((pf) => formKey === pf.form);
const pf = passwordFields[i]; if (formPasswordFields.length > 0) {
if (formKey !== pf.form) { let uf = this.findUsernameField(pageDetails, formPasswordFields[0], false, false);
continue;
}
let uf = this.findUsernameField(pageDetails, pf, false, false);
if (uf == null) { if (uf == null) {
// not able to find any viewable username fields. maybe there are some "hidden" ones? // not able to find any viewable username fields. maybe there are some "hidden" ones?
uf = this.findUsernameField(pageDetails, pf, true, false); uf = this.findUsernameField(pageDetails, formPasswordFields[0], true, false);
} }
formData.push({ formData.push({
form: pageDetails.forms[formKey], form: pageDetails.forms[formKey],
password: pf, password: formPasswordFields[0],
username: uf, username: uf,
passwords: formPasswordFields,
}); });
break;
} }
} }