mirror of
https://github.com/bitwarden/browser
synced 2025-12-17 16:53:34 +00:00
Merge pull request #367 from bitwarden/typescript
Typescript conversion
This commit is contained in:
@@ -1,14 +1,16 @@
|
||||
angular
|
||||
angular
|
||||
.module('bit.accounts')
|
||||
|
||||
.controller('accountsHintController', function ($scope, $state, apiService, toastr, $q, utilsService,
|
||||
$analytics, i18nService) {
|
||||
$analytics, i18nService, $timeout) {
|
||||
$timeout(function () {
|
||||
utilsService.initListSectionItemListeners(document, angular);
|
||||
document.getElementById('email').focus();
|
||||
}, 500);
|
||||
|
||||
$scope.i18n = i18nService;
|
||||
$scope.model = {};
|
||||
|
||||
utilsService.initListSectionItemListeners($(document), angular);
|
||||
$('#email').focus();
|
||||
|
||||
$scope.submitPromise = null;
|
||||
$scope.submit = function (model) {
|
||||
if (!model.email) {
|
||||
@@ -31,13 +33,11 @@
|
||||
|
||||
function hintPromise(request) {
|
||||
return $q(function (resolve, reject) {
|
||||
apiService.postPasswordHint(request,
|
||||
function () {
|
||||
resolve();
|
||||
},
|
||||
function (error) {
|
||||
reject(error);
|
||||
});
|
||||
apiService.postPasswordHint(request).then(function () {
|
||||
resolve();
|
||||
}, function (error) {
|
||||
reject(error);
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1,18 +1,19 @@
|
||||
angular
|
||||
angular
|
||||
.module('bit.accounts')
|
||||
|
||||
.controller('accountsLoginController', function ($scope, $state, $stateParams, authService, userService, toastr,
|
||||
utilsService, $analytics, i18nService) {
|
||||
utilsService.initListSectionItemListeners($(document), angular);
|
||||
utilsService, $analytics, i18nService, $timeout) {
|
||||
$timeout(function () {
|
||||
utilsService.initListSectionItemListeners(document, angular);
|
||||
if ($stateParams.email) {
|
||||
document.getElementById('master-password').focus();
|
||||
}
|
||||
else {
|
||||
document.getElementById('email').focus();
|
||||
}
|
||||
}, 500);
|
||||
|
||||
$scope.i18n = i18nService;
|
||||
|
||||
if ($stateParams.email) {
|
||||
$('#master-password').focus();
|
||||
}
|
||||
else {
|
||||
$('#email').focus();
|
||||
}
|
||||
|
||||
$scope.model = {
|
||||
email: $stateParams.email
|
||||
};
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
angular
|
||||
angular
|
||||
.module('bit.accounts')
|
||||
|
||||
.controller('accountsLoginTwoFactorController', function ($scope, $state, authService, toastr, utilsService, SweetAlert,
|
||||
$analytics, i18nService, $stateParams, $filter, constantsService, $timeout, $window, cryptoService, apiService,
|
||||
environmentService) {
|
||||
$timeout(function () {
|
||||
utilsService.initListSectionItemListeners(document, angular);
|
||||
}, 500);
|
||||
|
||||
$scope.i18n = i18nService;
|
||||
utilsService.initListSectionItemListeners($(document), angular);
|
||||
|
||||
var customWebVaultUrl = null;
|
||||
if (environmentService.baseUrl) {
|
||||
@@ -85,7 +88,7 @@
|
||||
}
|
||||
|
||||
var key = cryptoService.makeKey(masterPassword, email);
|
||||
cryptoService.hashPassword(masterPassword, key, function (hash) {
|
||||
cryptoService.hashPassword(masterPassword, key).then(function (hash) {
|
||||
var request = new TwoFactorEmailRequest(email, hash);
|
||||
apiService.postTwoFactorEmail(request, function () {
|
||||
if (doToast) {
|
||||
@@ -143,7 +146,10 @@
|
||||
u2f.cleanup();
|
||||
|
||||
$timeout(function () {
|
||||
$('#code').focus();
|
||||
var codeInput = document.getElementById('code');
|
||||
if (codeInput) {
|
||||
codeInput.focus();
|
||||
}
|
||||
|
||||
var params;
|
||||
if ($scope.providerType === constants.twoFactorProvider.duo) {
|
||||
@@ -153,8 +159,10 @@
|
||||
host: params.Host,
|
||||
sig_request: params.Signature,
|
||||
submit_callback: function (theForm) {
|
||||
var response = $(theForm).find('input[name="sig_response"]').val();
|
||||
$scope.login(response);
|
||||
var sigElement = theForm.querySelector('input[name="sig_response"]');
|
||||
if (sigElement) {
|
||||
$scope.login(sigElement.value);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
angular
|
||||
angular
|
||||
.module('bit.accounts')
|
||||
|
||||
.controller(
|
||||
'accountsRegisterController',
|
||||
function ($scope, $state, cryptoService, toastr, $q, apiService, utilsService, $analytics, i18nService) {
|
||||
function ($scope, $state, cryptoService, toastr, $q, apiService, utilsService, $analytics, i18nService, $timeout) {
|
||||
$timeout(function () {
|
||||
utilsService.initListSectionItemListeners(document, angular);
|
||||
document.getElementById('email').focus();
|
||||
}, 500);
|
||||
|
||||
$scope.i18n = i18nService;
|
||||
|
||||
$scope.model = {};
|
||||
utilsService.initListSectionItemListeners($(document), angular);
|
||||
$('#email').focus();
|
||||
|
||||
$scope.submitPromise = null;
|
||||
$scope.submit = function (model) {
|
||||
if (!model.email) {
|
||||
@@ -45,16 +46,16 @@
|
||||
|
||||
function registerPromise(key, masterPassword, email, hint) {
|
||||
var deferred = $q.defer();
|
||||
cryptoService.makeEncKey(key).then(function (encKey) {
|
||||
cryptoService.hashPassword(masterPassword, key, function (hashedPassword) {
|
||||
var request = new RegisterRequest(email, hashedPassword, hint, encKey.encryptedString);
|
||||
apiService.postRegister(request,
|
||||
function () {
|
||||
deferred.resolve();
|
||||
},
|
||||
function (error) {
|
||||
deferred.reject(error);
|
||||
});
|
||||
var encKey;
|
||||
cryptoService.makeEncKey(key).then(function (theEncKey) {
|
||||
encKey = theEncKey;
|
||||
return cryptoService.hashPassword(masterPassword, key);
|
||||
}).then(function (hashedPassword) {
|
||||
var request = new RegisterRequest(email, hashedPassword, hint, encKey.encryptedString);
|
||||
apiService.postRegister(request).then(function () {
|
||||
deferred.resolve();
|
||||
}, function (error) {
|
||||
deferred.reject(error);
|
||||
});
|
||||
});
|
||||
return deferred.promise;
|
||||
|
||||
@@ -86,7 +86,7 @@
|
||||
<div class="content">
|
||||
<div class="two-factor-key-page">
|
||||
<p>{{i18n.insertYubiKey}}</p>
|
||||
<img src="../images/two-factor/yubikey.jpg" alt="" class="img-rounded img-responsive" />
|
||||
<img src="../../../../images/two-factor/yubikey.jpg" alt="" class="img-rounded img-responsive" />
|
||||
</div>
|
||||
<div class="list">
|
||||
<div class="list-section">
|
||||
@@ -125,7 +125,7 @@
|
||||
<p ng-if="!u2fReady">Loading...</p>
|
||||
<div ng-if="u2fReady">
|
||||
<p>{{i18n.insertU2f}}</p>
|
||||
<img src="../images/two-factor/u2fkey.jpg" alt="" class="img-rounded img-responsive" />
|
||||
<img src="../../../../images/two-factor/u2fkey.jpg" alt="" class="img-rounded img-responsive" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="list">
|
||||
|
||||
1
src/popup/app/app.d.ts
vendored
Normal file
1
src/popup/app/app.d.ts
vendored
Normal file
@@ -0,0 +1 @@
|
||||
declare module '*.html';
|
||||
@@ -1,20 +1,139 @@
|
||||
angular
|
||||
window.Papa = require('papaparse');
|
||||
require('clipboard');
|
||||
|
||||
require('angular');
|
||||
|
||||
require('angular-animate');
|
||||
const uiRouter = require('@uirouter/angularjs').default;
|
||||
require('angular-toastr');
|
||||
|
||||
require('ngclipboard');
|
||||
|
||||
require('sweetalert');
|
||||
require('angular-sweetalert');
|
||||
require('angulartics');
|
||||
require('angulartics-google-analytics');
|
||||
require('ng-infinite-scroll');
|
||||
|
||||
require('../../scripts/analytics.js');
|
||||
require('../../scripts/duo.js');
|
||||
require('../../scripts/u2f.js');
|
||||
|
||||
require('../less/libs.less');
|
||||
require('../less/popup.less');
|
||||
|
||||
import ComponentsModule from './components/components.module';
|
||||
import ToolsModule from './tools/tools.module';
|
||||
import ServicesModule from './services/services.module';
|
||||
import LockModule from './lock/lock.module';
|
||||
|
||||
// Model imports
|
||||
import { Attachment } from '../../models/domain/attachment';
|
||||
import { Card } from '../../models/domain/card';
|
||||
import { Cipher } from '../../models/domain/cipher';
|
||||
import { Field } from '../../models/domain/field';
|
||||
import { Folder } from '../../models/domain/folder';
|
||||
import { Identity } from '../../models/domain/identity';
|
||||
import { Login } from '../../models/domain/login';
|
||||
import { SecureNote } from '../../models/domain/secureNote';
|
||||
|
||||
import { AttachmentData } from '../../models/data/attachmentData';
|
||||
import { CardData } from '../../models/data/cardData';
|
||||
import { CipherData } from '../../models/data/cipherData';
|
||||
import { FieldData } from '../../models/data/fieldData';
|
||||
import { FolderData } from '../../models/data/folderData';
|
||||
import { IdentityData } from '../../models/data/identityData';
|
||||
import { LoginData } from '../../models/data/loginData';
|
||||
import { SecureNoteData } from '../../models/data/secureNoteData';
|
||||
|
||||
import { CipherString } from '../../models/domain/cipherString';
|
||||
|
||||
import { CipherRequest } from '../../models/request/cipherRequest';
|
||||
import { DeviceRequest } from '../../models/request/deviceRequest';
|
||||
import { DeviceTokenRequest } from '../../models/request/deviceTokenRequest';
|
||||
import { FolderRequest } from '../../models/request/folderRequest';
|
||||
import { PasswordHintRequest } from '../../models/request/passwordHintRequest';
|
||||
import { RegisterRequest } from '../../models/request/registerRequest';
|
||||
import { TokenRequest } from '../../models/request/tokenRequest';
|
||||
import { TwoFactorEmailRequest } from '../../models/request/twoFactorEmailRequest';
|
||||
|
||||
import { AttachmentResponse } from '../../models/response/attachmentResponse';
|
||||
import { CipherResponse } from '../../models/response/cipherResponse';
|
||||
import { DeviceResponse } from '../../models/response/deviceResponse';
|
||||
import { DomainsResponse } from '../../models/response/domainsResponse';
|
||||
import { ErrorResponse } from '../../models/response/errorResponse';
|
||||
import { FolderResponse } from '../../models/response/folderResponse';
|
||||
import { GlobalDomainResponse } from '../../models/response/globalDomainResponse';
|
||||
import { IdentityTokenResponse } from '../../models/response/identityTokenResponse';
|
||||
import { KeysResponse } from '../../models/response/keysResponse';
|
||||
import { ListResponse } from '../../models/response/listResponse';
|
||||
import { ProfileOrganizationResponse } from '../../models/response/profileOrganizationResponse';
|
||||
import { ProfileResponse } from '../../models/response/profileResponse';
|
||||
import { SyncResponse } from '../../models/response/syncResponse';
|
||||
|
||||
angular
|
||||
.module('bit', [
|
||||
'ui.router',
|
||||
uiRouter,
|
||||
'ngAnimate',
|
||||
'toastr',
|
||||
'angulartics',
|
||||
'angulartics.google.analytics',
|
||||
|
||||
'bit.directives',
|
||||
'bit.components',
|
||||
'bit.services',
|
||||
ComponentsModule,
|
||||
ServicesModule,
|
||||
|
||||
'bit.global',
|
||||
'bit.accounts',
|
||||
'bit.current',
|
||||
'bit.vault',
|
||||
'bit.settings',
|
||||
'bit.tools',
|
||||
'bit.lock'
|
||||
ToolsModule,
|
||||
LockModule
|
||||
]);
|
||||
|
||||
require('./config');
|
||||
require('./directives/directivesModule.js');
|
||||
require('./directives/formDirective.js');
|
||||
require('./directives/stopClickDirective.js');
|
||||
require('./directives/stopPropDirective.js');
|
||||
require('./directives/fallbackSrcDirective.js');
|
||||
require('./global/globalModule.js');
|
||||
require('./global/mainController.js');
|
||||
require('./global/tabsController.js');
|
||||
require('./global/baseController.js');
|
||||
require('./global/privateModeController.js');
|
||||
require('./accounts/accountsModule.js');
|
||||
require('./accounts/accountsLoginController.js');
|
||||
require('./accounts/accountsLoginTwoFactorController.js');
|
||||
require('./accounts/accountsTwoFactorMethodsController.js');
|
||||
require('./accounts/accountsHintController.js');
|
||||
require('./accounts/accountsRegisterController.js');
|
||||
require('./current/currentModule.js');
|
||||
require('./current/currentController.js');
|
||||
require('./vault/vaultModule.js');
|
||||
require('./vault/vaultController.js');
|
||||
require('./vault/vaultViewFolderController.js');
|
||||
require('./vault/vaultAddCipherController.js');
|
||||
require('./vault/vaultEditCipherController.js');
|
||||
require('./vault/vaultViewCipherController.js');
|
||||
require('./vault/vaultAttachmentsController.js');
|
||||
require('./settings/settingsModule.js');
|
||||
require('./settings/settingsController.js');
|
||||
require('./settings/settingsHelpController.js');
|
||||
require('./settings/settingsAboutController.js');
|
||||
require('./settings/settingsCreditsController.js');
|
||||
require('./settings/settingsFeaturesController.js');
|
||||
require('./settings/settingsSyncController.js');
|
||||
require('./settings/settingsFoldersController.js');
|
||||
require('./settings/settingsAddFolderController.js');
|
||||
require('./settings/settingsEditFolderController.js');
|
||||
require('./settings/settingsPremiumController.js');
|
||||
require('./settings/settingsEnvironmentController.js');
|
||||
require('./tools/toolsPasswordGeneratorHistoryController.js');
|
||||
require('./tools/toolsExportController.js');
|
||||
|
||||
// Bootstrap the angular application
|
||||
angular.element(function () {
|
||||
angular.bootstrap(document, ['bit']);
|
||||
});
|
||||
|
||||
49
src/popup/app/components/action-buttons.component.ts
Normal file
49
src/popup/app/components/action-buttons.component.ts
Normal file
@@ -0,0 +1,49 @@
|
||||
import * as template from './action-buttons.component.html';
|
||||
|
||||
class ActionButtonsController implements ng.IController {
|
||||
onView: Function;
|
||||
|
||||
cipher: any;
|
||||
showView: boolean;
|
||||
i18n: any;
|
||||
constants: any;
|
||||
|
||||
constructor(private i18nService: any, private $analytics: any, private constantsService: any, private toastr: any,
|
||||
private $timeout: any, private $window: any, private utilsService: any) {
|
||||
this.i18n = i18nService;
|
||||
this.constants = constantsService;
|
||||
}
|
||||
|
||||
launch() {
|
||||
const self = this;
|
||||
this.$timeout(() => {
|
||||
if (self.cipher.login.uri.startsWith('http://') || self.cipher.login.uri.startsWith('https://')) {
|
||||
self.$analytics.eventTrack('Launched Website From Listing');
|
||||
chrome.tabs.create({ url: self.cipher.login.uri });
|
||||
if (self.utilsService.inPopup(self.$window)) {
|
||||
self.$window.close();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
clipboardError(e: any) {
|
||||
this.toastr.info(this.i18nService.browserNotSupportClipboard);
|
||||
}
|
||||
|
||||
clipboardSuccess(e: any, type: string, aType: string) {
|
||||
e.clearSelection();
|
||||
this.$analytics.eventTrack('Copied ' + aType);
|
||||
this.toastr.info(type + this.i18nService.valueCopied);
|
||||
}
|
||||
}
|
||||
|
||||
export const ActionButtonsComponent = {
|
||||
bindings: {
|
||||
cipher: '<',
|
||||
showView: '<',
|
||||
onView: '&',
|
||||
},
|
||||
controller: ActionButtonsController,
|
||||
template,
|
||||
};
|
||||
@@ -1,41 +0,0 @@
|
||||
angular
|
||||
.module('bit.components')
|
||||
|
||||
.component('actionButtons', {
|
||||
bindings: {
|
||||
cipher: '<',
|
||||
showView: '<',
|
||||
onView: '&'
|
||||
},
|
||||
templateUrl: 'app/components/views/actionButtons.html',
|
||||
controller: function (i18nService, $analytics, constantsService, toastr, $timeout, $window, utilsService) {
|
||||
var ctrl = this;
|
||||
|
||||
ctrl.$onInit = function () {
|
||||
ctrl.i18n = i18nService;
|
||||
ctrl.constants = constantsService;
|
||||
|
||||
ctrl.launch = function () {
|
||||
$timeout(function () {
|
||||
if (ctrl.cipher.login.uri.startsWith('http://') || ctrl.cipher.login.uri.startsWith('https://')) {
|
||||
$analytics.eventTrack('Launched Website From Listing');
|
||||
chrome.tabs.create({ url: ctrl.cipher.login.uri });
|
||||
if (utilsService.inPopup($window)) {
|
||||
$window.close();
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
ctrl.clipboardError = function (e) {
|
||||
toastr.info(i18nService.browserNotSupportClipboard);
|
||||
};
|
||||
|
||||
ctrl.clipboardSuccess = function (e, type, aType) {
|
||||
e.clearSelection();
|
||||
$analytics.eventTrack('Copied ' + aType);
|
||||
toastr.info(type + i18nService.valueCopied);
|
||||
};
|
||||
};
|
||||
}
|
||||
});
|
||||
29
src/popup/app/components/cipher-items.component.ts
Normal file
29
src/popup/app/components/cipher-items.component.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
import * as template from './cipher-items.component.html';
|
||||
|
||||
class CipherItemsController implements ng.IController {
|
||||
onSelected: Function;
|
||||
onView: Function;
|
||||
|
||||
constructor(private i18nService: any) {
|
||||
|
||||
}
|
||||
|
||||
view(cipher: any) {
|
||||
return this.onView()(cipher);
|
||||
}
|
||||
|
||||
select(cipher: any) {
|
||||
return this.onSelected()(cipher);
|
||||
}
|
||||
}
|
||||
|
||||
export const CipherItemsComponent = {
|
||||
bindings: {
|
||||
ciphers: '<',
|
||||
selectionTitle: '<',
|
||||
onSelected: '&',
|
||||
onView: '&',
|
||||
},
|
||||
controller: CipherItemsController,
|
||||
template,
|
||||
};
|
||||
@@ -1,27 +0,0 @@
|
||||
angular
|
||||
.module('bit.components')
|
||||
|
||||
.component('cipherItems', {
|
||||
bindings: {
|
||||
ciphers: '<',
|
||||
selectionTitle: '<',
|
||||
onView: '&',
|
||||
onSelected: '&'
|
||||
},
|
||||
templateUrl: 'app/components/views/cipherItems.html',
|
||||
controller: function (i18nService) {
|
||||
var ctrl = this;
|
||||
|
||||
ctrl.$onInit = function () {
|
||||
ctrl.i18n = i18nService;
|
||||
|
||||
ctrl.view = function (cipher) {
|
||||
ctrl.onView()(cipher);
|
||||
};
|
||||
|
||||
ctrl.select = function (cipher) {
|
||||
ctrl.onSelected()(cipher);
|
||||
};
|
||||
};
|
||||
}
|
||||
});
|
||||
11
src/popup/app/components/components.module.ts
Normal file
11
src/popup/app/components/components.module.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import * as angular from 'angular';
|
||||
import { ActionButtonsComponent } from './action-buttons.component';
|
||||
import { CipherItemsComponent } from './cipher-items.component';
|
||||
import { IconComponent } from './icon.component';
|
||||
|
||||
export default angular
|
||||
.module('bit.components', [])
|
||||
.component('cipherItems', CipherItemsComponent)
|
||||
.component('icon', IconComponent)
|
||||
.component('actionButtons', ActionButtonsComponent)
|
||||
.name;
|
||||
@@ -1,2 +0,0 @@
|
||||
angular
|
||||
.module('bit.components', []);
|
||||
@@ -1,4 +1,4 @@
|
||||
<div class="icon">
|
||||
<div class="icon">
|
||||
<img ng-src="{{$ctrl.image}}" fallback-src="{{$ctrl.fallbackImage}}" ng-if="$ctrl.imageEnabled && $ctrl.image" alt="" />
|
||||
<i class="fa fa-fw fa-lg {{$ctrl.icon}}" ng-if="!$ctrl.imageEnabled || !$ctrl.image"></i>
|
||||
</div>
|
||||
82
src/popup/app/components/icon.component.ts
Normal file
82
src/popup/app/components/icon.component.ts
Normal file
@@ -0,0 +1,82 @@
|
||||
import * as template from './icon.component.html';
|
||||
|
||||
class IconController implements ng.IController {
|
||||
cipher: any;
|
||||
icon: string;
|
||||
image: string;
|
||||
fallbackImage: string;
|
||||
imageEnabled: boolean;
|
||||
|
||||
private iconsUrl: string;
|
||||
|
||||
constructor(private stateService: any, private constantsService: any, private environmentService: any) {
|
||||
this.imageEnabled = stateService.getState('faviconEnabled');
|
||||
|
||||
this.iconsUrl = environmentService.iconsUrl;
|
||||
if (!this.iconsUrl) {
|
||||
if (environmentService.baseUrl) {
|
||||
this.iconsUrl = environmentService.baseUrl + '/icons';
|
||||
} else {
|
||||
this.iconsUrl = 'https://icons.bitwarden.com';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$onChanges() {
|
||||
switch (this.cipher.type) {
|
||||
case this.constantsService.cipherType.login:
|
||||
this.icon = 'fa-globe';
|
||||
this.setLoginIcon();
|
||||
break;
|
||||
case this.constantsService.cipherType.secureNote:
|
||||
this.icon = 'fa-sticky-note-o';
|
||||
break;
|
||||
case this.constantsService.cipherType.card:
|
||||
this.icon = 'fa-credit-card';
|
||||
break;
|
||||
case this.constantsService.cipherType.identity:
|
||||
this.icon = 'fa-id-card-o';
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private setLoginIcon() {
|
||||
if (this.cipher.login.uri) {
|
||||
let hostnameUri = this.cipher.login.uri;
|
||||
let isWebsite = false;
|
||||
|
||||
if (hostnameUri.indexOf('androidapp://') === 0) {
|
||||
this.icon = 'fa-android';
|
||||
this.image = null;
|
||||
} else if (hostnameUri.indexOf('iosapp://') === 0) {
|
||||
this.icon = 'fa-apple';
|
||||
this.image = null;
|
||||
} else if (this.imageEnabled && hostnameUri.indexOf('://') === -1 && hostnameUri.indexOf('.') > -1) {
|
||||
hostnameUri = 'http://' + hostnameUri;
|
||||
isWebsite = true;
|
||||
} else if (this.imageEnabled) {
|
||||
isWebsite = hostnameUri.indexOf('http') === 0 && hostnameUri.indexOf('.') > -1;
|
||||
}
|
||||
|
||||
if (this.imageEnabled && isWebsite) {
|
||||
try {
|
||||
const url = new URL(hostnameUri);
|
||||
this.image = this.iconsUrl + '/' + url.hostname + '/icon.png';
|
||||
this.fallbackImage = chrome.extension.getURL('images/fa-globe.png');
|
||||
} catch (e) { }
|
||||
}
|
||||
} else {
|
||||
this.image = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const IconComponent = {
|
||||
bindings: {
|
||||
cipher: '<',
|
||||
},
|
||||
controller: IconController,
|
||||
template,
|
||||
};
|
||||
@@ -1,78 +0,0 @@
|
||||
angular
|
||||
.module('bit.components')
|
||||
|
||||
.component('icon', {
|
||||
bindings: {
|
||||
cipher: '<'
|
||||
},
|
||||
templateUrl: 'app/components/views/icon.html',
|
||||
controller: function (stateService, constantsService, environmentService) {
|
||||
var ctrl = this;
|
||||
ctrl.imageEnabled = stateService.getState('faviconEnabled');
|
||||
|
||||
var iconsUrl = environmentService.iconsUrl;
|
||||
if (!iconsUrl) {
|
||||
if (environmentService.baseUrl) {
|
||||
iconsUrl = environmentService.baseUrl + '/icons';
|
||||
}
|
||||
else {
|
||||
iconsUrl = 'https://icons.bitwarden.com';
|
||||
}
|
||||
}
|
||||
|
||||
ctrl.$onChanges = function () {
|
||||
switch (ctrl.cipher.type) {
|
||||
case constantsService.cipherType.login:
|
||||
ctrl.icon = 'fa-globe';
|
||||
setLoginIcon(ctrl.cipher);
|
||||
break;
|
||||
case constantsService.cipherType.secureNote:
|
||||
ctrl.icon = 'fa-sticky-note-o';
|
||||
break;
|
||||
case constantsService.cipherType.card:
|
||||
ctrl.icon = 'fa-credit-card';
|
||||
break;
|
||||
case constantsService.cipherType.identity:
|
||||
ctrl.icon = 'fa-id-card-o';
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
function setLoginIcon() {
|
||||
if (ctrl.cipher.login.uri) {
|
||||
var hostnameUri = ctrl.cipher.login.uri,
|
||||
isWebsite = false;
|
||||
|
||||
if (hostnameUri.indexOf('androidapp://') === 0) {
|
||||
ctrl.icon = 'fa-android';
|
||||
ctrl.image = null;
|
||||
}
|
||||
else if (hostnameUri.indexOf('iosapp://') === 0) {
|
||||
ctrl.icon = 'fa-apple';
|
||||
ctrl.image = null;
|
||||
}
|
||||
else if (ctrl.imageEnabled && hostnameUri.indexOf('://') === -1 && hostnameUri.indexOf('.') > -1) {
|
||||
hostnameUri = "http://" + hostnameUri;
|
||||
isWebsite = true;
|
||||
}
|
||||
else if (ctrl.imageEnabled) {
|
||||
isWebsite = hostnameUri.indexOf('http') === 0 && hostnameUri.indexOf('.') > -1;
|
||||
}
|
||||
|
||||
if (ctrl.imageEnabled && isWebsite) {
|
||||
try {
|
||||
var url = new URL(hostnameUri);
|
||||
ctrl.image = iconsUrl + '/' + url.hostname + '/icon.png';
|
||||
ctrl.fallbackImage = chrome.extension.getURL('images/fa-globe.png');
|
||||
}
|
||||
catch (e) { }
|
||||
}
|
||||
}
|
||||
else {
|
||||
ctrl.image = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -1,4 +1,4 @@
|
||||
angular
|
||||
angular
|
||||
.module('bit')
|
||||
|
||||
.config(function ($stateProvider, $urlRouterProvider, $compileProvider, $sceDelegateProvider, toastrConfig) {
|
||||
@@ -23,20 +23,22 @@
|
||||
var userService = $injector.get('userService');
|
||||
var cryptoService = $injector.get('cryptoService');
|
||||
|
||||
cryptoService.getKey().then(function (key) {
|
||||
userService.isAuthenticated(function (isAuthenticated) {
|
||||
if (isAuthenticated) {
|
||||
if (!key) {
|
||||
$state.go('lock');
|
||||
}
|
||||
else {
|
||||
$state.go('tabs.current');
|
||||
}
|
||||
var key;
|
||||
cryptoService.getKey().then(function (theKey) {
|
||||
key = theKey;
|
||||
return userService.isAuthenticated();
|
||||
}).then(function (isAuthenticated) {
|
||||
if (isAuthenticated) {
|
||||
if (!key) {
|
||||
$state.go('lock');
|
||||
}
|
||||
else {
|
||||
$state.go('home');
|
||||
$state.go('tabs.current');
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
$state.go('home');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -44,21 +46,21 @@
|
||||
.state('splash', {
|
||||
url: '/splash',
|
||||
controller: 'baseController',
|
||||
templateUrl: 'app/global/splash.html',
|
||||
template: require('./global/splash.html'),
|
||||
data: { authorize: false },
|
||||
params: { animation: null }
|
||||
})
|
||||
.state('privateMode', {
|
||||
url: '/private-mode',
|
||||
controller: 'privateModeController',
|
||||
templateUrl: 'app/global/privateMode.html',
|
||||
template: require('./global/privateMode.html'),
|
||||
data: { authorize: false },
|
||||
params: { animation: null }
|
||||
})
|
||||
.state('home', {
|
||||
url: '/home',
|
||||
controller: 'baseController',
|
||||
templateUrl: 'app/global/home.html',
|
||||
template: require('./global/home.html'),
|
||||
data: { authorize: false },
|
||||
params: { animation: null }
|
||||
})
|
||||
@@ -66,35 +68,35 @@
|
||||
.state('login', {
|
||||
url: '/login',
|
||||
controller: 'accountsLoginController',
|
||||
templateUrl: 'app/accounts/views/accountsLogin.html',
|
||||
template: require('./accounts/views/accountsLogin.html'),
|
||||
data: { authorize: false },
|
||||
params: { animation: null, email: null }
|
||||
})
|
||||
.state('hint', {
|
||||
url: '/hint',
|
||||
controller: 'accountsHintController',
|
||||
templateUrl: 'app/accounts/views/accountsHint.html',
|
||||
template: require('./accounts/views/accountsHint.html'),
|
||||
data: { authorize: false },
|
||||
params: { animation: null }
|
||||
})
|
||||
.state('twoFactor', {
|
||||
url: '/two-factor',
|
||||
controller: 'accountsLoginTwoFactorController',
|
||||
templateUrl: 'app/accounts/views/accountsLoginTwoFactor.html',
|
||||
template: require('./accounts/views/accountsLoginTwoFactor.html'),
|
||||
data: { authorize: false },
|
||||
params: { animation: null, email: null, masterPassword: null, providers: null, provider: null }
|
||||
})
|
||||
.state('twoFactorMethods', {
|
||||
url: '/two-factor-methods',
|
||||
controller: 'accountsTwoFactorMethodsController',
|
||||
templateUrl: 'app/accounts/views/accountsTwoFactorMethods.html',
|
||||
template: require('./accounts/views/accountsTwoFactorMethods.html'),
|
||||
data: { authorize: false },
|
||||
params: { animation: null, email: null, masterPassword: null, providers: null, provider: null }
|
||||
})
|
||||
.state('register', {
|
||||
url: '/register',
|
||||
controller: 'accountsRegisterController',
|
||||
templateUrl: 'app/accounts/views/accountsRegister.html',
|
||||
template: require('./accounts/views/accountsRegister.html'),
|
||||
data: { authorize: false },
|
||||
params: { animation: null }
|
||||
})
|
||||
@@ -102,63 +104,62 @@
|
||||
.state('tabs', {
|
||||
url: '/tab',
|
||||
abstract: true,
|
||||
templateUrl: 'app/global/tabs.html',
|
||||
template: require('./global/tabs.html'),
|
||||
data: { authorize: true },
|
||||
params: { animation: null }
|
||||
})
|
||||
.state('tabs.current', {
|
||||
url: '/current',
|
||||
templateUrl: 'app/current/views/current.html',
|
||||
template: require('./current/views/current.html'),
|
||||
controller: 'currentController'
|
||||
})
|
||||
.state('tabs.vault', {
|
||||
url: '/vault',
|
||||
templateUrl: 'app/vault/views/vault.html',
|
||||
template: require('./vault/views/vault.html'),
|
||||
controller: 'vaultController',
|
||||
params: { syncOnLoad: false, searchText: null }
|
||||
})
|
||||
.state('tabs.settings', {
|
||||
url: '/settings',
|
||||
templateUrl: 'app/settings/views/settings.html',
|
||||
template: require('./settings/views/settings.html'),
|
||||
controller: 'settingsController'
|
||||
})
|
||||
.state('tabs.tools', {
|
||||
url: '/tools',
|
||||
templateUrl: 'app/tools/views/tools.html',
|
||||
controller: 'toolsController'
|
||||
component: 'tools'
|
||||
})
|
||||
|
||||
.state('viewFolder', {
|
||||
url: '/view-folder?folderId',
|
||||
templateUrl: 'app/vault/views/vaultViewFolder.html',
|
||||
template: require('./vault/views/vaultViewFolder.html'),
|
||||
controller: 'vaultViewFolderController',
|
||||
data: { authorize: true },
|
||||
params: { animation: null, from: 'vault' }
|
||||
})
|
||||
.state('viewCipher', {
|
||||
url: '/view-cipher?cipherId',
|
||||
templateUrl: 'app/vault/views/vaultViewCipher.html',
|
||||
template: require('./vault/views/vaultViewCipher.html'),
|
||||
controller: 'vaultViewCipherController',
|
||||
data: { authorize: true },
|
||||
params: { animation: null, from: 'vault' }
|
||||
})
|
||||
.state('addCipher', {
|
||||
url: '/add-cipher',
|
||||
templateUrl: 'app/vault/views/vaultAddCipher.html',
|
||||
template: require('./vault/views/vaultAddCipher.html'),
|
||||
controller: 'vaultAddCipherController',
|
||||
data: { authorize: true },
|
||||
params: { animation: null, name: null, uri: null, folderId: null, cipher: null, from: 'vault' }
|
||||
})
|
||||
.state('editCipher', {
|
||||
url: '/edit-cipher?cipherId',
|
||||
templateUrl: 'app/vault/views/vaultEditCipher.html',
|
||||
template: require('./vault/views/vaultEditCipher.html'),
|
||||
controller: 'vaultEditCipherController',
|
||||
data: { authorize: true },
|
||||
params: { animation: null, fromView: true, cipher: null, from: 'vault' }
|
||||
})
|
||||
.state('attachments', {
|
||||
url: '/attachments?id',
|
||||
templateUrl: 'app/vault/views/vaultAttachments.html',
|
||||
template: require('./vault/views/vaultAttachments.html'),
|
||||
controller: 'vaultAttachmentsController',
|
||||
data: { authorize: true },
|
||||
params: { animation: null, fromView: true, from: 'vault' }
|
||||
@@ -166,21 +167,20 @@
|
||||
|
||||
.state('passwordGenerator', {
|
||||
url: '/password-generator',
|
||||
templateUrl: 'app/tools/views/toolsPasswordGenerator.html',
|
||||
controller: 'toolsPasswordGeneratorController',
|
||||
component: 'passwordGenerator',
|
||||
data: { authorize: true },
|
||||
params: { animation: null, addState: null, editState: null }
|
||||
})
|
||||
.state('passwordGeneratorHistory', {
|
||||
url: '/history',
|
||||
templateUrl: 'app/tools/views/toolsPasswordGeneratorHistory.html',
|
||||
template: require('./tools/views/toolsPasswordGeneratorHistory.html'),
|
||||
controller: 'toolsPasswordGeneratorHistoryController',
|
||||
data: { authorize: true },
|
||||
params: { animation: null, addState: null, editState: null }
|
||||
})
|
||||
.state('export', {
|
||||
url: '/export',
|
||||
templateUrl: 'app/tools/views/toolsExport.html',
|
||||
template: require('./tools/views/toolsExport.html'),
|
||||
controller: 'toolsExportController',
|
||||
data: { authorize: true },
|
||||
params: { animation: null }
|
||||
@@ -188,42 +188,42 @@
|
||||
|
||||
.state('about', {
|
||||
url: '/about',
|
||||
templateUrl: 'app/settings/views/settingsAbout.html',
|
||||
template: require('./settings/views/settingsAbout.html'),
|
||||
controller: 'settingsAboutController',
|
||||
data: { authorize: true },
|
||||
params: { animation: null }
|
||||
})
|
||||
.state('credits', {
|
||||
url: '/credits',
|
||||
templateUrl: 'app/settings/views/settingsCredits.html',
|
||||
template: require('./settings/views/settingsCredits.html'),
|
||||
controller: 'settingsCreditsController',
|
||||
data: { authorize: true },
|
||||
params: { animation: null }
|
||||
})
|
||||
.state('features', {
|
||||
url: '/features',
|
||||
templateUrl: 'app/settings/views/settingsFeatures.html',
|
||||
template: require('./settings/views/settingsFeatures.html'),
|
||||
controller: 'settingsFeaturesController',
|
||||
data: { authorize: true },
|
||||
params: { animation: null }
|
||||
})
|
||||
.state('help', {
|
||||
url: '/help',
|
||||
templateUrl: 'app/settings/views/settingsHelp.html',
|
||||
template: require('./settings/views/settingsHelp.html'),
|
||||
controller: 'settingsHelpController',
|
||||
data: { authorize: true },
|
||||
params: { animation: null }
|
||||
})
|
||||
.state('sync', {
|
||||
url: '/sync',
|
||||
templateUrl: 'app/settings/views/settingsSync.html',
|
||||
template: require('./settings/views/settingsSync.html'),
|
||||
controller: 'settingsSyncController',
|
||||
data: { authorize: true },
|
||||
params: { animation: null }
|
||||
})
|
||||
.state('premium', {
|
||||
url: '/premium',
|
||||
templateUrl: 'app/settings/views/settingsPremium.html',
|
||||
template: require('./settings/views/settingsPremium.html'),
|
||||
controller: 'settingsPremiumController',
|
||||
data: { authorize: true },
|
||||
params: { animation: null }
|
||||
@@ -231,54 +231,60 @@
|
||||
|
||||
.state('folders', {
|
||||
url: '/folders',
|
||||
templateUrl: 'app/settings/views/settingsFolders.html',
|
||||
template: require('./settings/views/settingsFolders.html'),
|
||||
controller: 'settingsFoldersController',
|
||||
data: { authorize: true },
|
||||
params: { animation: null }
|
||||
})
|
||||
.state('addFolder', {
|
||||
url: '/addFolder',
|
||||
templateUrl: 'app/settings/views/settingsAddFolder.html',
|
||||
template: require('./settings/views/settingsAddFolder.html'),
|
||||
controller: 'settingsAddFolderController',
|
||||
data: { authorize: true },
|
||||
params: { animation: null }
|
||||
})
|
||||
.state('editFolder', {
|
||||
url: '/editFolder?folderId',
|
||||
templateUrl: 'app/settings/views/settingsEditFolder.html',
|
||||
template: require('./settings/views/settingsEditFolder.html'),
|
||||
controller: 'settingsEditFolderController',
|
||||
data: { authorize: true },
|
||||
params: { animation: null }
|
||||
})
|
||||
.state('environment', {
|
||||
url: '/environment',
|
||||
templateUrl: 'app/settings/views/settingsEnvironment.html',
|
||||
template: require('./settings/views/settingsEnvironment.html'),
|
||||
controller: 'settingsEnvironmentController',
|
||||
data: { authorize: false },
|
||||
params: { animation: null }
|
||||
})
|
||||
.state('lock', {
|
||||
url: '/lock',
|
||||
templateUrl: 'app/lock/views/lock.html',
|
||||
controller: 'lockController',
|
||||
component: 'lock',
|
||||
data: { authorize: true },
|
||||
params: { animation: null }
|
||||
});
|
||||
})
|
||||
.run(function ($rootScope, userService, $state, constantsService, stateService) {
|
||||
.run(function ($trace, $transitions, userService, $state, constantsService, stateService) {
|
||||
//$trace.enable('TRANSITION');
|
||||
|
||||
stateService.init();
|
||||
|
||||
$rootScope.$on('$stateChangeStart', function (event, toState, toParams) {
|
||||
$transitions.onStart({}, function (trans) {
|
||||
const $state = trans.router.stateService;
|
||||
const toState = trans.to();
|
||||
|
||||
if ($state.current.name.indexOf('tabs.') > -1 && toState.name.indexOf('tabs.') > -1) {
|
||||
stateService.removeState('vault');
|
||||
stateService.removeState('viewFolder');
|
||||
}
|
||||
|
||||
const userService = trans.injector().get('userService');
|
||||
|
||||
if (!userService) {
|
||||
return;
|
||||
}
|
||||
|
||||
userService.isAuthenticated(function (isAuthenticated) {
|
||||
userService.isAuthenticated().then((isAuthenticated) => {
|
||||
if (isAuthenticated) {
|
||||
var obj = {};
|
||||
obj[constantsService.lastActiveKey] = (new Date()).getTime();
|
||||
|
||||
@@ -14,7 +14,7 @@ angular
|
||||
$scope.otherCiphers = [];
|
||||
$scope.loaded = false;
|
||||
$scope.searchText = null;
|
||||
$('#search').focus();
|
||||
document.getElementById('search').focus();
|
||||
|
||||
$scope.$on('$viewContentLoaded', function () {
|
||||
$timeout(loadVault, 100);
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
angular
|
||||
angular
|
||||
.module('bit.directives')
|
||||
|
||||
.directive('fallbackSrc', function () {
|
||||
return function (scope, element, attrs) {
|
||||
var el = $(element);
|
||||
el.bind('error', function (event) {
|
||||
el.attr('src', attrs.fallbackSrc);
|
||||
element[0].addEventListener('error', function (e) {
|
||||
e.target.src = attrs.fallbackSrc;
|
||||
});
|
||||
};
|
||||
});
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
angular
|
||||
angular
|
||||
.module('bit.directives')
|
||||
|
||||
// ref: https://stackoverflow.com/a/14165848/1090359
|
||||
.directive('stopClick', function () {
|
||||
return function (scope, element, attrs) {
|
||||
$(element).click(function (event) {
|
||||
event.preventDefault();
|
||||
element[0].addEventListener('click', function (e) {
|
||||
e.preventDefault();
|
||||
});
|
||||
};
|
||||
});
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
angular
|
||||
angular
|
||||
.module('bit.directives')
|
||||
|
||||
.directive('stopProp', function () {
|
||||
return function (scope, element, attrs) {
|
||||
$(element).click(function (event) {
|
||||
event.stopPropagation();
|
||||
element[0].addEventListener('click', function (e) {
|
||||
e.stopPropagation();
|
||||
});
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<a ui-sref="environment({animation: 'in-slide-up'})" class="settings-icon">
|
||||
<i class="fa fa-cog fa-lg"></i><span> Settings</span>
|
||||
</a>
|
||||
<img src="../../../../images/logo@2x.png" alt="bitwarden" />
|
||||
<img src="../../../images/logo@2x.png" alt="bitwarden" />
|
||||
<p>{{i18n.loginOrCreateNewAccount}}</p>
|
||||
<div class="bottom-buttons">
|
||||
<a class="btn btn-lg btn-primary btn-block" ui-sref="register({animation: 'in-slide-up'})"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
angular
|
||||
.module('bit.global')
|
||||
|
||||
.controller('mainController', function ($scope, $state, authService, toastr, i18nService, $analytics, utilsService,
|
||||
.controller('mainController', function ($scope, $transitions, $state, authService, toastr, i18nService, $analytics, utilsService,
|
||||
$window) {
|
||||
var self = this;
|
||||
self.currentYear = new Date().getFullYear();
|
||||
@@ -11,12 +11,13 @@ angular
|
||||
self.disableSearch = utilsService && utilsService.isEdge();
|
||||
self.inSidebar = utilsService && utilsService.inSidebar($window);
|
||||
|
||||
$scope.$on('$stateChangeSuccess', function (event, toState, toParams, fromState, fromParams) {
|
||||
$transitions.onSuccess({}, function(transition) {
|
||||
const toParams = transition.params("to");
|
||||
|
||||
if (toParams.animation) {
|
||||
self.animation = toParams.animation;
|
||||
return;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
self.animation = '';
|
||||
}
|
||||
});
|
||||
@@ -42,11 +43,12 @@ angular
|
||||
href = hrefParts[0] + '?uilocation=popout' + (hrefParts.length > 0 ? '#' + hrefParts[1] : '');
|
||||
}
|
||||
|
||||
var bodyRect = document.querySelector('body').getBoundingClientRect();
|
||||
chrome.windows.create({
|
||||
url: href,
|
||||
type: 'popup',
|
||||
width: $('body').width() + 60,
|
||||
height: $('body').height()
|
||||
width: bodyRect.width + 60,
|
||||
height: bodyRect.height
|
||||
});
|
||||
|
||||
if (utilsService.inPopup($window)) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<div class="content">
|
||||
<div class="splash-page">
|
||||
<img src="../../../../images/logo@3x.png" alt="bitwarden" />
|
||||
<img src="../../../images/logo@3x.png" alt="bitwarden" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<form name="theForm" ng-submit="submit()" bit-form="submitPromise">
|
||||
<form name="theForm" ng-submit="$ctrl.submit()" bit-form="submitPromise">
|
||||
<div class="header">
|
||||
<div class="right">
|
||||
<button type="submit" class="btn btn-link">{{i18n.submit}}</button>
|
||||
<button type="submit" class="btn btn-link">{{$ctrl.i18n.submit}}</button>
|
||||
</div>
|
||||
<div class="title">{{i18n.verifyMasterPassword}}</div>
|
||||
<div class="title">{{$ctrl.i18n.verifyMasterPassword}}</div>
|
||||
</div>
|
||||
<div class="content">
|
||||
<div class="list">
|
||||
@@ -11,15 +11,15 @@
|
||||
<div class="list-section-items">
|
||||
<div class="list-section-item list-section-item-icon-input">
|
||||
<i class="fa fa-lock fa-lg fa-fw"></i>
|
||||
<label for="master-password" class="sr-only">{{i18n.masterPass}}</label>
|
||||
<input id="master-password" type="password" name="MasterPassword" placeholder="{{i18n.masterPass}}"
|
||||
<label for="master-password" class="sr-only">{{$ctrl.i18n.masterPass}}</label>
|
||||
<input id="master-password" type="password" name="MasterPassword" placeholder="{{$ctrl.i18n.masterPass}}"
|
||||
ng-model="masterPassword">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<p class="text-center text-accent">
|
||||
<a ng-click="logOut()" href="">{{i18n.logOut}}</a>
|
||||
<a ng-click="$ctrl.logOut()" href="">{{$ctrl.i18n.logOut}}</a>
|
||||
</p>
|
||||
</div>
|
||||
</form>
|
||||
53
src/popup/app/lock/lock.component.ts
Normal file
53
src/popup/app/lock/lock.component.ts
Normal file
@@ -0,0 +1,53 @@
|
||||
import CryptoService from '../../../services/crypto.service';
|
||||
import UserService from '../../../services/user.service';
|
||||
|
||||
import * as template from './lock.component.html';
|
||||
|
||||
class LockController {
|
||||
i18n: any;
|
||||
|
||||
constructor(public $scope: any, public $state: any, public i18nService: any,
|
||||
public cryptoService: CryptoService, public toastr: any, public userService: UserService,
|
||||
public SweetAlert: any, public $timeout: any) {
|
||||
this.i18n = i18nService;
|
||||
|
||||
$timeout(() => {
|
||||
document.getElementById('master-password').focus();
|
||||
});
|
||||
}
|
||||
|
||||
logOut() {
|
||||
this.SweetAlert.swal({
|
||||
title: this.i18nService.logOut,
|
||||
text: this.i18nService.logOutConfirmation,
|
||||
showCancelButton: true,
|
||||
confirmButtonText: this.i18nService.yes,
|
||||
cancelButtonText: this.i18nService.cancel,
|
||||
}, (confirmed: boolean) => {
|
||||
if (confirmed) {
|
||||
chrome.runtime.sendMessage({ command: 'logout' });
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async submit() {
|
||||
const email = await this.userService.getEmail();
|
||||
const key = this.cryptoService.makeKey(this.$scope.masterPassword, email);
|
||||
const keyHash = await this.cryptoService.hashPassword(this.$scope.masterPassword, key);
|
||||
const storedKeyHash = await this.cryptoService.getKeyHash();
|
||||
|
||||
if (storedKeyHash && keyHash && storedKeyHash === keyHash) {
|
||||
await this.cryptoService.setKey(key);
|
||||
chrome.runtime.sendMessage({ command: 'unlocked' });
|
||||
this.$state.go('tabs.current');
|
||||
} else {
|
||||
this.toastr.error(this.i18nService.invalidMasterPassword, this.i18nService.errorsOccurred);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const LockComponent = {
|
||||
bindings: {},
|
||||
controller: LockController,
|
||||
template,
|
||||
};
|
||||
9
src/popup/app/lock/lock.module.ts
Normal file
9
src/popup/app/lock/lock.module.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
import * as angular from 'angular';
|
||||
import { LockComponent } from './lock.component';
|
||||
|
||||
export default angular
|
||||
.module('bit.lock', ['ngAnimate', 'toastr'])
|
||||
|
||||
.component('lock', LockComponent)
|
||||
|
||||
.name;
|
||||
@@ -1,44 +0,0 @@
|
||||
angular
|
||||
.module('bit.lock')
|
||||
|
||||
.controller('lockController', function ($scope, $state, $analytics, i18nService, cryptoService, toastr,
|
||||
userService, SweetAlert, $timeout) {
|
||||
$scope.i18n = i18nService;
|
||||
|
||||
$timeout(function () {
|
||||
$('#master-password').focus();
|
||||
});
|
||||
|
||||
$scope.logOut = function () {
|
||||
SweetAlert.swal({
|
||||
title: i18nService.logOut,
|
||||
text: i18nService.logOutConfirmation,
|
||||
showCancelButton: true,
|
||||
confirmButtonText: i18nService.yes,
|
||||
cancelButtonText: i18nService.cancel
|
||||
}, function (confirmed) {
|
||||
if (confirmed) {
|
||||
chrome.runtime.sendMessage({ command: 'logout' });
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
$scope.submit = function () {
|
||||
userService.getEmail(function (email) {
|
||||
var key = cryptoService.makeKey($scope.masterPassword, email);
|
||||
cryptoService.hashPassword($scope.masterPassword, key, function (keyHash) {
|
||||
cryptoService.getKeyHash(function (storedKeyHash) {
|
||||
if (storedKeyHash && keyHash && storedKeyHash === keyHash) {
|
||||
cryptoService.setKey(key).then(function () {
|
||||
chrome.runtime.sendMessage({ command: 'unlocked' });
|
||||
$state.go('tabs.current');
|
||||
});
|
||||
}
|
||||
else {
|
||||
toastr.error(i18nService.invalidMasterPassword, i18nService.errorsOccurred);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
});
|
||||
@@ -1,2 +0,0 @@
|
||||
angular
|
||||
.module('bit.lock', ['ngAnimate', 'toastr']);
|
||||
73
src/popup/app/services/auth.service.ts
Normal file
73
src/popup/app/services/auth.service.ts
Normal file
@@ -0,0 +1,73 @@
|
||||
import { DeviceRequest } from '../../../models/request/deviceRequest';
|
||||
import { TokenRequest } from '../../../models/request/tokenRequest';
|
||||
|
||||
class AuthService {
|
||||
|
||||
constructor(public cryptoService: any, public apiService: any, public userService: any, public tokenService: any,
|
||||
public $rootScope: any, public appIdService: any, public utilsService: any,
|
||||
public constantsService: any) {
|
||||
|
||||
}
|
||||
|
||||
async logIn(email: string, masterPassword: string, twoFactorProvider?: number,
|
||||
twoFactorToken?: string, remember?: boolean) {
|
||||
email = email.toLowerCase();
|
||||
|
||||
const key = this.cryptoService.makeKey(masterPassword, email);
|
||||
const appId = await this.appIdService.getAppId();
|
||||
const storedTwoFactorToken = await this.tokenService.getTwoFactorToken(email);
|
||||
const hashedPassword = await this.cryptoService.hashPassword(masterPassword, key);
|
||||
|
||||
const deviceRequest = new DeviceRequest(appId, this.utilsService);
|
||||
|
||||
let request: TokenRequest;
|
||||
|
||||
if (twoFactorToken != null && twoFactorProvider != null) {
|
||||
request = new TokenRequest(email, hashedPassword, twoFactorProvider, twoFactorToken, remember,
|
||||
deviceRequest);
|
||||
} else if (storedTwoFactorToken) {
|
||||
request = new TokenRequest(email, hashedPassword, this.constantsService.twoFactorProvider.remember,
|
||||
storedTwoFactorToken, false, deviceRequest);
|
||||
} else {
|
||||
request = new TokenRequest(email, hashedPassword, null, null, false, deviceRequest);
|
||||
}
|
||||
|
||||
const response = await this.apiService.postIdentityToken(request);
|
||||
if (!response) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!response.accessToken) {
|
||||
// two factor required
|
||||
return {
|
||||
twoFactor: true,
|
||||
twoFactorProviders: response,
|
||||
};
|
||||
}
|
||||
|
||||
if (response.twoFactorToken) {
|
||||
this.tokenService.setTwoFactorToken(response.twoFactorToken, email);
|
||||
}
|
||||
|
||||
await this.tokenService.setTokens(response.accessToken, response.refreshToken);
|
||||
await this.cryptoService.setKey(key);
|
||||
await this.cryptoService.setKeyHash(hashedPassword);
|
||||
await this.userService.setUserIdAndEmail(this.tokenService.getUserId(), this.tokenService.getEmail());
|
||||
await this.cryptoService.setEncKey(response.key);
|
||||
await this.cryptoService.setEncPrivateKey(response.privateKey);
|
||||
|
||||
chrome.runtime.sendMessage({ command: 'loggedIn' });
|
||||
return {
|
||||
twoFactor: false,
|
||||
twoFactorProviders: null,
|
||||
};
|
||||
}
|
||||
|
||||
logOut(callback: Function) {
|
||||
this.$rootScope.vaultCiphers = null;
|
||||
this.$rootScope.vaultFolders = null;
|
||||
callback();
|
||||
}
|
||||
}
|
||||
|
||||
export default AuthService;
|
||||
@@ -1,83 +0,0 @@
|
||||
angular
|
||||
.module('bit.services')
|
||||
|
||||
.factory('authService', function (cryptoService, apiService, userService, tokenService, $q, $rootScope,
|
||||
folderService, settingsService, syncService, appIdService, utilsService, constantsService) {
|
||||
var _service = {};
|
||||
|
||||
_service.logIn = function (email, masterPassword, twoFactorProvider, twoFactorToken, remember) {
|
||||
email = email.toLowerCase();
|
||||
var key = cryptoService.makeKey(masterPassword, email),
|
||||
deferred = $q.defer(),
|
||||
deviceRequest = null;
|
||||
|
||||
appIdService.getAppId().then(function (appId) {
|
||||
deviceRequest = new DeviceRequest(appId, utilsService);
|
||||
return tokenService.getTwoFactorToken(email);
|
||||
}).then(function (twoFactorRememberedToken) {
|
||||
cryptoService.hashPassword(masterPassword, key, function (hashedPassword) {
|
||||
var request;
|
||||
|
||||
if (twoFactorToken && typeof (twoFactorProvider) !== 'undefined' && twoFactorProvider !== null) {
|
||||
request = new TokenRequest(email, hashedPassword, twoFactorProvider, twoFactorToken, remember,
|
||||
deviceRequest);
|
||||
}
|
||||
else if (twoFactorRememberedToken) {
|
||||
request = new TokenRequest(email, hashedPassword, constantsService.twoFactorProvider.remember,
|
||||
twoFactorRememberedToken, false, deviceRequest);
|
||||
}
|
||||
else {
|
||||
request = new TokenRequest(email, hashedPassword, null, null, false, deviceRequest);
|
||||
}
|
||||
|
||||
apiService.postIdentityToken(request, function (response) {
|
||||
// success
|
||||
if (!response || !response.accessToken) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (response.twoFactorToken) {
|
||||
tokenService.setTwoFactorToken(response.twoFactorToken, email, function () { });
|
||||
}
|
||||
|
||||
tokenService.setTokens(response.accessToken, response.refreshToken, function () {
|
||||
cryptoService.setKey(key).then(function () {
|
||||
cryptoService.setKeyHash(hashedPassword, function () {
|
||||
userService.setUserIdAndEmail(tokenService.getUserId(), tokenService.getEmail(),
|
||||
function () {
|
||||
cryptoService.setEncKey(response.key).then(function () {
|
||||
return cryptoService.setEncPrivateKey(response.privateKey);
|
||||
}).then(function () {
|
||||
chrome.runtime.sendMessage({ command: 'loggedIn' });
|
||||
deferred.resolve({
|
||||
twoFactor: false,
|
||||
twoFactorProviders: null
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}, function (providers) {
|
||||
// two factor required
|
||||
deferred.resolve({
|
||||
twoFactor: true,
|
||||
twoFactorProviders: providers
|
||||
});
|
||||
}, function (error) {
|
||||
// error
|
||||
deferred.reject(error);
|
||||
});
|
||||
});
|
||||
});
|
||||
return deferred.promise;
|
||||
};
|
||||
|
||||
_service.logOut = function (callback) {
|
||||
$rootScope.vaultCiphers = null;
|
||||
$rootScope.vaultFolders = null;
|
||||
callback();
|
||||
};
|
||||
|
||||
return _service;
|
||||
});
|
||||
24
src/popup/app/services/background.service.ts
Normal file
24
src/popup/app/services/background.service.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
function getBackgroundService(service: string) {
|
||||
return () => {
|
||||
const page = chrome.extension.getBackgroundPage();
|
||||
return page ? page['bg_' + service] : null;
|
||||
};
|
||||
}
|
||||
|
||||
export const tokenService = getBackgroundService('tokenService');
|
||||
export const cryptoService = getBackgroundService('cryptoService');
|
||||
export const userService = getBackgroundService('userService');
|
||||
export const apiService = getBackgroundService('apiService');
|
||||
export const folderService = getBackgroundService('folderService');
|
||||
export const cipherService = getBackgroundService('cipherService');
|
||||
export const syncService = getBackgroundService('syncService');
|
||||
export const autofillService = getBackgroundService('autofillService');
|
||||
export const passwordGenerationService = getBackgroundService('passwordGenerationService');
|
||||
export const utilsService = getBackgroundService('utilsService');
|
||||
export const appIdService = getBackgroundService('appIdService');
|
||||
export const i18nService = getBackgroundService('i18nService');
|
||||
export const constantsService = getBackgroundService('constantsService');
|
||||
export const settingsService = getBackgroundService('settingsService');
|
||||
export const lockService = getBackgroundService('lockService');
|
||||
export const totpService = getBackgroundService('totpService');
|
||||
export const environmentService = getBackgroundService('environmentService');
|
||||
@@ -1,71 +0,0 @@
|
||||
angular
|
||||
.module('bit.services')
|
||||
|
||||
.factory('tokenService', function () {
|
||||
var page = chrome.extension.getBackgroundPage();
|
||||
return page ? page.bg_tokenService : null;
|
||||
})
|
||||
.factory('cryptoService', function () {
|
||||
var page = chrome.extension.getBackgroundPage();
|
||||
return page ? page.bg_cryptoService : null;
|
||||
})
|
||||
.factory('userService', function () {
|
||||
var page = chrome.extension.getBackgroundPage();
|
||||
return page ? page.bg_userService : null;
|
||||
})
|
||||
.factory('apiService', function () {
|
||||
var page = chrome.extension.getBackgroundPage();
|
||||
return page ? page.bg_apiService : null;
|
||||
})
|
||||
.factory('folderService', function () {
|
||||
var page = chrome.extension.getBackgroundPage();
|
||||
return page ? page.bg_folderService : null;
|
||||
})
|
||||
.factory('cipherService', function () {
|
||||
var page = chrome.extension.getBackgroundPage();
|
||||
return page ? page.bg_cipherService : null;
|
||||
})
|
||||
.factory('syncService', function () {
|
||||
var page = chrome.extension.getBackgroundPage();
|
||||
return page ? page.bg_syncService : null;
|
||||
})
|
||||
.factory('autofillService', function () {
|
||||
var page = chrome.extension.getBackgroundPage();
|
||||
return page ? page.bg_autofillService : null;
|
||||
})
|
||||
.factory('passwordGenerationService', function () {
|
||||
var page = chrome.extension.getBackgroundPage();
|
||||
return page ? page.bg_passwordGenerationService : null;
|
||||
})
|
||||
.factory('utilsService', function () {
|
||||
var page = chrome.extension.getBackgroundPage();
|
||||
return page ? page.bg_utilsService : null;
|
||||
})
|
||||
.factory('appIdService', function () {
|
||||
var page = chrome.extension.getBackgroundPage();
|
||||
return page ? page.bg_appIdService : null;
|
||||
})
|
||||
.factory('i18nService', function () {
|
||||
var page = chrome.extension.getBackgroundPage();
|
||||
return page ? page.bg_i18nService : null;
|
||||
})
|
||||
.factory('constantsService', function () {
|
||||
var page = chrome.extension.getBackgroundPage();
|
||||
return page ? page.bg_constantsService : null;
|
||||
})
|
||||
.factory('settingsService', function () {
|
||||
var page = chrome.extension.getBackgroundPage();
|
||||
return page ? page.bg_settingsService : null;
|
||||
})
|
||||
.factory('lockService', function () {
|
||||
var page = chrome.extension.getBackgroundPage();
|
||||
return page ? page.bg_lockService : null;
|
||||
})
|
||||
.factory('totpService', function () {
|
||||
var page = chrome.extension.getBackgroundPage();
|
||||
return page ? page.bg_totpService : null;
|
||||
})
|
||||
.factory('environmentService', function () {
|
||||
var page = chrome.extension.getBackgroundPage();
|
||||
return page ? page.bg_environmentService : null;
|
||||
});
|
||||
31
src/popup/app/services/services.module.ts
Normal file
31
src/popup/app/services/services.module.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
import * as angular from 'angular';
|
||||
import AuthService from './auth.service';
|
||||
import * as backgroundServices from './background.service';
|
||||
import StateService from './state.service';
|
||||
import ValidationService from './validation.service';
|
||||
|
||||
export default angular
|
||||
.module('bit.services', ['toastr'])
|
||||
.service('stateService', StateService)
|
||||
.service('validationService', ValidationService)
|
||||
.service('authService', AuthService)
|
||||
|
||||
.factory('tokenService', backgroundServices.tokenService)
|
||||
.factory('cryptoService', backgroundServices.cryptoService)
|
||||
.factory('userService', backgroundServices.userService)
|
||||
.factory('apiService', backgroundServices.apiService)
|
||||
.factory('folderService', backgroundServices.folderService)
|
||||
.factory('cipherService', backgroundServices.cipherService)
|
||||
.factory('syncService', backgroundServices.syncService)
|
||||
.factory('autofillService', backgroundServices.autofillService)
|
||||
.factory('passwordGenerationService', backgroundServices.passwordGenerationService)
|
||||
.factory('utilsService', backgroundServices.utilsService)
|
||||
.factory('appIdService', backgroundServices.appIdService)
|
||||
.factory('i18nService', backgroundServices.i18nService)
|
||||
.factory('constantsService', backgroundServices.constantsService)
|
||||
.factory('settingsService', backgroundServices.settingsService)
|
||||
.factory('lockService', backgroundServices.lockService)
|
||||
.factory('totpService', backgroundServices.totpService)
|
||||
.factory('environmentService', backgroundServices.environmentService)
|
||||
|
||||
.name;
|
||||
@@ -1,2 +0,0 @@
|
||||
angular
|
||||
.module('bit.services', ['toastr']);
|
||||
35
src/popup/app/services/state.service.ts
Normal file
35
src/popup/app/services/state.service.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
class StateService {
|
||||
private state: any = {};
|
||||
|
||||
constructor(private utilsService: any, private constantsService: any) {
|
||||
}
|
||||
|
||||
async init() {
|
||||
const faviconsDisabled = await this.utilsService
|
||||
.getObjFromStorage(this.constantsService.disableFaviconKey);
|
||||
|
||||
this.saveState('faviconEnabled', !faviconsDisabled);
|
||||
}
|
||||
|
||||
saveState(key: string, data: any) {
|
||||
this.state[key] = data;
|
||||
}
|
||||
|
||||
getState(key: string): any {
|
||||
if (key in this.state) {
|
||||
return this.state[key];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
removeState(key: string) {
|
||||
delete this.state[key];
|
||||
}
|
||||
|
||||
purgeState() {
|
||||
this.state = {};
|
||||
}
|
||||
}
|
||||
|
||||
export default StateService;
|
||||
@@ -1,35 +0,0 @@
|
||||
angular
|
||||
.module('bit.services')
|
||||
|
||||
.factory('stateService', function (utilsService, constantsService) {
|
||||
var _service = {},
|
||||
_state = {};
|
||||
|
||||
_service.init = function () {
|
||||
utilsService.getObjFromStorage(constantsService.disableFaviconKey).then(function (disabledFavicons) {
|
||||
_service.saveState('faviconEnabled', !disabledFavicons);
|
||||
});
|
||||
};
|
||||
|
||||
_service.saveState = function (key, data) {
|
||||
_state[key] = data;
|
||||
};
|
||||
|
||||
_service.getState = function (key) {
|
||||
if (key in _state) {
|
||||
return _state[key];
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
_service.removeState = function (key) {
|
||||
delete _state[key];
|
||||
};
|
||||
|
||||
_service.purgeState = function () {
|
||||
_state = {};
|
||||
};
|
||||
|
||||
return _service;
|
||||
});
|
||||
33
src/popup/app/services/validation.service.ts
Normal file
33
src/popup/app/services/validation.service.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
import * as angular from 'angular';
|
||||
|
||||
class ValidationService {
|
||||
|
||||
constructor(private toastr: any, private i18nService: any) {
|
||||
}
|
||||
|
||||
showError(data: any) {
|
||||
const defaultErrorMessage = this.i18nService.unexpectedError;
|
||||
const errors: string[] = [];
|
||||
|
||||
if (!data || !angular.isObject(data)) {
|
||||
errors.push(defaultErrorMessage);
|
||||
} else if (!data.validationErrors) {
|
||||
errors.push(data.message ? data.message : defaultErrorMessage);
|
||||
} else {
|
||||
for (const error of data.validationErrors) {
|
||||
error.forEach((item: string) => {
|
||||
errors.push(item);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (errors.length) {
|
||||
this.toastr.error(errors[0], this.i18nService.errorsOccurred);
|
||||
}
|
||||
|
||||
return errors;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default ValidationService;
|
||||
@@ -1,42 +0,0 @@
|
||||
angular
|
||||
.module('bit.services')
|
||||
|
||||
.factory('validationService', function (toastr, i18nService) {
|
||||
var _service = {};
|
||||
|
||||
_service.showError = function (data) {
|
||||
var defaultErrorMessage = i18nService.unexpectedError;
|
||||
var errors = [];
|
||||
|
||||
if (!data || !angular.isObject(data)) {
|
||||
errors.push(defaultErrorMessage);
|
||||
}
|
||||
else if (!data.validationErrors) {
|
||||
if (data.message) {
|
||||
errors.push(data.message);
|
||||
}
|
||||
else {
|
||||
errors.push(defaultErrorMessage);
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (var key in data.validationErrors) {
|
||||
if (!data.validationErrors.hasOwnProperty(key)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (var i = 0; i < data.validationErrors[key].length; i++) {
|
||||
errors.push(data.validationErrors[key][i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (errors.length) {
|
||||
toastr.error(errors[0], i18nService.errorsOccurred);
|
||||
}
|
||||
|
||||
return errors;
|
||||
};
|
||||
|
||||
return _service;
|
||||
});
|
||||
@@ -2,12 +2,14 @@ angular
|
||||
.module('bit.settings')
|
||||
|
||||
.controller('settingsAddFolderController', function ($scope, $q, folderService, $state, toastr, utilsService,
|
||||
$analytics, i18nService) {
|
||||
$analytics, i18nService, $timeout) {
|
||||
$timeout(function () {
|
||||
utilsService.initListSectionItemListeners(document, angular);
|
||||
document.getElementById('name').focus();
|
||||
}, 500);
|
||||
|
||||
$scope.i18n = i18nService;
|
||||
$scope.folder = {};
|
||||
utilsService.initListSectionItemListeners($(document), angular);
|
||||
$('#name').focus();
|
||||
|
||||
$scope.savePromise = null;
|
||||
$scope.save = function (model) {
|
||||
if (!model.name) {
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
angular
|
||||
angular
|
||||
.module('bit.settings')
|
||||
|
||||
.controller('settingsController', function ($scope, $state, SweetAlert, utilsService, $analytics,
|
||||
i18nService, constantsService, cryptoService, lockService) {
|
||||
utilsService.initListSectionItemListeners($(document), angular);
|
||||
i18nService, constantsService, cryptoService, lockService, $timeout) {
|
||||
$timeout(function () {
|
||||
utilsService.initListSectionItemListeners(document, angular);
|
||||
}, 500);
|
||||
|
||||
$scope.showOnLocked = !utilsService.isFirefox() && !utilsService.isEdge();
|
||||
$scope.lockOption = '';
|
||||
$scope.i18n = i18nService;
|
||||
@@ -31,7 +34,7 @@
|
||||
}
|
||||
|
||||
chrome.storage.local.set(obj, function () {
|
||||
cryptoService.getKeyHash(function (keyHash) {
|
||||
cryptoService.getKeyHash().then(function (keyHash) {
|
||||
if (keyHash) {
|
||||
cryptoService.toggleKey();
|
||||
}
|
||||
|
||||
@@ -1,12 +1,16 @@
|
||||
angular
|
||||
angular
|
||||
.module('bit.settings')
|
||||
|
||||
.controller('settingsEditFolderController', function ($scope, $stateParams, folderService, toastr, $state, SweetAlert,
|
||||
utilsService, $analytics, i18nService) {
|
||||
utilsService, $analytics, i18nService, $timeout) {
|
||||
$timeout(function () {
|
||||
utilsService.initListSectionItemListeners(document, angular);
|
||||
document.getElementById('name').focus();
|
||||
}, 500);
|
||||
|
||||
$scope.i18n = i18nService;
|
||||
$scope.folder = {};
|
||||
var folderId = $stateParams.folderId;
|
||||
$('#name').focus();
|
||||
|
||||
folderService.get(folderId).then(function (folder) {
|
||||
return folder.decrypt();
|
||||
@@ -14,8 +18,6 @@
|
||||
$scope.folder = model;
|
||||
});
|
||||
|
||||
utilsService.initListSectionItemListeners($(document), angular);
|
||||
|
||||
$scope.savePromise = null;
|
||||
$scope.save = function (model) {
|
||||
if (!model.name) {
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
angular
|
||||
angular
|
||||
.module('bit.settings')
|
||||
|
||||
.controller('settingsEnvironmentController', function ($scope, i18nService, $analytics, utilsService,
|
||||
environmentService, toastr, $timeout) {
|
||||
$timeout(function () {
|
||||
utilsService.initListSectionItemListeners(document, angular);
|
||||
}, 500);
|
||||
|
||||
$scope.i18n = i18nService;
|
||||
|
||||
utilsService.initListSectionItemListeners($(document), angular);
|
||||
|
||||
$scope.baseUrl = environmentService.baseUrl || '';
|
||||
$scope.webVaultUrl = environmentService.webVaultUrl || '';
|
||||
$scope.apiUrl = environmentService.apiUrl || '';
|
||||
@@ -20,7 +21,7 @@
|
||||
identity: $scope.identityUrl,
|
||||
webVault: $scope.webVaultUrl,
|
||||
icons: $scope.iconsUrl
|
||||
}, function (resUrls) {
|
||||
}).then(function (resUrls) {
|
||||
$timeout(function () {
|
||||
// re-set urls since service can change them, ex: prefixing https://
|
||||
$scope.baseUrl = resUrls.base;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
angular
|
||||
angular
|
||||
.module('bit.settings')
|
||||
|
||||
.controller('settingsPremiumController', function ($scope, i18nService, tokenService, apiService, toastr, SweetAlert,
|
||||
@@ -8,7 +8,7 @@
|
||||
$scope.price = '$10';
|
||||
|
||||
$scope.refresh = function () {
|
||||
apiService.refreshIdentityToken(function () {
|
||||
apiService.refreshIdentityToken().then(function () {
|
||||
toastr.success(i18nService.refreshComplete);
|
||||
$timeout(function () {
|
||||
$scope.isPremium = tokenService.getPremium();
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
angular
|
||||
angular
|
||||
.module('bit.settings')
|
||||
|
||||
.controller('settingsSyncController', function ($scope, syncService, toastr, $analytics, i18nService) {
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
$scope.sync = function () {
|
||||
$scope.loading = true;
|
||||
syncService.fullSync(true, function (success) {
|
||||
syncService.fullSync(true).then(function (success) {
|
||||
$scope.loading = false;
|
||||
setLastSync();
|
||||
if (success) {
|
||||
@@ -23,7 +23,7 @@
|
||||
};
|
||||
|
||||
function setLastSync() {
|
||||
syncService.getLastSync(function (lastSync) {
|
||||
syncService.getLastSync().then(function (lastSync) {
|
||||
if (lastSync) {
|
||||
$scope.lastSync = lastSync.toLocaleDateString() + ' ' + lastSync.toLocaleTimeString();
|
||||
}
|
||||
|
||||
@@ -1,84 +1,84 @@
|
||||
<div class="header">
|
||||
<div class="left">
|
||||
<a ng-click="close()" href="">{{i18n.close}}</a>
|
||||
<a ng-click="$ctrl.close()" href="">{{$ctrl.i18n.close}}</a>
|
||||
</div>
|
||||
<div class="right">
|
||||
<a ng-click="select()" ng-show="showSelect" href="">{{i18n.select}}</a>
|
||||
<a ng-click="$ctrl.select()" ng-show="$ctrl.showSelect" href="">{{$ctrl.i18n.select}}</a>
|
||||
</div>
|
||||
<div class="title">{{i18n.generatePassword}}</div>
|
||||
<div class="title">{{$ctrl.i18n.generatePassword}}</div>
|
||||
</div>
|
||||
<div class="content">
|
||||
<div class="generate-password-block">
|
||||
{{password}}
|
||||
{{$ctrl.password}}
|
||||
</div>
|
||||
<div class="list" style="margin-top: 0;">
|
||||
<div class="list-section" style="padding-top: 0;">
|
||||
<div class="list-section-items">
|
||||
<a class="list-section-item text-primary" href="" ng-click="regenerate(true)">
|
||||
{{i18n.regeneratePassword}}
|
||||
<a class="list-section-item text-primary" href="" ng-click="$ctrl.regenerate(true)">
|
||||
{{$ctrl.i18n.regeneratePassword}}
|
||||
</a>
|
||||
<a class="list-section-item text-primary" href="" ngclipboard ngclipboard-error="clipboardError(e)"
|
||||
ngclipboard-success="clipboardSuccess(e)" data-clipboard-text="{{password}}">
|
||||
{{i18n.copyPassword}}
|
||||
<a class="list-section-item text-primary" href="" ngclipboard ngclipboard-error="$ctrl.clipboardError(e)"
|
||||
ngclipboard-success="$ctrl.clipboardSuccess(e)" data-clipboard-text="{{$ctrl.password}}">
|
||||
{{$ctrl.i18n.copyPassword}}
|
||||
</a>
|
||||
<a class="list-section-item text-primary" href="" ng-click="goHistory()">
|
||||
{{i18n.passwordHistory}}
|
||||
<a class="list-section-item text-primary" href="" ng-click="$ctrl.goHistory()">
|
||||
{{$ctrl.i18n.passwordHistory}}
|
||||
<i class="fa fa-chevron-right fa-lg"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="list-section">
|
||||
<div class="list-section-header">
|
||||
{{i18n.options}}
|
||||
{{$ctrl.i18n.options}}
|
||||
</div>
|
||||
<div class="list-section-items">
|
||||
<div class="list-section-item list-section-item-slider">
|
||||
<label for="length">{{i18n.length}}</label>
|
||||
<span class="slider-value">{{options.length}}</span>
|
||||
<label for="length">{{$ctrl.i18n.length}}</label>
|
||||
<span class="slider-value">{{$ctrl.options.length}}</span>
|
||||
<div class="slider-wrapper">
|
||||
<input id="length" type="range" min="5" max="128" step="1" ng-model="options.length"
|
||||
ng-change="sliderMoved()">
|
||||
<input id="length" type="range" min="5" max="128" step="1" ng-model="$ctrl.options.length"
|
||||
ng-change="$ctrl.sliderMoved()">
|
||||
</div>
|
||||
</div>
|
||||
<div class="list-section-item list-section-item-checkbox">
|
||||
<label for="uppercase">A-Z</label>
|
||||
<input id="uppercase" type="checkbox" ng-model="options.uppercase" ng-change="saveOptions(options)">
|
||||
<input id="uppercase" type="checkbox" ng-model="$ctrl.options.uppercase" ng-change="$ctrl.saveOptions($ctrl.options)">
|
||||
</div>
|
||||
<div class="list-section-item list-section-item-checkbox">
|
||||
<label for="lowercase">a-z</label>
|
||||
<input id="lowercase" type="checkbox" ng-model="options.lowercase" ng-change="saveOptions(options)">
|
||||
<input id="lowercase" type="checkbox" ng-model="$ctrl.options.lowercase" ng-change="$ctrl.saveOptions($ctrl.options)">
|
||||
</div>
|
||||
<div class="list-section-item list-section-item-checkbox">
|
||||
<label for="numbers">0-9</label>
|
||||
<input id="numbers" type="checkbox" ng-model="options.number" ng-change="saveOptions(options)">
|
||||
<input id="numbers" type="checkbox" ng-model="$ctrl.options.number" ng-change="$ctrl.saveOptions($ctrl.options)">
|
||||
</div>
|
||||
<div class="list-section-item list-section-item-checkbox">
|
||||
<label for="special">!@#$%^&*</label>
|
||||
<input id="special" type="checkbox" ng-model="options.special" ng-change="saveOptions(options)">
|
||||
<input id="special" type="checkbox" ng-model="$ctrl.options.special" ng-change="$ctrl.saveOptions($ctrl.options)">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="list-section">
|
||||
<div class="list-section-items">
|
||||
<div class="list-section-item list-section-item-input">
|
||||
<label for="min-numbers">{{i18n.minNumbers}}</label>
|
||||
<input id="min-numbers" type="number" min="0" max="5" ng-model="options.minNumber"
|
||||
ng-change="saveOptions(options)">
|
||||
<label for="min-numbers">{{$ctrl.i18n.minNumbers}}</label>
|
||||
<input id="min-numbers" type="number" min="0" max="5" ng-model="$ctrl.options.minNumber"
|
||||
ng-change="$ctrl.saveOptions($ctrl.options)">
|
||||
</div>
|
||||
<div class="list-section-item list-section-item-input">
|
||||
<label for="min-special">{{i18n.minSpecial}}</label>
|
||||
<input id="min-special" type="number" min="0" max="5" ng-model="options.minSpecial"
|
||||
ng-change="saveOptions(options)">
|
||||
<label for="min-special">{{$ctrl.i18n.minSpecial}}</label>
|
||||
<input id="min-special" type="number" min="0" max="5" ng-model="$ctrl.options.minSpecial"
|
||||
ng-change="$ctrl.saveOptions($ctrl.options)">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="list-section">
|
||||
<div class="list-section-items">
|
||||
<div class="list-section-item list-section-item-checkbox">
|
||||
<label for="ambiguous">{{i18n.avoidAmbChar}}</label>
|
||||
<input id="ambiguous" type="checkbox" ng-model="options.ambiguous"
|
||||
<label for="ambiguous">{{$ctrl.i18n.avoidAmbChar}}</label>
|
||||
<input id="ambiguous" type="checkbox" ng-model="$ctrl.options.ambiguous"
|
||||
ng-true-value="false" ng-false-value="true"
|
||||
ng-change="saveOptions(options)">
|
||||
ng-change="$ctrl.saveOptions($ctrl.options)">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
142
src/popup/app/tools/password-generator.component.ts
Normal file
142
src/popup/app/tools/password-generator.component.ts
Normal file
@@ -0,0 +1,142 @@
|
||||
import * as angular from 'angular';
|
||||
import * as template from './password-generator.component.html';
|
||||
|
||||
export class PasswordGeneratorController {
|
||||
$transition$: any;
|
||||
options: any;
|
||||
showSelect: any;
|
||||
password: string = '-';
|
||||
editState: any;
|
||||
addState: any;
|
||||
i18n: any;
|
||||
|
||||
constructor(private $state: any, private passwordGenerationService: any,
|
||||
private toastr: any, private utilsService: any, private $analytics: any,
|
||||
private i18nService: any, private $timeout: any) {
|
||||
this.i18n = i18nService;
|
||||
|
||||
passwordGenerationService.getOptions().then((options: any) => {
|
||||
this.options = options;
|
||||
this.regenerate(false);
|
||||
$analytics.eventTrack('Generated Password');
|
||||
passwordGenerationService.addHistory(this.password);
|
||||
});
|
||||
|
||||
// Save password once the slider stop moving.
|
||||
document.querySelector('#length').addEventListener('change', (e) => {
|
||||
e.preventDefault();
|
||||
|
||||
$analytics.eventTrack('Generated Password');
|
||||
this.saveOptions(this.options, false);
|
||||
passwordGenerationService.addHistory(this.password);
|
||||
});
|
||||
}
|
||||
|
||||
$onInit() {
|
||||
const params = this.$transition$.params('to');
|
||||
this.addState = params.addState;
|
||||
this.editState = params.editState;
|
||||
|
||||
this.showSelect = this.addState || this.editState;
|
||||
|
||||
const self = this;
|
||||
this.$timeout(() => {
|
||||
self.utilsService.initListSectionItemListeners(document, angular);
|
||||
}, 500);
|
||||
}
|
||||
|
||||
sliderMoved() {
|
||||
this.regenerate(false);
|
||||
}
|
||||
|
||||
regenerate(trackEvent: any) {
|
||||
this.password = this.passwordGenerationService.generatePassword(this.options);
|
||||
|
||||
if (trackEvent) {
|
||||
this.$analytics.eventTrack('Regenerated Password');
|
||||
this.passwordGenerationService.addHistory(this.password);
|
||||
}
|
||||
}
|
||||
|
||||
saveOptions(options: any, regenerate: boolean = true) {
|
||||
if (!options.uppercase && !options.lowercase && !options.number && !options.special) {
|
||||
options.lowercase = this.options.lowercase = true;
|
||||
}
|
||||
if (!options.minNumber) {
|
||||
options.minNumber = this.options.minNumber = 0;
|
||||
}
|
||||
if (!options.minSpecial) {
|
||||
options.minSpecial = this.options.minSpecial = 0;
|
||||
}
|
||||
|
||||
this.passwordGenerationService.saveOptions(options);
|
||||
if (regenerate) {
|
||||
this.regenerate(false);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
clipboardError(e: any, password: any) {
|
||||
this.toastr.info(this.i18nService.browserNotSupportClipboard);
|
||||
}
|
||||
|
||||
clipboardSuccess(e: any) {
|
||||
this.$analytics.eventTrack('Copied Generated Password');
|
||||
e.clearSelection();
|
||||
this.toastr.info(this.i18nService.passwordCopied);
|
||||
}
|
||||
|
||||
close() {
|
||||
this.dismiss();
|
||||
}
|
||||
|
||||
select() {
|
||||
this.$analytics.eventTrack('Selected Generated Password');
|
||||
|
||||
if (this.addState) {
|
||||
this.addState.cipher.login.password = this.password;
|
||||
} else if (this.editState) {
|
||||
this.editState.cipher.login.password = this.password;
|
||||
}
|
||||
|
||||
this.dismiss();
|
||||
}
|
||||
|
||||
goHistory() {
|
||||
this.$state.go('^.passwordGeneratorHistory', {
|
||||
animation: 'in-slide-left',
|
||||
addState: this.addState,
|
||||
editState: this.editState,
|
||||
});
|
||||
}
|
||||
|
||||
private dismiss() {
|
||||
if (this.addState) {
|
||||
this.$state.go('addCipher', {
|
||||
animation: 'out-slide-down',
|
||||
from: this.addState.from,
|
||||
cipher: this.addState.cipher,
|
||||
});
|
||||
} else if (this.editState) {
|
||||
this.$state.go('editCipher', {
|
||||
animation: 'out-slide-down',
|
||||
cipher: this.editState.cipher,
|
||||
fromView: this.editState.fromView,
|
||||
cipherId: this.editState.cipherId,
|
||||
from: this.editState.from,
|
||||
});
|
||||
} else {
|
||||
this.$state.go('tabs.tools', {
|
||||
animation: 'out-slide-down',
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const PasswordGeneratorComponent = {
|
||||
bindings: {
|
||||
$transition$: '<',
|
||||
},
|
||||
controller: PasswordGeneratorController,
|
||||
template,
|
||||
};
|
||||
52
src/popup/app/tools/tools.component.ts
Normal file
52
src/popup/app/tools/tools.component.ts
Normal file
@@ -0,0 +1,52 @@
|
||||
import UtilsService from '../../../services/utils.service';
|
||||
import * as template from './views/tools.html';
|
||||
|
||||
class ToolsController {
|
||||
showExport: boolean;
|
||||
i18n: any;
|
||||
|
||||
constructor(private SweetAlert: any, private i18nService: any,
|
||||
private $analytics: any, private utilsService: UtilsService) {
|
||||
this.i18n = i18nService;
|
||||
this.showExport = !utilsService.isEdge();
|
||||
}
|
||||
|
||||
launchWebVault(createOrg: any) {
|
||||
this.$analytics.eventTrack('Launch Web Vault' + (createOrg ? ' For Share' : ''));
|
||||
chrome.tabs.create({ url: 'https://vault.bitwarden.com/#/' + (createOrg ? '?org=free' : '') });
|
||||
}
|
||||
|
||||
launchAndroid() {
|
||||
this.$analytics.eventTrack('Launch Android');
|
||||
chrome.tabs.create({ url: 'https://play.google.com/store/apps/details?id=com.x8bit.bitwarden' });
|
||||
}
|
||||
|
||||
launchiOS() {
|
||||
this.$analytics.eventTrack('Launch iOS');
|
||||
chrome.tabs.create({
|
||||
url: 'https://itunes.apple.com/us/app/bitwarden-free-password-manager/' +
|
||||
'id1137397744?mt=8',
|
||||
});
|
||||
}
|
||||
|
||||
launchImport() {
|
||||
this.SweetAlert.swal({
|
||||
title: this.i18nService.importItems,
|
||||
text: this.i18nService.importItemsConfirmation,
|
||||
showCancelButton: true,
|
||||
confirmButtonText: this.i18nService.yes,
|
||||
cancelButtonText: this.i18nService.cancel,
|
||||
}, (confirmed: boolean) => {
|
||||
if (confirmed) {
|
||||
this.$analytics.eventTrack('Launch Web Vault For Import');
|
||||
chrome.tabs.create({ url: 'https://help.bitwarden.com/article/import-data/' });
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export const ToolsComponent = {
|
||||
bindings: {},
|
||||
controller: ToolsController,
|
||||
template,
|
||||
};
|
||||
11
src/popup/app/tools/tools.module.ts
Normal file
11
src/popup/app/tools/tools.module.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import * as angular from 'angular';
|
||||
import { PasswordGeneratorComponent } from './password-generator.component';
|
||||
import { ToolsComponent } from './tools.component';
|
||||
|
||||
export default angular
|
||||
.module('bit.tools', ['ngAnimate', 'ngclipboard', 'toastr', 'oitozero.ngSweetAlert'])
|
||||
|
||||
.component('tools', ToolsComponent)
|
||||
.component('passwordGenerator', PasswordGeneratorComponent)
|
||||
|
||||
.name;
|
||||
@@ -1,36 +0,0 @@
|
||||
angular
|
||||
.module('bit.tools')
|
||||
|
||||
.controller('toolsController', function ($scope, SweetAlert, i18nService, $analytics, utilsService) {
|
||||
$scope.i18n = i18nService;
|
||||
$scope.showExport = !utilsService.isEdge();
|
||||
$scope.launchWebVault = function (createOrg) {
|
||||
$analytics.eventTrack('Launch Web Vault' + (createOrg ? ' For Share' : ''));
|
||||
chrome.tabs.create({ url: 'https://vault.bitwarden.com/#/' + (createOrg ? '?org=free' : '') });
|
||||
};
|
||||
|
||||
$scope.launchiOS = function () {
|
||||
$analytics.eventTrack('Launch iOS');
|
||||
chrome.tabs.create({ url: 'https://itunes.apple.com/us/app/bitwarden-free-password-manager/id1137397744?mt=8' });
|
||||
};
|
||||
|
||||
$scope.launchAndroid = function () {
|
||||
$analytics.eventTrack('Launch Android');
|
||||
chrome.tabs.create({ url: 'https://play.google.com/store/apps/details?id=com.x8bit.bitwarden' });
|
||||
};
|
||||
|
||||
$scope.launchImport = function () {
|
||||
SweetAlert.swal({
|
||||
title: i18nService.importItems,
|
||||
text: i18nService.importItemsConfirmation,
|
||||
showCancelButton: true,
|
||||
confirmButtonText: i18nService.yes,
|
||||
cancelButtonText: i18nService.cancel
|
||||
}, function (confirmed) {
|
||||
if (confirmed) {
|
||||
$analytics.eventTrack('Launch Web Vault For Import');
|
||||
chrome.tabs.create({ url: 'https://help.bitwarden.com/article/import-data/' });
|
||||
}
|
||||
});
|
||||
};
|
||||
});
|
||||
@@ -1,11 +1,10 @@
|
||||
angular
|
||||
angular
|
||||
.module('bit.tools')
|
||||
|
||||
.controller('toolsExportController', function ($scope, $state, toastr, $q, $analytics,
|
||||
i18nService, cryptoService, userService, folderService, cipherService, $window, constantsService) {
|
||||
$scope.i18n = i18nService;
|
||||
|
||||
$('#master-password').focus();
|
||||
document.getElementById('master-password').focus();
|
||||
|
||||
$scope.submitPromise = null;
|
||||
$scope.submit = function () {
|
||||
@@ -22,17 +21,19 @@
|
||||
function checkPassword() {
|
||||
var deferred = $q.defer();
|
||||
|
||||
userService.getEmail(function (email) {
|
||||
userService.getEmail().then(function (email) {
|
||||
var key = cryptoService.makeKey($scope.masterPassword, email);
|
||||
cryptoService.hashPassword($scope.masterPassword, key, function (keyHash) {
|
||||
cryptoService.getKeyHash(function (storedKeyHash) {
|
||||
if (storedKeyHash && keyHash && storedKeyHash === keyHash) {
|
||||
deferred.resolve();
|
||||
}
|
||||
else {
|
||||
deferred.reject();
|
||||
}
|
||||
});
|
||||
var keyHash;
|
||||
cryptoService.hashPassword($scope.masterPassword, key).then(function (theKeyHash) {
|
||||
keyHash = theKeyHash;
|
||||
return cryptoService.getKeyHash();
|
||||
}).then(function (storedKeyHash) {
|
||||
if (storedKeyHash && keyHash && storedKeyHash === keyHash) {
|
||||
deferred.resolve();
|
||||
}
|
||||
else {
|
||||
deferred.reject();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
angular
|
||||
.module('bit.tools', ['ngAnimate', 'ngclipboard', 'toastr', 'oitozero.ngSweetAlert']);
|
||||
@@ -1,116 +0,0 @@
|
||||
angular
|
||||
.module('bit.tools')
|
||||
|
||||
.controller('toolsPasswordGeneratorController', function ($scope, $state, $stateParams, passwordGenerationService,
|
||||
toastr, utilsService, $analytics, i18nService) {
|
||||
$scope.i18n = i18nService;
|
||||
var addState = $stateParams.addState,
|
||||
editState = $stateParams.editState;
|
||||
|
||||
$scope.showSelect = $stateParams.addState || $stateParams.editState;
|
||||
|
||||
utilsService.initListSectionItemListeners($(document), angular);
|
||||
$scope.password = '-';
|
||||
|
||||
passwordGenerationService.getOptions().then(function (options) {
|
||||
$scope.options = options;
|
||||
$scope.regenerate(false);
|
||||
$analytics.eventTrack('Generated Password');
|
||||
passwordGenerationService.addHistory($scope.password);
|
||||
});
|
||||
|
||||
$scope.sliderMoved = function () {
|
||||
$scope.regenerate(false);
|
||||
};
|
||||
|
||||
$('#length').change(function (e) {
|
||||
e.preventDefault();
|
||||
$analytics.eventTrack('Generated Password');
|
||||
$scope.saveOptions($scope.options);
|
||||
passwordGenerationService.addHistory($scope.password);
|
||||
});
|
||||
|
||||
$scope.regenerate = function (trackEvent) {
|
||||
$scope.password = passwordGenerationService.generatePassword($scope.options);
|
||||
|
||||
if (trackEvent) {
|
||||
$analytics.eventTrack('Regenerated Password');
|
||||
passwordGenerationService.addHistory($scope.password);
|
||||
}
|
||||
};
|
||||
|
||||
$scope.saveOptions = function (options) {
|
||||
if (!options.uppercase && !options.lowercase && !options.number && !options.special) {
|
||||
options.lowercase = $scope.options.lowercase = true;
|
||||
}
|
||||
if (!options.minNumber) {
|
||||
options.minNumber = $scope.options.minNumber = 0;
|
||||
}
|
||||
if (!options.minSpecial) {
|
||||
options.minSpecial = $scope.options.minSpecial = 0;
|
||||
}
|
||||
|
||||
passwordGenerationService.saveOptions(options);
|
||||
$scope.regenerate(false);
|
||||
return true;
|
||||
};
|
||||
|
||||
$scope.clipboardError = function (e, password) {
|
||||
toastr.info(i18n.browserNotSupportClipboard);
|
||||
};
|
||||
|
||||
$scope.clipboardSuccess = function (e) {
|
||||
$analytics.eventTrack('Copied Generated Password');
|
||||
e.clearSelection();
|
||||
toastr.info(i18nService.passwordCopied);
|
||||
};
|
||||
|
||||
$scope.close = function () {
|
||||
dismiss();
|
||||
};
|
||||
|
||||
$scope.select = function () {
|
||||
$analytics.eventTrack('Selected Generated Password');
|
||||
|
||||
if (addState) {
|
||||
addState.cipher.login.password = $scope.password;
|
||||
}
|
||||
else if (editState) {
|
||||
editState.cipher.login.password = $scope.password;
|
||||
}
|
||||
|
||||
dismiss();
|
||||
};
|
||||
|
||||
$scope.goHistory = function () {
|
||||
$state.go('^.passwordGeneratorHistory', {
|
||||
animation: 'in-slide-left',
|
||||
addState: $stateParams.addState,
|
||||
editState: $stateParams.editState
|
||||
});
|
||||
};
|
||||
|
||||
function dismiss() {
|
||||
if (addState) {
|
||||
$state.go('addCipher', {
|
||||
animation: 'out-slide-down',
|
||||
from: addState.from,
|
||||
cipher: addState.cipher
|
||||
});
|
||||
}
|
||||
else if (editState) {
|
||||
$state.go('editCipher', {
|
||||
animation: 'out-slide-down',
|
||||
cipher: editState.cipher,
|
||||
fromView: editState.fromView,
|
||||
cipherId: editState.cipherId,
|
||||
from: editState.from
|
||||
});
|
||||
}
|
||||
else {
|
||||
$state.go('tabs.tools', {
|
||||
animation: 'out-slide-down'
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -2,7 +2,7 @@
|
||||
<div class="left">
|
||||
<a href="" ng-click="main.expandVault()"><i class="fa fa-external-link fa-rotate-270 fa-lg"></i></a>
|
||||
</div>
|
||||
<div class="title">{{i18n.tools}}</div>
|
||||
<div class="title">{{$ctrl.i18n.tools}}</div>
|
||||
</div>
|
||||
<div class="content content-tabs">
|
||||
<div class="list">
|
||||
@@ -10,38 +10,38 @@
|
||||
<div class="list-section-items">
|
||||
<a class="list-section-item wrap" ui-sref="passwordGenerator({animation: 'in-slide-up'})">
|
||||
<span class="leading-icon" style="color: #eba776;"><i class="fa fa-refresh fa-fw"></i></span>
|
||||
<span class="text">{{i18n.passGen}}</span>
|
||||
<span class="detail">{{i18n.passGenInfo}}</span>
|
||||
<span class="text">{{$ctrl.i18n.passGen}}</span>
|
||||
<span class="detail">{{$ctrl.i18n.passGenInfo}}</span>
|
||||
</a>
|
||||
<a class="list-section-item wrap" href="" ng-click="launchWebVault()">
|
||||
<a class="list-section-item wrap" href="" ng-click="$ctrl.launchWebVault()">
|
||||
<span class="leading-icon" style="color: #5bb630;"><i class="fa fa-globe fa-fw"></i></span>
|
||||
<span class="text">{{i18n.bitWebVault}}</span>
|
||||
<span class="detail">{{i18n.bitWebVaultInfo}}</span>
|
||||
<span class="text">{{$ctrl.i18n.bitWebVault}}</span>
|
||||
<span class="detail">{{$ctrl.i18n.bitWebVaultInfo}}</span>
|
||||
</a>
|
||||
<a class="list-section-item wrap" href="" ng-click="launchiOS()">
|
||||
<a class="list-section-item wrap" href="" ng-click="$ctrl.launchiOS()">
|
||||
<span class="leading-icon" style="color: #999999;"><i class="fa fa-apple fa-fw"></i></span>
|
||||
<span class="text">{{i18n.bitIosVault}}</span>
|
||||
<span class="detail">{{i18n.bitIosVaultInfo}}</span>
|
||||
<span class="text">{{$ctrl.i18n.bitIosVault}}</span>
|
||||
<span class="detail">{{$ctrl.i18n.bitIosVaultInfo}}</span>
|
||||
</a>
|
||||
<a class="list-section-item wrap" href="" ng-click="launchAndroid()">
|
||||
<a class="list-section-item wrap" href="" ng-click="$ctrl.launchAndroid()">
|
||||
<span class="leading-icon" style="color: #a4c639;"><i class="fa fa-android fa-fw"></i></span>
|
||||
<span class="text">{{i18n.bitAndrVault}}</span>
|
||||
<span class="detail">{{i18n.bitAndrVaultInfo}}</span>
|
||||
<span class="text">{{$ctrl.i18n.bitAndrVault}}</span>
|
||||
<span class="detail">{{$ctrl.i18n.bitAndrVaultInfo}}</span>
|
||||
</a>
|
||||
<a class="list-section-item wrap" href="" ng-click="launchWebVault(true)">
|
||||
<a class="list-section-item wrap" href="" ng-click="$ctrl.launchWebVault(true)">
|
||||
<span class="leading-icon" style="color: #8977af;"><i class="fa fa-share-alt fa-fw"></i></span>
|
||||
<span class="text">{{i18n.shareVault}}</span>
|
||||
<span class="detail">{{i18n.shareVaultInfo}}</span>
|
||||
<span class="text">{{$ctrl.i18n.shareVault}}</span>
|
||||
<span class="detail">{{$ctrl.i18n.shareVaultInfo}}</span>
|
||||
</a>
|
||||
<a class="list-section-item wrap" href="" ng-click="launchImport()">
|
||||
<a class="list-section-item wrap" href="" ng-click="$ctrl.launchImport()">
|
||||
<span class="leading-icon" style="color: #6fc2ff;"><i class="fa fa-cloud-upload fa-fw"></i></span>
|
||||
<span class="text">{{i18n.importItems}}</span>
|
||||
<span class="detail">{{i18n.importItemsInfo}}</span>
|
||||
<span class="text">{{$ctrl.i18n.importItems}}</span>
|
||||
<span class="detail">{{$ctrl.i18n.importItemsInfo}}</span>
|
||||
</a>
|
||||
<a class="list-section-item wrap" ui-sref="export({animation: 'in-slide-up'})" ng-if="showExport">
|
||||
<a class="list-section-item wrap" ui-sref="export({animation: 'in-slide-up'})" ng-if="$ctrl.showExport">
|
||||
<span class="leading-icon" style="color: #ff6f6f;"><i class="fa fa-cloud-download fa-fw"></i></span>
|
||||
<span class="text">{{i18n.exportVault}}</span>
|
||||
<span class="detail">{{i18n.exportVaultInfo}}</span>
|
||||
<span class="text">{{$ctrl.i18n.exportVault}}</span>
|
||||
<span class="detail">{{$ctrl.i18n.exportVaultInfo}}</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
angular
|
||||
angular
|
||||
.module('bit.vault')
|
||||
|
||||
.controller('vaultAddCipherController', function ($scope, $state, $stateParams, cipherService, folderService,
|
||||
cryptoService, toastr, utilsService, $analytics, i18nService, constantsService) {
|
||||
cryptoService, toastr, utilsService, $analytics, i18nService, constantsService, $timeout) {
|
||||
$scope.i18n = i18nService;
|
||||
$scope.constants = constantsService;
|
||||
$scope.addFieldType = constantsService.fieldType.text.toString();
|
||||
@@ -30,13 +30,16 @@
|
||||
angular.extend($scope.cipher, $stateParams.cipher);
|
||||
}
|
||||
|
||||
if (!$stateParams.cipher && $scope.cipher.name && $scope.cipher.login && $scope.cipher.login.uri) {
|
||||
$('#username').focus();
|
||||
}
|
||||
else {
|
||||
$('#name').focus();
|
||||
}
|
||||
utilsService.initListSectionItemListeners($(document), angular);
|
||||
$timeout(function () {
|
||||
utilsService.initListSectionItemListeners(document, angular);
|
||||
|
||||
if (!$stateParams.cipher && $scope.cipher.name && $scope.cipher.login && $scope.cipher.login.uri) {
|
||||
document.getElementById('loginUsername').focus();
|
||||
}
|
||||
else {
|
||||
document.getElementById('name').focus();
|
||||
}
|
||||
}, 500);
|
||||
|
||||
folderService.getAllDecrypted().then(function (folders) {
|
||||
$scope.folders = folders;
|
||||
|
||||
@@ -2,10 +2,12 @@ angular
|
||||
.module('bit.vault')
|
||||
|
||||
.controller('vaultAttachmentsController', function ($scope, $state, $stateParams, cipherService, toastr,
|
||||
SweetAlert, utilsService, $analytics, i18nService, cryptoService, tokenService) {
|
||||
$scope.i18n = i18nService;
|
||||
utilsService.initListSectionItemListeners($(document), angular);
|
||||
SweetAlert, utilsService, $analytics, i18nService, cryptoService, tokenService, $timeout) {
|
||||
$timeout(function () {
|
||||
utilsService.initListSectionItemListeners(document, angular);
|
||||
}, 500);
|
||||
|
||||
$scope.i18n = i18nService;
|
||||
$scope.isPremium = tokenService.getPremium();
|
||||
$scope.canAccessAttachments = $scope.isPremium;
|
||||
$scope.hasUpdatedKey = false;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
angular
|
||||
angular
|
||||
.module('bit.vault')
|
||||
|
||||
.controller('vaultController', function ($scope, $rootScope, cipherService, folderService, $q, $state, $stateParams, toastr,
|
||||
@@ -9,13 +9,13 @@
|
||||
$scope.i18n = i18nService;
|
||||
$scope.showFolderCounts = !utilsService.isEdge();
|
||||
$scope.showOnlyFolderView = utilsService.isEdge();
|
||||
$('#search').focus();
|
||||
document.getElementById('search').focus();
|
||||
|
||||
var syncOnLoad = $stateParams.syncOnLoad;
|
||||
if (syncOnLoad) {
|
||||
$scope.$on('$viewContentLoaded', function () {
|
||||
$timeout(function () {
|
||||
syncService.fullSync(true, function () { });
|
||||
syncService.fullSync(true);
|
||||
}, 0);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -2,7 +2,12 @@ angular
|
||||
.module('bit.vault')
|
||||
|
||||
.controller('vaultEditCipherController', function ($scope, $state, $stateParams, cipherService, folderService,
|
||||
cryptoService, toastr, SweetAlert, utilsService, $analytics, i18nService, constantsService) {
|
||||
cryptoService, toastr, SweetAlert, utilsService, $analytics, i18nService, constantsService, $timeout) {
|
||||
$timeout(function () {
|
||||
utilsService.initListSectionItemListeners(document, angular);
|
||||
document.getElementById('name').focus();
|
||||
}, 500);
|
||||
|
||||
$scope.i18n = i18nService;
|
||||
$scope.constants = constantsService;
|
||||
$scope.showAttachments = !utilsService.isEdge();
|
||||
@@ -16,8 +21,6 @@ angular
|
||||
folderId: null
|
||||
};
|
||||
|
||||
$('#name').focus();
|
||||
|
||||
if ($stateParams.cipher) {
|
||||
angular.extend($scope.cipher, $stateParams.cipher);
|
||||
}
|
||||
@@ -33,8 +36,6 @@ angular
|
||||
$scope.folders = folders;
|
||||
});
|
||||
|
||||
utilsService.initListSectionItemListeners($(document), angular);
|
||||
|
||||
$scope.typeChanged = function () {
|
||||
$scope.cipher.type = parseInt($scope.selectedType);
|
||||
};
|
||||
|
||||
@@ -43,7 +43,7 @@ angular
|
||||
}
|
||||
}
|
||||
|
||||
if (model.login.totp && (cipherObj.organizationUseTotp || tokenService.getPremium())) {
|
||||
if (model.login && model.login.totp && (cipherObj.organizationUseTotp || tokenService.getPremium())) {
|
||||
totpUpdateCode();
|
||||
totpTick();
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
angular
|
||||
angular
|
||||
.module('bit.vault')
|
||||
|
||||
.controller('vaultViewFolderController', function ($scope, cipherService, folderService, $q, $state, $stateParams, toastr,
|
||||
@@ -17,7 +17,7 @@
|
||||
name: i18nService.noneFolder
|
||||
};
|
||||
$scope.i18n = i18nService;
|
||||
$('#search').focus();
|
||||
document.getElementById('search').focus();
|
||||
|
||||
$scope.loaded = false;
|
||||
$scope.vaultCiphers = [];
|
||||
|
||||
@@ -1,121 +1,11 @@
|
||||
<!DOCTYPE html>
|
||||
<html ng-app="bit" ng-csp>
|
||||
<html ng-csp class="__BROWSER__">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width">
|
||||
|
||||
<title>bitwarden</title>
|
||||
|
||||
<!-- @if true !>
|
||||
<link rel="stylesheet" href="css/popup.css">
|
||||
<!-- @endif -->
|
||||
<!-- @exclude -->
|
||||
<link rel="stylesheet" href="css/webfonts.css">
|
||||
<link rel="stylesheet" href="../lib/font-awesome/css/font-awesome.css">
|
||||
<link rel="stylesheet" href="../lib/angular-toastr/angular-toastr.css">
|
||||
<link rel="stylesheet" href="../lib/sweetalert/sweetalert.css">
|
||||
<link rel="stylesheet" href="css/popup.css">
|
||||
<!-- @endexclude -->
|
||||
</head>
|
||||
<body ng-controller="mainController as main" class="{{main.animation}}"
|
||||
ng-class="{sm: main.smBody, xs: main.xsBody }">
|
||||
<body ng-controller="mainController as main" class="{{main.animation}}" ng-class="{sm: main.smBody, xs: main.xsBody }">
|
||||
<div ui-view class="main-view"></div>
|
||||
|
||||
<!-- @if true !>
|
||||
<script src="lib.js"></script>
|
||||
<script src="app.js"></script>
|
||||
<!-- @endif -->
|
||||
<!-- @exclude -->
|
||||
<script src="../lib/jquery/jquery.js"></script>
|
||||
<script src="../lib/bootstrap/js/bootstrap.js"></script>
|
||||
<script src="../lib/papaparse/papaparse.js"></script>
|
||||
<script src="../lib/clipboard/clipboard.js"></script>
|
||||
|
||||
<script src="../lib/angular/angular.js"></script>
|
||||
<script src="../lib/angular-animate/angular-animate.js"></script>
|
||||
<script src="../lib/angular-ui-router/angular-ui-router.js"></script>
|
||||
<script src="../lib/angular-toastr/angular-toastr.tpls.js"></script>
|
||||
<script src="../lib/ngclipboard/ngclipboard.js"></script>
|
||||
<script src="../lib/sweetalert/sweetalert-dev.js"></script>
|
||||
<script src="../lib/sweetalert/SweetAlert.js"></script>
|
||||
<script src="../lib/angulartics/angulartics.js"></script>
|
||||
<script src="../lib/angulartics/angulartics-ga.js"></script>
|
||||
<script src="../lib/ng-infinite-scroll/ng-infinite-scroll.js"></script>
|
||||
|
||||
<script src="../scripts/analytics.js"></script>
|
||||
<script src="../scripts/duo.js"></script>
|
||||
<script src="../scripts/u2f.js"></script>
|
||||
|
||||
<script src="../models/api/requestModels.js"></script>
|
||||
<script src="../models/api/responseModels.js"></script>
|
||||
<script src="../models/dataModels.js"></script>
|
||||
<script src="../models/domainModels.js"></script>
|
||||
|
||||
<script src="app/app.js"></script>
|
||||
<script src="app/config.js"></script>
|
||||
|
||||
<script src="app/directives/directivesModule.js"></script>
|
||||
<script src="app/directives/formDirective.js"></script>
|
||||
<script src="app/directives/stopClickDirective.js"></script>
|
||||
<script src="app/directives/stopPropDirective.js"></script>
|
||||
<script src="app/directives/fallbackSrcDirective.js"></script>
|
||||
|
||||
<script src="app/components/componentsModule.js"></script>
|
||||
<script src="app/components/iconComponent.js"></script>
|
||||
<script src="app/components/actionButtonsComponent.js"></script>
|
||||
<script src="app/components/cipherItemsComponent.js"></script>
|
||||
|
||||
<script src="app/services/servicesModule.js"></script>
|
||||
<script src="app/services/backgroundService.js"></script>
|
||||
<script src="app/services/authService.js"></script>
|
||||
<script src="app/services/validationService.js"></script>
|
||||
<script src="app/services/stateService.js"></script>
|
||||
|
||||
<script src="app/global/globalModule.js"></script>
|
||||
<script src="app/global/mainController.js"></script>
|
||||
<script src="app/global/tabsController.js"></script>
|
||||
<script src="app/global/baseController.js"></script>
|
||||
<script src="app/global/privateModeController.js"></script>
|
||||
|
||||
<script src="app/accounts/accountsModule.js"></script>
|
||||
<script src="app/accounts/accountsLoginController.js"></script>
|
||||
<script src="app/accounts/accountsLoginTwoFactorController.js"></script>
|
||||
<script src="app/accounts/accountsTwoFactorMethodsController.js"></script>
|
||||
<script src="app/accounts/accountsHintController.js"></script>
|
||||
<script src="app/accounts/accountsRegisterController.js"></script>
|
||||
|
||||
<script src="app/current/currentModule.js"></script>
|
||||
<script src="app/current/currentController.js"></script>
|
||||
|
||||
<script src="app/vault/vaultModule.js"></script>
|
||||
<script src="app/vault/vaultController.js"></script>
|
||||
<script src="app/vault/vaultViewFolderController.js"></script>
|
||||
<script src="app/vault/vaultAddCipherController.js"></script>
|
||||
<script src="app/vault/vaultEditCipherController.js"></script>
|
||||
<script src="app/vault/vaultViewCipherController.js"></script>
|
||||
<script src="app/vault/vaultAttachmentsController.js"></script>
|
||||
|
||||
<script src="app/settings/settingsModule.js"></script>
|
||||
<script src="app/settings/settingsController.js"></script>
|
||||
<script src="app/settings/settingsHelpController.js"></script>
|
||||
<script src="app/settings/settingsAboutController.js"></script>
|
||||
<script src="app/settings/settingsCreditsController.js"></script>
|
||||
<script src="app/settings/settingsFeaturesController.js"></script>
|
||||
<script src="app/settings/settingsSyncController.js"></script>
|
||||
<script src="app/settings/settingsFoldersController.js"></script>
|
||||
<script src="app/settings/settingsAddFolderController.js"></script>
|
||||
<script src="app/settings/settingsEditFolderController.js"></script>
|
||||
<script src="app/settings/settingsPremiumController.js"></script>
|
||||
<script src="app/settings/settingsEnvironmentController.js"></script>
|
||||
|
||||
<script src="app/tools/toolsModule.js"></script>
|
||||
<script src="app/tools/toolsController.js"></script>
|
||||
<script src="app/tools/toolsPasswordGeneratorController.js"></script>
|
||||
<script src="app/tools/toolsPasswordGeneratorHistoryController.js"></script>
|
||||
<script src="app/tools/toolsExportController.js"></script>
|
||||
|
||||
<script src="app/lock/lockModule.js"></script>
|
||||
<script src="app/lock/lockController.js"></script>
|
||||
<!-- @endexclude -->
|
||||
</body>
|
||||
</html>
|
||||
|
||||
4
src/popup/less/libs.less
Normal file
4
src/popup/less/libs.less
Normal file
@@ -0,0 +1,4 @@
|
||||
@import "~font-awesome/less/font-awesome.less";
|
||||
@import "~angular-toastr/src/toastr.less";
|
||||
@import (inline) "~sweetalert/dist/sweetalert.css";
|
||||
|
||||
@@ -1,31 +1,29 @@
|
||||
@import "../../../node_modules/bootstrap/less/bootstrap.less";
|
||||
@import (less) "../../../node_modules/angular/angular-csp.css";
|
||||
@import "~bootstrap/less/bootstrap.less";
|
||||
@import (less) "~angular/angular-csp.css";
|
||||
@import "variables.less";
|
||||
@import "mixins.less";
|
||||
@import "components.less";
|
||||
@import "animations.less";
|
||||
@import "plugins.less";
|
||||
@import "pages.less";
|
||||
@import (less) "../css/webfonts.css";
|
||||
|
||||
html {
|
||||
-webkit-font-smoothing: antialiased;
|
||||
}
|
||||
|
||||
body {
|
||||
width: 320px !important;
|
||||
height: 568px !important;
|
||||
width: 375px !important;
|
||||
height: 667px !important;
|
||||
background-color: @background-color;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* @ifndef firefox */
|
||||
/* @ifndef edge */
|
||||
body {
|
||||
width: 375px !important;
|
||||
height: 667px !important;
|
||||
html.firefox body,
|
||||
html.edge body {
|
||||
width: 320px !important;
|
||||
height: 568px !important;
|
||||
}
|
||||
/* @endif */
|
||||
/* @endif */
|
||||
|
||||
body.sm {
|
||||
width: 375px !important;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
@import (reference) "../../../node_modules/bootstrap/less/bootstrap.less";
|
||||
@import (reference) "../../../node_modules/bootstrap/less/mixins.less";
|
||||
@import (reference) "../../../node_modules/bootstrap/less/variables.less";
|
||||
@import (reference) "~bootstrap/less/bootstrap.less";
|
||||
@import (reference) "~bootstrap/less/mixins.less";
|
||||
@import (reference) "~bootstrap/less/variables.less";
|
||||
|
||||
@font-family-sans-serif: "Open Sans", sans-serif;
|
||||
@text-color: #000000;
|
||||
|
||||
Reference in New Issue
Block a user