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') |
||
0 ignored issues
–
show
|
|||
136 | return parseInt($j(e).css('z-index')) || 1; |
||
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 |
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.