Completed
Push — master ( 8aeb93...3da151 )
by Sander
10s
created

background.js ➔ getSetting   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 1
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
/* global API */
2
3
var background = (function () {
4
    var storage = new API.Storage();
5
    var _self = this;
6
    var _window = {};
7
    API.runtime.onConnect.addListener(function (port) {
8
9
        port.onMessage.addListener(function (msg) {
10
            if (msg === 'credential_amount') {
11
                port.postMessage('credential_amount:' + local_credentials.length);
12
            }
13
14
        });
15
16
    });
17
18
    var master_password = null;
19
20
    function getMasterPasswordSet() {
21
        return (master_password !== null);
22
    }
23
24
    _self.getMasterPasswordSet = getMasterPasswordSet;
25
26
    function setMasterPassword(opts) {
27
        master_password = opts.password;
28
        if (opts.hasOwnProperty('savePassword') && opts.savePassword === true) {
29
            // Save the password in plain text on user request.
30
            // No secure local storage is available :/
31
            storage.set('master_password', opts.password);
32
        } else {
33
            storage.set('master_password', null);
34
        }
35
36
        if (opts.password) {
37
            getSettings();
38
        } else {
39
            displayLogoutIcons();
40
        }
41
42
    }
43
44
    _self.setMasterPassword = setMasterPassword;
45
46
47
    var testMasterPasswordAgainst;
48
49
    function isMasterPasswordValid(password) {
50
        //return true;
51
        try {
52
            PAPI.decryptString(testMasterPasswordAgainst, password);
53
            return true;
54
        } catch (e) {
55
            return false;
56
        }
57
    }
58
59
    _self.isMasterPasswordValid = isMasterPasswordValid;
60
61
62
    var local_credentials = [];
63
    var local_vault = [];
64
    var encryptedFieldSettings = ['default_vault', 'nextcloud_host', 'nextcloud_username', 'nextcloud_password', 'vault_password'];
65
    _self.settings = {};
66
    _self.ticker = null;
67
    _self.running = false;
68
    function getSettings() {
69
70
        storage.get('settings').then(function (_settings) {
71
72
            if (!_settings || !_settings.hasOwnProperty('nextcloud_host')) {
73
                return;
74
            }
75
76
            if (!master_password && _settings.hasOwnProperty('nextcloud_username') && _settings.hasOwnProperty('vault_password')) {
77
                _self.settings.isInstalled = 1;
78
                testMasterPasswordAgainst = _settings.nextcloud_username;
79
                return;
80
            }
81
82
            for (var i = 0; i < encryptedFieldSettings.length; i++) {
83
                var field = encryptedFieldSettings[i];
84
                _settings[field] = JSON.parse(PAPI.decryptString(_settings[field], master_password));
85
            }
86
87
88
            _self.settings = _settings;
89
90
91
            PAPI.host = _settings.nextcloud_host;
92
            PAPI.username = _settings.nextcloud_username;
93
            PAPI.password = _settings.nextcloud_password;
94
            if (!_settings.vault_password) {
95
                return;
96
            }
97
            if (PAPI.credentialsSet()) {
98
                getCredentials();
99
                if (_self.running) {
100
                    clearInterval(_self.ticker);
101
                }
102
103
                _self.running = true;
104
                _self.ticker = setInterval(function () {
105
                    getCredentials();
106
                }, _self.settings.refreshTime * 1000);
107
            } else {
108
                console.log('Login details are missing!');
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...
109
            }
110
        });
111
    }
112
113
    _self.getSettings = getSettings;
114
115
    function getRuntimeSettings() {
116
        return _self.settings;
117
    }
118
119
    _self.getRuntimeSettings = getRuntimeSettings;
120
121
    function getSetting(name) {
122
        return _self.settings[name];
123
    }
124
    _self.getSetting = getSetting;
125
126
    function saveSettings(settings, cb) {
0 ignored issues
show
Unused Code introduced by
The parameter cb 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...
127
        for (var i = 0; i < encryptedFieldSettings.length; i++) {
128
            var field = encryptedFieldSettings[i];
129
            settings[field] = PAPI.encryptString(JSON.stringify(settings[field]), master_password);
130
        }
131
        PAPI.host = settings.nextcloud_host;
132
        PAPI.username = settings.nextcloud_username;
133
        PAPI.password = settings.nextcloud_password;
134
        //window.settings contains the run-time settings
135
        _self.settings = settings;
136
137
138
        storage.set('settings', settings).then(function () {
139
            getSettings();
140
        });
141
142
    }
143
144
    _self.saveSettings = saveSettings;
145
146
147
    function getCredentials() {
148
        //console.log('Loading vault with the following settings: ', settings);
149
        var tmpList = [];
150
        PAPI.getVault(_self.settings.default_vault.guid, function (vault) {
151
            if (vault.hasOwnProperty('error')) {
152
                return;
153
            }
154
            var _credentials = vault.credentials;
155
            for (var i = 0; i < _credentials.length; i++) {
156
                var key = _self.settings.vault_password;
157
                var credential = _credentials[i];
158
                if (credential.hidden === 1) {
159
                    continue;
160
                }
161
                var usedKey = key;
162
                //Shared credentials are not implemented yet
163
                if (credential.hasOwnProperty('shared_key') && credential.shared_key) {
164
                    usedKey = PAPI.decryptString(credential.shared_key, key);
165
166
                }
167
                credential = PAPI.decryptCredential(credential, usedKey);
168
                if (credential.delete_time === 0) {
169
                    tmpList.push(credential);
170
                }
171
172
            }
173
            delete vault.credentials;
174
            local_vault = vault;
175
            local_credentials = tmpList;
176
            updateTabsIcon();
177
        });
178
    }
179
180
    _self.getCredentials = getCredentials;
181
182
    function getCredentialsByUrl(_url, sender) {
0 ignored issues
show
Unused Code introduced by
The parameter sender 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...
183
        if (!master_password) {
184
            return [];
185
        }
186
        if (!_url || _url === '') {
187
            return [];
188
        }
189
        var url = processURL(_url, _self.settings.ignoreProtocol, _self.settings.ignoreSubdomain, _self.settings.ignorePath, _self.settings.ignorePort);
190
        var found_list = [];
191
        for (var i = 0; i < local_credentials.length; i++) {
192
            if (local_credentials[i].url && local_credentials[i].username && local_credentials[i].password) {
193
                if (local_credentials[i].url.indexOf(url) !== -1) {
194
                    found_list.push(local_credentials[i]);
195
                }
196
            }
197
        }
198
        return found_list;
199
    }
200
201
    _self.getCredentialsByUrl = getCredentialsByUrl;
202
203
204
    function getCredentialForHTTPAuth(req) {
205
        return getCredentialsByUrl(req.url)[0];
206
    }
207
208
    _window.getCredentialForHTTPAuth = getCredentialForHTTPAuth;
209
210
    var mined_data = [];
211
212
    function minedForm(data, sender) {
213
        var url = sender.url;
214
        var existingLogins = getCredentialsByUrl(sender.url);
215
        var title = "Detected new login:";
216
        var minedMatchingID = null;
217
        for (var j = 0; j < existingLogins.length; j++) {
218
            var login = existingLogins[j];
219
            if (login.username === data.username) {
220
                if (login.password !== data.password) {
221
                    minedMatchingID = login.guid;
222
                    title = "Detected changed password for user:";
223
                }
224
                else {
225
                    //console.log('No changes detected');
226
                    delete mined_data[sender.tab.id];
227
                    return;
228
                }
229
            }
230
        }
231
        mined_data[sender.tab.id] = {
232
            title: title,
233
            url: url,
234
            username: data.username,
235
            password: data.password,
236
            label: sender.title,
237
            guid: minedMatchingID
238
        };
239
240
        //console.log('Done mining, ', mined_data, sender.tab.id);
241
    }
242
243
    _self.minedForm = minedForm;
244
245
    function getMinedData(args, sender) {
246
        //console.log('Fecthing  mined data for tab id', sender.tab.id)
247
        return mined_data[sender.tab.id];
248
    }
249
250
    _self.getMinedData = getMinedData;
251
252
    function clearMined(args, sender) {
253
        delete mined_data[sender.tab.id];
254
    }
255
256
    _self.clearMined = clearMined;
257
258
    function saveMinedCallback(args) {
259
        createIconForTab(args.sender.tab);
260
        API.tabs.query({active: true, currentWindow: true}).then(function (tabs) {
261
            API.tabs.sendMessage(args.sender.tab.id, {method: "minedLoginSaved", args: args}).then(function (response) {
0 ignored issues
show
Unused Code introduced by
The parameter response 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...
262
            });
263
        });
264
    }
265
266
    function passToParent(args, sender) {
267
        API.tabs.sendMessage(sender.tab.id, {method: args.injectMethod, args: args.args}).then(function (response) {
0 ignored issues
show
Unused Code introduced by
The parameter response 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...
268
        });
269
    }
270
271
    _self.passToParent = passToParent;
272
273
    function getActiveTab(opt) {
274
        API.tabs.query({active: true, currentWindow: true}).then(function (tabs) {
275
            var tab = tabs[0];
276
            API.tabs.sendMessage(tab.id, {method: opt.returnFn, args: tab}).then(function (response) {
0 ignored issues
show
Unused Code introduced by
The parameter response 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...
277
            });
278
        });
279
    }
280
281
    _self.getActiveTab = getActiveTab;
282
283
    function updateCredentialUrlDoorhanger(login) {
284
        API.tabs.query({active: true, currentWindow: true}).then(function (tabs) {
285
            var tab = tabs[0];
286
            var data = login;
287
            data.url = tab.url;
288
            data.title = 'Detected changed url for: ';
289
            API.tabs.sendMessage(tab.id, {
290
                method: 'showUrlUpdateDoorhanger',
291
                args: {data: data}
292
            });
293
        });
294
    }
295
296
    _self.updateCredentialUrlDoorhanger = updateCredentialUrlDoorhanger;
297
298
    function updateCredentialUrl(data, sender) {
299
        mined_data[sender.tab.id] = data;
300
        saveMined({}, sender);
301
302
    }
303
    _self.updateCredentialUrl = updateCredentialUrl;
304
305
    function saveMined(args, sender) {
306
        var data = mined_data[sender.tab.id];
307
        var credential,
308
            credential_index;
309
310
        if (data.guid === null) {
311
            credential = PAPI.newCredential();
312
        } else {
313
            for (var i = 0; i < local_credentials.length; i++) {
314
                if (local_credentials[i].guid === data.guid) {
315
                    credential = local_credentials[i];
316
                    credential_index = i;
317
                    break;
318
                }
319
            }
320
        }
321
        credential.username = data.username;
0 ignored issues
show
Bug introduced by
The variable credential seems to not be initialized for all possible execution paths.
Loading history...
322
        credential.password = data.password;
323
        credential.url = sender.tab.url;
324
        if (credential.guid !== null) {
325
            PAPI.updateCredential(credential, _self.settings.vault_password, function (updatedCredential) {
326
                if(credential_index){
327
                    local_credentials[credential_index] = updatedCredential;
328
                }
329
                saveMinedCallback({credential: credential, updated: true, sender: sender});
0 ignored issues
show
Bug introduced by
The variable credential seems to not be initialized for all possible execution paths.
Loading history...
330
                delete mined_data[sender.tab.id];
331
            });
332
        } else {
333
            credential.label = sender.tab.title;
334
            credential.vault_id = local_vault.vault_id;
335
            PAPI.createCredential(credential, _self.settings.vault_password, function (createdCredential) {
336
                saveMinedCallback({credential: credential, updated: false, sender: sender});
0 ignored issues
show
Bug introduced by
The variable credential seems to not be initialized for all possible execution paths.
Loading history...
337
                local_credentials.push(createdCredential);
338
                delete mined_data[sender.tab.id];
339
            });
340
        }
341
    }
342
343
    _self.saveMined = saveMined;
344
345
    function searchCredential(searchText) {
346
        var searchFields = ['label', 'username', 'email', 'url', 'description'];
347
        var results = [];
348
        for (var i = 0; i < local_credentials.length; i++) {
349
            var credential = local_credentials[i];
350
            for (var f = 0; f < searchFields.length; f++) {
351
                var field = searchFields[f];
352
                if (credential[field] && credential[field].indexOf(searchText) !== -1) {
353
                    results.push(credential);
354
                    break;
355
                }
356
            }
357
        }
358
        return results;
359
    }
360
361
    _self.searchCredential = searchCredential;
362
363
364
    function injectCreateCredential(args, sender) {
365
        var credential = PAPI.newCredential();
366
        credential.label = args.label;
367
        credential.username = args.username;
368
        credential.password = args.username;
369
        credential.vault_id = local_vault.vault_id;
370
        credential.url = sender.tab.url;
371
        PAPI.createCredential(credential, _self.settings.vault_password, function (createdCredential) {
372
            saveMinedCallback({credential: credential, updated: false, sender: sender, selfAdded: true});
373
            local_credentials.push(createdCredential);
374
375
        });
376
    }
377
378
    self.injectCreateCredential = injectCreateCredential;
0 ignored issues
show
Bug introduced by
The variable self seems to be never declared. If this is a global, consider adding a /** global: self */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
379
380
    function isVaultKeySet() {
381
        return (_self.settings.vault_password !== null);
382
    }
383
384
    _self.isVaultKeySet = isVaultKeySet;
385
386
    function isAutoFillEnabled() {
387
        if (!_self.settings.hasOwnProperty('disableAutoFill')) {
388
            return true;
389
        }
390
        return (_self.settings.disableAutoFill === false);
391
    }
392
393
    _self.isAutoFillEnabled = isAutoFillEnabled;
394
395
    API.runtime.onMessage.addListener(function (msg, sender, sendResponse) {
396
397
        if (!msg || !msg.hasOwnProperty('method')) {
398
            return;
399
        }
400
        var result = false;
401
        if (_self[msg.method]) {
402
            result = _self[msg.method](msg.args, sender);
403
        } else {
404
            console.warn('[NOT FOUND] Method call', msg.method, 'args: ', msg.args);
405
        }
406
407
        sendResponse(result);
408
    });
409
410
    var defaultColor = '#0082c9';
411
412
    function createIconForTab(tab) {
413
        if (!master_password) {
414
            return;
415
        }
416
        var tabUrl = tab.url;
417
        var logins = getCredentialsByUrl(tabUrl);
418
        if (tab.active) {
419
            window.contextMenu.setContextItems(logins);
420
        }
421
        var credentialAmount = logins.length;
422
        API.browserAction.setBadgeText({
423
            text: credentialAmount.toString(),
424
            tabId: tab.id
425
        });
426
        API.browserAction.setBadgeBackgroundColor({
427
            color: defaultColor,
428
            tabId: tab.id
429
        });
430
        var plural = (credentialAmount === 1) ? 'credential' : 'credentials';
431
        API.browserAction.setTitle({
432
            title: 'Passman - ' + credentialAmount.toString() + ' ' + plural + ' found for this page',
433
            tabId: tab.id
434
        });
435
    }
436
437
    function displayLogoutIcons() {
438
        if (_self.settings) {
439
            API.tabs.query({}).then(function (tabs) {
440
                for (var t = 0; t < tabs.length; t++) {
441
                    var tab = tabs[t];
442
                    API.browserAction.setBadgeText({
443
                        text: '🔑',
444
                        tabId: tab.id
445
                    });
446
                    API.browserAction.setBadgeBackgroundColor({
447
                        color: '#ff0000',
448
                        tabId: tab.id
449
                    });
450
                    API.browserAction.setTitle({
451
                        title: 'Passman - Locked',
452
                        tabId: tab.id
453
                    });
454
                }
455
            });
456
        }
457
    }
458
459
    function updateTabsIcon() {
460
        API.tabs.query({}).then(function (tabs) {
461
            for (var t = 0; t < tabs.length; t++) {
462
                var tab = tabs[t];
463
                createIconForTab(tab);
464
            }
465
        });
466
    }
467
468
469
    API.tabs.onUpdated.addListener(function (tabId, changeInfo, tab) {
470
        if (master_password) {
471
            createIconForTab(tab);
472
        } else {
473
            displayLogoutIcons();
474
        }
475
    });
476
477
    API.tabs.onActivated.addListener(function () {
478
        API.tabs.query({active: true, currentWindow: true}).then(function (tabs) {
479
            if (master_password) {
480
                createIconForTab(tabs[0]);
481
            } else {
482
                displayLogoutIcons();
483
            }
484
        });
485
    });
486
487
    displayLogoutIcons();
488
489
    storage.get('master_password').then(function (password) {
490
        if (password) {
491
            master_password = password;
492
            API.api.browserAction.setBadgeBackgroundColor({
493
                color: defaultColor
494
            });
495
        }
496
        getSettings();
497
    }).error(function (error) {
498
        if (error === "Data not found") {
499
            getSettings();
500
        }
501
    });
502
    return _window;
503
}());
504
505