Completed
Push — master ( 46b4dd...c0e2c5 )
by Sander
52s
created

API.runtime.onInstalled.addListener   A

Complexity

Conditions 2
Paths 1

Size

Total Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
c 0
b 0
f 0
nc 1
nop 0
dl 0
loc 5
rs 9.4285
1
/* global API */
2
3
var background = (function () {
4
    var storage = new API.Storage();
5
    var _self = this;
6
    var _window = {};
7
8
9
    API.runtime.onConnect.addListener(function (port) {
10
11
        port.onMessage.addListener(function (msg) {
12
            if (msg === 'credential_amount') {
13
                port.postMessage('credential_amount:' + local_credentials.length);
14
            }
15
16
        });
17
18
    });
19
20
    API.runtime.onInstalled.addListener(function () {
21
        storage.get('settings').error(function () {
22
            var prot = (typeof browser !== 'undefined') ? 'moz-extension' : 'chrome-extension';
0 ignored issues
show
Bug introduced by brantje
The variable browser seems to be never declared. If this is a global, consider adding a /** global: browser */ 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...
23
            var url = prot + '://' + API.runtime.id + '/html/browser_action/browser_action.html';
24
            API.tabs.create({url: url});
25
        });
26
    });
27
28
    var master_password = null;
29
30
    function getMasterPasswordSet() {
31
        return (master_password !== null);
32
    }
33
34
    _self.getMasterPasswordSet = getMasterPasswordSet;
35
36
    function setMasterPassword(opts) {
37
        master_password = opts.password;
38
        if (opts.hasOwnProperty('savePassword') && opts.savePassword === true) {
39
            // Save the password in plain text on user request.
40
            // No secure local storage is available :/
41
            storage.set('master_password', opts.password);
42
        } else {
43
            storage.set('master_password', null);
44
        }
45
46
        if (opts.password) {
47
            getSettings();
48
        } else {
49
            displayLogoutIcons();
50
        }
51
52
    }
53
54
    _self.setMasterPassword = setMasterPassword;
55
56
57
    var testMasterPasswordAgainst;
58
59
    function isMasterPasswordValid(password) {
60
        try {
61
            PAPI.decryptString(testMasterPasswordAgainst, password);
62
            return true;
63
        } catch (e) {
64
            return false;
65
        }
66
    }
67
68
    _self.isMasterPasswordValid = isMasterPasswordValid;
69
70
71
    var local_credentials = [];
72
    var local_vault = [];
0 ignored issues
show
Unused Code introduced by brantje
The variable local_vault seems to be never used. Consider removing it.
Loading history...
73
    var encryptedFieldSettings = ['accounts'];
74
    _self.settings = {};
75
    _self.ticker = null;
76
    _self.running = false;
77
    function getSettings() {
78
79
        storage.get('settings').then(function (_settings) {
80
            if ((!_settings || Object.keys(_settings).length === 0 || !_settings.hasOwnProperty('accounts')) && !master_password) {
81
                return;
82
            }
83
            if (!master_password && _settings.hasOwnProperty('accounts') && _settings.accounts.length > 0) {
84
                _self.settings.isInstalled = 1;
85
                testMasterPasswordAgainst = _settings.accounts;
86
                return;
87
            }
88
89
            for (var i = 0; i < encryptedFieldSettings.length; i++) {
90
                var field = encryptedFieldSettings[i];
91
                _settings[field] = JSON.parse(PAPI.decryptString(_settings[field], master_password));
92
            }
93
94
            _self.settings = _settings;
95
96
            if (!_self.settings.hasOwnProperty('ignored_sites')) {
97
                _self.settings.ignored_sites = [];
98
            }
99
100
            if (!_self.settings.hasOwnProperty('no_results_found_tab')) {
101
                _self.settings.no_results_found_tab = 'list';
102
            }
103
104
            if (!_self.settings.hasOwnProperty('enablePasswordPicker')) {
105
                _self.settings.enablePasswordPicker = !_self.settings.disablePasswordPicker;
106
            }
107
108
            if (!_self.settings.hasOwnProperty('enableAutoFill')) {
109
                _self.settings.enableAutoFill = !_self.settings.disableAutoFill;
110
            }
111
112
            if (!_self.settings.hasOwnProperty('enableUpdateUrl')) {
113
                _self.settings.enableUpdateUrl = true;
114
            }
115
            if (!_self.settings.hasOwnProperty('passwordPickerGotoList')) {
116
                _self.settings.passwordPickerGotoList = false;
117
            }
118
119
            getCredentials();
120
121
            if (_self.running) {
122
                clearInterval(_self.ticker);
123
            }
124
            _self.running = true;
125
            _self.ticker = setInterval(function () {
126
127
            }, _self.settings.refreshTime * 1000);
128
129
        });
130
    }
131
132
    _self.getSettings = getSettings;
133
134
    function getRuntimeSettings() {
135
        return _self.settings;
136
    }
137
138
    _self.getRuntimeSettings = getRuntimeSettings;
139
140
    function getSetting(name) {
141
        return _self.settings[name];
142
    }
143
144
    _self.getSetting = getSetting;
145
146
    function saveSettings(settings, cb) {
0 ignored issues
show
Unused Code introduced by brantje
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...
147
        for (var i = 0; i < encryptedFieldSettings.length; i++) {
148
            var field = encryptedFieldSettings[i];
149
            settings[field] = PAPI.encryptString(JSON.stringify(settings[field]), master_password);
150
        }
151
152
        if (!settings.hasOwnProperty('ignored_sites')) {
153
            settings.ignored_sites = [];
154
        }
155
156
        if (!_self.settings.hasOwnProperty('password_picker_first_tab')) {
157
            _self.settings.disable_browser_autofill = 'list';
158
        }
159
160
        //window.settings contains the run-time settings
161
        _self.settings = settings;
162
163
164
        storage.set('settings', settings).then(function () {
165
            getSettings();
166
        });
167
168
    }
169
170
    _self.saveSettings = saveSettings;
171
172
    function resetSettings() {
173
        storage.set('settings', {});
174
        _self.settings = {};
175
    }
176
177
    _self.resetSettings = resetSettings;
178
179
180
    function getCredentials() {
181
        if (!master_password) {
182
            return;
183
        }
184
        //console.log('Loading vault with the following settings: ', settings);
185
        var tmpList = [];
186
187
        for (var i = 0; i < _self.settings.accounts.length; i++) {
188
            var account = _self.settings.accounts[i];
189
            /* jshint ignore:start */
190
            (function (inner_account) {
191
                PAPI.getVault(inner_account, function (vault) {
192
                    if (vault.hasOwnProperty('error')) {
193
                        return;
194
                    }
195
                    var _credentials = vault.credentials;
196
                    for (var i = 0; i < _credentials.length; i++) {
197
                        var key = inner_account.vault_password;
198
                        var credential = _credentials[i];
199
                        if (credential.hidden === 1) {
200
                            continue;
201
                        }
202
                        var usedKey = key;
203
                        //Shared credentials are not implemented yet
204
                        if (credential.hasOwnProperty('shared_key') && credential.shared_key) {
205
                            usedKey = PAPI.decryptString(credential.shared_key, key);
206
207
                        }
208
                        credential = PAPI.decryptCredential(credential, usedKey);
209
                        credential.account = inner_account;
210
                        if (credential.delete_time === 0) {
211
                            tmpList.push(credential);
212
                        }
213
214
                    }
215
                    delete vault.credentials;
216
                    local_vault = vault;
0 ignored issues
show
Unused Code introduced by brantje
The variable local_vault seems to be never used. Consider removing it.
Loading history...
217
                    local_credentials = tmpList;
218
219
                    getSharedCredentials(inner_account);
220
221
222
                });
223
            }(account));
224
            /* jshint ignore:end */
225
        }
226
    }
227
228
    _self.getCredentials = getCredentials;
229
230
    function getSharedCredentials(account) {
231
        PAPI.getCredendialsSharedWithUs(account, account.vault.guid, function (credentials) {
232
            for (var i = 0; i < credentials.length; i++) {
233
                var _shared_credential = credentials[i];
234
                var _shared_credential_data;
235
                var sharedKey = PAPI.decryptString(_shared_credential.shared_key, account.vault_password);
236
                try {
237
                    _shared_credential_data = PAPI.decryptSharedCredential(_shared_credential.credential_data, sharedKey);
238
                } catch (e) {
0 ignored issues
show
Coding Style Comprehensibility Best Practice introduced by brantje
Empty catch clauses should be used with caution; consider adding a comment why this is needed.
Loading history...
239
240
                }
241
                if (_shared_credential_data) {
242
                    delete _shared_credential.credential_data;
243
                    _shared_credential_data.acl = _shared_credential;
244
                    _shared_credential_data.acl.permissions = new SharingACL(_shared_credential_data.acl.permissions);
0 ignored issues
show
Bug introduced by brantje
The variable SharingACL seems to be never declared. If this is a global, consider adding a /** global: SharingACL */ 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...
245
                    _shared_credential_data.tags_raw = _shared_credential_data.tags;
246
                    _shared_credential_data.account = account;
247
                    local_credentials.push(_shared_credential_data);
248
                }
249
            }
250
            updateTabsIcon();
251
        });
252
    }
253
254
    function getCredentialsByUrl(_url, sender) {
0 ignored issues
show
Unused Code introduced by brantje
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...
255
        if (!master_password) {
256
            return [];
257
        }
258
        if (!_url || _url === '') {
259
            return [];
260
        }
261
        if (Array.isArray(_url)) {
262
            _url = _url.pop();
263
        }
264
265
        var p = document.createElement('a');
266
        p.href = _url;
267
        if (p.pathname) {
268
            //_url = _url.substring(0, _url.lastIndexOf("/"));
269
        }
270
271
        var url = processURL(_url, _self.settings.ignoreProtocol, _self.settings.ignoreSubdomain, _self.settings.ignorePath, _self.settings.ignorePort);
272
        var found_list = [];
273
        for (var i = 0; i < local_credentials.length; i++) {
274
            var credential_url = local_credentials[i].url;
275
            if (!/^(ht)tps?:\/\//i.test(credential_url) && credential_url !== '' && _url) {
276
                try {
277
                    var protocol = _url.split('://').shift();
278
                    credential_url = protocol + "://" + credential_url;
279
                } catch (e) {
280
                    //ignore
281
                }
282
            }
283
            credential_url = processURL(credential_url, _self.settings.ignoreProtocol, _self.settings.ignoreSubdomain, _self.settings.ignorePath, _self.settings.ignorePort);
284
            if (credential_url) {
285
                if (credential_url.split("\n").indexOf(url) !== -1) {
286
                    found_list.push(local_credentials[i]);
287
                }
288
            }
289
290
        }
291
        return found_list;
292
    }
293
294
    _self.getCredentialsByUrl = getCredentialsByUrl;
295
296
297
    function saveCredential(credential) {
298
        //@TODO save shared password
299
        if (!credential.credential_id) {
300
            PAPI.createCredential(credential.account, credential, credential.account.vault_password, function (createdCredential) {
301
                local_credentials.push(createdCredential);
302
            });
303
        } else {
304
            var credential_index;
305
            for (var i = 0; i < local_credentials.length; i++) {
306
                if (local_credentials[i].guid === credential.guid) {
307
                    credential_index = i;
308
                    break;
309
                }
310
            }
311
312
            if (credential.hasOwnProperty('acl')) {
313
                var permissons = new SharingACL(credential.acl.permissions.permission);
0 ignored issues
show
Bug introduced by brantje
The variable SharingACL seems to be never declared. If this is a global, consider adding a /** global: SharingACL */ 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...
314
                if (!permissons.hasPermission(0x02)) {
315
                    return;
316
                }
317
            }
318
319
            PAPI.updateCredential(credential.account, credential, credential.account.vault_password, function (updatedCredential) {
320
                if (credential_index) {
321
                    local_credentials[credential_index] = updatedCredential;
322
                }
323
            });
324
        }
325
    }
326
327
    _self.saveCredential = saveCredential;
328
329
    function getCredentialByGuid(guid) {
330
        for (var i = 0; i < local_credentials.length; i++) {
331
            var credential = local_credentials[i];
332
            if (credential.guid === guid) {
333
                return credential;
334
            }
335
        }
0 ignored issues
show
Best Practice introduced by brantje
There is no return statement in this branch, but you do return something in other branches. Did you maybe miss it? If you do not want to return anything, consider adding return undefined; explicitly.
Loading history...
336
    }
337
338
    _self.getCredentialByGuid = getCredentialByGuid;
339
340
    function getCredentialForHTTPAuth(req) {
341
        return getCredentialsByUrl(req.url)[0];
342
    }
343
344
    _window.getCredentialForHTTPAuth = getCredentialForHTTPAuth;
345
346
    var mined_data = [];
347
348
    function minedForm(data, sender) {
349
        var url = sender.url;
350
        var existingLogins = getCredentialsByUrl(sender.url);
351
        var title = API.i18n.getMessage('detected_new_login') + ':';
352
        var minedMatchingID = null;
353
        for (var j = 0; j < existingLogins.length; j++) {
354
            var login = existingLogins[j];
355
            if (login.username === data.username) {
356
                if (login.password !== data.password) {
357
                    minedMatchingID = login.guid;
358
                    title = API.i18n.getMessage('detected_changed_login') + ':';
359
                }
360
                else {
361
                    //console.log('No changes detected');
362
                    delete mined_data[sender.tab.id];
363
                    return;
364
                }
365
            }
366
        }
367
        mined_data[sender.tab.id] = {
368
            title: title,
369
            url: url,
370
            username: data.username,
371
            password: data.password,
372
            label: sender.title,
373
            guid: minedMatchingID
374
        };
375
376
        //console.log('Done mining, ', mined_data, sender.tab.id);
377
    }
378
379
    _self.minedForm = minedForm;
380
381
    function getMinedData(args, sender) {
382
        //console.log('Fecthing  mined data for tab id', sender.tab.id)
383
        var senderUrl = sender.tab.url;
384
        var site = processURL(senderUrl, _self.settings.ignoreProtocol, _self.settings.ignoreSubdomain, _self.settings.ignorePath, _self.settings.ignorePort);
385
        if (!_self.settings) {
386
            return null;
387
        }
388
        if (!_self.settings.hasOwnProperty('ignored_sites')) {
389
            return mined_data[sender.tab.id];
390
        }
391
        var matches = _self.settings.ignored_sites.filter(function (item) {
392
            return typeof item === 'string' && site.indexOf(item) > -1;
393
        });
394
395
        if (matches.length !== 0) {
396
            return null;
397
        }
398
        return mined_data[sender.tab.id];
399
    }
400
401
    _self.getMinedData = getMinedData;
402
403
    function clearMined(args, sender) {
404
        delete mined_data[sender.tab.id];
405
    }
406
407
    _self.clearMined = clearMined;
408
409
    function saveMinedCallback(args) {
410
        createIconForTab(args.sender.tab);
411
        API.tabs.query({active: true, currentWindow: true}).then(function (tabs) {
412
            API.tabs.sendMessage(args.sender.tab.id, {method: "minedLoginSaved", args: args}).then(function (response) {
0 ignored issues
show
Unused Code introduced by brantje
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...
413
            });
414
        });
415
    }
416
417
    function ignoreSite(_url) {
418
        if (!_self.settings.hasOwnProperty('ignored_sites')) {
419
            _self.settings.ignored_sites = [];
420
        }
421
        var site = processURL(_url, false, false, true, false);
422
        if (_self.settings.ignored_sites.indexOf(site) === -1) {
423
            _self.settings.ignored_sites.push(site);
424
            saveSettings(_self.settings);
425
        }
426
        clearMined();
427
    }
428
429
    _self.ignoreSite = ignoreSite;
430
431
    function ignoreURL(url) {
432
        if (!_self.settings.hasOwnProperty('ignored_sites')) {
433
            _self.settings.ignored_sites = [];
434
        }
435
        if (_self.settings.ignored_sites.indexOf(url) === -1) {
436
            _self.settings.ignored_sites.push(url);
437
            saveSettings(_self.settings);
438
        }
439
    }
440
441
    _self.ignoreURL = ignoreURL;
442
443
    function passToParent(args, sender) {
444
        API.tabs.sendMessage(sender.tab.id, {method: args.injectMethod, args: args.args}).then(function (response) {
0 ignored issues
show
Unused Code introduced by brantje
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...
445
        });
446
    }
447
448
    _self.passToParent = passToParent;
449
450
    function getActiveTab(opt) {
451
        API.tabs.query({active: true, currentWindow: true}).then(function (tabs) {
452
            var tab = tabs[0];
453
            API.tabs.sendMessage(tab.id, {method: opt.returnFn, args: tab}).then(function (response) {
0 ignored issues
show
Unused Code introduced by brantje
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...
454
            });
455
        });
456
    }
457
458
    _self.getActiveTab = getActiveTab;
459
460
    function updateCredentialUrlDoorhanger(login) {
461
        if(!_self.settings.enableUpdateUrl){
462
            return;
463
        }
464
465
        API.tabs.query({active: true, currentWindow: true}).then(function (tabs) {
466
            var tab = tabs[0];
467
            var data = login;
468
            data.url = tab.url;
469
            data.title = API.i18n.getMessage('detected_changed_url') + ':';
470
            API.tabs.sendMessage(tab.id, {
471
                method: 'showUrlUpdateDoorhanger',
472
                args: {data: data}
473
            });
474
        });
475
    }
476
477
    _self.updateCredentialUrlDoorhanger = updateCredentialUrlDoorhanger;
478
479
    function updateCredentialUrl(data, sender) {
480
        mined_data[sender.tab.id] = data;
481
        saveMined({}, sender);
482
483
    }
484
485
    _self.updateCredentialUrl = updateCredentialUrl;
486
487
    function saveMined(args, sender) {
488
        var data = mined_data[sender.tab.id];
489
        var credential = {},
490
            credential_index;
491
492
        if (data.guid === null) {
493
            credential = PAPI.newCredential();
494
        } else {
495
            for (var i = 0; i < local_credentials.length; i++) {
496
                if (local_credentials[i].guid === data.guid) {
497
                    credential = local_credentials[i];
498
                    credential_index = i;
499
                    break;
500
                }
501
            }
502
        }
503
        if (!credential.hasOwnProperty('account')) {
504
            credential.account = args.account;
505
        }
506
        credential.username = data.username;
507
        credential.password = data.password;
508
        credential.url = sender.tab.url;
509
        if (credential.guid !== null) {
510
            PAPI.updateCredential(credential.account, credential, credential.account.vault_password, function (updatedCredential) {
511
                updatedCredential.account = credential.account;
512
                if (credential_index) {
513
                    local_credentials[credential_index] = updatedCredential;
514
                }
515
                saveMinedCallback({credential: credential, updated: true, sender: sender});
516
                delete mined_data[sender.tab.id];
517
            });
518
        } else {
519
            credential.label = sender.tab.title;
520
            credential.vault_id = credential.account.vault.vault_id;
521
            PAPI.createCredential(credential.account, credential, credential.account.vault_password, function (createdCredential) {
522
                createdCredential.account = args.account;
523
                saveMinedCallback({credential: credential, updated: false, sender: sender});
524
                local_credentials.push(createdCredential);
525
                delete mined_data[sender.tab.id];
526
            });
527
        }
528
    }
529
530
    _self.saveMined = saveMined;
531
532
    function searchCredential(searchText) {
533
        searchText = searchText.toLowerCase();
534
        var searchFields = ['label', 'username', 'email', 'url', 'description'];
535
        var results = [];
536
        for (var i = 0; i < local_credentials.length; i++) {
537
            var credential = local_credentials[i];
538
            for (var f = 0; f < searchFields.length; f++) {
539
                var field = searchFields[f];
540
                if (!credential[field]) {
541
                    continue;
542
                }
543
544
                var field_value = credential[field].toLowerCase();
545
                if (field_value.indexOf(searchText) !== -1) {
546
                    results.push(credential);
547
                    break;
548
                }
549
            }
550
        }
551
        return results;
552
    }
553
554
    _self.searchCredential = searchCredential;
555
556
557
    function injectCreateCredential(args, sender) {
558
        var account = getRuntimeSettings().accounts[parseInt(args.vaultIndex)];
559
        var credential = PAPI.newCredential();
560
        credential.label = args.label;
561
        credential.username = args.username;
562
        credential.password = args.password;
563
        credential.url = sender.tab.url;
564
        credential.vault_id = account.vault.vault_id;
565
        PAPI.createCredential(account, credential, account.vault_password, function (createdCredential) {
566
            credential.account = account;
567
            saveMinedCallback({credential: credential, updated: false, sender: sender, selfAdded: true});
568
            local_credentials.push(createdCredential);
569
570
        });
571
    }
572
573
    self.injectCreateCredential = injectCreateCredential;
0 ignored issues
show
Bug introduced by brantje
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...
574
575
    function isVaultKeySet() {
576
        return (_self.settings.vault_password !== null);
577
    }
578
579
    _self.isVaultKeySet = isVaultKeySet;
580
581
    function isAutoFillEnabled() {
582
        if (!_self.settings.hasOwnProperty('enableAutoFill')) {
583
            return true;
584
        }
585
        return _self.settings.enableAutoFill;
586
    }
587
588
    _self.isAutoFillEnabled = isAutoFillEnabled;
589
590
    function isAutoSubmitEnabled() {
591
        if (!_self.settings.hasOwnProperty('enableAutoSubmit')) {
592
            return false;
593
        }
594
        return _self.settings.enableAutoSubmit;
595
    }
596
597
    _self.isAutoSubmitEnabled = isAutoSubmitEnabled;
598
599
    var doorhangerData = null;
600
601
    function setDoorhangerData(data) {
602
        doorhangerData = data;
603
    }
604
605
    _self.setDoorhangerData = setDoorhangerData;
606
607
    function getDoorhangerData() {
608
        return doorhangerData;
609
    }
610
611
    _self.getDoorhangerData = getDoorhangerData;
612
613
    function closeSetupTab() {
614
        API.tabs.query({url: 'chrome-extension://' + API.runtime.id + '/html/browser_action/browser_action.html'}).then(function (tabs) {
615
            if (tabs && tabs[0]) {
616
                API.tabs.remove(tabs[0].id);
617
            }
618
        });
619
    }
620
621
    _self.closeSetupTab = closeSetupTab;
622
623
    API.runtime.onMessage.addListener(function (msg, sender, sendResponse) {
624
625
        if (!msg || !msg.hasOwnProperty('method')) {
626
            return;
627
        }
628
        var result = false;
629
        if (_self[msg.method]) {
630
            result = _self[msg.method](msg.args, sender);
631
        } else {
632
            console.warn('[NOT FOUND] Method call', msg.method, 'args: ', msg.args);
633
        }
634
635
        sendResponse(result);
636
    });
637
638
    var defaultColor = '#0082c9';
639
640
    function createIconForTab(tab) {
641
        if (!master_password) {
642
            return;
643
        }
644
        var tabUrl = tab.url;
645
        var logins = getCredentialsByUrl(tabUrl);
646
        if (tab.active) {
647
            window.contextMenu.setContextItems(logins);
648
        }
649
        var credentialAmount = logins.length;
650
        API.browserAction.setBadgeText({
651
            text: credentialAmount.toString(),
652
            tabId: tab.id
653
        });
654
        API.browserAction.setBadgeBackgroundColor({
655
            color: defaultColor,
656
            tabId: tab.id
657
        });
658
659
        var plural = (credentialAmount === 1) ? API.i18n.getMessage('credential') : API.i18n.getMessage('credentials');
660
        API.browserAction.setTitle({
661
            title: API.i18n.getMessage('browser_action_title_login', [credentialAmount.toString(), plural.toString()]),
662
            tabId: tab.id
663
        });
664
    }
665
666
    function displayLogoutIcons() {
667
        if (_self.settings) {
668
            API.tabs.query({}).then(function (tabs) {
669
                for (var t = 0; t < tabs.length; t++) {
670
                    var tab = tabs[t];
671
                    API.browserAction.setBadgeText({
672
                        text: '🔑',
673
                        tabId: tab.id
674
                    });
675
                    API.browserAction.setBadgeBackgroundColor({
676
                        color: '#ff0000',
677
                        tabId: tab.id
678
                    });
679
                    API.browserAction.setTitle({
680
                        title: API.i18n.getMessage('browser_action_title_locked'),
681
                        tabId: tab.id
682
                    });
683
                }
684
            });
685
        }
686
    }
687
688
    function updateTabsIcon() {
689
        API.tabs.query({}).then(function (tabs) {
690
            for (var t = 0; t < tabs.length; t++) {
691
                var tab = tabs[t];
692
                createIconForTab(tab);
693
            }
694
        });
695
    }
696
697
698
    API.tabs.onUpdated.addListener(function (tabId, changeInfo, tab) {
699
        if (master_password) {
700
            createIconForTab(tab);
701
        } else {
702
            displayLogoutIcons();
703
        }
704
    });
705
706
    API.tabs.onActivated.addListener(function () {
707
        API.tabs.query({active: true, currentWindow: true}).then(function (tabs) {
708
            if (master_password) {
709
                createIconForTab(tabs[0]);
710
            } else {
711
                displayLogoutIcons();
712
            }
713
        });
714
    });
715
716
    displayLogoutIcons();
717
718
719
    storage.get('master_password').then(function (password) {
720
        if (password) {
721
            master_password = password;
722
            API.api.browserAction.setBadgeBackgroundColor({
723
                color: defaultColor
724
            });
725
        }
726
        getSettings();
727
    }).error(function (error) {
728
        if (error === "Data not found") {
729
            getSettings();
730
        }
731
    });
732
    return _window;
733
}());
734
735