1 | /* global API */ |
||
2 | var $j = jQuery.noConflict(); |
||
3 | |||
4 | $j(document).ready(function () { |
||
5 | |||
6 | $j(document).click(function (event) { |
||
7 | var passwordPickerRef = '.passwordPickerIframe'; |
||
8 | if (!$j(event.target).closest(passwordPickerRef).length) { |
||
9 | if ($j(passwordPickerRef).is(":visible")) { |
||
10 | removePasswordPicker(); |
||
11 | } |
||
12 | } |
||
13 | }); |
||
14 | |||
15 | var _this = this; |
||
16 | Array.prototype.findUrl = function (match) { |
||
0 ignored issues
–
show
Compatibility
Best Practice
introduced
by
Loading history...
|
|||
17 | return this.filter(function (item) { |
||
18 | var matchParse = processURL(match, false, false, true, false); |
||
19 | return typeof item === 'string' && item.indexOf(matchParse) > -1; |
||
20 | }); |
||
21 | }; |
||
22 | |||
23 | function removePasswordPicker() { |
||
24 | activeForm = undefined; |
||
25 | $j('.passwordPickerIframe').remove(); |
||
26 | } |
||
27 | |||
28 | _this.removePasswordPicker = removePasswordPicker; |
||
29 | |||
30 | function enterLoginDetails(login, allowSubmit) { |
||
31 | var username; |
||
32 | |||
33 | if (login.hasOwnProperty('username')) { |
||
34 | username = (login.username !== '' ) ? login.username : login.email; |
||
35 | } |
||
36 | if (!username) { |
||
37 | username = null; |
||
38 | } |
||
39 | |||
40 | fillPassword(username, login.password); |
||
41 | |||
42 | if (activeForm) { |
||
43 | API.runtime.sendMessage(API.runtime.id, {method: 'isAutoSubmitEnabled'}).then(function (isEnabled) { |
||
44 | if (isEnabled && allowSubmit) { |
||
45 | submitLoginForm(username); |
||
46 | } |
||
47 | }); |
||
48 | } |
||
49 | } |
||
50 | |||
51 | _this.enterLoginDetails = enterLoginDetails; |
||
52 | |||
53 | function enterCustomFields(login, settings) { |
||
54 | var customFieldPattern = /^\#(.*)$/; |
||
55 | var elementId; |
||
56 | var element = false; |
||
0 ignored issues
–
show
|
|||
57 | |||
58 | /* parhaps wise to try / catch this as this is non essential and no reason to abort previous processing */ |
||
59 | try { |
||
60 | /* do we have custom_fields for this entry */ |
||
61 | if (login.hasOwnProperty('custom_fields') && login.custom_fields.length) { |
||
62 | /* yes we do, iterate over all the custom_fields values */ |
||
63 | for (var i = 0, len = login.custom_fields.length; i < len; i++) { |
||
64 | /* does this custom field label begin with a hash? */ |
||
65 | if (customFieldPattern.test(login.custom_fields[i].label)) { |
||
66 | /* set variable elementid to whatever element we are trying to auto fill */ |
||
67 | elementId = customFieldPattern.exec(login.custom_fields[i].label)[1]; |
||
68 | enterCustomFieldElement(elementId, login.custom_fields[i].value); |
||
69 | } |
||
70 | else if ($j('label[for]:contains(' + login.custom_fields[i].label + ')').length) { |
||
71 | elementId = $j('label[for]:contains(' + login.custom_fields[i].label + ')').attr('for'); |
||
72 | enterCustomFieldElement(elementId, login.custom_fields[i].value); |
||
73 | } |
||
74 | } |
||
75 | } |
||
76 | } |
||
77 | catch (e) { |
||
78 | if (settings.debug) { |
||
79 | console.log('While attempting to auto fill custom fields the following exception was thrown: ' + e); |
||
0 ignored issues
–
show
|
|||
80 | } |
||
81 | } |
||
82 | } |
||
83 | |||
84 | function enterCustomFieldElement(elementId, value) { |
||
85 | /* check to see if element id exist */ |
||
86 | if ($j('#' + elementId).length) { |
||
87 | element = $j('#' + elementId); |
||
0 ignored issues
–
show
|
|||
88 | } |
||
89 | else if ($j('input[name$="' + elementId + '"]').length) { /* maybe element name exist */ |
||
90 | element = $j('input[name$="' + elementId + '"]'); |
||
91 | } |
||
92 | else { /* neither element id or name exist */ |
||
93 | element = false; |
||
94 | } |
||
95 | /* if we have an element and it is type text, number or password, lets auto fill it */ |
||
96 | if (element && (element[0].type === 'text' || element[0].type === 'number' || element[0].type === 'password')) { |
||
97 | element.val(value); |
||
98 | } |
||
99 | } |
||
100 | |||
101 | function submitLoginForm(username) { |
||
102 | if (!activeForm) { |
||
103 | // @TODO detect login form on the current page |
||
104 | return; |
||
105 | } |
||
106 | |||
107 | var formEl = $j(activeForm).closest('form'); |
||
108 | var iframeUrl = API.extension.getURL('/html/inject/auto_login.html'); |
||
109 | $j('#loginPopupIframe').remove(); |
||
110 | var loginPopup = $j('<iframe class="loginPopupIframe" scrolling="no" frameborder="0" src="' + iframeUrl + '"></iframe>'); |
||
111 | var padding = parseInt($j(formEl).css('padding').replace('px', '')); |
||
112 | var margin = parseInt($j(formEl).css('margin').replace('px', '')); |
||
113 | var height = Math.round($j(formEl).height() + (padding * 2) + (margin * 2)); |
||
114 | var width = Math.round($j(formEl).width() + (padding * 2) + (margin * 2)); |
||
115 | loginPopup.attr('height', height); |
||
116 | loginPopup.attr('width', width); |
||
117 | loginPopup.css('position', 'absolute'); |
||
118 | loginPopup.css('z-index', getMaxZ() + 1); |
||
119 | loginPopup.css('background-color', 'rgba(0, 0, 0, 0.73)'); |
||
120 | loginPopup.css('left', Math.floor($j(formEl).offset().left - padding - margin)); |
||
121 | loginPopup.css('top', Math.floor($j(formEl).offset().top - padding - margin)); |
||
122 | removePasswordPicker(); |
||
123 | $j(document.body).prepend(loginPopup); |
||
124 | API.runtime.sendMessage(API.runtime.id, {'setIframeUsername': username}).then(function () { |
||
125 | $j(formEl).submit(); |
||
126 | setTimeout(function () { |
||
127 | loginPopup.remove(); |
||
128 | }, 2000); |
||
129 | }); |
||
130 | } |
||
131 | |||
132 | function getMaxZ() { |
||
133 | return Math.max.apply(null, |
||
134 | $j.map($j('body *'), function (e) { |
||
135 | if ($j(e).css('position') !== 'static') |
||
0 ignored issues
–
show
There is no return statement if
$j(e).css("position") !== "static" is false . Are you sure this is correct? If so, consider adding return; explicitly.
This check looks for functions where a Consider this little piece of code function isBig(a) {
if (a > 5000) {
return "yes";
}
}
console.log(isBig(5001)); //returns yes
console.log(isBig(42)); //returns undefined
The function This behaviour may not be what you had intended. In any case, you can add a
Loading history...
|
|||
136 | return parseInt($j(e).css('z-index')) || 1; |
||
0 ignored issues
–
show
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.
Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later. Consider: if (a > 0)
b = 42;
If you or someone else later decides to put another statement in, only the first statement will be executed. if (a > 0)
console.log("a > 0");
b = 42;
In this case the statement if (a > 0) {
console.log("a > 0");
b = 42;
}
ensures that the proper code will be executed conditionally no matter how many statements are added or removed.
Loading history...
|
|||
137 | })); |
||
138 | } |
||
139 | |||
140 | var activeForm; |
||
141 | |||
142 | function showPasswordPicker(form) { |
||
143 | var jPasswordPicker = $j('.passwordPickerIframe'); |
||
144 | if (jPasswordPicker.length > 1) { |
||
145 | return; |
||
146 | } |
||
147 | var loginField = $j(form[0]); |
||
148 | var loginFieldPos = loginField.offset(); |
||
149 | var loginFieldVisible = loginField.is(':visible'); |
||
150 | |||
151 | var position = $j(form[1]).position(); |
||
0 ignored issues
–
show
|
|||
152 | var passwordField = $j(form[1]); |
||
153 | var passwordFieldPos = passwordField.offset(); |
||
154 | var passwordFieldVisible = loginField.is(':visible'); |
||
0 ignored issues
–
show
|
|||
155 | var left = (loginFieldPos) ? loginFieldPos.left : passwordFieldPos.left; |
||
156 | var top = (loginFieldPos) ? loginFieldPos.top : passwordFieldPos.top; |
||
157 | var maxZ = getMaxZ(); |
||
158 | |||
159 | if (loginFieldPos && passwordFieldPos.top > loginFieldPos.top) { |
||
160 | //console.log('login fields below each other') |
||
161 | top = passwordFieldPos.top + passwordField.height() + 10; |
||
162 | } else { |
||
163 | // console.log('login fields next to each other') |
||
164 | if (loginFieldPos) { |
||
165 | top = top + loginField.height() + 10; |
||
166 | } else { |
||
167 | top = top + passwordField.height() + 10; |
||
168 | } |
||
169 | } |
||
170 | if (!loginFieldVisible) { |
||
171 | left = passwordFieldPos.left; |
||
172 | } |
||
173 | |||
174 | var pickerUrl = API.extension.getURL('/html/inject/password_picker.html'); |
||
175 | |||
176 | var picker = $j('<iframe class="passwordPickerIframe" scrolling="no" height="385" width="350" frameborder="0" src="' + pickerUrl + '"></iframe>'); |
||
177 | picker.css('position', 'absolute'); |
||
178 | picker.css('left', left); |
||
179 | picker.css('z-index', maxZ + 10); |
||
180 | picker.css('top', top); |
||
181 | $j('body').prepend($j(picker)); |
||
182 | activeForm = form; |
||
183 | // picker.css('width', $j(form).width()); |
||
184 | $j('.passwordPickerIframe:not(:last)').remove(); |
||
185 | } |
||
186 | |||
187 | function onFormIconClick(e) { |
||
188 | e.preventDefault(); |
||
189 | e.stopPropagation(); |
||
190 | var offsetX = e.offsetX; |
||
191 | var offsetRight = (e.data.width - offsetX); |
||
192 | if (offsetRight < e.data.height) { |
||
193 | showPasswordPicker(e.data.form); |
||
194 | } |
||
195 | } |
||
196 | |||
197 | function createFormIcon(el, form) { |
||
198 | var offset = el.offset(); |
||
0 ignored issues
–
show
|
|||
199 | var width = el.width(); |
||
200 | var height = el.height() * 1; |
||
201 | var margin = (el.css('margin')) ? parseInt(el.css('margin').replace('px', '')) : 0; |
||
0 ignored issues
–
show
|
|||
202 | var padding = (el.css('padding')) ? parseInt(el.css('padding').replace('px', '')) : 0; |
||
0 ignored issues
–
show
|
|||
203 | |||
204 | var pickerIcon = API.extension.getURL('/icons/icon.svg'); |
||
205 | $j(el).css('background-image', 'url("' + pickerIcon + '")'); |
||
206 | $j(el).css('background-repeat', 'no-repeat'); |
||
207 | //$j(el).css('background-position', ''); |
||
208 | $j(el).css('cssText', el.attr('style') + ' background-position: right 3px center !important;'); |
||
209 | |||
210 | $j(el).unbind('click', onFormIconClick); |
||
211 | $j(el).click({width: width, height: height, form: form}, onFormIconClick); |
||
212 | } |
||
213 | |||
214 | function createPasswordPicker(form) { |
||
215 | for (var i = 0; i < form.length; i++) { |
||
216 | var el = $j(form[i]); |
||
217 | createFormIcon(el, form); |
||
218 | } |
||
219 | } |
||
220 | |||
221 | function formSubmitted(fields) { |
||
222 | var user = fields[0].value; |
||
223 | var pass = fields[1].value; |
||
224 | var params = { |
||
225 | username: user, |
||
226 | password: pass |
||
227 | }; |
||
228 | //Disable password mining |
||
229 | //$j(fields[1]).attr('type', 'hidden'); |
||
230 | API.runtime.sendMessage(API.runtime.id, {method: "minedForm", args: params}); |
||
231 | |||
232 | } |
||
233 | |||
234 | function inIframe() { |
||
235 | try { |
||
236 | return window.self !== window.top; |
||
237 | } catch (e) { |
||
238 | return true; |
||
239 | } |
||
240 | } |
||
241 | |||
242 | function showDoorhanger(data) { |
||
243 | if (inIframe()) { |
||
244 | return; |
||
245 | } |
||
246 | data.data.currentLocation = window.location.href; |
||
247 | API.runtime.sendMessage(API.runtime.id, {method: "setDoorhangerData", args: data}); |
||
248 | var pickerUrl = API.extension.getURL('/html/inject/doorhanger.html'); |
||
249 | |||
250 | var doorhanger = $j('<iframe id="password-toolbarIframe" style="display: none;" scrolling="no" height="60" width="100%" frameborder="0" src="' + pickerUrl + '"></iframe>'); |
||
251 | $j('#password-toolbarIframe').remove(); |
||
252 | doorhanger.css('z-index', getMaxZ() + 1); |
||
253 | $j('body').prepend(doorhanger); |
||
254 | $j('#password-toolbarIframe').fadeIn(); |
||
255 | } |
||
256 | |||
257 | _this.showDoorhanger = showDoorhanger; |
||
258 | |||
259 | function showUrlUpdateDoorhanger(data) { |
||
260 | var buttons = ['cancel', 'updateUrl']; |
||
261 | showDoorhanger({ |
||
262 | data: data.data, |
||
263 | buttons: buttons |
||
264 | }); |
||
265 | } |
||
266 | |||
267 | _this.showUrlUpdateDoorhanger = showUrlUpdateDoorhanger; |
||
268 | |||
269 | function checkForMined() { |
||
270 | if (inIframe()) { |
||
271 | return; |
||
272 | } |
||
273 | |||
274 | API.runtime.sendMessage(API.runtime.id, {method: "getMinedData"}).then(function (data) { |
||
275 | if (!data) { |
||
276 | return; |
||
277 | } |
||
278 | if (data.hasOwnProperty('username') && data.hasOwnProperty('password') && data.hasOwnProperty('url')) { |
||
279 | var buttons = ['cancel', 'ignore', 'save']; |
||
280 | showDoorhanger({data: data, buttons: buttons}); |
||
281 | } |
||
282 | }); |
||
283 | } |
||
284 | |||
285 | |||
286 | function closeDoorhanger() { |
||
287 | $j('#password-toolbarIframe').hide(400); |
||
288 | $j('#password-toolbarIframe').remove(); |
||
289 | } |
||
290 | |||
291 | _this.closeDoorhanger = closeDoorhanger; |
||
292 | |||
293 | var flagFilledForm = false; |
||
294 | function initForms() { |
||
295 | API.runtime.sendMessage(API.runtime.id, {method: 'getRuntimeSettings'}).then(function (settings) { |
||
296 | var enablePasswordPicker = settings.enablePasswordPicker; |
||
297 | var url = window.location.href; |
||
298 | var loginFields = getLoginFields(); |
||
299 | if (!settings.hasOwnProperty('ignored_sites') || settings.ignored_sites.findUrl(url).length !== 0) { |
||
300 | return; |
||
301 | } |
||
302 | |||
303 | if (loginFields.length > 0) { |
||
304 | for (var i = 0; i < loginFields.length; i++) { |
||
305 | var form = getFormFromElement(loginFields[i][0]); |
||
306 | if (enablePasswordPicker) { |
||
307 | createPasswordPicker(loginFields[i], form); |
||
0 ignored issues
–
show
|
|||
308 | } |
||
309 | |||
310 | //Password miner |
||
311 | /* jshint ignore:start */ |
||
312 | $j(form).submit((function (loginFields) { |
||
313 | return function () { |
||
314 | formSubmitted(loginFields); |
||
315 | }; |
||
316 | })(loginFields[i])); |
||
317 | /* jshint ignore:end */ |
||
318 | } |
||
319 | |||
320 | API.runtime.sendMessage(API.runtime.id, { |
||
321 | method: "getCredentialsByUrl", |
||
322 | args: url |
||
323 | }).then(function (logins) { |
||
324 | console.log('Found ' + logins.length + ' logins for this site'); |
||
0 ignored issues
–
show
|
|||
325 | if (logins.length === 1) { |
||
326 | API.runtime.sendMessage(API.runtime.id, {method: 'isAutoFillEnabled'}).then(function (isEnabled) { |
||
327 | if (isEnabled && !flagFilledForm) { |
||
328 | enterLoginDetails(logins[0], false); |
||
329 | flagFilledForm = true; |
||
330 | } |
||
331 | }); |
||
332 | } |
||
333 | }); |
||
334 | } |
||
335 | |||
336 | API.runtime.sendMessage(API.runtime.id, { |
||
337 | method: "getCredentialsByUrl", |
||
338 | args: url |
||
339 | }).then(function (logins) { |
||
340 | if (logins.length === 1) { |
||
341 | API.runtime.sendMessage(API.runtime.id, {method: 'isAutoFillEnabled'}).then(function (isEnabled) { |
||
342 | if (isEnabled) { |
||
343 | enterCustomFields(logins[0], settings); |
||
344 | } |
||
345 | }); |
||
346 | } |
||
347 | }); |
||
348 | |||
349 | }); |
||
350 | } |
||
351 | |||
352 | function minedLoginSaved(args) { |
||
353 | // If the login added by the user then this is true |
||
354 | if (args.selfAdded) { |
||
355 | showDoorhanger({ |
||
356 | data: args, |
||
357 | buttons: ['cancel'] |
||
358 | }); |
||
359 | enterLoginDetails(args.credential, false); |
||
360 | } |
||
361 | } |
||
362 | |||
363 | _this.minedLoginSaved = minedLoginSaved; |
||
364 | |||
365 | function resizeIframe(height) { |
||
366 | $j('#password-toolbarIframe').height(60 + height); |
||
367 | } |
||
368 | |||
369 | _this.resizeIframe = resizeIframe; |
||
370 | |||
371 | function copyText(text) { |
||
372 | var txtToCopy = document.createElement('input'); |
||
373 | txtToCopy.style.left = '-300px'; |
||
374 | txtToCopy.style.position = 'absolute'; |
||
375 | txtToCopy.value = text; |
||
376 | document.body.appendChild(txtToCopy); |
||
377 | txtToCopy.select(); |
||
378 | document.execCommand('copy'); |
||
379 | txtToCopy.parentNode.removeChild(txtToCopy); |
||
380 | } |
||
381 | |||
382 | _this.copyText = copyText; |
||
383 | |||
384 | function init() { |
||
385 | checkForMined(); |
||
386 | initForms(); |
||
387 | } |
||
388 | |||
389 | var readyStateCheckInterval = setInterval(function () { |
||
390 | if (document.readyState === "complete") { |
||
391 | clearInterval(readyStateCheckInterval); |
||
392 | API.runtime.sendMessage(API.runtime.id, {method: 'getMasterPasswordSet'}).then(function (result) { |
||
393 | if (result) { |
||
394 | init(); |
||
395 | var body = document.getElementsByTagName('body')[0]; |
||
396 | if (body) { |
||
397 | observeDOM(body, initForms); |
||
398 | } |
||
399 | } else { |
||
400 | console.log('[Passman extension] Stopping, vault key not set'); |
||
0 ignored issues
–
show
|
|||
401 | } |
||
402 | }); |
||
403 | } |
||
404 | }, 10); |
||
405 | |||
406 | API.runtime.onMessage.addListener(function (msg, sender) { |
||
407 | //console.log('Method call', msg.method); |
||
408 | if (_this[msg.method]) { |
||
409 | _this[msg.method](msg.args, sender); |
||
410 | } |
||
411 | }); |
||
412 | }); |
||
413 |