Completed
Push — master ( 431046...3800ca )
by Sander
01:05
created

js/background/inject/inject.js   D

Complexity

Total Complexity 68
Complexity/F 2.27

Size

Lines of Code 335
Function Count 30

Duplication

Duplicated Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 0
c 1
b 0
f 0
nc 3072
dl 0
loc 335
rs 4.2608
wmc 68
mnd 3
bc 61
fnc 30
bpm 2.0333
cpm 2.2666
noi 6

1 Function

Rating   Name   Duplication   Size   Complexity  
B $j.ready 0 334 1

How to fix   Complexity   

Complexity

Complex classes like js/background/inject/inject.js often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
/* global API */
2
var $j = jQuery.noConflict();
3
$j(document).ready(function () {
4
    var _this = this;
5
6
    function removePasswordPicker() {
7
        $j('#passwordPickerIframe').remove();
8
    }
9
    _this.removePasswordPicker = removePasswordPicker;
10
11
    function enterLoginDetails(login) {
12
        var username = (login.username.trim() !== '' ) ? login.username : login.email;
13
14
        fillPassword(username, login.password);
15
        if ($j('#passwordPickerIframe').is(':visible')) {
16
            removePasswordPicker();
17
        }
18
    }
19
20
    _this.enterLoginDetails = enterLoginDetails;
21
22
23
    function showPasswordPicker(form) {
24
        var loginField = $j(form[0]);
25
        var loginFieldPos = loginField.offset();
26
        var passwordField = $j(form[1]);
27
        var passwordFieldPos = passwordField.offset();
28
29
        var left = loginFieldPos.left;
30
        var top = loginFieldPos.top;
31
32
        if (passwordFieldPos.top > loginFieldPos.top) {
33
            //console.log('login fields below each other')
34
            top = passwordFieldPos.top + passwordField.height() + 10;
35
36
        } else {
37
            // console.log('login fields next to each other')
38
            top = top + loginField.height() + 10;
39
        }
40
41
        var position = $j(form[1]).position();
0 ignored issues
show
Unused Code introduced by
The assignment to variable position seems to be never used. Consider removing it.
Loading history...
42
        var pickerUrl = API.extension.getURL('/html/inject/password_picker.html');
43
44
        $j(document.body).after('<iframe id="passwordPickerIframe" scrolling="no" height="400" width="350" frameborder="0" src="'+ pickerUrl +'"></iframe>');
45
46
        var picker = $j('#passwordPickerIframe');
47
        picker.css('position', 'absolute');
48
        picker.css('left', left);
49
        picker.css('z-index', 999);
50
        picker.css('top', top);
51
        // picker.css('width', $j(form).width());
52
53
    }
54
55
    function createFormIcon(el, form) {
56
        var offset = el.offset();
57
        var width = el.width();
58
        var height = el.height();
59
        var margin = (el.css('margin')) ? parseInt(el.css('margin').replace('px', '')) : 0;
60
        var padding = (el.css('padding')) ? parseInt(el.css('padding').replace('px', '')) : 0;
61
        var paddingRight = parseInt(el.css('padding-right').replace('px', ''));
62
        var fontSize = el.css('font-size');
63
        var borderh = (el.css('border-height')) ? el.css('border-height') : '2px';
64
        var borderw = (el.css('border-width')) ? el.css('border-width') : '2px';
65
        var borderColor = el.css('border-color');
0 ignored issues
show
Unused Code introduced by
The variable borderColor seems to be never used. Consider removing it.
Loading history...
66
        var borderHeight = parseInt(borderh.replace('px', ''));
67
        var borderWidth = parseInt(borderw.replace('px', ''));
68
        var iconWidth = width * 0.1;
69
        var pickerButton = $j('<span class="passwordPickerIcon" style="display: inline-block"> </span>');
70
        $j('body').append(pickerButton);
71
        if (el.find('.passwordPickerIcon').length > 0) {
72
            pickerButton = el.find('.passwordPickerIcon')[0];
73
        }
74
75
76
        //pickerButton.css('background-image', 'url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAASCAYAAABSO15qAAAAAXNSR0IArs4c6QAAAPhJREFUOBHlU70KgzAQPlMhEvoQTg6OPoOjT+JWOnRqkUKHgqWP4OQbOPokTk6OTkVULNSLVc62oJmbIdzd95NcuGjX2/3YVI/Ts+t0WLE2ut5xsQ0O+90F6UxFjAI8qNcEGONia08e6MNONYwCS7EQAizLmtGUDEzTBNd1fxsYhjEBnHPQNG3KKTYV34F8ec/zwHEciOMYyrIE3/ehKAqIoggo9inGXKmFXwbyBkmSQJqmUNe15IRhCG3byphitm1/eUzDM4qR0TTNjEixGdAnSi3keS5vSk2UDKqqgizLqB4YzvassiKhGtZ/jDMtLOnHz7TE+yf8BaDZXA509yeBAAAAAElFTkSuQmCC")');
77
        pickerButton.css('background-image', 'url("data:image/png;base64,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")');
78
        pickerButton.css('background-repeat', 'no-repeat');
79
        pickerButton.css('background-attachment', 'scroll');
80
        //pickerButton.css('background-size', '16px 18px');
81
        pickerButton.css('background-size', 'contain');
82
        pickerButton.css('background-position', '98% 50%');
83
        pickerButton.css('cursor', 'pointer');
84
        pickerButton.css('text-align', 'center');
85
        pickerButton.css('box-sizing', 'content-box');
86
        pickerButton.css('position', 'absolute');
87
        /*
88
         pickerButton.css('background-color', 'rgb(234, 234, 234)');
89
         pickerButton.css('border-top-right-radius', el.css('border-top-right-radius'));
90
         pickerButton.css('border-bottom-right-radius', el.css('border-bottom-right-radius'));
91
         pickerButton.css('border-color', borderColor);*/
92
93
        pickerButton.css('z-index', '999');
94
        pickerButton.css('width', iconWidth);
95
96
97
        pickerButton.css('padding', padding);
98
        pickerButton.css('font-size', fontSize);
99
        pickerButton.css('height', height);
100
        pickerButton.css('margin', margin);
101
        pickerButton.css('font-weight', el.css('font-weight'));
102
        pickerButton.css('top', Math.round((offset.top + (height / 4) - margin / 2 - padding / 2 ) - (borderHeight / 2)) + 'px');
103
        pickerButton.css('left', Math.round((offset.left + width * 0.9) + paddingRight - padding + borderWidth) + 'px');
104
105
106
        var onClick = function () {
107
            showPasswordPicker(form);
108
        };
109
110
        //$j('body').append(pickerButton);
111
112
        pickerButton.find('fa-key').click(onClick);
113
        $j(pickerButton).click(onClick);
114
115
    }
116
117
    function createPasswordPicker(form) {
118
        for (var i = 0; i < form.length; i++) {
119
            var el = $j(form[i]);
120
            createFormIcon(el, form);
121
122
        }
123
    }
124
125
    function updatePositions() {
126
        $j('.passwordPickerIcon').remove();
127
        var forms = getLoginFields();
128
        for (var f = 0; f < forms.length; f++) {
129
            var form = forms[f];
130
            for (var i = 0; i < form.length; i++) {
131
                var el = $j(form[i]);
132
                createFormIcon(el, form);
133
            }
134
        }
135
    }
136
137
138
    function togglePasswordPicker(e) {
139
        if (e.target.className === "passwordPickerIcon" || e.target.className === "fa fa-key") {
140
            return;
141
        }
142
        var picker = $j('#passwordPickerIframe');
143
        if (!picker.is(e.target) && picker.has(e.target).length === 0) {
144
            if (picker) {
145
                picker.remove();
146
            }
147
        }
148
    }
149
150
    function formSubmitted(fields) {
151
        var user = fields[0].value;
152
        var pass = fields[1].value;
153
        var params = {
154
            username: user,
155
            password: pass
156
        };
157
        //Disable password mining
158
        //$j(fields[1]).attr('type', 'hidden');
159
        API.runtime.sendMessage(API.runtime.id, {method: "minedForm", args: params});
160
161
    }
162
163
    function inIframe() {
164
        try {
165
            return window.self !== window.top;
166
        } catch (e) {
167
            return true;
168
        }
169
    }
170
171
172
    function checkForMined() {
173
        if (inIframe()) {
174
            return;
175
        }
176
        if(getLoginFields()){
177
            return;
178
        }
179
180
        API.runtime.sendMessage(API.runtime.id, {method: "getMinedData"}).then(function (data) {
181
            if (!data) {
182
                return;
183
            }
184
            if (data.hasOwnProperty('username') && data.hasOwnProperty('password') && data.hasOwnProperty('url')) {
185
                var doorhanger = $j('<div id="password-toolbar" class="container" style="display: none;">' +
186
                    '<span class="toolbar-text">' + data.title + ' ' + data.username + ' at ' + data.url + '</span></div>');
187
188
                var btnText = (data.guid === null) ? 'Save' : 'Update';
189
                var btnSave = $j('<button class="btn btn-success">' + btnText + '</button>');
190
                var btnCancel = $j('<button class="btn btn-default">Cancel</button>');
191
                btnSave.click(function () {
192
                    //closeToolbar();
193
                    API.runtime.sendMessage(API.runtime.id, {method: "saveMined"});
194
                });
195
196
                btnCancel.click(function () {
197
                    closeToolbar();
198
                    API.runtime.sendMessage(API.runtime.id, {method: "clearMined"});
199
                });
200
201
                doorhanger.append(btnCancel).append(btnSave);
202
                $j('#password-toolbar').remove();
203
                $j('body').append(doorhanger);
204
                $j('#password-toolbar').slideDown();
205
            }
206
        });
207
    }
208
209
    function minedLoginSaved(args) {
210
        // If the login added by the user then this is true
211
        if (args.selfAdded) {
212
            enterLoginDetails(args.credential);
213
            return;
214
        }
215
        if ($j('#password-toolbar').is(':visible')) {
216
            var action = (args.updated) ? 'updated' : 'saved';
217
            $j('#password-toolbar').html('Credential ' + action + '!');
218
            setTimeout(function () {
219
                closeToolbar();
220
            }, 2500);
221
        }
222
    }
223
224
    _this.minedLoginSaved = minedLoginSaved;
225
226
    function closeToolbar() {
227
        $j('#password-toolbar').slideUp(400, function () {
228
            $j('#password-toolbar').remove();
229
        });
230
    }
231
232
    function insertFontCSS() {
233
        var fontPath = API.extension.getURL('');
234
        var fontCss = ["@font-face {",
235
            "font-family: 'FontAwesome';",
236
            "src: url('" + fontPath + "fonts/fontawesome-webfont.eot?v=4.7.0');",
237
            "src: url('" + fontPath + "fonts/fontawesome-webfont.eot?#iefix&v=4.7.0') format('embedded-opentype'), url('" + fontPath + "fonts/fontawesome-webfont.woff2?v=4.7.0') format('woff2'), url('" + fontPath + "fonts/fontawesome-webfont.woff?v=4.7.0') format('woff'), url('" + fontPath + "fonts/fontawesome-webfont.ttf?v=4.7.0') format('truetype'), url('" + fontPath + "fonts/fontawesome-webfont.svg?v=4.7.0#fontawesomeregular') format('svg');",
238
            "font-weight: normal;",
239
            "font-style: normal;",
240
            "}"];
241
        if (window.navigator.userAgent.indexOf('Firefox') !== -1) {
242
            fontCss[2] = "src: url('" + fontPath + "fonts/fontawesome-webfont.eot?v=4.7.0');";
243
            fontCss[3] = "src: url('" + fontPath + "fonts/fontawesome-webfont.eot?#iefix&v=4.7.0') format('embedded-opentype'), url('" + fontPath + "fonts/fontawesome-webfont.woff2?v=4.7.0') format('woff2'), url('" + fontPath + "fonts/fontawesome-webfont.woff?v=4.7.0') format('woff'), url('" + fontPath + "fonts/fontawesome-webfont.ttf?v=4.7.0') format('truetype'), url('" + fontPath + "fonts/fontawesome-webfont.svg?v=4.7.0#fontawesomeregular') format('svg');";
244
        }
245
        var css = fontCss.join('');
246
        var style = document.createElement('style'),
247
            head = document.head || document.getElementsByTagName('head')[0];
248
249
        style.type = 'text/css';
250
        if (style.styleSheet) {
251
            style.styleSheet.cssText = css;
252
        } else {
253
            style.appendChild(document.createTextNode(css));
254
        }
255
256
        head.appendChild(style);
257
    }
258
259
260
    function init() {
261
        insertFontCSS();
262
        $j(document).unbind('click', togglePasswordPicker);
263
        checkForMined();
264
        API.runtime.sendMessage(API.runtime.id, {method: 'getRuntimeSettings'}).then(function (result) {
265
            var disablePasswordPicker = result.disablePasswordPicker;
266
267
            var loginFields = getLoginFields();
268
            if (loginFields.length > 0) {
269
                //@TODO prevent chrome from captuting pw's: http://stackoverflow.com/questions/27280461/prevent-chrome-from-prompting-to-save-password-from-input-box
270
                for (var i = 0; i < loginFields.length; i++) {
271
                    var form = getFormFromElement(loginFields[i][0]);
272
                    if(!disablePasswordPicker) {
273
                        createPasswordPicker(loginFields[i], form);
0 ignored issues
show
Bug introduced by
The call to createPasswordPicker seems to have too many arguments starting with form.
Loading history...
274
                    }
275
                    //Password miner
276
                    /* jshint ignore:start */
277
                    $j(form).submit((function (loginFields) {
278
                        return function () {
279
                            formSubmitted(loginFields);
280
                        };
281
                    })(loginFields[i]));
282
                    /* jshint ignore:end */
283
                }
284
285
                var url = window.location.href; //@TODO use a extension function
286
                API.runtime.sendMessage(API.runtime.id, {
287
                    method: "getCredentialsByUrl",
288
                    args: [url]
289
                }).then(function (logins) {
290
                    //console.log('Found ' + logins.length + ' logins for this site');
291
                    if (logins.length === 1) {
292
                        API.runtime.sendMessage(API.runtime.id, {method: 'isAutoFillEnabled'}).then(function (isEnabled) {
293
                            if (isEnabled) {
294
                                enterLoginDetails(logins[0]);
295
                            }
296
                        });
297
                    }
298
299
                });
300
            }
301
302
        });
303
304
        $j(document).click(togglePasswordPicker);
305
        $j(window).on('resize', function () {
306
            if (getLoginFields().length > 0) {
307
                updatePositions();
308
            }
309
        });
310
    }
311
312
    var readyStateCheckInterval = setInterval(function () {
313
        if (document.readyState === "complete") {
314
            clearInterval(readyStateCheckInterval);
315
            API.runtime.sendMessage(API.runtime.id, {method: 'getMasterPasswordSet'}).then(function (result) {
316
                if (result) {
317
                    init();
318
                } else {
319
                    console.log('[Passman extension] Stopping, vault key not set');
0 ignored issues
show
Debugging Code introduced by
console.log looks like debug code. Are you sure you do not want to remove it?
Loading history...
320
                }
321
            });
322
323
            // var body = document.getElementsByTagName('body')[0];
324
            // observeDOM(body, function () {
325
            //     //init()
326
            // });
327
        }
328
    }, 10);
329
330
    API.runtime.onMessage.addListener(function (msg, sender, sendResponse) {
0 ignored issues
show
Unused Code introduced by
The parameter sendResponse is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
331
        console.log('Method call', msg.method);
0 ignored issues
show
Debugging Code introduced by
console.log looks like debug code. Are you sure you do not want to remove it?
Loading history...
332
        if(_this[msg.method]) {
333
            _this[msg.method](msg.args, sender);
334
        }
335
    });
336
});