2018-01-12 20:44:44 +01:00
! ( function ( ) {
2016-09-16 05:24:45 +02:00
/ *
1 Password Extension
2021-12-21 15:43:35 +01:00
2016-09-16 05:24:45 +02:00
Lovingly handcrafted by Dave Teare , Michael Fey , Rad Azzouz , and Roustem Karimov .
Copyright ( c ) 2014 AgileBits . All rights reserved .
2021-12-21 15:43:35 +01:00
2016-09-16 05:24:45 +02:00
=== === === === === === === === === === === === === === === === === === === === === === === === === === ==
2021-12-21 15:43:35 +01:00
2016-09-16 05:24:45 +02:00
Copyright ( c ) 2014 AgileBits Inc .
2021-12-21 15:43:35 +01:00
2016-09-16 05:24:45 +02:00
Permission is hereby granted , free of charge , to any person obtaining a copy
of this software and associated documentation files ( the "Software" ) , to deal
in the Software without restriction , including without limitation the rights
to use , copy , modify , merge , publish , distribute , sublicense , and / or sell
copies of the Software , and to permit persons to whom the Software is
furnished to do so , subject to the following conditions :
2021-12-21 15:43:35 +01:00
2016-09-16 05:24:45 +02:00
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software .
2021-12-21 15:43:35 +01:00
2016-09-16 05:24:45 +02:00
THE SOFTWARE IS PROVIDED "AS IS" , WITHOUT WARRANTY OF ANY KIND , EXPRESS OR
IMPLIED , INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY ,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT . IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM , DAMAGES OR OTHER
LIABILITY , WHETHER IN AN ACTION OF CONTRACT , TORT OR OTHERWISE , ARISING FROM ,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE .
* /
2021-12-21 15:43:35 +01:00
2017-01-20 01:16:13 +01:00
/ *
MODIFICATIONS FROM ORIGINAL
2021-12-21 15:43:35 +01:00
2017-01-20 01:16:13 +01:00
1. Populate isFirefox
2. Remove isChrome and isSafari since they are not used .
3. Unminify and format to meet Mozilla review requirements .
2017-10-11 15:01:59 +02:00
4. Remove unnecessary input types from getFormElements query selector and limit number of elements returned .
2017-10-26 05:07:00 +02:00
5. Remove fakeTested prop .
2018-04-14 04:42:32 +02:00
6. Rename com . agilebits . * stuff to com . bitwarden . *
2018-09-12 19:24:30 +02:00
7. Remove "some useful globals" on window
2021-09-30 22:02:13 +02:00
8. Add ability to autofill span [ data - bwautofill ] elements
2022-08-10 03:30:26 +02:00
9. Add new handler , for new command that responds with page details in response callback
2022-10-21 18:55:20 +02:00
10. Handle sandbox iframe and sandbox rule in CSP
2022-11-04 16:44:21 +01:00
11. Work on array of saved urls instead of just one to determine if we should autofill non - https sites
2022-12-16 17:02:13 +01:00
12. Remove setting of attribute com . browser . browser . userEdited on user - inputs
2022-12-28 15:49:38 +01:00
13. Handle null value URLs in urlNotSecure
2017-01-20 01:16:13 +01:00
* /
2021-12-21 15:43:35 +01:00
2017-10-02 16:29:46 +02:00
function collect ( document , undefined ) {
2017-10-26 05:07:00 +02:00
// START MODIFICATION
2016-11-27 06:31:45 +01:00
var isFirefox = navigator . userAgent . indexOf ( 'Firefox' ) !== - 1 || navigator . userAgent . indexOf ( 'Gecko/' ) !== - 1 ;
2017-10-26 05:07:00 +02:00
// END MODIFICATION
2021-12-21 15:43:35 +01:00
2017-01-20 01:16:13 +01:00
document . elementsByOPID = { } ;
2021-12-21 15:43:35 +01:00
2017-01-20 04:43:45 +01:00
function getPageDetails ( theDoc , oneShotId ) {
// start helpers
2021-12-21 15:43:35 +01:00
2023-02-10 15:51:54 +01:00
/ * *
* For a given element ` el ` , returns the value of the attribute ` attrName ` .
* @ param { HTMLElement } el
* @ param { string } attrName
* @ returns { string } The value of the attribute
* /
2017-01-20 04:43:45 +01:00
function getElementAttrValue ( el , attrName ) {
var attrVal = el [ attrName ] ;
if ( 'string' == typeof attrVal ) {
return attrVal ;
2017-01-20 01:16:13 +01:00
}
2017-01-20 04:43:45 +01:00
attrVal = el . getAttribute ( attrName ) ;
return 'string' == typeof attrVal ? attrVal : null ;
2017-01-20 01:16:13 +01:00
}
2021-12-21 15:43:35 +01:00
2017-01-20 04:43:45 +01:00
// has the element been fake tested?
function checkIfFakeTested ( field , el ) {
if ( - 1 === [ 'text' , 'password' ] . indexOf ( el . type . toLowerCase ( ) ) ||
2017-10-03 22:11:11 +02:00
! ( passwordRegEx . test ( field . value ) ||
2017-01-20 04:43:45 +01:00
passwordRegEx . test ( field . htmlID ) || passwordRegEx . test ( field . htmlName ) ||
passwordRegEx . test ( field . placeholder ) || passwordRegEx . test ( field [ 'label-tag' ] ) ||
passwordRegEx . test ( field [ 'label-data' ] ) || passwordRegEx . test ( field [ 'label-aria' ] ) ) ) {
2017-01-20 01:16:13 +01:00
return false ;
}
2021-12-21 15:43:35 +01:00
2017-01-20 04:43:45 +01:00
if ( ! field . visible ) {
2017-01-20 01:16:13 +01:00
return true ;
}
2021-12-21 15:43:35 +01:00
2017-01-20 04:43:45 +01:00
if ( 'password' == el . type . toLowerCase ( ) ) {
2017-01-20 01:16:13 +01:00
return false ;
}
2021-12-21 15:43:35 +01:00
2017-01-20 04:43:45 +01:00
var elType = el . type ;
focusElement ( el , true ) ;
return elType !== el . type ;
2017-01-20 01:16:13 +01:00
}
2021-12-21 15:43:35 +01:00
2023-02-10 15:51:54 +01:00
/ * *
* Returns the value of the given element .
* @ param { HTMLElement } el
* @ returns { any } Value of the element
* /
2017-01-20 04:43:45 +01:00
function getElementValue ( el ) {
switch ( toLowerString ( el . type ) ) {
2017-01-20 01:16:13 +01:00
case 'checkbox' :
2017-01-20 04:43:45 +01:00
return el . checked ? '✓' : '' ;
2021-12-21 15:43:35 +01:00
2017-01-20 01:16:13 +01:00
case 'hidden' :
2017-01-20 04:43:45 +01:00
el = el . value ;
if ( ! el || 'number' != typeof el . length ) {
2017-01-20 01:16:13 +01:00
return '' ;
}
2017-01-20 04:43:45 +01:00
254 < el . length && ( el = el . substr ( 0 , 254 ) + '...SNIPPED' ) ;
return el ;
2021-12-21 15:43:35 +01:00
2017-01-20 01:16:13 +01:00
default :
2021-09-30 22:02:13 +02:00
// START MODIFICATION
if ( ! el . type && el . tagName . toLowerCase ( ) === 'span' ) {
return el . innerText ;
}
// END MODIFICATION
2017-01-20 04:43:45 +01:00
return el . value ;
2017-01-20 01:16:13 +01:00
}
}
2021-12-21 15:43:35 +01:00
2023-02-10 15:51:54 +01:00
/ * *
* If ` el ` is a ` <select> ` element , return an array of all of the options ' ` text ` properties .
* @ param { HTMLElement } el
* @ returns { string [ ] } An array of options for the given ` <select> ` element
* /
2017-01-20 04:43:45 +01:00
function getSelectElementOptions ( el ) {
if ( ! el . options ) {
return null ;
}
2021-12-21 15:43:35 +01:00
2017-01-20 04:43:45 +01:00
var options = Array . prototype . slice . call ( el . options ) . map ( function ( option ) {
var optionText = option . text ?
2017-10-03 22:11:11 +02:00
toLowerString ( option . text ) . replace ( /\\s/gm , '' ) . replace ( /[~`!@$%^&*()\\-_+=:;'\"\\[\\]|\\\\,<.>\\?]/gm , '' ) :
null ;
2021-12-21 15:43:35 +01:00
2017-01-20 04:43:45 +01:00
return [ optionText ? optionText : null , option . value ] ;
} )
2021-12-21 15:43:35 +01:00
2017-01-20 04:43:45 +01:00
return {
options : options
} ;
2017-01-20 01:16:13 +01:00
}
2021-12-21 15:43:35 +01:00
2023-02-10 15:51:54 +01:00
/ * *
* If ` el ` is in a data table , get the label in the row directly above it
* @ param { HTMLElement } el
* @ returns { string } A string containing the label , or null if not found
* /
2017-01-20 04:43:45 +01:00
function getLabelTop ( el ) {
var parent ;
2023-02-10 15:51:54 +01:00
// Traverse up the DOM until we reach either the top or the table data element containing our field
2017-10-03 22:11:11 +02:00
for ( el = el . parentElement || el . parentNode ; el && 'td' != toLowerString ( el . tagName ) ; ) {
2017-01-20 04:43:45 +01:00
el = el . parentElement || el . parentNode ;
2017-01-20 01:16:13 +01:00
}
2021-12-21 15:43:35 +01:00
2023-02-10 15:51:54 +01:00
// If we reached the top, return null
2017-01-20 04:43:45 +01:00
if ( ! el || void 0 === el ) {
2017-01-20 01:16:13 +01:00
return null ;
}
2021-12-21 15:43:35 +01:00
2023-02-10 15:51:54 +01:00
// Establish the parent of the table and make sure it's a table row
2017-01-20 04:43:45 +01:00
parent = el . parentElement || el . parentNode ;
if ( 'tr' != parent . tagName . toLowerCase ( ) ) {
2017-01-20 01:16:13 +01:00
return null ;
}
2021-12-21 15:43:35 +01:00
2023-02-10 15:51:54 +01:00
// Get the previous sibling of the table row and make sure it's a table row
2017-01-20 04:43:45 +01:00
parent = parent . previousElementSibling ;
if ( ! parent || 'tr' != ( parent . tagName + '' ) . toLowerCase ( ) ||
parent . cells && el . cellIndex >= parent . cells . length ) {
2017-01-20 01:16:13 +01:00
return null ;
}
2021-12-21 15:43:35 +01:00
2023-02-10 15:51:54 +01:00
// Parent is established as the row above the table data element containing our field
// Now let's traverse over to the cell in the same column as our field
2017-01-20 04:43:45 +01:00
el = parent . cells [ el . cellIndex ] ;
2023-02-10 15:51:54 +01:00
// Get the contents of this label
2017-01-20 04:43:45 +01:00
var elText = el . textContent || el . innerText ;
return elText = cleanText ( elText ) ;
2017-01-20 01:16:13 +01:00
}
2021-12-21 15:43:35 +01:00
2023-02-10 15:51:54 +01:00
/ * *
* Get the contents of the elements that are labels for ` el `
* @ param { HTMLElement } el
* @ returns { string } A string containing all of the ` innerText ` or ` textContent ` values for all elements that are labels for ` el `
* /
2017-01-20 04:43:45 +01:00
function getLabelTag ( el ) {
var docLabel ,
theLabels = [ ] ;
2021-12-21 15:43:35 +01:00
2017-01-20 04:43:45 +01:00
if ( el . labels && el . labels . length && 0 < el . labels . length ) {
theLabels = Array . prototype . slice . call ( el . labels ) ;
2017-01-20 01:16:13 +01:00
} else {
2017-01-20 04:43:45 +01:00
if ( el . id ) {
theLabels = theLabels . concat ( Array . prototype . slice . call (
queryDoc ( theDoc , 'label[for=' + JSON . stringify ( el . id ) + ']' ) ) ) ;
}
2021-12-21 15:43:35 +01:00
2017-01-20 04:43:45 +01:00
if ( el . name ) {
docLabel = queryDoc ( theDoc , 'label[for=' + JSON . stringify ( el . name ) + ']' ) ;
2021-12-21 15:43:35 +01:00
2017-01-20 04:43:45 +01:00
for ( var labelIndex = 0 ; labelIndex < docLabel . length ; labelIndex ++ ) {
if ( - 1 === theLabels . indexOf ( docLabel [ labelIndex ] ) ) {
theLabels . push ( docLabel [ labelIndex ] )
}
2017-01-20 01:16:13 +01:00
}
}
2021-12-21 15:43:35 +01:00
2017-01-20 04:43:45 +01:00
for ( var theEl = el ; theEl && theEl != theDoc ; theEl = theEl . parentNode ) {
if ( 'label' === toLowerString ( theEl . tagName ) && - 1 === theLabels . indexOf ( theEl ) ) {
theLabels . push ( theEl ) ;
}
}
}
2021-12-21 15:43:35 +01:00
2017-01-20 04:43:45 +01:00
if ( 0 === theLabels . length ) {
theEl = el . parentNode ;
if ( 'dd' === theEl . tagName . toLowerCase ( ) && null !== theEl . previousElementSibling
&& 'dt' === theEl . previousElementSibling . tagName . toLowerCase ( ) ) {
theLabels . push ( theEl . previousElementSibling ) ;
2017-01-20 01:16:13 +01:00
}
}
2021-12-21 15:43:35 +01:00
2017-01-20 04:43:45 +01:00
if ( 0 > theLabels . length ) {
return null ;
}
2021-12-21 15:43:35 +01:00
2017-01-20 04:43:45 +01:00
return theLabels . map ( function ( l ) {
return ( l . textContent || l . innerText )
. replace ( /^\\s+/ , '' ) . replace ( /\\s+$/ , '' ) . replace ( '\\n' , '' ) . replace ( /\\s{2,}/ , ' ' ) ;
} ) . join ( '' ) ;
2017-01-20 01:16:13 +01:00
}
2021-12-21 15:43:35 +01:00
2023-02-10 15:51:54 +01:00
/ * *
* Add property ` prop ` with value ` val ` to the object ` obj `
* @ param { object } obj
* @ param { string } prop
* @ param { any } val
* @ param { * } d
* /
2017-01-20 04:43:45 +01:00
function addProp ( obj , prop , val , d ) {
if ( 0 !== d && d === val || null === val || void 0 === val ) {
return ;
}
2021-12-21 15:43:35 +01:00
2017-01-20 04:43:45 +01:00
obj [ prop ] = val ;
2017-01-20 01:16:13 +01:00
}
2021-12-21 15:43:35 +01:00
2023-02-10 15:51:54 +01:00
/ * *
* Converts the string ` s ` to lowercase
* @ param { string } s
* @ returns Lowercase string
* /
2017-01-20 01:16:13 +01:00
function toLowerString ( s ) {
return 'string' === typeof s ? s . toLowerCase ( ) : ( '' + s ) . toLowerCase ( ) ;
}
2021-12-21 15:43:35 +01:00
2023-02-10 15:51:54 +01:00
/ * *
* Query the document ` doc ` for elements matching the selector ` selector `
* @ param { Document } doc
* @ param { string } query
* @ returns { HTMLElement [ ] } An array of elements matching the selector
* /
2017-01-20 01:16:13 +01:00
function queryDoc ( doc , query ) {
var els = [ ] ;
try {
els = doc . querySelectorAll ( query ) ;
} catch ( e ) { }
return els ;
}
2021-12-21 15:43:35 +01:00
2017-01-20 04:43:45 +01:00
// end helpers
2021-12-21 15:43:35 +01:00
2017-01-20 01:16:13 +01:00
var theView = theDoc . defaultView ? theDoc . defaultView : window ,
passwordRegEx = RegExp ( '((\\\\b|_|-)pin(\\\\b|_|-)|password|passwort|kennwort|(\\\\b|_|-)passe(\\\\b|_|-)|contraseña|senha|密码|adgangskode|hasło|wachtwoord)' , 'i' ) ;
2021-12-21 15:43:35 +01:00
2017-01-20 04:43:45 +01:00
// get all the docs
var theForms = Array . prototype . slice . call ( queryDoc ( theDoc , 'form' ) ) . map ( function ( formEl , elIndex ) {
2017-01-20 01:16:13 +01:00
var op = { } ,
formOpId = '__form__' + elIndex ;
2021-12-21 15:43:35 +01:00
2017-01-20 01:16:13 +01:00
formEl . opid = formOpId ;
op . opid = formOpId ;
2017-01-20 04:43:45 +01:00
addProp ( op , 'htmlName' , getElementAttrValue ( formEl , 'name' ) ) ;
addProp ( op , 'htmlID' , getElementAttrValue ( formEl , 'id' ) ) ;
formOpId = getElementAttrValue ( formEl , 'action' ) ;
2017-01-20 01:16:13 +01:00
formOpId = new URL ( formOpId , window . location . href ) ;
2017-01-20 04:43:45 +01:00
addProp ( op , 'htmlAction' , formOpId ? formOpId . href : null ) ;
addProp ( op , 'htmlMethod' , getElementAttrValue ( formEl , 'method' ) ) ;
2021-12-21 15:43:35 +01:00
2017-01-20 01:16:13 +01:00
return op ;
} ) ;
2021-12-21 15:43:35 +01:00
2017-01-20 04:43:45 +01:00
// get all the form fields
2017-10-11 15:01:59 +02:00
var theFields = Array . prototype . slice . call ( getFormElements ( theDoc , 50 ) ) . map ( function ( el , elIndex ) {
2017-01-20 04:43:45 +01:00
var field = { } ,
opId = '__' + elIndex ,
elMaxLen = - 1 == el . maxLength ? 999 : el . maxLength ;
2021-12-21 15:43:35 +01:00
2017-01-20 04:43:45 +01:00
if ( ! elMaxLen || 'number' === typeof elMaxLen && isNaN ( elMaxLen ) ) {
elMaxLen = 999 ;
2017-01-20 01:16:13 +01:00
}
2021-12-21 15:43:35 +01:00
2017-01-20 04:43:45 +01:00
theDoc . elementsByOPID [ opId ] = el ;
el . opid = opId ;
field . opid = opId ;
field . elementNumber = elIndex ;
addProp ( field , 'maxLength' , Math . min ( elMaxLen , 999 ) , 999 ) ;
field . visible = isElementVisible ( el ) ;
field . viewable = isElementViewable ( el ) ;
addProp ( field , 'htmlID' , getElementAttrValue ( el , 'id' ) ) ;
addProp ( field , 'htmlName' , getElementAttrValue ( el , 'name' ) ) ;
addProp ( field , 'htmlClass' , getElementAttrValue ( el , 'class' ) ) ;
addProp ( field , 'tabindex' , getElementAttrValue ( el , 'tabindex' ) ) ;
addProp ( field , 'title' , getElementAttrValue ( el , 'title' ) ) ;
2021-12-21 15:43:35 +01:00
2018-04-14 04:42:32 +02:00
// START MODIFICATION
2021-09-30 22:02:13 +02:00
var elTagName = el . tagName . toLowerCase ( ) ;
addProp ( field , 'tagName' , elTagName ) ;
2021-12-21 15:43:35 +01:00
2021-09-30 22:02:13 +02:00
if ( elTagName === 'span' ) {
return field ;
}
2018-04-14 04:42:32 +02:00
// END MODIFICATION
2021-12-21 15:43:35 +01:00
2017-01-20 04:43:45 +01:00
if ( 'hidden' != toLowerString ( el . type ) ) {
addProp ( field , 'label-tag' , getLabelTag ( el ) ) ;
addProp ( field , 'label-data' , getElementAttrValue ( el , 'data-label' ) ) ;
addProp ( field , 'label-aria' , getElementAttrValue ( el , 'aria-label' ) ) ;
addProp ( field , 'label-top' , getLabelTop ( el ) ) ;
var labelArr = [ ] ;
for ( var sib = el ; sib && sib . nextSibling ; ) {
sib = sib . nextSibling ;
if ( isKnownTag ( sib ) ) {
2017-01-20 01:16:13 +01:00
break ;
}
2017-01-20 04:43:45 +01:00
checkNodeType ( labelArr , sib ) ;
2017-01-20 01:16:13 +01:00
}
2017-01-20 04:43:45 +01:00
addProp ( field , 'label-right' , labelArr . join ( '' ) ) ;
labelArr = [ ] ;
shiftForLeftLabel ( el , labelArr ) ;
labelArr = labelArr . reverse ( ) . join ( '' ) ;
addProp ( field , 'label-left' , labelArr ) ;
addProp ( field , 'placeholder' , getElementAttrValue ( el , 'placeholder' ) ) ;
2017-01-20 01:16:13 +01:00
}
2021-12-21 15:43:35 +01:00
2017-01-20 04:43:45 +01:00
addProp ( field , 'rel' , getElementAttrValue ( el , 'rel' ) ) ;
addProp ( field , 'type' , toLowerString ( getElementAttrValue ( el , 'type' ) ) ) ;
addProp ( field , 'value' , getElementValue ( el ) ) ;
addProp ( field , 'checked' , el . checked , false ) ;
addProp ( field , 'autoCompleteType' , el . getAttribute ( 'x-autocompletetype' ) || el . getAttribute ( 'autocompletetype' ) || el . getAttribute ( 'autocomplete' ) , 'off' ) ;
addProp ( field , 'disabled' , el . disabled ) ;
addProp ( field , 'readonly' , el . b || el . readOnly ) ;
addProp ( field , 'selectInfo' , getSelectElementOptions ( el ) ) ;
addProp ( field , 'aria-hidden' , 'true' == el . getAttribute ( 'aria-hidden' ) , false ) ;
addProp ( field , 'aria-disabled' , 'true' == el . getAttribute ( 'aria-disabled' ) , false ) ;
addProp ( field , 'aria-haspopup' , 'true' == el . getAttribute ( 'aria-haspopup' ) , false ) ;
addProp ( field , 'data-unmasked' , el . dataset . unmasked ) ;
addProp ( field , 'data-stripe' , getElementAttrValue ( el , 'data-stripe' ) ) ;
addProp ( field , 'onepasswordFieldType' , el . dataset . onepasswordFieldType || el . type ) ;
addProp ( field , 'onepasswordDesignation' , el . dataset . onepasswordDesignation ) ;
addProp ( field , 'onepasswordSignInUrl' , el . dataset . onepasswordSignInUrl ) ;
addProp ( field , 'onepasswordSectionTitle' , el . dataset . onepasswordSectionTitle ) ;
addProp ( field , 'onepasswordSectionFieldKind' , el . dataset . onepasswordSectionFieldKind ) ;
addProp ( field , 'onepasswordSectionFieldTitle' , el . dataset . onepasswordSectionFieldTitle ) ;
addProp ( field , 'onepasswordSectionFieldValue' , el . dataset . onepasswordSectionFieldValue ) ;
2021-12-21 15:43:35 +01:00
2017-01-20 04:43:45 +01:00
if ( el . form ) {
field . form = getElementAttrValue ( el . form , 'opid' ) ;
}
2021-12-21 15:43:35 +01:00
2017-10-26 05:07:00 +02:00
// START MODIFICATION
//addProp(field, 'fakeTested', checkIfFakeTested(field, el), false);
// END MODIFICATION
2021-12-21 15:43:35 +01:00
2017-01-20 04:43:45 +01:00
return field ;
2017-01-20 01:16:13 +01:00
} ) ;
2021-12-21 15:43:35 +01:00
2017-01-20 04:43:45 +01:00
// test form fields
theFields . filter ( function ( f ) {
return f . fakeTested ;
} ) . forEach ( function ( f ) {
var el = theDoc . elementsByOPID [ f . opid ] ;
el . getBoundingClientRect ( ) ;
2021-12-21 15:43:35 +01:00
2017-01-20 04:43:45 +01:00
var originalValue = el . value ;
// click it
! el || el && 'function' !== typeof el . click || el . click ( ) ;
focusElement ( el , false ) ;
2021-12-21 15:43:35 +01:00
2017-01-20 04:43:45 +01:00
el . dispatchEvent ( doEventOnElement ( el , 'keydown' ) ) ;
el . dispatchEvent ( doEventOnElement ( el , 'keypress' ) ) ;
el . dispatchEvent ( doEventOnElement ( el , 'keyup' ) ) ;
2021-12-21 15:43:35 +01:00
2017-01-20 04:43:45 +01:00
el . value !== originalValue && ( el . value = originalValue ) ;
2021-12-21 15:43:35 +01:00
2017-01-20 04:43:45 +01:00
el . click && el . click ( ) ;
f . postFakeTestVisible = isElementVisible ( el ) ;
f . postFakeTestViewable = isElementViewable ( el ) ;
f . postFakeTestType = el . type ;
2021-12-21 15:43:35 +01:00
2017-01-20 04:43:45 +01:00
var elValue = el . value ;
2021-12-21 15:43:35 +01:00
2017-01-20 04:43:45 +01:00
var event1 = el . ownerDocument . createEvent ( 'HTMLEvents' ) ,
event2 = el . ownerDocument . createEvent ( 'HTMLEvents' ) ;
el . dispatchEvent ( doEventOnElement ( el , 'keydown' ) ) ;
el . dispatchEvent ( doEventOnElement ( el , 'keypress' ) ) ;
el . dispatchEvent ( doEventOnElement ( el , 'keyup' ) ) ;
event2 . initEvent ( 'input' , true , true ) ;
el . dispatchEvent ( event2 ) ;
2017-01-21 18:38:52 +01:00
event1 . initEvent ( 'change' , true , true ) ;
el . dispatchEvent ( event1 ) ;
2021-12-21 15:43:35 +01:00
2017-01-20 04:43:45 +01:00
el . blur ( ) ;
el . value !== elValue && ( el . value = elValue ) ;
2017-01-20 01:16:13 +01:00
} ) ;
2021-12-21 15:43:35 +01:00
2017-01-20 04:43:45 +01:00
// build out the page details object. this is the final result
2017-01-20 01:16:13 +01:00
var pageDetails = {
documentUUID : oneShotId ,
title : theDoc . title ,
url : theView . location . href ,
documentUrl : theDoc . location . href ,
tabUrl : theView . location . href ,
2017-01-20 04:43:45 +01:00
forms : function ( forms ) {
var formObj = { } ;
forms . forEach ( function ( f ) {
formObj [ f . opid ] = f ;
2017-01-20 01:16:13 +01:00
} ) ;
2017-01-20 04:43:45 +01:00
return formObj ;
} ( theForms ) ,
2017-01-20 01:16:13 +01:00
fields : theFields ,
collectedTimestamp : new Date ( ) . getTime ( )
} ;
2021-12-21 15:43:35 +01:00
2017-01-20 01:16:13 +01:00
// get proper page title. maybe they are using the special meta tag?
2017-01-20 04:43:45 +01:00
var theTitle = document . querySelector ( '[data-onepassword-title]' )
2017-01-20 01:16:13 +01:00
if ( theTitle && theTitle . dataset [ DISPLAY _TITLE _ATTRIBUE ] ) {
pageDetails . displayTitle = theTitle . dataset . onepasswordTitle ;
}
2021-12-21 15:43:35 +01:00
2017-01-20 01:16:13 +01:00
return pageDetails ;
}
2021-12-21 15:43:35 +01:00
2017-01-20 04:43:45 +01:00
document . elementForOPID = getElementForOPID ;
2021-12-21 15:43:35 +01:00
2023-02-10 15:51:54 +01:00
/ * *
* Do the event on the element .
* @ param { HTMLElement } kedol The element to do the event on
* @ param { string } fonor The event name
* @ returns
* /
2017-01-20 04:43:45 +01:00
function doEventOnElement ( kedol , fonor ) {
2017-01-20 01:16:13 +01:00
var quebo ;
isFirefox ? ( quebo = document . createEvent ( 'KeyboardEvent' ) , quebo . initKeyEvent ( fonor , true , false , null , false , false , false , false , 0 , 0 ) ) : ( quebo = kedol . ownerDocument . createEvent ( 'Events' ) ,
2017-10-03 22:11:11 +02:00
quebo . initEvent ( fonor , true , false ) , quebo . charCode = 0 , quebo . keyCode = 0 , quebo . which = 0 ,
quebo . srcElement = kedol , quebo . target = kedol ) ;
2017-01-20 01:16:13 +01:00
return quebo ;
}
2021-12-21 15:43:35 +01:00
2023-02-10 15:51:54 +01:00
/ * *
* Clean up the string ` s ` to remove non - printable characters and whitespace .
* @ param { string } s
* @ returns { string } Clean text
* /
2017-01-20 04:43:45 +01:00
function cleanText ( s ) {
var sVal = null ;
s && ( sVal = s . replace ( /^\\s+|\\s+$|\\r?\\n.*$/gm , '' ) , sVal = 0 < sVal . length ? sVal : null ) ;
return sVal ;
2017-01-20 01:16:13 +01:00
}
2021-12-21 15:43:35 +01:00
2023-02-10 15:51:54 +01:00
/ * *
* If ` el ` is a text node , add the node ' s text to ` arr ` .
* If ` el ` is an element node , add the element ' s ` textContent or ` innerText ` to ` arr ` .
* @ param { string [ ] } arr An array of ` textContent ` or ` innerText ` values
* @ param { HTMLElement } el The element to push to the array
* /
2017-01-20 04:43:45 +01:00
function checkNodeType ( arr , el ) {
var theText = '' ;
3 === el . nodeType ? theText = el . nodeValue : 1 === el . nodeType && ( theText = el . textContent || el . innerText ) ;
( theText = cleanText ( theText ) ) && arr . push ( theText ) ;
2017-01-20 01:16:13 +01:00
}
2021-12-21 15:43:35 +01:00
2023-02-10 15:51:54 +01:00
/ * *
* Check if ` el ` is a type that indicates the transition to a new section of the page .
* If so , this indicates that we should not use ` el ` or its children for getting autofill context for the previous element .
* @ param { HTMLElement } el The element to check
* @ returns { boolean } Returns ` true ` if ` el ` is an HTML element from a known set and ` false ` otherwise
* /
2017-01-20 04:43:45 +01:00
function isKnownTag ( el ) {
if ( el && void 0 !== el ) {
var tags = 'select option input form textarea button table iframe body head script' . split ( ' ' ) ;
2021-12-21 15:43:35 +01:00
2017-01-20 04:43:45 +01:00
if ( el ) {
var elTag = el ? ( el . tagName || '' ) . toLowerCase ( ) : '' ;
return tags . constructor == Array ? 0 <= tags . indexOf ( elTag ) : elTag === tags ;
}
else {
return false ;
}
}
else {
return true ;
}
2017-01-20 01:16:13 +01:00
}
2021-12-21 15:43:35 +01:00
2023-02-10 15:51:54 +01:00
/ * *
* Recursively gather all of the text values from the elements preceding ` el ` in the DOM
* @ param { HTMLElement } el
* @ param { string [ ] } arr An array of ` textContent ` or ` innerText ` values
* @ param { number } steps The number of steps to take up the DOM tree
* /
2017-01-20 04:43:45 +01:00
function shiftForLeftLabel ( el , arr , steps ) {
var sib ;
2017-10-03 22:11:11 +02:00
for ( steps || ( steps = 0 ) ; el && el . previousSibling ; ) {
2017-01-20 04:43:45 +01:00
el = el . previousSibling ;
if ( isKnownTag ( el ) ) {
2017-01-20 01:16:13 +01:00
return ;
}
2021-12-21 15:43:35 +01:00
2017-01-20 04:43:45 +01:00
checkNodeType ( arr , el ) ;
2017-01-20 01:16:13 +01:00
}
2017-01-20 04:43:45 +01:00
if ( el && 0 === arr . length ) {
for ( sib = null ; ! sib ; ) {
el = el . parentElement || el . parentNode ;
if ( ! el ) {
2017-01-20 01:16:13 +01:00
return ;
}
2017-01-20 04:43:45 +01:00
for ( sib = el . previousSibling ; sib && ! isKnownTag ( sib ) && sib . lastChild ; ) {
sib = sib . lastChild ;
2017-01-20 01:16:13 +01:00
}
}
2021-12-21 15:43:35 +01:00
2017-01-20 04:43:45 +01:00
// base case and recurse
isKnownTag ( sib ) || ( checkNodeType ( arr , sib ) , 0 === arr . length && shiftForLeftLabel ( sib , arr , steps + 1 ) ) ;
2017-01-20 01:16:13 +01:00
}
}
2021-12-21 15:43:35 +01:00
2023-02-10 15:51:54 +01:00
/ * *
* Determine if the element is visible .
* Visible is define as not having ` display: none ` or ` visibility: hidden ` .
* @ param { HTMLElement } el
* @ returns { boolean } Returns ` true ` if the element is visible and ` false ` otherwise
* /
2017-01-20 04:43:45 +01:00
function isElementVisible ( el ) {
var theEl = el ;
2023-02-10 15:51:54 +01:00
// Get the top level document
2017-01-20 04:43:45 +01:00
el = ( el = el . ownerDocument ) ? el . defaultView : { } ;
2021-12-21 15:43:35 +01:00
2023-02-10 15:51:54 +01:00
// walk the dom tree until we reach the top
2017-01-20 04:43:45 +01:00
for ( var elStyle ; theEl && theEl !== document ; ) {
2023-02-10 15:51:54 +01:00
// Calculate the style of the element
2017-01-20 04:43:45 +01:00
elStyle = el . getComputedStyle ? el . getComputedStyle ( theEl , null ) : theEl . style ;
2023-02-10 15:51:54 +01:00
// If there's no computed style at all, we're done, as we know that it's not hidden
2017-01-20 04:43:45 +01:00
if ( ! elStyle ) {
2017-01-20 01:16:13 +01:00
return true ;
}
2021-12-21 15:43:35 +01:00
2023-02-10 15:51:54 +01:00
// If the element's computed style includes `display: none` or `visibility: hidden`, we know it's hidden
2017-01-20 04:43:45 +01:00
if ( 'none' === elStyle . display || 'hidden' == elStyle . visibility ) {
2017-01-20 01:16:13 +01:00
return false ;
}
2021-12-21 15:43:35 +01:00
2023-02-10 15:51:54 +01:00
// At this point, we aren't sure if the element is hidden or not, so we need to keep walking up the tree
2017-01-20 04:43:45 +01:00
theEl = theEl . parentNode ;
2017-01-20 01:16:13 +01:00
}
2021-12-21 15:43:35 +01:00
2017-01-20 04:43:45 +01:00
return theEl === document ;
2017-01-20 01:16:13 +01:00
}
2021-12-21 15:43:35 +01:00
2023-02-10 15:51:54 +01:00
/ * *
* Determine if the element is "viewable" on the screen .
* "Viewable" is defined as being visible in the DOM and being within the confines of the viewport .
* @ param { HTMLElement } el
* @ returns { boolean } Returns ` true ` if the element is viewable and ` false ` otherwise
* /
2017-01-20 04:43:45 +01:00
function isElementViewable ( el ) {
var theDoc = el . ownerDocument . documentElement ,
2023-02-10 15:51:54 +01:00
rect = el . getBoundingClientRect ( ) , // getBoundingClientRect is relative to the viewport
docScrollWidth = theDoc . scrollWidth , // scrollWidth is the width of the document including any overflow
docScrollHeight = theDoc . scrollHeight , // scrollHeight is the height of the document including any overflow
leftOffset = rect . left - theDoc . clientLeft , // How far from the left of the viewport is the element, minus the left border width?
topOffset = rect . top - theDoc . clientTop , // How far from the top of the viewport is the element, minus the top border width?
2017-01-20 04:43:45 +01:00
theRect ;
2021-12-21 15:43:35 +01:00
2017-01-20 04:43:45 +01:00
if ( ! isElementVisible ( el ) || ! el . offsetParent || 10 > el . clientWidth || 10 > el . clientHeight ) {
2017-01-20 01:16:13 +01:00
return false ;
}
2021-12-21 15:43:35 +01:00
2017-01-20 04:43:45 +01:00
var rects = el . getClientRects ( ) ;
if ( 0 === rects . length ) {
2017-01-20 01:16:13 +01:00
return false ;
}
2021-12-21 15:43:35 +01:00
2023-02-10 15:51:54 +01:00
// If any of the rects have a left side that is further right than the document width or a right side that is
// further left than the origin (i.e. is negative), we consider the element to be not viewable
2017-01-20 04:43:45 +01:00
for ( var i = 0 ; i < rects . length ; i ++ ) {
if ( theRect = rects [ i ] , theRect . left > docScrollWidth || 0 > theRect . right ) {
2017-01-20 01:16:13 +01:00
return false ;
}
}
2021-12-21 15:43:35 +01:00
2023-02-10 15:51:54 +01:00
// If the element is further left than the document width, or further down than the document height, we know that it's not viewable
2019-04-23 15:34:05 +02:00
if ( 0 > leftOffset || leftOffset > docScrollWidth || 0 > topOffset || topOffset > docScrollHeight ) {
2017-01-20 01:16:13 +01:00
return false ;
}
2021-12-21 15:43:35 +01:00
2023-02-10 15:51:54 +01:00
// Our next check is going to get the center point of the element, and then use elementFromPoint to see if the element
// is actually returned from that point. If it is, we know that it's viewable. If it isn't, we know that it's not viewable.
// If the right side of the bounding rectangle is outside the viewport, the x coordinate of the center point is the window width (minus offset) divided by 2.
// If the right side of the bounding rectangle is inside the viewport, the x coordinate of the center point is the width of the bounding rectangle divided by 2.
// If the bottom of the bounding rectangle is outside the viewport, the y coordinate of the center point is the window height (minus offset) divided by 2.
// If the bottom side of the bounding rectangle is inside the viewport, the y coordinate of the center point is the height of the bounding rectangle divided by
// We then use elementFromPoint to find the element at that point.
2017-10-03 22:11:11 +02:00
for ( var pointEl = el . ownerDocument . elementFromPoint ( leftOffset + ( rect . right > window . innerWidth ? ( window . innerWidth - leftOffset ) / 2 : rect . width / 2 ) , topOffset + ( rect . bottom > window . innerHeight ? ( window . innerHeight - topOffset ) / 2 : rect . height / 2 ) ) ; pointEl && pointEl !== el && pointEl !== document ; ) {
2023-02-10 15:51:54 +01:00
// If the element we found is a label, and the element we're checking has labels
if ( pointEl . tagName && 'string' === typeof pointEl . tagName && 'label' === pointEl . tagName . toLowerCase ( )
&& el . labels && 0 < el . labels . length ) {
// Return true if the element we found is one of the labels for the element we're checking.
// This means that the element we're looking for is considered viewable
return 0 <= Array . prototype . slice . call ( el . labels ) . indexOf ( pointEl ) ;
}
// Walk up the DOM tree to check the parent element
pointEl = pointEl . parentNode ;
2017-01-20 01:16:13 +01:00
}
2021-12-21 15:43:35 +01:00
2023-02-10 15:51:54 +01:00
// If the for loop exited because we found the element we're looking for, return true, as it's viewable
// If the element that we found isn't the element we're looking for, it means the element we're looking for is not viewable
2017-01-20 04:43:45 +01:00
return pointEl === el ;
2017-01-20 01:16:13 +01:00
}
2021-12-21 15:43:35 +01:00
2023-02-10 15:51:54 +01:00
/ * *
* Retrieve the element from the document with the specified ` opid ` property
* @ param { number } opId
* @ returns { HTMLElement } The element with the specified ` opiId ` , or ` null ` if no such element exists
* /
2017-01-20 04:43:45 +01:00
function getElementForOPID ( opId ) {
var theEl ;
if ( void 0 === opId || null === opId ) {
2017-01-20 01:16:13 +01:00
return null ;
}
2021-12-21 15:43:35 +01:00
2017-01-20 01:16:13 +01:00
try {
2017-01-20 04:43:45 +01:00
var formEls = Array . prototype . slice . call ( getFormElements ( document ) ) ;
var filteredFormEls = formEls . filter ( function ( el ) {
return el . opid == opId ;
2017-01-20 01:16:13 +01:00
} ) ;
2021-12-21 15:43:35 +01:00
2017-01-20 04:43:45 +01:00
if ( 0 < filteredFormEls . length ) {
theEl = filteredFormEls [ 0 ] , 1 < filteredFormEls . length && console . warn ( 'More than one element found with opid ' + opId ) ;
2017-01-20 01:16:13 +01:00
} else {
2017-01-20 04:43:45 +01:00
var theIndex = parseInt ( opId . split ( '__' ) [ 1 ] , 10 ) ;
isNaN ( theIndex ) || ( theEl = formEls [ theIndex ] ) ;
2017-01-20 01:16:13 +01:00
}
2017-01-20 04:43:45 +01:00
} catch ( e ) {
console . error ( 'An unexpected error occurred: ' + e ) ;
2017-01-20 01:16:13 +01:00
} finally {
2017-01-20 04:43:45 +01:00
return theEl ;
2017-01-20 01:16:13 +01:00
}
}
2021-12-21 15:43:35 +01:00
2023-02-10 15:51:54 +01:00
/ * *
* Query ` theDoc ` for form elements that we can use for autofill , ranked by importance and limited by ` limit `
* @ param { Document } theDoc The Document to query
* @ param { number } limit The maximum number of elements to return
* @ returns An array of HTMLElements
* /
2017-10-11 15:01:59 +02:00
function getFormElements ( theDoc , limit ) {
2017-10-26 05:07:00 +02:00
// START MODIFICATION
2017-01-20 01:16:13 +01:00
var els = [ ] ;
try {
2017-10-12 04:11:34 +02:00
var elsList = theDoc . querySelectorAll ( 'input:not([type="hidden"]):not([type="submit"]):not([type="reset"])' +
2021-09-30 22:02:13 +02:00
':not([type="button"]):not([type="image"]):not([type="file"]):not([data-bwignore]), select, ' +
'span[data-bwautofill]' ) ;
2017-10-12 04:11:34 +02:00
els = Array . prototype . slice . call ( elsList ) ;
2017-01-20 01:16:13 +01:00
} catch ( e ) { }
2021-12-21 15:43:35 +01:00
2017-10-26 15:19:18 +02:00
if ( ! limit || els . length <= limit ) {
return els ;
}
2021-12-21 15:43:35 +01:00
2017-11-04 15:21:23 +01:00
// non-checkboxes/radios have higher priority
var returnEls = [ ] ;
var unimportantEls = [ ] ;
for ( var i = 0 ; i < els . length ; i ++ ) {
if ( returnEls . length >= limit ) {
break ;
}
2021-12-21 15:43:35 +01:00
2017-11-04 15:21:23 +01:00
var el = els [ i ] ;
var type = el . type ? el . type . toLowerCase ( ) : el . type ;
if ( type === 'checkbox' || type === 'radio' ) {
unimportantEls . push ( el ) ;
2017-10-26 15:19:18 +02:00
}
2017-11-04 15:21:23 +01:00
else {
returnEls . push ( el ) ;
2017-10-26 15:19:18 +02:00
}
2017-11-04 15:21:23 +01:00
}
2021-12-21 15:43:35 +01:00
2017-11-04 15:21:23 +01:00
var unimportantElsToAdd = limit - returnEls . length ;
if ( unimportantElsToAdd > 0 ) {
returnEls = returnEls . concat ( unimportantEls . slice ( 0 , unimportantElsToAdd ) ) ;
}
2021-12-21 15:43:35 +01:00
2017-11-04 15:21:23 +01:00
return returnEls ;
2017-10-26 05:07:00 +02:00
// END MODIFICATION
2017-01-20 01:16:13 +01:00
}
2021-12-21 15:43:35 +01:00
2023-02-10 15:51:54 +01:00
/ * *
* Focus the element ` el ` and optionally restore its original value
* @ param { HTMLElement } el
* @ param { boolean } setVal Set the value of the element to its original value
* /
2017-01-20 04:43:45 +01:00
function focusElement ( el , setVal ) {
if ( setVal ) {
var initialValue = el . value ;
el . focus ( ) ;
2021-12-21 15:43:35 +01:00
2017-01-20 04:43:45 +01:00
if ( el . value !== initialValue ) {
el . value = initialValue ;
}
2017-01-20 01:16:13 +01:00
} else {
2017-01-20 04:43:45 +01:00
el . focus ( ) ;
2017-01-20 01:16:13 +01:00
}
}
2021-12-21 15:43:35 +01:00
2017-01-20 04:43:45 +01:00
return JSON . stringify ( getPageDetails ( document , 'oneshotUUID' ) ) ;
2016-09-16 05:24:45 +02:00
}
2021-12-21 15:43:35 +01:00
2016-09-16 05:24:45 +02:00
function fill ( document , fillScript , undefined ) {
2016-11-27 06:31:45 +01:00
var isFirefox = navigator . userAgent . indexOf ( 'Firefox' ) !== - 1 || navigator . userAgent . indexOf ( 'Gecko/' ) !== - 1 ;
2021-12-21 15:43:35 +01:00
2017-01-20 01:16:13 +01:00
var markTheFilling = true ,
animateTheFilling = true ;
2021-12-21 15:43:35 +01:00
2017-01-20 01:16:13 +01:00
// Check if URL is not secure when the original saved one was
2022-11-04 16:44:21 +01:00
function urlNotSecure ( savedURLs ) {
2017-01-20 01:16:13 +01:00
var passwordInputs = null ;
2022-11-04 16:44:21 +01:00
if ( ! savedURLs ) {
2017-01-20 01:16:13 +01:00
return false ;
}
2021-12-21 15:43:35 +01:00
2022-12-28 15:49:38 +01:00
return savedURLs . some ( url => url ? . indexOf ( 'https://' ) === 0 ) && 'http:' === document . location . protocol && ( passwordInputs = document . querySelectorAll ( 'input[type=password]' ) ,
2022-11-04 16:44:21 +01:00
0 < passwordInputs . length && ( confirmResult = confirm ( 'Warning: This is an unsecured HTTP page, and any information you submit can potentially be seen and changed by others. This Login was originally saved on a secure (HTTPS) page.\n\nDo you still wish to fill this login?' ) ,
2017-10-03 22:11:11 +02:00
0 == confirmResult ) ) ? true : false ;
2017-01-20 01:16:13 +01:00
}
2021-12-21 15:43:35 +01:00
2022-10-21 18:55:20 +02:00
// Detect if within an iframe, and the iframe is sandboxed
function isSandboxed ( ) {
// self.origin is 'null' if inside a frame with sandboxed csp or iframe tag
return self . origin == null || self . origin === 'null' ;
}
2017-01-20 01:16:13 +01:00
function doFill ( fillScript ) {
var fillScriptOps ,
theOpIds = [ ] ,
fillScriptProperties = fillScript . properties ,
operationDelayMs = 1 ,
doOperation ,
operationsToDo = [ ] ;
2021-12-21 15:43:35 +01:00
2017-01-20 01:16:13 +01:00
fillScriptProperties &&
2017-10-03 22:11:11 +02:00
fillScriptProperties . delay _between _operations &&
( operationDelayMs = fillScriptProperties . delay _between _operations ) ;
2021-12-21 15:43:35 +01:00
2022-11-04 16:44:21 +01:00
if ( isSandboxed ( ) || urlNotSecure ( fillScript . savedUrls ) ) {
2017-01-20 01:16:13 +01:00
return ;
}
2021-12-21 15:43:35 +01:00
2017-01-20 01:16:13 +01:00
doOperation = function ( ops , theOperation ) {
var op = ops [ 0 ] ;
if ( void 0 === op ) {
theOperation ( ) ;
} else {
// should we delay?
if ( 'delay' === op . operation || 'delay' === op [ 0 ] ) {
operationDelayMs = op . parameters ? op . parameters [ 0 ] : op [ 1 ] ;
} else {
if ( op = normalizeOp ( op ) ) {
for ( var opIndex = 0 ; opIndex < op . length ; opIndex ++ ) {
- 1 === operationsToDo . indexOf ( op [ opIndex ] ) && operationsToDo . push ( op [ opIndex ] ) ;
}
}
theOpIds = theOpIds . concat ( operationsToDo . map ( function ( operationToDo ) {
return operationToDo && operationToDo . hasOwnProperty ( 'opid' ) ? operationToDo . opid : null ;
} ) ) ;
}
setTimeout ( function ( ) {
doOperation ( ops . slice ( 1 ) , theOperation ) ;
} , operationDelayMs ) ;
}
} ;
2021-12-21 15:43:35 +01:00
2017-01-20 01:16:13 +01:00
if ( fillScriptOps = fillScript . options ) {
fillScriptOps . hasOwnProperty ( 'animate' ) && ( animateTheFilling = fillScriptOps . animate ) ,
2017-10-03 22:11:11 +02:00
fillScriptOps . hasOwnProperty ( 'markFilling' ) && ( markTheFilling = fillScriptOps . markFilling ) ;
2017-01-20 01:16:13 +01:00
}
2021-12-21 15:43:35 +01:00
2017-01-20 01:16:13 +01:00
// don't mark a password filling
fillScript . itemType && 'fillPassword' === fillScript . itemType && ( markTheFilling = false ) ;
2021-12-21 15:43:35 +01:00
2017-01-20 01:16:13 +01:00
if ( ! fillScript . hasOwnProperty ( 'script' ) ) {
return ;
}
2021-12-21 15:43:35 +01:00
2017-01-20 01:16:13 +01:00
// custom fill script
2021-12-21 15:43:35 +01:00
2017-01-20 01:16:13 +01:00
fillScriptOps = fillScript . script ;
doOperation ( fillScriptOps , function ( ) {
// Done now
// Do we have anything to autosubmit?
if ( fillScript . hasOwnProperty ( 'autosubmit' ) && 'function' == typeof autosubmit ) {
fillScript . itemType && 'fillLogin' !== fillScript . itemType || ( 0 < operationsToDo . length ? setTimeout ( function ( ) {
autosubmit ( fillScript . autosubmit , fillScriptProperties . allow _clicky _autosubmit , operationsToDo ) ;
} , AUTOSUBMIT _DELAY ) : DEBUG _AUTOSUBMIT && console . log ( '[AUTOSUBMIT] Not attempting to submit since no fields were filled: ' , operationsToDo ) )
}
2021-12-21 15:43:35 +01:00
2017-01-20 01:16:13 +01:00
// handle protectedGlobalPage
if ( 'object' == typeof protectedGlobalPage ) {
protectedGlobalPage . b ( 'fillItemResults' , {
documentUUID : documentUUID ,
fillContextIdentifier : fillScript . fillContextIdentifier ,
usedOpids : theOpIds
} , function ( ) {
fillingItemType = null ;
} )
}
} ) ;
}
2021-12-21 15:43:35 +01:00
2017-01-20 01:16:13 +01:00
// fill for reference
var thisFill = {
fill _by _opid : doFillByOpId ,
fill _by _query : doFillByQuery ,
click _on _opid : doClickByOpId ,
click _on _query : doClickByQuery ,
touch _all _fields : touchAllFields ,
simple _set _value _by _query : doSimpleSetByQuery ,
focus _by _opid : doFocusByOpId ,
delay : null
} ;
2021-12-21 15:43:35 +01:00
2017-01-20 01:16:13 +01:00
// normalize the op versus the reference
function normalizeOp ( op ) {
var thisOperation ;
if ( op . hasOwnProperty ( 'operation' ) && op . hasOwnProperty ( 'parameters' ) ) {
thisOperation = op . operation , op = op . parameters ;
} else {
if ( '[object Array]' === Object . prototype . toString . call ( op ) ) {
thisOperation = op [ 0 ] ,
2017-10-03 22:11:11 +02:00
op = op . splice ( 1 ) ;
2017-01-20 01:16:13 +01:00
} else {
return null ;
}
}
return thisFill . hasOwnProperty ( thisOperation ) ? thisFill [ thisOperation ] . apply ( this , op ) : null ;
}
2021-12-21 15:43:35 +01:00
2017-01-20 01:16:13 +01:00
// do a fill by opid operation
function doFillByOpId ( opId , op ) {
var el = getElementByOpId ( opId ) ;
return el ? ( fillTheElement ( el , op ) , [ el ] ) : null ;
}
2021-12-21 15:43:35 +01:00
2023-02-10 15:51:54 +01:00
/ * *
* Find all elements matching ` query ` and fill them using the value ` op ` from the fill script
* @ param { string } query
* @ param { string } op
* @ returns { HTMLElement }
* /
2017-01-20 01:16:13 +01:00
function doFillByQuery ( query , op ) {
var elements = selectAllFromDoc ( query ) ;
return Array . prototype . map . call ( Array . prototype . slice . call ( elements ) , function ( el ) {
fillTheElement ( el , op ) ;
return el ;
} , this ) ;
}
2021-12-21 15:43:35 +01:00
2023-02-10 15:51:54 +01:00
/ * *
* Assign ` valueToSet ` to all elements in the DOM that match ` query ` .
* @ param { string } query
* @ param { string } valueToSet
* @ returns { Array } Array of elements that were set .
* /
2017-01-20 01:16:13 +01:00
function doSimpleSetByQuery ( query , valueToSet ) {
var elements = selectAllFromDoc ( query ) ,
arr = [ ] ;
Array . prototype . forEach . call ( Array . prototype . slice . call ( elements ) , function ( el ) {
el . disabled || el . a || el . readOnly || void 0 === el . value || ( el . value = valueToSet , arr . push ( el ) ) ;
} ) ;
return arr ;
}
2021-12-21 15:43:35 +01:00
2023-02-10 15:51:54 +01:00
/ * *
* Do a a click and focus on the element with the given ` opId ` .
* @ param { number } opId
* @ returns
* /
2017-01-20 01:16:13 +01:00
function doFocusByOpId ( opId ) {
var el = getElementByOpId ( opId )
if ( el ) {
'function' === typeof el . click && el . click ( ) ,
2017-10-03 22:11:11 +02:00
'function' === typeof el . focus && doFocusElement ( el , true ) ;
2017-01-20 01:16:13 +01:00
}
2021-12-21 15:43:35 +01:00
2017-01-20 01:16:13 +01:00
return null ;
}
2021-12-21 15:43:35 +01:00
2023-02-10 15:51:54 +01:00
/ * *
* Do a click on the element with the given ` opId ` .
* @ param { number } opId
* @ returns
* /
2017-01-20 01:16:13 +01:00
function doClickByOpId ( opId ) {
var el = getElementByOpId ( opId ) ;
return el ? clickElement ( el ) ? [ el ] : null : null ;
}
2021-12-21 15:43:35 +01:00
2023-02-10 15:51:54 +01:00
/ * *
* Do a ` click ` and ` focus ` on all elements that match the query .
* @ param { string } query
* @ returns
* /
2017-01-20 01:16:13 +01:00
function doClickByQuery ( query ) {
query = selectAllFromDoc ( query ) ;
return Array . prototype . map . call ( Array . prototype . slice . call ( query ) , function ( el ) {
clickElement ( el ) ;
'function' === typeof el . click && el . click ( ) ;
'function' === typeof el . focus && doFocusElement ( el , true ) ;
return [ el ] ;
} , this ) ;
}
2021-12-21 15:43:35 +01:00
2017-01-20 01:16:13 +01:00
var checkRadioTrueOps = {
'true' : true ,
y : true ,
1 : true ,
yes : true ,
'✓' : true
} ,
2017-10-03 22:11:11 +02:00
styleTimeout = 200 ;
2021-12-21 15:43:35 +01:00
2023-02-10 15:51:54 +01:00
/ * *
* Fll an element ` el ` using the value ` op ` from the fill script
* @ param { HTMLElement } el
* @ param { string } op
* /
2017-01-20 01:16:13 +01:00
function fillTheElement ( el , op ) {
var shouldCheck ;
if ( el && null !== op && void 0 !== op && ! ( el . disabled || el . a || el . readOnly ) ) {
switch ( markTheFilling && el . form && ! el . form . opfilled && ( el . form . opfilled = true ) ,
el . type ? el . type . toLowerCase ( ) : null ) {
case 'checkbox' :
shouldCheck = op && 1 <= op . length && checkRadioTrueOps . hasOwnProperty ( op . toLowerCase ( ) ) && true === checkRadioTrueOps [ op . toLowerCase ( ) ] ;
el . checked === shouldCheck || doAllFillOperations ( el , function ( theEl ) {
theEl . checked = shouldCheck ;
} ) ;
break ;
case 'radio' :
true === checkRadioTrueOps [ op . toLowerCase ( ) ] && el . click ( ) ;
break ;
default :
el . value == op || doAllFillOperations ( el , function ( theEl ) {
2021-09-30 22:02:13 +02:00
// START MODIFICATION
if ( ! theEl . type && theEl . tagName . toLowerCase ( ) === 'span' ) {
theEl . innerText = op ;
return ;
}
// END MODIFICATION
2017-01-20 01:16:13 +01:00
theEl . value = op ;
} ) ;
}
}
}
2021-12-21 15:43:35 +01:00
2023-02-10 15:51:54 +01:00
/ * *
* Do all the fill operations needed on the element ` el ` .
* @ param { HTMLElement } el
* @ param { * } afterValSetFunc The function to perform after the operations are complete .
* /
2017-01-20 01:16:13 +01:00
function doAllFillOperations ( el , afterValSetFunc ) {
setValueForElement ( el ) ;
afterValSetFunc ( el ) ;
setValueForElementByEvent ( el ) ;
2021-12-21 15:43:35 +01:00
2020-10-22 18:32:33 +02:00
// START MODIFICATION
if ( canSeeElementToStyle ( el ) ) {
el . classList . add ( 'com-bitwarden-browser-animated-fill' ) ;
2017-10-03 22:11:11 +02:00
setTimeout ( function ( ) {
2020-10-22 18:32:33 +02:00
if ( el ) {
el . classList . remove ( 'com-bitwarden-browser-animated-fill' ) ;
}
} , styleTimeout ) ;
}
// END MODIFICATION
2017-01-20 01:16:13 +01:00
}
2021-12-21 15:43:35 +01:00
2017-01-20 01:16:13 +01:00
document . elementForOPID = getElementByOpId ;
2021-12-21 15:43:35 +01:00
2023-02-10 15:51:54 +01:00
/ * *
* Normalize the event based on API support
* @ param { HTMLElement } el
* @ param { string } eventName
* @ returns { Event } A normalized event
* /
2017-01-20 01:16:13 +01:00
function normalizeEvent ( el , eventName ) {
var ev ;
2021-08-11 19:40:36 +02:00
if ( 'KeyboardEvent' in window ) {
ev = new window . KeyboardEvent ( eventName , {
bubbles : true ,
cancelable : false ,
} ) ;
2017-01-20 01:16:13 +01:00
}
else {
ev = el . ownerDocument . createEvent ( 'Events' ) ;
ev . initEvent ( eventName , true , false ) ;
ev . charCode = 0 ;
ev . keyCode = 0 ;
ev . which = 0 ;
ev . srcElement = el ;
ev . target = el ;
}
2021-12-21 15:43:35 +01:00
2017-01-20 01:16:13 +01:00
return ev ;
}
2021-12-21 15:43:35 +01:00
2023-02-10 15:51:54 +01:00
/ * *
* Simulate the entry of a value into an element .
* Clicks the element , focuses it , and then fires a keydown , keypress , and keyup event .
* @ param { HTMLElement } el
* /
2017-01-20 01:16:13 +01:00
function setValueForElement ( el ) {
var valueToSet = el . value ;
clickElement ( el ) ;
doFocusElement ( el , false ) ;
el . dispatchEvent ( normalizeEvent ( el , 'keydown' ) ) ;
el . dispatchEvent ( normalizeEvent ( el , 'keypress' ) ) ;
el . dispatchEvent ( normalizeEvent ( el , 'keyup' ) ) ;
el . value !== valueToSet && ( el . value = valueToSet ) ;
}
2021-12-21 15:43:35 +01:00
2023-02-10 15:51:54 +01:00
/ * *
* Simulate the entry of a value into an element by using events .
* Dispatches a keydown , keypress , and keyup event , then fires the ` input ` and ` change ` events before removing focus .
* @ param { HTMLElement } el
* /
2017-01-20 01:16:13 +01:00
function setValueForElementByEvent ( el ) {
var valueToSet = el . value ,
ev1 = el . ownerDocument . createEvent ( 'HTMLEvents' ) ,
ev2 = el . ownerDocument . createEvent ( 'HTMLEvents' ) ;
2021-12-21 15:43:35 +01:00
2017-01-20 01:16:13 +01:00
el . dispatchEvent ( normalizeEvent ( el , 'keydown' ) ) ;
el . dispatchEvent ( normalizeEvent ( el , 'keypress' ) ) ;
el . dispatchEvent ( normalizeEvent ( el , 'keyup' ) ) ;
ev2 . initEvent ( 'input' , true , true ) ;
el . dispatchEvent ( ev2 ) ;
ev1 . initEvent ( 'change' , true , true ) ;
el . dispatchEvent ( ev1 ) ;
el . blur ( ) ;
el . value !== valueToSet && ( el . value = valueToSet ) ;
}
2021-12-21 15:43:35 +01:00
2023-02-10 15:51:54 +01:00
/ * *
* Click on an element ` el `
* @ param { HTMLElement } el
* @ returns { boolean } Returns true if the element was clicked and false if it was not able to be clicked
* /
2017-01-20 01:16:13 +01:00
function clickElement ( el ) {
if ( ! el || el && 'function' !== typeof el . click ) {
return false ;
}
el . click ( ) ;
return true ;
}
2021-12-21 15:43:35 +01:00
2023-02-10 15:51:54 +01:00
/ * *
* Get all the elements on the DOM that are likely to be a password field
* @ returns { Array } Array of elements
* /
2017-01-20 01:16:13 +01:00
function getAllFields ( ) {
var r = RegExp ( '((\\\\b|_|-)pin(\\\\b|_|-)|password|passwort|kennwort|passe|contraseña|senha|密码|adgangskode|hasło|wachtwoord)' , 'i' ) ;
return Array . prototype . slice . call ( selectAllFromDoc ( "input[type='text']" ) ) . filter ( function ( el ) {
return el . value && r . test ( el . value ) ;
} , this ) ;
}
2021-12-21 15:43:35 +01:00
2023-02-10 15:51:54 +01:00
/ * *
* Touch all the fields
* /
2017-01-20 01:16:13 +01:00
function touchAllFields ( ) {
getAllFields ( ) . forEach ( function ( el ) {
setValueForElement ( el ) ;
el . click && el . click ( ) ;
setValueForElementByEvent ( el ) ;
} ) ;
}
2021-12-21 15:43:35 +01:00
2023-02-10 15:51:54 +01:00
/ * *
* Determine if we can apply styling to ` el ` to indicate that it was filled .
* @ param { HTMLElement } el
* @ returns { boolean } Returns true if we can see the element to apply styling .
* /
2017-01-20 01:16:13 +01:00
function canSeeElementToStyle ( el ) {
var currentEl ;
if ( currentEl = animateTheFilling ) {
a : {
currentEl = el ;
for ( var owner = el . ownerDocument , owner = owner ? owner . defaultView : { } , theStyle ; currentEl && currentEl !== document ; ) {
theStyle = owner . getComputedStyle ? owner . getComputedStyle ( currentEl , null ) : currentEl . style ;
if ( ! theStyle ) {
currentEl = true ;
break a ;
}
if ( 'none' === theStyle . display || 'hidden' == theStyle . visibility ) {
currentEl = false ;
break a ;
}
currentEl = currentEl . parentNode ;
}
currentEl = currentEl === document ;
}
}
2021-09-30 22:02:13 +02:00
// START MODIFICATION
if ( el && ! el . type && el . tagName . toLowerCase ( ) === 'span' ) {
return true ;
}
// END MODIFICATION
2017-01-20 01:16:13 +01:00
return currentEl ? - 1 !== 'email text password number tel url' . split ( ' ' ) . indexOf ( el . type || '' ) : false ;
}
2021-12-21 15:43:35 +01:00
2023-02-10 15:51:54 +01:00
/ * *
* Find the element for the given ` opid ` .
* @ param { number } theOpId
* @ returns { HTMLElement } The element for the given ` opid ` , or ` null ` if not found .
* /
2017-01-20 01:16:13 +01:00
function getElementByOpId ( theOpId ) {
var theElement ;
if ( void 0 === theOpId || null === theOpId ) {
return null ;
}
try {
2021-09-30 22:02:13 +02:00
// START MODIFICATION
var elements = Array . prototype . slice . call ( selectAllFromDoc ( 'input, select, button, ' +
'span[data-bwautofill]' ) ) ;
// END MODIFICATION
2017-01-20 01:16:13 +01:00
var filteredElements = elements . filter ( function ( o ) {
return o . opid == theOpId ;
} ) ;
if ( 0 < filteredElements . length ) {
theElement = filteredElements [ 0 ] ,
2017-10-03 22:11:11 +02:00
1 < filteredElements . length && console . warn ( 'More than one element found with opid ' + theOpId ) ;
2017-01-20 01:16:13 +01:00
} else {
var elIndex = parseInt ( theOpId . split ( '__' ) [ 1 ] , 10 ) ;
isNaN ( elIndex ) || ( theElement = elements [ elIndex ] ) ;
}
} catch ( e ) {
console . error ( 'An unexpected error occurred: ' + e ) ;
} finally {
return theElement ;
}
}
2021-12-21 15:43:35 +01:00
2023-02-10 15:51:54 +01:00
/ * *
* Helper for doc . querySelectorAll
* @ param { string } theSelector
* @ returns
* /
2017-01-20 01:16:13 +01:00
function selectAllFromDoc ( theSelector ) {
var d = document , elements = [ ] ;
try {
elements = d . querySelectorAll ( theSelector ) ;
} catch ( e ) { }
return elements ;
}
2021-12-21 15:43:35 +01:00
2023-02-10 15:51:54 +01:00
/ * *
* Focus an element and optionally re - set its value after focusing
* @ param { HTMLElement } el
* @ param { boolean } setValue Re - set the value after focusing
* /
2017-01-20 01:16:13 +01:00
function doFocusElement ( el , setValue ) {
if ( setValue ) {
var existingValue = el . value ;
el . focus ( ) ;
el . value !== existingValue && ( el . value = existingValue ) ;
} else {
el . focus ( ) ;
}
}
2021-12-21 15:43:35 +01:00
2017-01-20 01:16:13 +01:00
doFill ( fillScript ) ;
2021-12-21 15:43:35 +01:00
2017-01-20 01:16:13 +01:00
return JSON . stringify ( {
success : true
} ) ;
2016-09-16 05:24:45 +02:00
}
2021-12-21 15:43:35 +01:00
2016-09-16 05:24:45 +02:00
/ *
End 1 Password Extension
* /
2021-12-21 15:43:35 +01:00
2016-09-16 05:24:45 +02:00
chrome . runtime . onMessage . addListener ( function ( msg , sender , sendResponse ) {
if ( msg . command === 'collectPageDetails' ) {
2017-10-02 16:29:46 +02:00
var pageDetails = collect ( document ) ;
2016-11-26 04:01:46 +01:00
var pageDetailsObj = JSON . parse ( pageDetails ) ;
chrome . runtime . sendMessage ( {
command : 'collectPageDetailsResponse' ,
2017-08-28 19:00:46 +02:00
tab : msg . tab ,
2016-12-30 08:09:54 +01:00
details : pageDetailsObj ,
2017-08-28 19:00:46 +02:00
sender : msg . sender
2016-11-26 04:01:46 +01:00
} ) ;
sendResponse ( ) ;
2016-09-16 05:24:45 +02:00
return true ;
}
else if ( msg . command === 'fillForm' ) {
fill ( document , msg . fillScript ) ;
sendResponse ( ) ;
return true ;
2022-08-10 03:30:26 +02:00
} else if ( msg . command === 'collectPageDetailsImmediately' ) {
var pageDetails = collect ( document ) ;
var pageDetailsObj = JSON . parse ( pageDetails ) ;
sendResponse ( pageDetailsObj ) ;
return true ;
2016-09-16 05:24:45 +02:00
}
} ) ;
} ) ( ) ;