Completed
Push — master ( 1f2a02...d2ed98 )
by Sander
01:05
created

background.js ➔ ... ➔ PAPI.getVault   C

Complexity

Conditions 7
Paths 7

Size

Total Lines 28

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 7
c 1
b 0
f 0
nc 7
nop 1
dl 0
loc 28
rs 6.7272
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 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...
122
        for (var i = 0; i < encryptedFieldSettings.length; i++) {
123
            var field = encryptedFieldSettings[i];
124
            settings[field] = PAPI.encryptString(JSON.stringify(settings[field]), master_password);
125
        }
126
        PAPI.host = settings.nextcloud_host;
127
        PAPI.username = settings.nextcloud_username;
128
        PAPI.password = settings.nextcloud_password;
129
        //window.settings contains the run-time settings
130
        _self.settings = settings;
131
132
133
        storage.set('settings', settings).then(function () {
134
            getSettings();
135
        });
136
137
    }
138
139
    _self.saveSettings = saveSettings;
140
141
142
    function getCredentials() {
143
        //console.log('Loading vault with the following settings: ', settings);
144
        var tmpList = [];
145
        PAPI.getVault(_self.settings.default_vault.guid, function (vault) {
146
            if(vault.hasOwnProperty('error')){
147
                return;
148
            }
149
            var _credentials = vault.credentials;
150
            for (var i = 0; i < _credentials.length; i++) {
151
                var key = _self.settings.vault_password;
152
                var credential = _credentials[i];
153
                if (credential.hidden === 1) {
154
                    continue;
155
                }
156
                var usedKey = key;
157
                //Shared credentials are not implemented yet
158
                if (credential.hasOwnProperty('shared_key') && credential.shared_key) {
159
                    usedKey = PAPI.decryptString(credential.shared_key, key);
160
161
                }
162
                credential = PAPI.decryptCredential(credential, usedKey);
163
                if(credential.delete_time === 0){
164
                    tmpList.push(credential);
165
                }
166
167
            }
168
            delete vault.credentials;
169
            local_vault = vault;
170
            local_credentials = tmpList;
171
            updateTabsIcon();
172
        });
173
    }
174
175
    _self.getCredentials = getCredentials;
176
177
    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...
178
        if (!master_password) {
179
            return [];
180
        }
181
        if(!_url || _url === '' ){
182
            return [];
183
        }
184
        var url = processURL(_url, _self.settings.ignoreProtocol, _self.settings.ignoreSubdomain, _self.settings.ignorePath, _self.settings.ignorePort);
185
        var found_list = [];
186
        for (var i = 0; i < local_credentials.length; i++) {
187
            if (local_credentials[i].url && local_credentials[i].username && local_credentials[i].password) {
188
                if (local_credentials[i].url.indexOf(url) !== -1) {
189
                    found_list.push(local_credentials[i]);
190
                }
191
            }
192
        }
193
        return found_list;
194
    }
195
196
    _self.getCredentialsByUrl = getCredentialsByUrl;
197
198
199
    function getCredentialForHTTPAuth(req){
200
        return getCredentialsByUrl(req.url)[0];
201
    }
202
203
    _window.getCredentialForHTTPAuth = getCredentialForHTTPAuth;
204
205
    var mined_data = [];
206
207
    function minedForm(data, sender) {
208
        var url = sender.url;
209
        var existingLogins = getCredentialsByUrl(sender.url);
210
        var title = "Detected new login:";
211
        var minedMatchingID = null;
212
        for (var j = 0; j < existingLogins.length; j++) {
213
            var login = existingLogins[j];
214
            if (login.username === data.username) {
215
                if (login.password !== data.password) {
216
                    minedMatchingID = login.guid;
217
                    title = "Detected changed password for user:";
218
                }
219
                else {
220
                    //console.log('No changes detected');
221
                    delete mined_data[sender.tab.id];
222
                    return;
223
                }
224
            }
225
        }
226
        mined_data[sender.tab.id] = {
227
            title: title,
228
            url: url,
229
            username: data.username,
230
            password: data.password,
231
            label: sender.title,
232
            guid: minedMatchingID
233
        };
234
235
        //console.log('Done mining, ', mined_data, sender.tab.id);
236
    }
237
238
    _self.minedForm = minedForm;
239
240
    function getMinedData(args, sender) {
241
        //console.log('Fecthing  mined data for tab id', sender.tab.id)
242
        return mined_data[sender.tab.id];
243
    }
244
245
    _self.getMinedData = getMinedData;
246
247
    function clearMined(args, sender) {
248
        delete mined_data[sender.tab.id];
249
    }
250
251
    _self.clearMined = clearMined;
252
253
    function saveMinedCallback(args) {
254
        createIconForTab(args.sender.tab);
255
        API.tabs.query({active: true, currentWindow: true}).then(function (tabs) {
256
            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...
257
            });
258
        });
259
    }
260
261
    function passToParent(args,sender) {
262
        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...
263
        });
264
    }
