1
0
mirror of https://github.com/bitwarden/web synced 2025-12-06 00:03:28 +00:00

Compare commits

...

24 Commits

Author SHA1 Message Date
Kyle Spearrin
c7802940b1 version bump 2017-09-29 11:44:32 -04:00
Kyle Spearrin
f7b60febe9 Only load u2f-api.js implementation when necessary
Some browsers such as Firefox already provide a window.u2f
implementation. Detect the existing implementation and abort from
u2f-api.js.
2017-09-29 11:22:23 -04:00
Kyle Spearrin
6c93a63c06 import ciphers, no logins 2017-09-28 13:12:39 -04:00
Kyle Spearrin
c44a638644 version bump and lint fixes 2017-09-28 11:16:01 -04:00
Kyle Spearrin
0d3fead0f3 added session activity message 2017-09-27 17:21:27 -04:00
Kyle Spearrin
5ba4b37610 disable autocomplete on various forms 2017-09-27 13:04:03 -04:00
Kyle Spearrin
44a2d071ae update apps 2017-09-21 23:38:48 -04:00
Kyle Spearrin
3b22764368 adjust authenticator qr code 2017-09-21 23:35:42 -04:00
Kyle Spearrin
11336da6df adjust modal sizes 2017-09-21 23:31:16 -04:00
Kyle Spearrin
a0e5591f8e larger modals. sm breakpoints on login add/edit 2017-09-21 23:19:06 -04:00
Kyle Spearrin
e952073c3c new remove button 2017-09-21 23:00:49 -04:00
Kyle Spearrin
9bdd0d116a disable fields when cannot edit 2017-09-21 22:56:31 -04:00
Kyle Spearrin
05c8a39e6d custom fields on all add/edit login pages 2017-09-21 14:27:07 -04:00
Kyle Spearrin
8fa6ff48cf touch-ups on custom field layout 2017-09-21 13:53:54 -04:00
Kyle Spearrin
7a31783ea4 custom fields added to edit login page 2017-09-21 13:21:09 -04:00
Kyle Spearrin
96585b183d subclassing for encrypted login 2017-09-21 10:44:00 -04:00
Kyle Spearrin
f81e7b02dc only delete dist folder contents when cleaned 2017-09-20 23:42:26 -04:00
Kyle Spearrin
f7fbdf2081 move logins to ciphers apis 2017-09-20 16:45:13 -04:00
Kyle Spearrin
06a877c755 style org icon for self host 2017-09-19 22:20:42 -04:00
Kyle Spearrin
30abd52189 lighten sidebar header color 2017-09-19 18:09:39 -04:00
Kyle Spearrin
6af0e62976 light skin for self hosted instances 2017-09-19 17:34:20 -04:00
Kyle Spearrin
84a36a18d6 must verify your email before upgrading to premium 2017-09-18 16:11:30 -04:00
Kyle Spearrin
595cf6c375 use Content-Language header for auth bearer 2017-09-14 10:12:13 -04:00
Kyle Spearrin
4262e2cc1d remove old qs params 2017-09-14 09:34:29 -04:00
64 changed files with 1202 additions and 869 deletions

2
.gitignore vendored
View File

