Completed
Push — master ( e4d488...d7a2df )
by Sander
30s
created

js/background/service/background.js (13 issues)

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