265
    self.passToParent = passToParent;
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...
266
267
    function saveMined(args, sender) {
268
        var data = mined_data[sender.tab.id];
269
        var credential,
270
            credential_index;
271
272
        if (data.guid === null) {
273
            credential = PAPI.newCredential();
274
        } else {
275
            for (var i = 0; i < local_credentials.length; i++) {
276
                if (local_credentials[i].guid === data.guid) {
277
                    credential = local_credentials[i];
278
                    credential_index = i;
279
                    return;
280
                }
281
            }
282
        }
283
        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...
284
        credential.password = data.password;
285
        credential.url = sender.tab.url;
286
        if (credential.guid !== null) {
287
            PAPI.updateCredential(credential, _self.settings.vault_password, function (updatedCredential) {
288
                local_credentials[credential_index] = updatedCredential;
289
                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...
290
                delete mined_data[sender.tab.id];
291
            });
292
        } else {
293
            credential.label = sender.tab.title;
294
            credential.vault_id = local_vault.vault_id;
295
            PAPI.createCredential(credential, _self.settings.vault_password, function (createdCredential) {
296
                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...
297
                local_credentials.push(createdCredential);
298
                delete mined_data[sender.tab.id];
299
            });
300
        }
301
    }
302
303
    _self.saveMined = saveMined;
304
305
306
    function injectCreateCredential(args, sender) {
307
        var credential = PAPI.newCredential();
308
        credential.label = args.label;
309
        credential.username = args.username;
310
        credential.password = args.username;
311
        credential.vault_id = local_vault.vault_id;
312
        credential.url = sender.tab.url;
313
        PAPI.createCredential(credential, _self.settings.vault_password, function (createdCredential) {
314
            saveMinedCallback({credential: credential, updated: false, sender: sender, selfAdded: true});
315
            local_credentials.push(createdCredential);
316
317
        });
318
    }
319
    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...
320
321
    function isVaultKeySet() {
322
        return (_self.settings.vault_password !== null);
323
    }
324
325
    _self.isVaultKeySet = isVaultKeySet;
326
327
    function isAutoFillEnabled() {
328
        if(!_self.settings.hasOwnProperty('disableAutoFill')){
329
            return true;
330
        }
331
        return (_self.settings.disableAutoFill === false);
332
    }
333
334
    _self.isAutoFillEnabled = isAutoFillEnabled;
335
336
    API.runtime.onMessage.addListener(function (msg, sender, sendResponse) {
337
        console.log('Method call', msg.method, 'args: ', msg.args);
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...
338
339
        if (!msg || !msg.hasOwnProperty('method')) {
340
            return;
341
        }
342
        var result = false;
343
        if(_self[msg.method]) {
344
            result = _self[msg.method](msg.args, sender);
345
        } else {
346
            console.log('[NOT FOUND] Method call', msg.method, 'args: ', msg.args);
347
        }
348
349
        sendResponse(result);
350
    });
351
352
    var defaultColor = '#0082c9';
353
    function createIconForTab(tab) {
354
        if (!master_password) {
355
            return;
356
        }
357
        var tabUrl = tab.url;
358
        var logins = getCredentialsByUrl(tabUrl);
359
        if(tab.active) {
360
            window.contextMenu.setContextItems(logins);
361
        }
362
        var credentialAmount = logins.length;
363
            API.browserAction.setBadgeText({
364
            text: credentialAmount.toString(),
365
            tabId: tab.id
366
        });
367
        API.browserAction.setBadgeBackgroundColor({
368
            color: defaultColor,
369
            tabId: tab.id
370
        });
371
        var plural = (credentialAmount === 1) ? 'credential' : 'credentials';
372
        API.browserAction.setTitle({
373
            title: 'Passman - ' + credentialAmount.toString() + ' '+ plural +' found for this page',
374
            tabId: tab.id
375
        });
376
    }
377
378
    function displayLogoutIcons() {
379
        if(_self.settings) {
380
            API.tabs.query({}).then(function (tabs) {
381
                for (var t = 0; t < tabs.length; t++) {
382
                    var tab = tabs[t];
383
                    API.browserAction.setBadgeText({
384
                        text: '🔑',
385
                        tabId: tab.id
386
                    });
387
                    API.browserAction.setBadgeBackgroundColor({
388
                        color: '#ff0000',
389
                        tabId: tab.id
390
                    });
391
                    API.browserAction.setTitle({
392
                        title: 'Passman - Locked',
393
                        tabId: tab.id
394
                    });
395
                }
396
            });
397
        }
398
    }
399
400
    function updateTabsIcon() {
401
        API.tabs.query({}).then(function (tabs) {
402
            for (var t = 0; t < tabs.length; t++) {
403
                var tab = tabs[t];
404
                createIconForTab(tab);
405
            }
406
        });
407
    }
408
409
410
    API.tabs.onUpdated.addListener(function (tabId, changeInfo, tab) {
411
        if(master_password){
412
            createIconForTab(tab);
413
        } else {
414
            displayLogoutIcons();
415
        }
416
    });
417
418
    API.tabs.onActivated.addListener(function () {
419
        API.tabs.query({active: true, currentWindow: true}).then(function (tabs) {
420
            if(master_password){
421
                createIconForTab(tabs[0]);
422
            } else {
423
                displayLogoutIcons();
424
            }
425
        });
426
    });
427
428
    displayLogoutIcons();
429
430
    storage.get('master_password').then(function (password) {
431
        if (password) {
432
            master_password = password;
433
            API.api.browserAction.setBadgeBackgroundColor({
434
                color: defaultColor
435
            });
436
        }
437
        getSettings();
438
    }).error(function (error) {
439
        if (error === "Data not found") {
440
            getSettings();
441
        }
442
    });
443
    return _window;
444
}());
445
446