Completed
Push — master ( e19ef6...b42b53 )
by Sander
28s
created

API.runtime.onInstalled.addListener   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

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