1
0
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:
Kyle Spearrin
2017-11-09 22:45:30 -05:00
committed by GitHub
178 changed files with 7362 additions and 41201 deletions

View File

@@ -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);
});
});
}
});

View File

@@ -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
};

View File

@@ -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);
}
}
});
}

View File

@@ -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;

View File

@@ -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
View File

@@ -0,0 +1 @@
declare module '*.html';

View File

@@ -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']);
});

View 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,
};

View File

@@ -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);
};
};
}
});

View 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,
};

View File

@@ -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);
};
};
}
});

View 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;

View File

@@ -1,2 +0,0 @@
angular
.module('bit.components', []);

View File

@@ -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>

View 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,
};

View File

@@ -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;
}
}
}
});

View File

@@ -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();

View File

@@ -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);

View File

@@ -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;
});
};
});

View File

@@ -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();
});
};
});

View File

@@ -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();
});
};
});
});

View File

@@ -2,7 +2,7 @@
<a ui-sref="environment({animation: 'in-slide-up'})" class="settings-icon">
<i class="fa fa-cog fa-lg"></i><span>&nbsp;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'})"

View File

@@ -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)) {

View File

@@ -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>

View File

@@ -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>

View 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,
};

View 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;

View File

@@ -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);
}
});
});
});
};
});

View File

@@ -1,2 +0,0 @@
angular
.module('bit.lock', ['ngAnimate', 'toastr']);

View 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;

View File

@@ -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;
});

View 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');

View File

@@ -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;
});

View 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;

View File

@@ -1,2 +0,0 @@
angular
.module('bit.services', ['toastr']);

View 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;

View File

@@ -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;
});

View 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;

View File

@@ -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;
});

View File

@@ -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) {

View File

@@ -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();
}

View File

@@ -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) {

View File

@@ -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;

View File

@@ -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();

View File

@@ -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();
}

View File

@@ -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>

View 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,
};

View 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,
};

View 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;

View File

@@ -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/' });
}
});
};
});

View File

@@ -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();
}
});
});

View File

@@ -1,2 +0,0 @@
angular
.module('bit.tools', ['ngAnimate', 'ngclipboard', 'toastr', 'oitozero.ngSweetAlert']);

View File

@@ -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'
});
}
}
});

View File

@@ -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>

View File

@@ -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;

View File

@@ -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;

View File

@@ -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);
});
}

View File

@@ -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);
};

View File

@@ -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();

View File

@@ -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 = [];

View File

@@ -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
View File

@@ -0,0 +1,4 @@
@import "~font-awesome/less/font-awesome.less";
@import "~angular-toastr/src/toastr.less";
@import (inline) "~sweetalert/dist/sweetalert.css";

View File

@@ -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;

View File

@@ -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;