1 | var formManager = function(){ |
||
2 | /** |
||
3 | Code based on: |
||
4 | @url https://dxr.mozilla.org/firefox/source/toolkit/components/passwordmgr/src/nsLoginManager.js#655 |
||
5 | */ |
||
6 | var settings = {}; |
||
7 | |||
8 | return { |
||
9 | _init_: function () { |
||
10 | API.runtime.sendMessage(API.runtime.id, {method: 'getSetting', args: 'debug'}).then(function (result) { |
||
11 | settings.debug = (result); |
||
12 | }); |
||
13 | }, |
||
14 | /* |
||
15 | * _isAutoCompleteDisabled |
||
16 | * |
||
17 | * Returns true if the page requests autocomplete be disabled for the |
||
18 | * specified form input. |
||
19 | */ |
||
20 | isAutocompleteDisabled: function (element) { |
||
21 | return !!(element && element.hasAttribute("autocomplete") && element.getAttribute("autocomplete").toLowerCase() === "off"); |
||
22 | }, |
||
23 | |||
24 | /* |
||
25 | * _getPasswordFields |
||
26 | * |
||
27 | * Returns an array of password field elements for the specified form. |
||
28 | * If no pw fields are found, or if more than 3 are found, then null |
||
29 | * is returned. |
||
30 | * |
||
31 | * skipEmptyFields can be set to ignore password fields with no value. |
||
32 | */ |
||
33 | _getPasswordFields: function (form, skipEmptyFields) { |
||
34 | // Locate the password fields in the form. |
||
35 | var pwFields = []; |
||
36 | for (var i = 0; i < form.elements.length; i++) { |
||
37 | if (form.elements[i].type !== "password"){ |
||
38 | continue; |
||
39 | } |
||
40 | |||
41 | |||
42 | if (skipEmptyFields && !form.elements[i].value){ |
||
43 | continue; |
||
44 | } |
||
45 | |||
46 | pwFields[pwFields.length] = { |
||
47 | index: i, |
||
48 | element: form.elements[i] |
||
49 | }; |
||
50 | } |
||
51 | |||
52 | // If too few or too many fields, bail out. |
||
53 | if (pwFields.length === 0) { |
||
54 | this.log('(form ignored ('+ form.action +') -- no password fields.)'); |
||
55 | return null; |
||
56 | } else if (pwFields.length > 3) { |
||
57 | this.log('(form ignored -- too many password fields. [got ' + |
||
58 | pwFields.length + "])"); |
||
59 | return null; |
||
60 | } |
||
61 | |||
62 | return pwFields; |
||
63 | }, |
||
64 | /* |
||
65 | * _getFormFields |
||
66 | * |
||
67 | * Returns the username and password fields found in the form. |
||
68 | * Can handle complex forms by trying to figure out what the |
||
69 | * relevant fields are. |
||
70 | * |
||
71 | * Returns: [usernameField, newPasswordField, oldPasswordField] |
||
72 | * |
||
73 | * usernameField may be null. |
||
74 | * newPasswordField will always be non-null. |
||
75 | * oldPasswordField may be null. If null, newPasswordField is just |
||
76 | * "theLoginField". If not null, the form is apparently a |
||
77 | * change-password field, with oldPasswordField containing the password |
||
78 | * that is being changed. |
||
79 | */ |
||
80 | getFormFields: function (form, isSubmission) { |
||
81 | var usernameField = null; |
||
82 | |||
83 | // Locate the password field(s) in the form. Up to 3 supported. |
||
84 | // If there's no password field, there's nothing for us to do. |
||
85 | var pwFields = this._getPasswordFields(form, isSubmission); |
||
86 | if (!pwFields){ |
||
87 | return [null, null, null]; |
||
88 | } |
||
89 | |||
90 | |||
91 | // Locate the username field in the form by searching backwards |
||
92 | // from the first passwordfield, assume the first text field is the |
||
93 | // username. We might not find a username field if the user is |
||
94 | // already logged in to the site. |
||
95 | for (var i = pwFields[0].index - 1; i >= 0; i--) { |
||
96 | if (form.elements[i].type.toLowerCase() === "text" || form.elements[i].type.toLowerCase() === "email") { |
||
97 | usernameField = form.elements[i]; |
||
98 | break; |
||
99 | } |
||
100 | } |
||
101 | |||
102 | if (!usernameField){ |
||
103 | this.log('(form ('+ form.action +') ignored -- no username field found)'); |
||
104 | } |
||
105 | |||
106 | |||
107 | |||
108 | // If we're not submitting a form (it's a page load), there are no |
||
109 | // password field values for us to use for identifying fields. So, |
||
110 | // just assume the first password field is the one to be filled in. |
||
111 | if (!isSubmission || pwFields.length === 1){ |
||
112 | return [usernameField, pwFields[0].element, null]; |
||
113 | } |
||
114 | |||
115 | |||
116 | |||
117 | // Try to figure out WTF is in the form based on the password values. |
||
118 | var oldPasswordField, newPasswordField; |
||
119 | var pw1 = pwFields[0].element.value; |
||
120 | var pw2 = pwFields[1].element.value; |
||
121 | var pw3 = (pwFields[2] ? pwFields[2].element.value : null); |
||
122 | |||
123 | if (pwFields.length === 3) { |
||
124 | // Look for two identical passwords, that's the new password |
||
125 | |||
126 | if (pw1 === pw2 && pw2 === pw3) { |
||
127 | // All 3 passwords the same? Weird! Treat as if 1 pw field. |
||
128 | newPasswordField = pwFields[0].element; |
||
129 | oldPasswordField = null; |
||
130 | } else if (pw1 === pw2) { |
||
131 | newPasswordField = pwFields[0].element; |
||
132 | oldPasswordField = pwFields[2].element; |
||
133 | } else if (pw2 === pw3) { |
||
134 | oldPasswordField = pwFields[0].element; |
||
135 | newPasswordField = pwFields[2].element; |
||
136 | } else if (pw1 === pw3) { |
||
137 | // A bit odd, but could make sense with the right page layout. |
||
138 | newPasswordField = pwFields[0].element; |
||
139 | oldPasswordField = pwFields[1].element; |
||
140 | } else { |
||
141 | // We can't tell which of the 3 passwords should be saved. |
||
142 | this.log("(form ignored -- all 3 pw fields differ)"); |
||
143 | return [null, null, null]; |
||
144 | } |
||
145 | } else { // pwFields.length == 2 |
||
146 | if (pw1 === pw2) { |
||
147 | // Treat as if 1 pw field |
||
148 | newPasswordField = pwFields[0].element; |
||
149 | oldPasswordField = null; |
||
150 | } else { |
||
151 | // Just assume that the 2nd password is the new password |
||
152 | oldPasswordField = pwFields[0].element; |
||
153 | newPasswordField = pwFields[1].element; |
||
154 | } |
||
155 | } |
||
156 | |||
157 | return [usernameField, newPasswordField, oldPasswordField]; |
||
158 | }, |
||
159 | log: function (str) { |
||
160 | if(settings.debug){ |
||
161 | console.log(str); |
||
162 | } |
||
163 | } |
||
164 | }; |
||
165 | }(); |
||
166 | |||
167 | function getLoginFields(isSubmission) { |
||
168 | var forms = document.forms; |
||
169 | var loginForms = []; |
||
170 | |||
171 | for (var i = 0; i < forms.length; i++) { |
||
172 | var form = forms[i]; |
||
173 | var result = formManager.getFormFields(form, isSubmission); |
||
174 | var usernameField = result[0]; |
||
175 | var passwordField = result[1]; |
||
176 | // Need a valid password field to do anything. |
||
177 | if (passwordField === null){ |
||
178 | continue; |
||
179 | } |
||
180 | loginForms.push([usernameField, passwordField]); |
||
181 | } |
||
182 | return loginForms; |
||
183 | } |
||
184 | |||
185 | function getFormFromElement(elem) { |
||
186 | if(elem) { |
||
0 ignored issues
–
show
|
|||
187 | while (elem.parentNode) { |
||
188 | if (elem.parentNode.nodeName.toLowerCase() === "form") { |
||
189 | return elem.parentNode; |
||
190 | } |
||
191 | elem = elem.parentNode; |
||
192 | } |
||
193 | } |
||
194 | } |
||
195 | |||
196 | function dispatchEvents(element){ |
||
197 | var eventNames = [ 'click', 'focus', 'keypress', 'keydown', 'keyup', 'input', 'blur', 'change' ]; |
||
198 | eventNames.forEach(function(eventName) { |
||
199 | element.dispatchEvent(new Event(eventName, {"bubbles":true})); |
||
200 | }); |
||
201 | } |
||
202 | |||
203 | function fillPassword(user, password) { |
||
204 | var loginFields = getLoginFields(); |
||
205 | for (var i = 0; i < loginFields.length; i++) { |
||
206 | if(user && loginFields[i][0]){ |
||
207 | loginFields[i][0].value = user; |
||
208 | if(loginFields[i][0].offsetParent) { |
||
209 | dispatchEvents(loginFields[i][0]); |
||
210 | } |
||
211 | } |
||
212 | if(password && loginFields[i][1]) { |
||
213 | loginFields[i][1].value = password; |
||
214 | if(loginFields[i][1].offsetParent) { |
||
215 | dispatchEvents(loginFields[i][1]); |
||
216 | } |
||
217 | } |
||
218 | } |
||
219 | |||
220 | } |
||
221 | formManager._init_(); |
This check looks for functions where a
return
statement is found in some execution paths, but not in all.Consider this little piece of code
The function
isBig
will only return a specific value when its parameter is bigger than 5000. In any other case, it will implicitly returnundefined
.This behaviour may not be what you had intended. In any case, you can add a
return undefined
to the other execution path to make the return value explicit.