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) { |
||
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; |
||
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); |
||
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); |
||
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') |
||
136 | return parseInt($j(e).css('z-index')) || 1; |
||
0 ignored issues
–
show
|
|||
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(); |
||
152 | var passwordField = $j(form[1]); |
||
153 | var passwordFieldPos = passwordField.offset(); |
||
154 | var passwordFieldVisible = loginField.is(':visible'); |
||
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(); |
||
199 | var width = el.width(); |
||
200 | var height = el.height() * 1; |
||
201 | var margin = (el.css('margin')) ? parseInt(el.css('margin').replace('px', '')) : 0; |
||
202 | var padding = (el.css('padding')) ? parseInt(el.css('padding').replace('px', '')) : 0; |
||
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); |
||
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'); |
||
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'); |
||
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 |
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 you or someone else later decides to put another statement in, only the first statement will be executed.
In this case the statement
b = 42
will always be executed, while the logging statement will be executed conditionally.ensures that the proper code will be executed conditionally no matter how many statements are added or removed.