@@ -199,5 +199,5 @@ FakesAssemblies/
*.opt
# Other
project.lock.json
package-lock.json
src/js/*.min.js

View File

@@ -291,7 +291,7 @@ gulp.task('browserify:cc', function () {
});
gulp.task('dist:clean', function (cb) {
return rimraf(paths.dist, cb);
return rimraf(paths.dist + '**/*', cb);
});
gulp.task('dist:move', function () {

View File

@@ -1,6 +1,6 @@
{
"name": "bitwarden",
"version": "1.16.0",
"version": "1.17.1",
"env": "Production",
"devDependencies": {
"connect": "3.6.3",

View File

@@ -49,7 +49,8 @@
<p class="login-box-msg">
Complete logging in with YubiKey.
</p>
<form name="twoFactorForm" ng-submit="twoFactorForm.$valid && twoFactor(token)" api-form="twoFactorPromise">
<form name="twoFactorForm" ng-submit="twoFactorForm.$valid && twoFactor(token)" api-form="twoFactorPromise"
autocomplete="off">
<div class="callout callout-danger validation-errors" ng-show="twoFactorForm.$errors">
<h4>Errors have occurred</h4>
<ul>
@@ -85,7 +86,8 @@
<p class="login-box-msg">
Complete logging in with Duo.
</p>
<form name="twoFactorForm" ng-submit="twoFactorForm.$valid && twoFactor(token)" api-form="twoFactorPromise">
<form name="twoFactorForm" ng-submit="twoFactorForm.$valid && twoFactor(token)" api-form="twoFactorPromise"
autocomplete="off">
<div class="callout callout-danger validation-errors" ng-show="twoFactorForm.$errors">
<h4>Errors have occurred</h4>
<ul>
@@ -116,7 +118,7 @@
<p class="login-box-msg">
Complete logging in with FIDO U2F.
</p>
<form name="twoFactorForm" api-form="twoFactorPromise">
<form name="twoFactorForm" api-form="twoFactorPromise" autocomplete="off">
<div class="callout callout-danger validation-errors" ng-show="twoFactorForm.$errors">
<h4>Errors have occurred</h4>
<ul>

View File

@@ -12,7 +12,8 @@ angular
$qProvider.errorOnUnhandledRejections(false);
$locationProvider.hashPrefix('');
jwtOptionsProvider.config({
urlParam: 'access_token',
// Using Content-Language header since it is unused and is a CORS-safelisted header. This avoids pre-flights.
authHeader: 'Content-Language',
whiteListedDomains: appSettings.whitelistDomains
});
var refreshPromise;

View File

@@ -4,6 +4,7 @@ angular
.controller('mainController', function ($scope, $state, authService, appSettings, toastr, $window, $document,
cryptoService, $uibModal, apiService) {
var vm = this;
vm.skinClass = appSettings.selfHosted ? 'skin-blue-light' : 'skin-blue';
vm.bodyClass = '';
vm.usingControlSidebar = vm.openControlSidebar = false;
vm.searchVaultText = null;

View File

@@ -1,12 +1,23 @@
angular
.module('bit.global')
.controller('sideNavController', function ($scope, $state, authService, toastr, $analytics, constants) {
.controller('sideNavController', function ($scope, $state, authService, toastr, $analytics, constants, appSettings) {
$scope.$state = $state;
$scope.params = $state.params;
$scope.orgs = [];
$scope.name = '';
if(appSettings.selfHosted) {
$scope.orgIconBgColor = '#ffffff';
$scope.orgIconBorder = '3px solid #a0a0a0';
$scope.orgIconTextColor = '#333333';
}
else {
$scope.orgIconBgColor = '#2c3b41';
$scope.orgIconBorder = '3px solid #1a2226';
$scope.orgIconTextColor = '#ffffff';
}
authService.getUserProfile().then(function (userProfile) {
$scope.name = userProfile.extended && userProfile.extended.name ?
userProfile.extended.name : userProfile.email;

View File

@@ -71,7 +71,7 @@
apiService.ciphers.importOrg({ orgId: $state.params.orgId }, {
collections: cipherService.encryptCollections(collections, $state.params.orgId),
logins: cipherService.encryptLogins(logins, cryptoService.getOrgKey($state.params.orgId)),
ciphers: cipherService.encryptLogins(logins, cryptoService.getOrgKey($state.params.orgId)),
collectionRelationships: collectionRelationships
}, function () {
$uibModalInstance.dismiss('cancel');

View File

@@ -16,7 +16,7 @@
$scope.save = function (model) {
model.organizationId = orgId;
var login = cipherService.encryptLogin(model);
$scope.savePromise = apiService.logins.postAdmin(login, function (loginResponse) {
$scope.savePromise = apiService.ciphers.postAdmin(login, function (loginResponse) {
$analytics.eventTrack('Created Organization Login');
var decLogin = cipherService.decryptLogin(loginResponse);
$uibModalInstance.close(decLogin);
@@ -30,6 +30,25 @@
}
};
$scope.addField = function () {
if (!$scope.login.fields) {
$scope.login.fields = [];
}
$scope.login.fields.push({
type: '0',
name: null,
value: null
});
};
$scope.removeField = function (field) {
var index = $scope.login.fields.indexOf(field);
if (index > -1) {
$scope.login.fields.splice(index, 1);
}
};
$scope.clipboardSuccess = function (e) {
e.clearSelection();
selectPassword(e);

View File

@@ -10,7 +10,7 @@
$scope.canUseAttachments = true;
var closing = false;
apiService.logins.getAdmin({ id: loginId }, function (login) {
apiService.ciphers.getAdmin({ id: loginId }, function (login) {
$scope.login = cipherService.decryptLogin(login);
$scope.loading = false;
}, function () {

View File

@@ -7,14 +7,14 @@
$scope.login = {};
$scope.hideFolders = $scope.hideFavorite = $scope.fromOrg = true;
apiService.logins.getAdmin({ id: loginId }, function (login) {
apiService.ciphers.getAdmin({ id: loginId }, function (login) {
$scope.login = cipherService.decryptLogin(login);
$scope.useTotp = $scope.login.organizationUseTotp;
});
$scope.save = function (model) {
var login = cipherService.encryptLogin(model);
$scope.savePromise = apiService.logins.putAdmin({ id: loginId }, login, function (loginResponse) {
$scope.savePromise = apiService.ciphers.putAdmin({ id: loginId }, login, function (loginResponse) {
$analytics.eventTrack('Edited Organization Login');
var decLogin = cipherService.decryptLogin(loginResponse);
$uibModalInstance.close({
@@ -31,6 +31,25 @@
}
};
$scope.addField = function () {
if (!$scope.login.fields) {
$scope.login.fields = [];
}
$scope.login.fields.push({
type: '0',
name: null,
value: null
});
};
$scope.removeField = function (field) {
var index = $scope.login.fields.indexOf(field);
if (index > -1) {
$scope.login.fields.splice(index, 1);
}
};
$scope.clipboardSuccess = function (e) {
e.clearSelection();
selectPassword(e);

View File

@@ -5,7 +5,7 @@
{{add ? 'Add Seats' : 'Remove Seats'}}
</h4>
</div>
<form name="form" ng-submit="form.$valid && submit()" api-form="submitPromise">
<form name="form" ng-submit="form.$valid && submit()" api-form="submitPromise" autocomplete="off">
<div class="modal-body">
<div class="callout callout-default" ng-show="add">
<h4><i class="fa fa-dollar"></i> Note About Charges</h4>

View File

@@ -2,7 +2,7 @@
<button type="button" class="close" ng-click="close()" aria-label="Close"><span aria-hidden="true">&times;</span></button>
<h4 class="modal-title"><i class="fa fa-file-text-o"></i> Change Plan</h4>
</div>
<form name="form" ng-submit="form.$valid && submit()" api-form="submitPromise">
<form name="form" ng-submit="form.$valid && submit()" api-form="submitPromise" autocomplete="off">
<div class="modal-body">
You can <a href="https://bitwarden.com/contact/" target="_blank">contact us</a>
if you would like to change your plan. Please ensure that you have an active payment

View File

@@ -5,7 +5,7 @@
Verify Bank Account
</h4>
</div>
<form name="form" ng-submit="form.$valid && submit()" api-form="submitPromise">
<form name="form" ng-submit="form.$valid && submit()" api-form="submitPromise" autocomplete="off">
<div class="modal-body">
<p>
Enter the two micro-deposit amounts from your bank account. Both amounts will be less than $1.00 each.

View File

@@ -2,7 +2,7 @@
<button type="button" class="close" ng-click="close()" aria-label="Close"><span aria-hidden="true">&times;</span></button>
<h4 class="modal-title"><i class="fa fa-cubes"></i> Add New Collection</h4>
</div>
<form name="form" ng-submit="form.$valid && submit(model)" api-form="submitPromise">
<form name="form" ng-submit="form.$valid && submit(model)" api-form="submitPromise" autocomplete="off">
<div class="modal-body">
<div class="callout callout-default">
<h4><i class="fa fa-info-circle"></i> Note</h4>

View File

@@ -2,7 +2,7 @@
<button type="button" class="close" ng-click="close()" aria-label="Close"><span aria-hidden="true">&times;</span></button>
<h4 class="modal-title"><i class="fa fa-cubes"></i> Edit Collection</h4>
</div>
<form name="form" ng-submit="form.$valid && submit(collection)" api-form="submitPromise">
<form name="form" ng-submit="form.$valid && submit(collection)" api-form="submitPromise" autocomplete="off">
<div class="modal-body">
<div class="callout callout-default">
<h4><i class="fa fa-info-circle"></i> Note</h4>

View File

@@ -2,7 +2,7 @@
<button type="button" class="close" ng-click="close()" aria-label="Close"><span aria-hidden="true">&times;</span></button>
<h4 class="modal-title"><i class="fa fa-sitemap"></i> Add New Group</h4>
</div>
<form name="form" ng-submit="form.$valid && submit(model)" api-form="submitPromise">
<form name="form" ng-submit="form.$valid && submit(model)" api-form="submitPromise" autocomplete="off">
<div class="modal-body">
<div class="callout callout-default">
<h4><i class="fa fa-info-circle"></i> Note</h4>

View File

@@ -2,7 +2,7 @@
<button type="button" class="close" ng-click="close()" aria-label="Close"><span aria-hidden="true">&times;</span></button>
<h4 class="modal-title"><i class="fa fa-sitemap"></i> Edit Group</h4>
</div>
<form name="form" ng-submit="form.$valid && submit()" api-form="submitPromise">
<form name="form" ng-submit="form.$valid && submit()" api-form="submitPromise" autocomplete="off">
<div class="modal-body">
<div class="callout callout-default">
<h4><i class="fa fa-info-circle"></i> Note</h4>

View File

@@ -2,7 +2,7 @@
<button type="button" class="close" ng-click="close()" aria-label="Close"><span aria-hidden="true">&times;</span></button>
<h4 class="modal-title"><i class="fa fa-user"></i> Edit User <small>{{email}}</small></h4>
</div>
<form name="form" ng-submit="form.$valid && submit()" api-form="submitPromise">
<form name="form" ng-submit="form.$valid && submit()" api-form="submitPromise" autocomplete="off">
<div class="modal-body">
<div class="callout callout-danger validation-errors" ng-show="form.$errors">
<h4>Errors have occurred</h4>

View File

@@ -2,7 +2,7 @@
<button type="button" class="close" ng-click="close()" aria-label="Close"><span aria-hidden="true">&times;</span></button>
<h4 class="modal-title"><i class="fa fa-sitemap"></i> Edit User Groups <small>{{orgUser.email}}</small></h4>
</div>
<form name="form" ng-submit="form.$valid && submit()" api-form="submitPromise">
<form name="form" ng-submit="form.$valid && submit()" api-form="submitPromise" autocomplete="off">
<div class="modal-body">
<div class="callout callout-danger validation-errors" ng-show="form.$errors">
<h4>Errors have occurred</h4>

View File

@@ -2,7 +2,7 @@
<button type="button" class="close" ng-click="close()" aria-label="Close"><span aria-hidden="true">&times;</span></button>
<h4 class="modal-title"><i class="fa fa-user"></i> Invite User</h4>
</div>
<form name="inviteForm" ng-submit="inviteForm.$valid && submit(model)" api-form="submitPromise">
<form name="inviteForm" ng-submit="inviteForm.$valid && submit(model)" api-form="submitPromise" autocomplete="off">
<div class="modal-body">
<p>
Invite a new user to your organization by entering their bitwarden account email address below. If they do not have

View File

@@ -9,7 +9,8 @@
<div class="box-header with-border">
<h3 class="box-title">General</h3>
</div>
<form role="form" name="generalForm" ng-submit="generalForm.$valid && generalSave()" api-form="generalPromise">
<form role="form" name="generalForm" ng-submit="generalForm.$valid && generalSave()" api-form="generalPromise"
autocomplete="off">
<div class="box-body">
<div class="row">
<div class="col-sm-9">

View File

@@ -2,7 +2,7 @@
<button type="button" class="close" ng-click="close()" aria-label="Close"><span aria-hidden="true">&times;</span></button>
<h4 class="modal-title"><i class="fa fa-cubes"></i> Collections <small>{{cipher.name}}</small></h4>
</div>
<form name="form" ng-submit="form.$valid && submit()" api-form="submitPromise">
<form name="form" ng-submit="form.$valid && submit()" api-form="submitPromise" autocomplete="off">
<div class="modal-body">
<p>Edit the collections that this login is being shared with.</p>
<div class="callout callout-danger validation-errors" ng-show="form.$errors">

View File

@@ -6,17 +6,6 @@
_apiUri = appSettings.apiUri,
_identityUri = appSettings.identityUri;
_service.logins = $resource(_apiUri + '/logins/:id', {}, {
get: { method: 'GET', params: { id: '@id' } },
getAdmin: { url: _apiUri + '/logins/:id/admin', method: 'GET', params: { id: '@id' } },
list: { method: 'GET', params: {} },
post: { method: 'POST', params: {} },
postAdmin: { url: _apiUri + '/logins/admin', method: 'POST', params: {} },
put: { method: 'POST', params: { id: '@id' } },
putAdmin: { url: _apiUri + '/logins/:id/admin', method: 'POST', params: { id: '@id' } },
del: { url: _apiUri + '/logins/:id/delete', method: 'POST', params: { id: '@id' } }
});
_service.folders = $resource(_apiUri + '/folders/:id', {}, {
get: { method: 'GET', params: { id: '@id' } },
list: { method: 'GET', params: {} },
@@ -27,13 +16,17 @@
_service.ciphers = $resource(_apiUri + '/ciphers/:id', {}, {
get: { method: 'GET', params: { id: '@id' } },
getAdmin: { url: _apiUri + '/ciphers/:id/admin', method: 'GET', params: { id: '@id' } },
getDetails: { url: _apiUri + '/ciphers/:id/details', method: 'GET', params: { id: '@id' } },
list: { method: 'GET', params: { includeFolders: false, includeShared: true } },
list: { method: 'GET', params: {} },
listDetails: { url: _apiUri + '/ciphers/details', method: 'GET', params: {} },
listOrganizationDetails: { url: _apiUri + '/ciphers/organization-details', method: 'GET', params: {} },
post: { method: 'POST', params: {} },
postAdmin: { url: _apiUri + '/ciphers/admin', method: 'POST', params: {} },
put: { method: 'POST', params: { id: '@id' } },
putAdmin: { url: _apiUri + '/ciphers/:id/admin', method: 'POST', params: { id: '@id' } },
'import': { url: _apiUri + '/ciphers/import', method: 'POST', params: {} },
importOrg: { url: _apiUri + '/ciphers/import-organization?organizationId=:orgId', method: 'POST', params: { orgId: '@orgId' } },
favorite: { url: _apiUri + '/ciphers/:id/favorite', method: 'POST', params: { id: '@id' } },
putPartial: { url: _apiUri + '/ciphers/:id/partial', method: 'POST', params: { id: '@id' } },
putShare: { url: _apiUri + '/ciphers/:id/share', method: 'POST', params: { id: '@id' } },
putCollections: { url: _apiUri + '/ciphers/:id/collections', method: 'POST', params: { id: '@id' } },

View File

@@ -35,7 +35,7 @@ angular
attachments: null
};
var loginData = encryptedLogin.Data || encryptedLogin;
var loginData = encryptedLogin.Data;
if (loginData) {
login.name = cryptoService.decrypt(loginData.Name, key);
login.uri = loginData.Uri && loginData.Uri !== '' ? cryptoService.decrypt(loginData.Uri, key) : null;
@@ -43,6 +43,7 @@ angular
login.password = loginData.Password && loginData.Password !== '' ? cryptoService.decrypt(loginData.Password, key) : null;
login.notes = loginData.Notes && loginData.Notes !== '' ? cryptoService.decrypt(loginData.Notes, key) : null;
login.totp = loginData.Totp && loginData.Totp !== '' ? cryptoService.decrypt(loginData.Totp, key) : null;
login.fields = _service.decryptFields(key, loginData.Fields);
}
if (!encryptedLogin.Attachments) {
@@ -76,7 +77,7 @@ angular
hasAttachments: !!encryptedCipher.Attachments && encryptedCipher.Attachments.length > 0
};
var loginData = encryptedCipher.Data || encryptedCipher;
var loginData = encryptedCipher.Data;
if (loginData) {
login.name = _service.decryptProperty(loginData.Name, key, false);
login.username = _service.decryptProperty(loginData.Username, key, true);
@@ -134,6 +135,28 @@ angular
return deferred.promise;
};
_service.decryptFields = function (key, encryptedFields) {
var unencryptedFields = [];
if (encryptedFields) {
for (var i = 0; i < encryptedFields.length; i++) {
unencryptedFields.push(_service.decryptField(key, encryptedFields[i]));
}
}
return unencryptedFields;
};
_service.decryptField = function (key, encryptedField) {
if (!encryptedField) throw "encryptedField is undefined or null";
return {
type: encryptedField.Type.toString(),
name: encryptedField.Name && encryptedField.Name !== '' ? cryptoService.decrypt(encryptedField.Name, key) : null,
value: encryptedField.Value && encryptedField.Value !== '' ? cryptoService.decrypt(encryptedField.Value, key) : null
};
};
_service.decryptFolders = function (encryptedFolders) {
if (!encryptedFolders) throw "encryptedFolders is undefined or null";
@@ -227,12 +250,15 @@ angular
organizationId: unencryptedLogin.organizationId || null,
folderId: unencryptedLogin.folderId === '' ? null : unencryptedLogin.folderId,
favorite: unencryptedLogin.favorite !== null ? unencryptedLogin.favorite : false,
uri: !unencryptedLogin.uri || unencryptedLogin.uri === '' ? null : cryptoService.encrypt(unencryptedLogin.uri, key),
name: cryptoService.encrypt(unencryptedLogin.name, key),
username: !unencryptedLogin.username || unencryptedLogin.username === '' ? null : cryptoService.encrypt(unencryptedLogin.username, key),
password: !unencryptedLogin.password || unencryptedLogin.password === '' ? null : cryptoService.encrypt(unencryptedLogin.password, key),
notes: !unencryptedLogin.notes || unencryptedLogin.notes === '' ? null : cryptoService.encrypt(unencryptedLogin.notes, key),
totp: !unencryptedLogin.totp || unencryptedLogin.totp === '' ? null : cryptoService.encrypt(unencryptedLogin.totp, key)
login: {
uri: !unencryptedLogin.uri || unencryptedLogin.uri === '' ? null : cryptoService.encrypt(unencryptedLogin.uri, key),
username: !unencryptedLogin.username || unencryptedLogin.username === '' ? null : cryptoService.encrypt(unencryptedLogin.username, key),
password: !unencryptedLogin.password || unencryptedLogin.password === '' ? null : cryptoService.encrypt(unencryptedLogin.password, key),
totp: !unencryptedLogin.totp || unencryptedLogin.totp === '' ? null : cryptoService.encrypt(unencryptedLogin.totp, key)
},
fields: _service.encryptFields(unencryptedLogin.fields, key)
};
if (unencryptedLogin.attachments && attachments) {
@@ -272,6 +298,33 @@ angular
return deferred.promise;
};
_service.encryptFields = function (unencryptedFields, key) {
if (!unencryptedFields || !unencryptedFields.length) {
return null;
}
var encFields = [];
for (var i = 0; i < unencryptedFields.length; i++) {
if (!unencryptedFields[i]) {
continue;
}
encFields.push(_service.encryptField(unencryptedFields[i], key));
}
return encFields;
};
_service.encryptField = function (unencryptedField, key) {
if (!unencryptedField) throw "unencryptedField is undefined or null";
return {
type: parseInt(unencryptedField.type),
name: unencryptedField.name ? cryptoService.encrypt(unencryptedField.name, key) : null,
value: unencryptedField.value ? cryptoService.encrypt(unencryptedField.value.toString(), key) : null
};
};
_service.encryptFolders = function (unencryptedFolders, key) {
if (!unencryptedFolders) throw "unencryptedFolders is undefined or null";

View File

@@ -1,2 +1,2 @@
angular.module("bit")
.constant("appSettings", {"apiUri":"https://api.bitwarden.com","identityUri":"https://identity.bitwarden.com","stripeKey":"pk_live_bpN0P37nMxrMQkcaHXtAybJk","braintreeKey":"production_qfbsv8kc_njj2zjtyngtjmbjd","whitelistDomains":["api.bitwarden.com"],"selfHosted":false,"version":"1.16.0","environment":"Production"});
.constant("appSettings", {"apiUri":"https://api.bitwarden.com","identityUri":"https://identity.bitwarden.com","stripeKey":"pk_live_bpN0P37nMxrMQkcaHXtAybJk","braintreeKey":"production_qfbsv8kc_njj2zjtyngtjmbjd","whitelistDomains":["api.bitwarden.com"],"selfHosted":false,"version":"1.17.1","environment":"Production"});

View File

@@ -7,8 +7,11 @@
, stripe
// @endif
) {
authService.getUserProfile().then(function (profile) {
if (profile.premium) {
var profile = null;
authService.getUserProfile().then(function (theProfile) {
profile = theProfile;
if (profile && profile.premium) {
return $state.go('backend.user.settingsBilling');
}
});
@@ -63,6 +66,11 @@
$scope.submit = function (model, form) {
if ($scope.selfHosted) {
if (profile && !profile.emailVerified) {
validationService.addError(form, null, 'Your account\'s email address first must be verified.', true);
return;
}
var fileEl = document.getElementById('file');
var files = fileEl.files;
if (!files || !files.length) {

View File

@@ -44,7 +44,7 @@
$scope.model = {
key: formatString(_key),
qr: 'https://chart.googleapis.com/chart?chs=123x123&chld=L|0&cht=qr&chl=otpauth://totp/' +
qr: 'https://chart.googleapis.com/chart?chs=160x160&chld=L|0&cht=qr&chl=otpauth://totp/' +
_issuer + ':' + encodeURIComponent(_profile.email) +
'%3Fsecret=' + encodeURIComponent(_key) +
'%26issuer=' + _issuer

View File

@@ -32,7 +32,7 @@
var madeEncKey = cryptoService.makeEncKey(null);
var reencryptedLogins = [];
var loginsPromise = apiService.logins.list({}, function (encryptedLogins) {
var loginsPromise = apiService.ciphers.list({}, function (encryptedLogins) {
var filteredEncryptedLogins = [];
for (var i = 0; i < encryptedLogins.Data.length; i++) {
if (encryptedLogins.Data[i].OrganizationId) {

View File

@@ -9,7 +9,8 @@
<div class="box-header with-border">
<h3 class="box-title">General</h3>
</div>
<form role="form" name="generalForm" ng-submit="generalForm.$valid && generalSave()" api-form="generalPromise">
<form role="form" name="generalForm" ng-submit="generalForm.$valid && generalSave()" api-form="generalPromise"
autocomplete="off">
<div class="box-body">
<div class="row">
<div class="col-sm-9">
@@ -57,7 +58,7 @@
<h3 class="box-title">Master Password</h3>
</div>
<form role="form" name="masterPasswordForm" ng-submit="masterPasswordForm.$valid && passwordHintSave()"
api-form="passwordHintPromise">
api-form="passwordHintPromise" autocomplete="off">
<div class="box-body">
<div class="row">
<div class="col-sm-9">

View File

@@ -2,7 +2,7 @@
<button type="button" class="close" ng-click="close()" aria-label="Close"><span aria-hidden="true">&times;</span></button>
<h4 class="modal-title"><i class="fa fa-globe"></i> {{index ? 'Edit Equivalent Domain' : 'Add Equivalent Domain'}}</h4>
</div>
<form name="domainAddEditForm" ng-submit="domainAddEditForm.$valid && submit(domainAddEditForm)">
<form name="domainAddEditForm" ng-submit="domainAddEditForm.$valid && submit(domainAddEditForm)" autocomplete="off">
<div class="modal-body">
<div class="callout callout-danger validation-errors" ng-show="domainAddEditForm.$errors">
<h4>Errors have occurred</h4>

View File

@@ -5,7 +5,7 @@
{{add ? 'Add Storage' : 'Remove Storage'}}
</h4>
</div>
<form name="form" ng-submit="form.$valid && submit()" api-form="submitPromise">
<form name="form" ng-submit="form.$valid && submit()" api-form="submitPromise" autocomplete="off">
<div class="modal-body">
<div class="callout callout-default" ng-show="add">
<h4><i class="fa fa-dollar"></i> Note About Charges</h4>

View File

@@ -5,7 +5,7 @@
{{existingPaymentMethod ? 'Change Payment Method' : 'Add Payment Method'}}
</h4>
</div>
<form name="form" ng-submit="form.$valid && submit()" api-form="submitPromise">
<form name="form" ng-submit="form.$valid && submit()" api-form="submitPromise" autocomplete="off">
<div class="modal-body">
<div class="callout callout-danger validation-errors" ng-show="form.$errors">
<h4>Errors have occurred</h4>

View File

@@ -5,7 +5,7 @@
Update License
</h4>
</div>
<form name="form" ng-submit="form.$valid && submit(form)" api-form="submitPromise">
<form name="form" ng-submit="form.$valid && submit(form)" api-form="submitPromise" autocomplete="off">
<div class="modal-body">
<div class="callout callout-danger validation-errors" ng-show="form.$errors">
<h4>Errors have occurred</h4>

View File

@@ -30,12 +30,13 @@
</div>
</form>
<form name="changeEmailConfirmForm" ng-submit="changeEmailConfirmForm.$valid && confirm(model)" api-form="confirmPromise"
ng-show="tokenSent">
ng-show="tokenSent" autocomplete="off">
<div class="modal-body">
<p>We have emailed a verification code to <b>{{model.newEmail}}</b>. Please check your email for this code and enter it below to finalize your the email address change.</p>
<div class="callout callout-warning">
<h4><i class="fa fa-warning"></i> Warning</h4>
Proceeding will log you out of your current session, requiring you to log back in.
Proceeding will log you out of your current session, requiring you to log back in. Active sessions on other devices
may continue to remain active for up to one hour.
</div>
<div class="callout callout-danger validation-errors" ng-show="changeEmailConfirmForm.$errors">
<h4>Errors have occurred</h4>

View File

@@ -8,7 +8,8 @@
<p>We recommend that you change your master password immediately if you believe that your credentials have been compromised.</p>
<div class="callout callout-warning">
<h4><i class="fa fa-warning"></i> Warning</h4>
Proceeding will log you out of your current session, requiring you to log back in.
Proceeding will log you out of your current session, requiring you to log back in. Active sessions on other devices
may continue to remain active for up to one hour.
</div>
<div class="callout callout-danger validation-errors" ng-show="changePasswordForm.$errors">
<h4>Errors have occurred</h4>

View File

@@ -6,7 +6,7 @@
If you have the same login across multiple different website domains, you can mark the website as "equivalent".
"Global" domains are ones already created for you by bitwarden.
</p>
<form name="customForm" ng-submit="customForm.$valid && saveCustom()" api-form="customPromise">
<form name="customForm" ng-submit="customForm.$valid && saveCustom()" api-form="customPromise" autocomplete="off">
<div class="box box-default">
<div class="box-header with-border">
<h3 class="box-title">Custom <span class="hidden-xs">Equivalent Domains</span></h3>
@@ -59,7 +59,7 @@
</div>
</form>
<form name="globalForm" ng-submit="globalForm.$valid && saveGlobal()" api-form="globalPromise">
<form name="globalForm" ng-submit="globalForm.$valid && saveGlobal()" api-form="globalPromise" autocomplete="off">
<div class="box box-default">
<div class="box-header with-border">
<h3 class="box-title">Global <span class="hidden-xs">Equivalent Domains</span></h3>

View File

@@ -13,7 +13,8 @@
<div class="callout callout-warning">
<h4><i class="fa fa-warning"></i> Warning</h4>
Proceeding will also log you out of your current session, requiring you to log back in. You will also be prompted
for two-step login again, if enabled.
for two-step login again, if enabled. Active sessions on other devices may continue to remain active for up to
one hour.
</div>
<div class="callout callout-danger validation-errors" ng-show="logoutSessionsForm.$errors">
<h4>Errors have occurred</h4>

View File

@@ -28,7 +28,7 @@
</div>
</form>
<form name="submitTwoStepForm" ng-submit="submitTwoStepForm.$valid && submit(updateModel)" api-form="submitPromise"
ng-if="model">
ng-if="model" autocomplete="off">
<div class="modal-body">
<div ng-if="enabled">
<div class="callout callout-success">
@@ -74,10 +74,10 @@
<hr ng-if="enabled" />
<h4 ng-if="!enabled" style="margin-top: 30px;">2. Scan this QR code with your authenticator app</h4>
<div class="row">
<div class="col-md-4 text-center">
<div class="col-sm-4 text-center">
<p><img ng-src="{{model.qr}}" alt="QR" /></p>
</div>
<div class="col-md-8">
<div class="col-sm-8">
<p>
<strong>Can't scan the code?</strong> You can add the code to your application manually using the
following details:

View File

@@ -28,7 +28,7 @@
</div>
</form>
<form name="submitTwoStepForm" ng-submit="submitTwoStepForm.$valid && submit(updateModel)" api-form="submitPromise"
ng-if="authed">
ng-if="authed" autocomplete="off">
<div class="modal-body">
<div ng-if="enabled">
<div class="callout callout-success">

View File

@@ -28,7 +28,7 @@
</div>
</form>
<form name="submitTwoStepForm" ng-submit="submitTwoStepForm.$valid && submit(updateModel)" api-form="submitPromise"
ng-if="authed">
ng-if="authed" autocomplete="off">
<div class="modal-body">
<div ng-if="enabled">
<div class="callout callout-success">

View File

@@ -28,7 +28,7 @@
</div>
</form>
<form name="submitTwoStepForm" ng-submit="submitTwoStepForm.$valid && submit()" api-form="submitPromise"
ng-if="authed">
ng-if="authed" autocomplete="off">
<div class="modal-body">
<div class="callout callout-warning">
<h4><i class="fa fa-warning"></i> Warning <i class="fa fa-warning"></i></h4>

View File

@@ -28,7 +28,7 @@
</div>
</form>
<form name="submitTwoStepForm" ng-submit="submitTwoStepForm.$valid && submit(updateModel)" api-form="submitPromise"
ng-if="authed">
ng-if="authed" autocomplete="off">
<div class="modal-body">
<div class="callout callout-warning">
<h4><i class="fa fa-warning"></i> Warning <i class="fa fa-warning"></i></h4>

View File

@@ -13,7 +13,7 @@
decFolders = cipherService.decryptFolders(folders.Data);
}).$promise;
var loginsPromise = apiService.logins.list({}, function (logins) {
var loginsPromise = apiService.ciphers.list({}, function (logins) {
decLogins = cipherService.decryptLogins(logins.Data);
}).$promise;

View File

@@ -288,7 +288,7 @@
apiService.ciphers.import({
folders: cipherService.encryptFolders(folders),
logins: cipherService.encryptLogins(logins),
ciphers: cipherService.encryptLogins(logins),
folderRelationships: folderRelationships
}, function () {
$uibModalInstance.dismiss('cancel');

View File

@@ -17,7 +17,7 @@
$scope.savePromise = null;
$scope.save = function (model) {
var login = cipherService.encryptLogin(model);
$scope.savePromise = apiService.logins.post(login, function (loginResponse) {
$scope.savePromise = apiService.ciphers.post(login, function (loginResponse) {
$analytics.eventTrack('Created Login');
var decLogin = cipherService.decryptLogin(loginResponse);
$uibModalInstance.close(decLogin);
@@ -31,6 +31,29 @@
}
};
$scope.addField = function () {
if (!$scope.login.fields) {
$scope.login.fields = [];
}
$scope.login.fields.push({
type: '0',
name: null,
value: null
});
};
$scope.removeField = function (field) {
var index = $scope.login.fields.indexOf(field);
if (index > -1) {
$scope.login.fields.splice(index, 1);
}
};
$scope.toggleFavorite = function () {
$scope.login.favorite = !$scope.login.favorite;
};
$scope.clipboardSuccess = function (e) {
e.clearSelection();
selectPassword(e);

View File

@@ -13,10 +13,10 @@
authService.getUserProfile().then(function (profile) {
$scope.isPremium = profile.premium;
return apiService.logins.get({ id: loginId }).$promise;
}).then(function (login) {
$scope.login = cipherService.decryptLogin(login);
$scope.readOnly = !login.Edit;
return apiService.ciphers.get({ id: loginId }).$promise;
}).then(function (cipher) {
$scope.login = cipherService.decryptLogin(cipher);
$scope.readOnly = !$scope.login.edit;
$scope.canUseAttachments = $scope.isPremium || $scope.login.organizationId;
$scope.loading = false;
}, function () {

View File

@@ -193,7 +193,7 @@
return;
}
apiService.logins.del({ id: login.id }, function () {
apiService.ciphers.del({ id: login.id }, function () {
$analytics.eventTrack('Deleted Login');
removeLoginFromScopes(login);
});

View File

@@ -10,10 +10,10 @@
authService.getUserProfile().then(function (profile) {
$scope.useTotp = profile.premium;
return apiService.logins.get({ id: loginId }).$promise;
return apiService.ciphers.get({ id: loginId }).$promise;
}).then(function (login) {
$scope.login = cipherService.decryptLogin(login);
$scope.readOnly = !login.Edit;
$scope.readOnly = !$scope.login.edit;
$scope.useTotp = $scope.useTotp || $scope.login.organizationUseTotp;
});
@@ -36,7 +36,7 @@
}
else {
var login = cipherService.encryptLogin(model);
$scope.savePromise = apiService.logins.put({ id: loginId }, login, function (loginResponse) {
$scope.savePromise = apiService.ciphers.put({ id: loginId }, login, function (loginResponse) {
$analytics.eventTrack('Edited Login');
var decLogin = cipherService.decryptLogin(loginResponse);
$uibModalInstance.close({
@@ -54,6 +54,29 @@
}
};
$scope.addField = function () {
if (!$scope.login.fields) {
$scope.login.fields = [];
}
$scope.login.fields.push({
type: '0',
name: null,
value: null
});
};
$scope.removeField = function (field) {
var index = $scope.login.fields.indexOf(field);
if (index > -1) {
$scope.login.fields.splice(index, 1);
}
};
$scope.toggleFavorite = function () {
$scope.login.favorite = !$scope.login.favorite;
};
$scope.clipboardSuccess = function (e) {
e.clearSelection();
selectPassword(e);
@@ -86,7 +109,7 @@
return;
}
apiService.logins.del({ id: $scope.login.id }, function () {
apiService.ciphers.del({ id: $scope.login.id }, function () {
$analytics.eventTrack('Deleted Login From Edit');
$uibModalInstance.close({
action: 'delete',

View File

@@ -14,7 +14,7 @@
$scope.loading = true;
$scope.readOnly = false;
apiService.logins.get({ id: loginId }).$promise.then(function (login) {
apiService.ciphers.get({ id: loginId }).$promise.then(function (login) {
$scope.readOnly = !login.Edit;
if (login.Edit) {
$scope.login = cipherService.decryptLogin(login);

View File

@@ -2,7 +2,7 @@
<button type="button" class="close" ng-click="close()" aria-label="Close"><span aria-hidden="true">&times;</span></button>
<h4 class="modal-title" id="addFolderModelLabel"><i class="fa fa-folder"></i> Add New Folder</h4>
</div>
<form name="addFolderForm" ng-submit="addFolderForm.$valid && save(folder)" api-form="savePromise">
<form name="addFolderForm" ng-submit="addFolderForm.$valid && save(folder)" api-form="savePromise" autocomplete="off">
<div class="modal-body">
<div class="callout callout-danger validation-errors" ng-show="addFolderForm.$errors">
<h4>Errors have occurred</h4>

View File

@@ -2,7 +2,7 @@
<button type="button" class="close" ng-click="close()" aria-label="Close"><span aria-hidden="true">&times;</span></button>
<h4 class="modal-title" id="addLoginModelLabel"><i class="fa fa-globe"></i> Add New Login</h4>
</div>
<form name="addLoginForm" ng-submit="addLoginForm.$valid && save(login)" api-form="savePromise">
<form name="addLoginForm" ng-submit="addLoginForm.$valid && save(login)" api-form="savePromise" autocomplete="off">
<div class="modal-body">
<div class="callout callout-danger validation-errors" ng-show="addLoginForm.$errors">
<h4>Errors have occurred</h4>
@@ -11,13 +11,13 @@
</ul>
</div>
<div class="row">
<div class="col-md-6">
<div class="col-sm-6">
<div class="form-group" show-errors>
<label for="name">Name</label> <span>*</span>
<input type="text" id="name" name="Name" ng-model="login.name" class="form-control" required api-field />
</div>
</div>
<div class="col-md-6" ng-if="!hideFolders">
<div class="col-sm-6" ng-if="!hideFolders">
<div class="form-group" show-errors>
<label for="folder">Folder</label>
<select id="folder" name="FolderId" ng-model="login.folderId" class="form-control" api-field>
@@ -40,7 +40,7 @@
</div>
</div>
<div class="row">
<div class="col-md-6">
<div class="col-sm-6">
<div class="form-group" show-errors>
<label for="username">Username</label>
<div class="input-group">
@@ -55,7 +55,7 @@
</div>
</div>
</div>
<div class="col-md-6">
<div class="col-sm-6">
<div class="form-group" show-errors style="margin-bottom: 5px;">
<div class="pull-right password-options">
<i class="fa fa-lg fa-refresh" uib-tooltip="Generate Password" tooltip-placement="left" ng-click="generatePassword()"></i>
@@ -80,14 +80,14 @@
</div>
</div>
<div class="row">
<div class="col-md-6">
<div class="col-sm-6">
<div class="form-group" show-errors>
<label for="totp">Authenticator Key (TOTP)</label>
<input type="text" id="totp" name="Totp" ng-model="login.totp" class="form-control"
ng-readonly="readOnly" api-field />
</div>
</div>
<div class="col-md-6 totp-col">
<div class="col-sm-6 totp-col">
<div totp="login.totp" id="verification-code" ng-if="useTotp"></div>
<div ng-if="!useTotp">
<a href="#" stop-click ng-click="showUpgrade()"><img src="images/totp-countdown.png" alt="" /></a>
@@ -99,17 +99,73 @@
<label for="notes">Notes</label>
<textarea id="notes" name="Notes" class="form-control" ng-model="login.notes" api-field></textarea>
</div>
<div class="checkbox" ng-if="!hideFavorite">
<label>
<input type="checkbox" ng-model="login.favorite" name="Favorite" />
Favorite
</label>
<hr />
<h4><i class="fa fa-list-ul"></i> Custom Fields</h4>
<div ng-repeat="field in login.fields">
<div class="row">
<div class="col-sm-3">
<div class="form-group">
<label for="field_name{{$index}}">Name</label>
<input type="text" id="field_name{{$index}}" name="Field.Name{{$index}}" class="form-control" ng-model="field.name" />
</div>
</div>
<div class="col-sm-3">
<div class="form-group">
<label for="field_type{{$index}}">Type</label>
<select id="field_type{{$index}}" name="Field.Type{{$index}}" class="form-control" ng-model="field.type">
<option value="0">Text</option>
<option value="1">Hidden</option>
<option value="2">Boolean</option>
</select>
</div>
</div>
<div class="col-sm-5">
<div class="form-group">
<div class="pull-right password-options" ng-if="field.type === '1'">
<i class="fa fa-lg fa-eye" uib-tooltip="Toggle Visibility" tooltip-placement="left"
password-viewer="#field_value{{$index}}"></i>
</div>
<label for="field_value{{$index}}">Value</label>
<div class="input-group" ng-if="field.type !== '2'">
<input ng-attr-type="{{field.type === '0' ? 'text' : 'password'}}" id="field_value{{$index}}"
name="Field.Value{{$index}}" class="form-control" ng-model="field.value" />
<span class="input-group-btn" uib-tooltip="Copy Value" tooltip-placement="left">
<button class="btn btn-default btn-flat" type="button" ngclipboard
ngclipboard-success="clipboardSuccess(e)" ngclipboard-error="clipboardError(e, true)"
data-clipboard-text="{{field.value}}">
<i class="fa fa-clipboard"></i>
</button>
</span>
</div>
<div ng-if="field.type === '2'">
<input type="checkbox" id="field_value{{$index}}" name="Field.Value{{$index}}" ng-model="field.value"
data-ng-true-value="'true'" />
</div>
</div>
</div>
<div class="col-sm-1">
<br class="hidden-xs" />
<a href="#" ng-click="removeField(field)" stop-click>
<i class="fa fa-window-close-o fa-lg"></i>
<span class="visible-xs-inline">Remove Custom Field</span>
</a>
</div>
</div>
<hr class="visible-xs-block" />
</div>
<a href="#" ng-click="addField()" stop-click>
<i class="fa fa-plus-circle"></i> New Custom Field
</a>
</div>
<div class="modal-footer">
<button type="submit" class="btn btn-primary btn-flat" ng-disabled="addLoginForm.$loading">
<i class="fa fa-refresh fa-spin loading-icon" ng-show="addLoginForm.$loading"></i>Submit
</button>
<button type="button" class="btn btn-default btn-flat" ng-click="close()">Close</button>
<button type="button" ng-if="!hideFavorite" class="btn btn-link pull-right" ng-click="toggleFavorite()"
uib-tooltip="Toggle Favorite" tooltip-placement="left">
<i class="fa fa-lg" ng-class="login.favorite ? 'fa-star' : 'fa-star-o'"></i>
<span class="sr-only">Toggle Favorite</span>
</button>
</div>
</form>

View File

@@ -4,7 +4,7 @@
<i class="fa fa-paperclip"></i> Secure Attachments <small>{{login.name}}</small>
</h4>
</div>
<form name="form" ng-submit="form.$valid && save(form)" api-form="savePromise">
<form name="form" ng-submit="form.$valid && save(form)" api-form="savePromise" autocomplete="off">
<div class="modal-body">
<div ng-if="loading">
Loading...

View File

@@ -2,7 +2,7 @@
<button type="button" class="close" ng-click="close()" aria-label="Close"><span aria-hidden="true">&times;</span></button>
<h4 class="modal-title" id="editFolderModelLabel"><i class="fa fa-folder"></i> Edit Folder <small>{{folder.name}}</small></h4>
</div>
<form name="editFolderForm" ng-submit="editFolderForm.$valid && save(folder)" api-form="savePromise">
<form name="editFolderForm" ng-submit="editFolderForm.$valid && save(folder)" api-form="savePromise" autocomplete="off">
<div class="modal-body">
<div class="callout callout-danger validation-errors" ng-show="editFolderForm.$errors">
<h4>Errors have occurred</h4>

View File

@@ -4,7 +4,7 @@
<i class="fa fa-globe"></i> Login Information <small>{{login.name}}</small>
</h4>
</div>
<form name="editLoginForm" ng-submit="editLoginForm.$valid && save(login)" api-form="savePromise">
<form name="editLoginForm" ng-submit="editLoginForm.$valid && save(login)" api-form="savePromise" autocomplete="off">
<div class="modal-body">
<div class="callout callout-danger validation-errors" ng-show="editLoginForm.$errors">
<h4>Errors have occurred</h4>
@@ -13,14 +13,14 @@
</ul>
</div>
<div class="row">
<div class="col-md-6">
<div class="col-sm-6">
<div class="form-group" show-errors>
<label for="name">Name</label> <span>*</span>
<input type="text" id="name" name="Name" ng-model="login.name" class="form-control"
ng-readonly="readOnly" required api-field />
</div>
</div>
<div class="col-md-6" ng-if="!hideFolders">
<div class="col-sm-6" ng-if="!hideFolders">
<div class="form-group" show-errors>
<label for="folder">Folder</label>
<select id="folder" name="FolderId" ng-model="login.folderId" class="form-control" api-field>
@@ -50,7 +50,7 @@
</div>
</div>
<div class="row">
<div class="col-md-6">
<div class="col-sm-6">
<div class="form-group" show-errors>
<label for="username">Username</label>
<div class="input-group">
@@ -66,7 +66,7 @@
</div>
</div>
</div>
<div class="col-md-6">
<div class="col-sm-6">
<div class="form-group" show-errors style="margin-bottom: 5px;">
<div class="pull-right password-options">
<i class="fa fa-lg fa-refresh" uib-tooltip="Generate Password" tooltip-placement="left"
@@ -92,14 +92,14 @@
</div>
</div>
<div class="row">
<div class="col-md-6">
<div class="col-sm-6">
<div class="form-group" show-errors>
<label for="totp">Authenticator Key (TOTP)</label>
<input type="text" id="totp" name="Totp" ng-model="login.totp" class="form-control"
ng-readonly="readOnly" api-field />
</div>
</div>
<div class="col-md-6 totp-col">
<div class="col-sm-6 totp-col">
<div totp="login.totp" id="verification-code" ng-if="useTotp"></div>
<div ng-if="!useTotp">
<a href="#" stop-click ng-click="showUpgrade()"><img src="images/totp-countdown.png" alt="" /></a>
@@ -112,20 +112,81 @@
<textarea id="notes" name="Notes" class="form-control" ng-model="login.notes"
ng-readonly="readOnly" api-field></textarea>
</div>
<div class="checkbox" ng-if="!hideFavorite">
<label>
<input type="checkbox" ng-model="login.favorite" name="Favorite" />
Favorite
</label>
<div ng-if="!readOnly || (login.fields && login.fields.length)">
<hr />
<h4><i class="fa fa-list-ul"></i> Custom Fields</h4>
</div>
<div ng-repeat="field in login.fields">
<div class="row">
<div class="col-sm-3">
<div class="form-group">
<label for="field_name{{$index}}">Name</label>
<input type="text" id="field_name{{$index}}" class="form-control" ng-model="field.name"
ng-readonly="readOnly" />
</div>
</div>
<div class="col-sm-3">
<div class="form-group">
<label for="field_type{{$index}}">Type</label>
<select id="field_type{{$index}}" class="form-control" ng-model="field.type" ng-disabled="readOnly">
<option value="0">Text</option>
<option value="1">Hidden</option>
<option value="2">Boolean</option>
</select>
</div>
</div>
<div class="col-sm-5">
<div class="form-group">
<div class="pull-right password-options" ng-if="field.type === '1'">
<i class="fa fa-lg fa-eye" uib-tooltip="Toggle Visibility" tooltip-placement="left"
password-viewer="#field_value{{$index}}"></i>
</div>
<label for="field_value{{$index}}">Value</label>
<div class="input-group" ng-if="field.type !== '2'">
<input ng-attr-type="{{field.type === '0' ? 'text' : 'password'}}" id="field_value{{$index}}"
class="form-control" ng-model="field.value" ng-readonly="readOnly" />
<span class="input-group-btn" uib-tooltip="Copy Value" tooltip-placement="left">
<button class="btn btn-default btn-flat" type="button" ngclipboard
ngclipboard-success="clipboardSuccess(e)" ngclipboard-error="clipboardError(e, true)"
data-clipboard-text="{{field.value}}">
<i class="fa fa-clipboard"></i>
</button>
</span>
</div>
<div ng-if="field.type === '2'">
<input type="checkbox" id="field_value{{$index}}" ng-model="field.value"
data-ng-true-value="'true'" ng-disabled="readOnly" />
</div>
</div>
</div>
<div class="col-sm-1">
<br class="hidden-xs" />
<a href="#" ng-click="removeField(field)" stop-click ng-if="!readOnly">
<i class="fa fa-window-close-o fa-lg"></i>
<span class="visible-xs-inline">Remove Custom Field</span>
</a>
</div>
</div>
<hr class="visible-xs-block" />
</div>
<a href="#" ng-click="addField()" stop-click ng-if="!readOnly">
<i class="fa fa-plus-circle"></i> New Custom Field
</a>
</div>
<div class="modal-footer">
<button type="submit" class="btn btn-primary btn-flat" ng-disabled="editLoginForm.$loading">
<i class="fa fa-refresh fa-spin loading-icon" ng-show="editLoginForm.$loading"></i>Save
</button>
<button type="button" class="btn btn-default btn-flat" ng-click="close()">Close</button>
<button type="button" class="btn btn-link pull-right" ng-click="delete()" uib-tooltip="Delete" ng-disabled="readOnly">
<button type="button" class="btn btn-link pull-right" ng-click="delete()" uib-tooltip="Delete"
tooltip-placement="left" ng-disabled="readOnly">
<i class="fa fa-trash fa-lg"></i>
<span class="sr-only">Delete</span>
</button>
<button type="button" ng-if="!hideFavorite" class="btn btn-link pull-right" ng-click="toggleFavorite()"
uib-tooltip="Toggle Favorite" tooltip-placement="left">
<i class="fa fa-lg" ng-class="login.favorite ? 'fa-star' : 'fa-star-o'"></i>
<span class="sr-only">Toggle Favorite</span>
</button>
</div>
</form>

View File

@@ -2,7 +2,7 @@
<button type="button" class="close" ng-click="close()" aria-label="Close"><span aria-hidden="true">&times;</span></button>
<h4 class="modal-title"><i class="fa fa-cubes"></i> Collections <small>{{login.name}}</small></h4>
</div>
<form name="form" ng-submit="form.$valid && submit()" api-form="submitPromise">
<form name="form" ng-submit="form.$valid && submit()" api-form="submitPromise" autocomplete="off">
<div class="modal-body">
<p>Edit the collections that this login is being shared with.</p>
<div class="callout callout-danger validation-errors" ng-show="form.$errors">

View File

@@ -4,7 +4,7 @@
<i class="fa fa-share"></i> Move Logins
</h4>
</div>
<form name="form" ng-submit="form.$valid && save()" api-form="savePromise">
<form name="form" ng-submit="form.$valid && save()" api-form="savePromise" autocomplete="off">
<div class="modal-body">
<div class="callout callout-danger validation-errors" ng-show="form.$errors">
<h4>Errors have occurred</h4>

View File

@@ -2,7 +2,7 @@
<button type="button" class="close" ng-click="close()" aria-label="Close"><span aria-hidden="true">&times;</span></button>
<h4 class="modal-title"><i class="fa fa-share-alt"></i> Share Login <small>{{login.name}}</small></h4>
</div>
<form name="form" ng-submit="form.$valid && submit(model)" api-form="submitPromise">
<form name="form" ng-submit="form.$valid && submit(model)" api-form="submitPromise" autocomplete="off">
<div class="modal-body">
<p>Choose an organization that you wish to share this login with.</p>
<div class="callout callout-danger validation-errors" ng-show="form.$errors">

View File

@@ -15,12 +15,12 @@
<ul class="fa-ul">
<li>
<a href="https://chrome.google.com/webstore/detail/bitwarden-free-password-m/nngceckbapebfimnlniiiahkandclblb" target="_blank">
<i class="fa fa-chrome fa-lg fa-fw fa-li"></i> Chrome
<i class="fa fa-chrome fa-lg fa-fw fa-li"></i> Google Chrome
</a>
</li>
<li>
<a href="https://addons.mozilla.org/firefox/addon/bitwarden-password-manager/" target="_blank">
<i class="fa fa-firefox fa-lg fa-fw fa-li"></i> Firefox
<i class="fa fa-firefox fa-lg fa-fw fa-li"></i> Mozilla Firefox
</a>
</li>
<li>
@@ -29,9 +29,8 @@
</a>
</li>
<li>
<a href="#" stop-click>
<i class="fa fa-edge fa-lg fa-fw fa-li"></i> Edge
<small class="text-muted">(coming soon)</small>
<a href="https://www.microsoft.com/store/p/bitwarden-free-password-manager/9p6kxl0svnnl" target="_blank">
<i class="fa fa-edge fa-lg fa-fw fa-li"></i> Microsoft Edge
</a>
</li>
</ul>
@@ -51,7 +50,7 @@
</li>
<li>
<a href="https://addons.mozilla.org/firefox/addon/bitwarden-password-manager/" target="_blank">
Tor
Tor Browser
</a>
</li>
</ul>

View File

@@ -59,8 +59,6 @@
</li>
<li class="treeview" ng-class="{active: $state.is('backend.user.shared')}">
<a ui-sref="backend.user.shared">
<small class="label pull-right bg-orange">NEW</small>
<i class="fa fa-share-alt fa-fw"></i> <span>Shared</span>
</a>
</li>
@@ -137,8 +135,8 @@
<li ng-repeat="org in orgs | orderBy: ['name'] track by org.id">
<a href="#" stop-click ng-click="viewOrganization(org)">
<letter-avatar data="{{org.name}}" avclass="img-responsive img-rounded" round="false"
avheight="40" avwidth="40" bgcolor="#2c3b41" avborder="true"
borderstyle="3px solid #1a2226"></letter-avatar>
avheight="40" avwidth="40" bgcolor="{{orgIconBgColor}}" avborder="true"
borderstyle="{{orgIconBorder}}" textcolor="{{orgIconTextColor}}"></letter-avatar>
</a>
</li>
</ul>

View File

@@ -103,7 +103,7 @@
<link rel="stylesheet" href="css/vault.css" />
<!-- @endexclude -->
</head>
<body ng-controller="mainController as main" class="layout-boxed skin-blue sidebar-mini {{main.bodyClass}}"
<body ng-controller="mainController as main" class="layout-boxed {{main.skinClass}} sidebar-mini {{main.bodyClass}}"
ng-class="{'using-control-sidebar': main.usingControlSidebar,
'control-sidebar-open': main.usingControlSidebar && main.openControlSidebar}">
<div ui-view></div>

File diff suppressed because it is too large Load Diff

View File

@@ -46,3 +46,4 @@
/* End AdminLTE */
@import "../../node_modules/admin-lte/build/less/skins/skin-blue.less";
@import "../../node_modules/admin-lte/build/less/skins/skin-blue-light.less";

View File

@@ -20,6 +20,45 @@ h1, h2, h3, h4, h5, h6,
font-family: 'Open Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif;
}
body.skin-blue-light {
.main-header {
.logo {
.logo-variant(darken(@light-blue, 5%));
}
}
.sidebar-menu > li {
> a {
font-weight: normal;
}
&:hover > a, &.active > a {
border-left-color: @light-blue;
font-weight: normal;
}
&.header {
background: darken(@sidebar-light-hover-bg, 3%);
}
> .treeview-menu {
background: #ffffff;
}
}
}
body.skin-blue {
.content-wrapper, .main-footer {
border-left: 1px solid transparent;
}
.sidebar-menu > li {
&.header {
color: @sidebar-dark-submenu-color;
}
}
}
.login-box, .register-box {
width: 400px;
margin: 4% auto;
@@ -215,9 +254,7 @@ form div.validation-errors ul {
}
}
}
/* Buttons */
.btn-table {
padding: 1px 5px;
line-height: 1;
@@ -259,9 +296,7 @@ form .btn .loading-icon {
display: none;
}
}
/* Forms */
.form-control {
border-radius: 0 !important;
}
@@ -353,13 +388,27 @@ form .btn .loading-icon {
}
/* Modals */
.modal-footer {
text-align: left;
}
/* Tables */
@media (min-width: @screen-sm-min) {
.modal-dialog {
width: 750px;
}
.modal-sm {
width: 300px;
}
}
@media (min-width: @screen-md-min) {
.modal-lg {
width: 970px;
}
}
/* Tables */
.table-selectable {
td:not(.actions) {
cursor: pointer;
@@ -386,9 +435,7 @@ form .btn .loading-icon {
display: none;
}
}
/* Callouts */
.callout.callout-default {
background-color: #fff;
border-color: darken(@gray, 10%);
@@ -420,9 +467,7 @@ form .btn .loading-icon {
color: @btn-default-color;
}
}
/* Alerts */
.alert-notification {
border-radius: 0;
border-left: none;
@@ -430,9 +475,7 @@ form .btn .loading-icon {
margin-bottom: 0;
cursor: pointer;
}
/* Boxes */
.box > .list-group {
margin-bottom: 0;
}
@@ -489,9 +532,7 @@ form .btn .loading-icon {
}
}
}
/* Toastr */
#toast-container {
position: absolute;
@@ -563,15 +604,11 @@ form .btn .loading-icon {
}
}
}
/* Typography */
h1, h2, h3, h4, h5, h6 {
margin-top: 0;
}
/* Misc */
.strike {
text-decoration: line-through;
color: @text-muted;
@@ -740,7 +777,7 @@ h1, h2, h3, h4, h5, h6 {
margin-bottom: 10px;
}
@media (min-width: @screen-md) {
@media (min-width: @screen-sm) {
.progress {
margin-bottom: 0;
}