Completed
Push — master ( 09aba7...ebd425 )
by Sander
01:24
created

$j.ready   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
c 0
b 0
f 0
nc 1
nop 1
dl 0
loc 11
rs 9.4285
1
/* global API */
2
var $j = jQuery.noConflict();
3
4
$j(document).ready(function () {
5
    var _this = this;
6
    Array.prototype.findUrl = function(match) {
0 ignored issues
show
Compatibility Best Practice introduced by
You are extending the built-in type Array. This may have unintended consequences on other objects using this built-in type. Consider subclassing instead.
Loading history...
7
        return this.filter(function(item){
8
            return typeof item === 'string' && item.indexOf(match) > -1;
9
        });
10
    };
11
12
    function removePasswordPicker() {
13
        $j('.passwordPickerIframe').remove();
14
    }
15
16
    _this.removePasswordPicker = removePasswordPicker;
17
18
    function enterLoginDetails(login) {
19
        var username;
20
21
        if(login.hasOwnProperty('username')){
22
            username = (login.username.trim() !== '' ) ? login.username : login.email;
23
        }
24
25
        fillPassword(username, login.password);
0 ignored issues
show
Bug introduced by
The variable username does not seem to be initialized in case login.hasOwnProperty("username") on line 21 is false. Are you sure the function fillPassword handles undefined variables?
Loading history...
26
        if ($j('.passwordPickerIframe').is(':visible')) {
27
            removePasswordPicker();
28
        }
29
    }
30
31
    _this.enterLoginDetails = enterLoginDetails;
32
33
34
    function showPasswordPicker(form) {
35
        if ($j('.passwordPickerIframe').length > 1) {
36
            return;
37
        }
38
        var loginField = $j(form[0]);
39
        var loginFieldPos = loginField.offset();
40
        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...
41
        var passwordField = $j(form[1]);
42
        var passwordFieldPos = passwordField.offset();
43
44
        var left = loginFieldPos.left;
45
        var top = loginFieldPos.top;
46
        var maxZ = Math.max.apply(null,
47
            $j.map($j('body *'), function(e) {
48
                if ($j(e).css('position') !== 'static')
0 ignored issues
show
Complexity Best Practice introduced by
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 return statement is found in some execution paths, but not in all.

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 isBig will only return a specific value when its parameter is bigger than 5000. In any other case, it will implicitly return undefined.

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.

Loading history...
49
                    return parseInt($j(e).css('z-index')) || 1;
0 ignored issues
show
Coding Style Best Practice introduced by
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 b = 42 will always be executed, while the logging statement will be executed conditionally.

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...
50
            }));
51
        if (passwordFieldPos.top > loginFieldPos.top) {
52
            //console.log('login fields below each other')
53
            top = passwordFieldPos.top + passwordField.height() + 10;
54
55
        } else {
56
            // console.log('login fields next to each other')
57
            top = top + loginField.height() + 10;
58
        }
59
60
61
        var pickerUrl = API.extension.getURL('/html/inject/password_picker.html');
62
63
        var picker = $j('<iframe class="passwordPickerIframe" scrolling="no" height="400" width="350" frameborder="0" src="' + pickerUrl + '"></iframe>');
64
        picker.css('position', 'absolute');
65
        picker.css('left', left);
66
        picker.css('z-index', maxZ);
67
        picker.css('top', top);
68
        $j('body').append($j(picker));
69
        // picker.css('width', $j(form).width());
70
        $j('.passwordPickerIframe:not(:last)').remove();
71
    }
72
73
    function createFormIcon(el, form) {
74
        var offset = el.offset();
0 ignored issues
show
Unused Code introduced by
The assignment to variable offset seems to be never used. Consider removing it.
Loading history...
75
        var width = el.width();
76
        var height = el.height() * 1;
77
        var margin = (el.css('margin')) ? parseInt(el.css('margin').replace('px', '')) : 0;
0 ignored issues
show
Unused Code introduced by
The variable margin seems to be never used. Consider removing it.
Loading history...
78
        var padding = (el.css('padding')) ? parseInt(el.css('padding').replace('px', '')) : 0;
0 ignored issues
show
Unused Code introduced by
The variable padding seems to be never used. Consider removing it.
Loading history...
79
80
        var pickerIcon = API.extension.getURL('/icons/icon.svg');
81
        $j(el).css('background-image', 'url("' + pickerIcon + '")');
82
        $j(el).css('background-repeat', 'no-repeat');
83
        $j(el).css('background-position', 'right 3px center');
84
85
86
        function onClick(e) {
87
            e.preventDefault();
88
            var offsetX = e.offsetX;
89
            var offsetRight = (width - offsetX);
90
            if (offsetRight < height) {
91
                showPasswordPicker(form);
92
            }
93
        }
94
95
        // $j(el).bind('click', onClick);
96
        $j(el).click(onClick);
97
98
    }
99
100
    function createPasswordPicker(form) {
101
        for (var i = 0; i < form.length; i++) {
102
            var el = $j(form[i]);
103
            createFormIcon(el, form);
104
105
        }
106
    }
107
108
    function formSubmitted(fields) {
109
        var user = fields[0].value;
110
        var pass = fields[1].value;
111
        var params = {
112
            username: user,
113
            password: pass
114
        };
115
        //Disable password mining
116
        //$j(fields[1]).attr('type', 'hidden');
117
        API.runtime.sendMessage(API.runtime.id, {method: "minedForm", args: params});
118
119
    }
120
121
    function inIframe() {
122
        try {
123
            return window.self !== window.top;
124
        } catch (e) {
125
            return true;
126
        }
127
    }
128
129
    function showDoorhanger(data) {
130
        var buttons = data.buttons;
131
        data = data.data;
132
        if (inIframe()) {
133
            return;
134
        }
135
        var doorhanger_div = $j('<div id="password-toolbar" style="display: none;">');
136
        $j('<span>', {
137
            class: 'toolbar-text',
138
            text: data.title + ' ' + data.username + ' at ' + data.url
139
        }).appendTo(doorhanger_div);
140
141
142
        $j.each(buttons, function (k, button) {
143
            var html_button = $j('<button class="passman-btn passnman-btn-success"></button>').text(button.text);
144
            html_button.click(button.onClickFn);
145
            doorhanger_div.append(html_button);
146
        });
147
148
149
        $j('#password-toolbar').remove();
150
        $j('body').append(doorhanger_div);
151
        $j('#password-toolbar').slideDown();
152
    }
153
154
    _this.showDoorhanger = showDoorhanger;
155
156
    function showUrlUpdateDoorhanger(data) {
157
        var buttons = [
158
            {
159
                text: 'Cancel',
160
                onClickFn: function () {
161
                    $j('#password-toolbar').slideUp();
162
                }
163
            },
164
            {
165
                text: 'Update',
166
                onClickFn: function () {
167
                    //closeToolbar();
168
                    API.runtime.sendMessage(API.runtime.id, {method: "updateCredentialUrl", args: data.data});
169
                    $j('#password-toolbar').find('.toolbar-text').text('Saving...');
170
                    $j('#password-toolbar').find('.passman-btn').hide();
171
                }
172
            }
173
        ];
174
        showDoorhanger({
175
            data: data.data,
176
            buttons: buttons
177
        });
178
    }
179
180
    _this.showUrlUpdateDoorhanger = showUrlUpdateDoorhanger;
181
182
    function checkForMined() {
183
        if (inIframe()) {
184
            return;
185
        }
186
187
188
        API.runtime.sendMessage(API.runtime.id, {method: "getMinedData"}).then(function (data) {
189
            if (!data) {
190
                return;
191
            }
192
            if (data.hasOwnProperty('username') && data.hasOwnProperty('password') && data.hasOwnProperty('url')) {
193
                var btnText = (data.guid === null) ? 'Save' : 'Update';
194
195
                var buttons = [
196
                    {
197
                        text: 'Cancel',
198
                        onClickFn: function () {
199
                            closeToolbar();
200
                            API.runtime.sendMessage(API.runtime.id, {method: "clearMined"});
201
                        }
202
                    },
203
                    {
204
                        text: btnText,
205
                        onClickFn: function () {
206
                            //closeToolbar();
207
                            API.runtime.sendMessage(API.runtime.id, {method: "saveMined"});
208
                            $j('#password-toolbar').find('.toolbar-text').text('Saving...');
209
                            $j('#password-toolbar').find('.passman-btn').hide();
210
                        }
211
                    },
212
                    {
213
                        text: 'Ignore site',
214
                        onClickFn: function () {
215
                            //closeToolbar();
216
                            API.runtime.sendMessage(API.runtime.id, {method: "ignoreSite", args: window.location.href});
217
                            $j('#password-toolbar').find('.toolbar-text').text('Site ignored');
218
                            $j('#password-toolbar').find('.passman-btn').hide();
219
                            setTimeout(function () {
220
                                closeToolbar();
221
                            }, 3000);
222
                        }
223
                    }
224
225
                ];
226
                showDoorhanger({data: data, buttons: buttons});
227
            }
228
        });
229
    }
230
231
    function minedLoginSaved(args) {
232
        // If the login added by the user then this is true
233
        if (args.selfAdded) {
234
            enterLoginDetails(args.credential);
235
            return;
236
        }
237
        if ($j('#password-toolbar').is(':visible')) {
238
            var action = (args.updated) ? 'updated' : 'saved';
239
            $j('#password-toolbar').html('Credential ' + action + '!');
240
            setTimeout(function () {
241
                closeToolbar();
242
            }, 2500);
243
        }
244
    }
245
246
    _this.minedLoginSaved = minedLoginSaved;
247
248
    function closeToolbar() {
249
        $j('#password-toolbar').slideUp(400, function () {
250
            $j('#password-toolbar').remove();
251
        });
252
    }
253
254
    function initForms(){
255
        API.runtime.sendMessage(API.runtime.id, {method: 'getRuntimeSettings'}).then(function (result) {
256
            var disablePasswordPicker = result.disablePasswordPicker;
257
            var url = window.location.href;
258
            var loginFields = getLoginFields();
259
            if (loginFields.length > 0) {
260
                for (var i = 0; i < loginFields.length; i++) {
261
                    var form = getFormFromElement(loginFields[i][0]);
262
                    if (!disablePasswordPicker) {
263
                        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...
264
                    }
265
                    //Password miner
266
                    /* jshint ignore:start */
267
                    if(!result.hasOwnProperty('ignored_sites') || result.ignored_sites.findUrl(url) !== -1 ) {
268
                        $j(form).submit((function (loginFields) {
269
                            return function () {
270
                                formSubmitted(loginFields);
271
                            };
272
                        })(loginFields[i]));
273
                    }
274
                    /* jshint ignore:end */
275
                }
276
277
                API.runtime.sendMessage(API.runtime.id, {
278
                    method: "getCredentialsByUrl",
279
                    args: url
280
                }).then(function (logins) {
281
                    console.log('Found ' + logins.length + ' logins for this site');
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...
282
                    if (logins.length === 1) {
283
                        API.runtime.sendMessage(API.runtime.id, {method: 'isAutoFillEnabled'}).then(function (isEnabled) {
284
                            if (isEnabled) {
285
                                enterLoginDetails(logins[0]);
286
                            }
287
                        });
288
                    }
289
290
                });
291
            }
292
293
        });
294
    }
295
296
    function copyText(text) {
297
        console.log('copt')
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...
298
        var txtToCopy = document.createElement('input');
299
        txtToCopy.style.left = '-300px';
300
        txtToCopy.style.position = 'absolute';
301
        txtToCopy.value = text;
302
        document.body.appendChild(txtToCopy);
303
        txtToCopy.select();
304
        document.execCommand('copy');
305
        txtToCopy.parentNode.removeChild(txtToCopy);
306
    }
307
    _this.copyText = copyText;
308
309
    function init() {
310
        checkForMined();
311
        initForms();
312
    }
313
314
    var readyStateCheckInterval = setInterval(function () {
315
        if (document.readyState === "complete") {
316
            clearInterval(readyStateCheckInterval);
317
            API.runtime.sendMessage(API.runtime.id, {method: 'getMasterPasswordSet'}).then(function (result) {
318
                if (result) {
319
                    init();
320
                    // var body = document.getElementsByTagName('body')[0];
321
                    // observeDOM(body, function () {
322
                    //     initForms();
323
                    // });
324
                } else {
325
                    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...
326
                }
327
            });
328
        }
329
    }, 10);
330
331
    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...
332
        //console.log('Method call', msg.method);
333
        if (_this[msg.method]) {
334
            _this[msg.method](msg.args, sender);
335
        }
336
    });
337
});