shared vault listing conversion to ciphers
This commit is contained in:
parent
3b71760f9e
commit
7c93c82d24
|
@ -74,7 +74,7 @@ angular
|
||||||
|
|
||||||
var key = null;
|
var key = null;
|
||||||
if (encryptedCipher.OrganizationId) {
|
if (encryptedCipher.OrganizationId) {
|
||||||
key = cryptoService.getOrgKey(encryptedLogin.OrganizationId);
|
key = cryptoService.getOrgKey(encryptedCipher.OrganizationId);
|
||||||
}
|
}
|
||||||
|
|
||||||
var cipher = {
|
var cipher = {
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
|
|
||||||
.controller('vaultSharedController', function ($scope, apiService, cipherService, $analytics, $q, $localStorage,
|
.controller('vaultSharedController', function ($scope, apiService, cipherService, $analytics, $q, $localStorage,
|
||||||
$uibModal, $filter, $rootScope, authService, cryptoService) {
|
$uibModal, $filter, $rootScope, authService, cryptoService) {
|
||||||
$scope.logins = [];
|
$scope.ciphers = [];
|
||||||
$scope.collections = [];
|
$scope.collections = [];
|
||||||
$scope.loading = true;
|
$scope.loading = true;
|
||||||
|
|
||||||
|
@ -22,16 +22,16 @@
|
||||||
}).$promise;
|
}).$promise;
|
||||||
|
|
||||||
var cipherPromise = apiService.ciphers.listDetails({}, function (ciphers) {
|
var cipherPromise = apiService.ciphers.listDetails({}, function (ciphers) {
|
||||||
var decLogins = [];
|
var decCiphers = [];
|
||||||
|
|
||||||
for (var i = 0; i < ciphers.Data.length; i++) {
|
for (var i = 0; i < ciphers.Data.length; i++) {
|
||||||
if (ciphers.Data[i].Type === 1) {
|
if (ciphers.Data[i].Type === 1) {
|
||||||
var decLogin = cipherService.decryptLoginPreview(ciphers.Data[i]);
|
var decCipher = cipherService.decryptCipherPreview(ciphers.Data[i]);
|
||||||
decLogins.push(decLogin);
|
decCiphers.push(decCipher);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (decLogins.length) {
|
if (decCiphers.length) {
|
||||||
$scope.collections.push({
|
$scope.collections.push({
|
||||||
id: null,
|
id: null,
|
||||||
name: 'Unassigned',
|
name: 'Unassigned',
|
||||||
|
@ -39,7 +39,7 @@
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
$scope.logins = decLogins;
|
$scope.ciphers = decCiphers;
|
||||||
}).$promise;
|
}).$promise;
|
||||||
|
|
||||||
$q.all([collectionPromise, cipherPromise]).then(function () {
|
$q.all([collectionPromise, cipherPromise]).then(function () {
|
||||||
|
@ -49,29 +49,29 @@
|
||||||
|
|
||||||
$scope.clipboardError = function (e) {
|
$scope.clipboardError = function (e) {
|
||||||
alert('Your web browser does not support easy clipboard copying. ' +
|
alert('Your web browser does not support easy clipboard copying. ' +
|
||||||
'Edit the login and copy it manually instead.');
|
'Edit the item and copy it manually instead.');
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.attachments = function (login) {
|
$scope.attachments = function (cipher) {
|
||||||
authService.getUserProfile().then(function (profile) {
|
authService.getUserProfile().then(function (profile) {
|
||||||
return {
|
return {
|
||||||
isPremium: profile.premium,
|
isPremium: profile.premium,
|
||||||
orgUseStorage: login.organizationId && !!profile.organizations[login.organizationId].maxStorageGb
|
orgUseStorage: cipher.organizationId && !!profile.organizations[cipher.organizationId].maxStorageGb
|
||||||
};
|
};
|
||||||
}).then(function (perms) {
|
}).then(function (perms) {
|
||||||
if (login.organizationId && !perms.orgUseStorage) {
|
if (cipher.organizationId && !perms.orgUseStorage) {
|
||||||
$uibModal.open({
|
$uibModal.open({
|
||||||
animation: true,
|
animation: true,
|
||||||
templateUrl: 'app/views/paidOrgRequired.html',
|
templateUrl: 'app/views/paidOrgRequired.html',
|
||||||
controller: 'paidOrgRequiredController',
|
controller: 'paidOrgRequiredController',
|
||||||
resolve: {
|
resolve: {
|
||||||
orgId: function () { return login.organizationId; }
|
orgId: function () { return cipher.organizationId; }
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!login.organizationId && !perms.isPremium) {
|
if (!cipher.organizationId && !perms.isPremium) {
|
||||||
$uibModal.open({
|
$uibModal.open({
|
||||||
animation: true,
|
animation: true,
|
||||||
templateUrl: 'app/views/premiumRequired.html',
|
templateUrl: 'app/views/premiumRequired.html',
|
||||||
|
@ -80,7 +80,7 @@
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!login.organizationId && !cryptoService.getEncKey()) {
|
if (!cipher.organizationId && !cryptoService.getEncKey()) {
|
||||||
toastr.error('You cannot use this feature until you update your encryption key.', 'Feature Unavailable');
|
toastr.error('You cannot use this feature until you update your encryption key.', 'Feature Unavailable');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -90,12 +90,12 @@
|
||||||
templateUrl: 'app/vault/views/vaultAttachments.html',
|
templateUrl: 'app/vault/views/vaultAttachments.html',
|
||||||
controller: 'vaultAttachmentsController',
|
controller: 'vaultAttachmentsController',
|
||||||
resolve: {
|
resolve: {
|
||||||
loginId: function () { return login.id; }
|
loginId: function () { return cipher.id; }
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
attachmentModel.result.then(function (hasAttachments) {
|
attachmentModel.result.then(function (hasAttachments) {
|
||||||
login.hasAttachments = hasAttachments;
|
cipher.hasAttachments = hasAttachments;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -133,62 +133,62 @@
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.editLogin = function (login) {
|
$scope.editCipher = function (cipher) {
|
||||||
var editModel = $uibModal.open({
|
var editModel = $uibModal.open({
|
||||||
animation: true,
|
animation: true,
|
||||||
templateUrl: 'app/vault/views/vaultEditLogin.html',
|
templateUrl: 'app/vault/views/vaultEditCipher.html',
|
||||||
controller: 'vaultEditLoginController',
|
controller: 'vaultEditCipherController',
|
||||||
resolve: {
|
resolve: {
|
||||||
loginId: function () { return login.id; }
|
cipherId: function () { return cipher.id; }
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
editModel.result.then(function (returnVal) {
|
editModel.result.then(function (returnVal) {
|
||||||
var rootLogin = findRootLogin(login) || {};
|
var rootCipher = findRootCipher(cipher) || { meta: {} };
|
||||||
|
|
||||||
if (returnVal.action === 'edit') {
|
if (returnVal.action === 'edit') {
|
||||||
login.folderId = rootLogin.folderId = returnVal.data.folderId;
|
cipher.folderId = rootCipher.folderId = returnVal.data.folderId;
|
||||||
login.name = rootLogin.name = returnVal.data.name;
|
cipher.name = rootCipher.name = returnVal.data.name;
|
||||||
login.username = rootLogin.username = returnVal.data.username;
|
cipher.subTitle = rootCipher.subTitle = returnVal.data.login.username;
|
||||||
login.password = rootLogin.password = returnVal.data.password;
|
cipher.meta.password = rootCipher.meta.password = returnVal.data.login.password;
|
||||||
login.favorite = rootLogin.favorite = returnVal.data.favorite;
|
cipher.favorite = rootCipher.favorite = returnVal.data.favorite;
|
||||||
}
|
}
|
||||||
else if (returnVal.action === 'partialEdit') {
|
else if (returnVal.action === 'partialEdit') {
|
||||||
login.folderId = rootLogin.folderId = returnVal.data.folderId;
|
cipher.folderId = rootCipher.folderId = returnVal.data.folderId;
|
||||||
login.favorite = rootLogin.favorite = returnVal.data.favorite;
|
cipher.favorite = rootCipher.favorite = returnVal.data.favorite;
|
||||||
}
|
}
|
||||||
else if (returnVal.action === 'delete') {
|
else if (returnVal.action === 'delete') {
|
||||||
var index = $scope.logins.indexOf(login);
|
var index = $scope.ciphers.indexOf(cipher);
|
||||||
if (index > -1) {
|
if (index > -1) {
|
||||||
$scope.logins.splice(index, 1);
|
$scope.ciphers.splice(index, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
removeRootLogin(rootLogin);
|
removeRootCipher(rootCipher);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.editCollections = function (login) {
|
$scope.editCollections = function (cipher) {
|
||||||
var modal = $uibModal.open({
|
var modal = $uibModal.open({
|
||||||
animation: true,
|
animation: true,
|
||||||
templateUrl: 'app/vault/views/vaultLoginCollections.html',
|
templateUrl: 'app/vault/views/vaultLoginCollections.html',
|
||||||
controller: 'vaultLoginCollectionsController',
|
controller: 'vaultLoginCollectionsController',
|
||||||
resolve: {
|
resolve: {
|
||||||
loginId: function () { return login.id; }
|
loginId: function () { return cipher.id; }
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
modal.result.then(function (response) {
|
modal.result.then(function (response) {
|
||||||
if (response.collectionIds) {
|
if (response.collectionIds) {
|
||||||
login.collectionIds = response.collectionIds;
|
cipher.collectionIds = response.collectionIds;
|
||||||
// TODO: if there are no collectionIds now, it is possible that the user no longer has access to this login
|
// TODO: if there are no collectionIds now, it is possible that the user no longer has access to this cipher
|
||||||
// which means it should be removed by calling removeRootLogin(findRootLogin(login))
|
// which means it should be removed by calling removeRootCipher(findRootCipher(cipher))
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.removeLogin = function (login, collection) {
|
$scope.removeCipher = function (cipher, collection) {
|
||||||
if (!confirm('Are you sure you want to remove this login (' + login.name + ') from the ' +
|
if (!confirm('Are you sure you want to remove this item (' + cipher.name + ') from the ' +
|
||||||
'collection (' + collection.name + ') ?')) {
|
'collection (' + collection.name + ') ?')) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -197,34 +197,34 @@
|
||||||
collectionIds: []
|
collectionIds: []
|
||||||
};
|
};
|
||||||
|
|
||||||
for (var i = 0; i < login.collectionIds.length; i++) {
|
for (var i = 0; i < cipher.collectionIds.length; i++) {
|
||||||
if (login.collectionIds[i] !== collection.id) {
|
if (cipher.collectionIds[i] !== collection.id) {
|
||||||
request.collectionIds.push(login.collectionIds[i]);
|
request.collectionIds.push(cipher.collectionIds[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
apiService.ciphers.putCollections({ id: login.id }, request).$promise.then(function (response) {
|
apiService.ciphers.putCollections({ id: cipher.id }, request).$promise.then(function (response) {
|
||||||
$analytics.eventTrack('Removed From Collection');
|
$analytics.eventTrack('Removed From Collection');
|
||||||
login.collectionIds = request.collectionIds;
|
cipher.collectionIds = request.collectionIds;
|
||||||
// TODO: if there are no collectionIds now, it is possible that the user no longer has access to this login
|
// TODO: if there are no collectionIds now, it is possible that the user no longer has access to this cipher
|
||||||
// which means it should be removed by calling removeRootLogin(findRootLogin(login))
|
// which means it should be removed by calling removeRootCipher(findRootCipher(cipher))
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
function findRootLogin(login) {
|
function findRootCipher(cipher) {
|
||||||
if ($rootScope.vaultCiphers) {
|
if ($rootScope.vaultCiphers) {
|
||||||
var rootLogins = $filter('filter')($rootScope.vaultCiphers, { id: login.id });
|
var rootCiphers = $filter('filter')($rootScope.vaultCiphers, { id: cipher.id });
|
||||||
if (rootLogins && rootLogins.length) {
|
if (rootCiphers && rootCiphers.length) {
|
||||||
return rootLogins[0];
|
return rootCiphers[0];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
function removeRootLogin(rootLogin) {
|
function removeRootCipher(rootCipher) {
|
||||||
if (rootLogin && rootLogin.id) {
|
if (rootCipher && rootCipher.id) {
|
||||||
var index = $rootScope.vaultCiphers.indexOf(rootLogin);
|
var index = $rootScope.vaultCiphers.indexOf(rootCipher);
|
||||||
if (index > -1) {
|
if (index > -1) {
|
||||||
$rootScope.vaultCiphers.splice(index, 1);
|
$rootScope.vaultCiphers.splice(index, 1);
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,18 +3,18 @@
|
||||||
Shared
|
Shared
|
||||||
<small>
|
<small>
|
||||||
<span ng-pluralize
|
<span ng-pluralize
|
||||||
count="collections.length > 0 && logins.length ? collections.length - 1 : collections.length"
|
count="collections.length > 0 && ciphers.length ? collections.length - 1 : collections.length"
|
||||||
when="{'1': '{} collection', 'other': '{} collections'}"></span>,
|
when="{'1': '{} collection', 'other': '{} collections'}"></span>,
|
||||||
<span ng-pluralize count="logins.length" when="{'1': '{} login', 'other': '{} logins'}"></span>
|
<span ng-pluralize count="ciphers.length" when="{'1': '{} item', 'other': '{} items'}"></span>
|
||||||
</small>
|
</small>
|
||||||
</h1>
|
</h1>
|
||||||
</section>
|
</section>
|
||||||
<section class="content">
|
<section class="content">
|
||||||
<p ng-show="loading && !collections.length">Loading...</p>
|
<p ng-show="loading && !collections.length">Loading...</p>
|
||||||
<div class="callout callout-default" style="background: #fff;" ng-show="!loading && !collections.length && !logins.length">
|
<div class="callout callout-default" style="background: #fff;" ng-show="!loading && !collections.length && !ciphers.length">
|
||||||
<h4>Nothing shared <i class="fa fa-frown-o"></i></h4>
|
<h4>Nothing shared <i class="fa fa-frown-o"></i></h4>
|
||||||
<p>
|
<p>
|
||||||
You do not have any logins or collections being shared with you.
|
You do not have any items or collections being shared with you.
|
||||||
To start sharing, create an organization or ask an existing organization to invite you.
|
To start sharing, create an organization or ask an existing organization to invite you.
|
||||||
</p>
|
</p>
|
||||||
<a ui-sref="backend.user.settingsCreateOrg" class="btn btn-default btn-flat">
|
<a ui-sref="backend.user.settingsCreateOrg" class="btn btn-default btn-flat">
|
||||||
|
@ -28,7 +28,7 @@
|
||||||
<h3 class="box-title">
|
<h3 class="box-title">
|
||||||
<i class="fa" ng-class="{'fa-cubes': collection.id, 'fa-sitemap': !collection.id}"></i>
|
<i class="fa" ng-class="{'fa-cubes': collection.id, 'fa-sitemap': !collection.id}"></i>
|
||||||
{{collection.name}}
|
{{collection.name}}
|
||||||
<small ng-pluralize count="collectionLogins.length" when="{'1': '{} login', 'other': '{} logins'}"></small>
|
<small ng-pluralize count="collectionCiphers.length" when="{'1': '{} item', 'other': '{} items'}"></small>
|
||||||
</h3>
|
</h3>
|
||||||
<div class="box-tools">
|
<div class="box-tools">
|
||||||
<button type="button" class="btn btn-box-tool" data-widget="collapse" title="Collapse/Expand"
|
<button type="button" class="btn btn-box-tool" data-widget="collapse" title="Collapse/Expand"
|
||||||
|
@ -37,20 +37,20 @@
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="box-body" ng-class="{'no-padding': collectionLogins.length}">
|
<div class="box-body" ng-class="{'no-padding': collectionCiphers.length}">
|
||||||
<div ng-show="!collectionLogins.length && collection.id">
|
<div ng-show="!collectionCiphers.length && collection.id">
|
||||||
<p>No logins in this collection.</p>
|
<p>No items in this collection.</p>
|
||||||
<p>
|
<p>
|
||||||
Share a login to this collection by selecting <i class="fa fa-share-alt"></i> <b>Share</b> or
|
Share an item to this collection by selecting <i class="fa fa-share-alt"></i> <b>Share</b> or
|
||||||
<i class="fa fa-cubes"></i> <b>Collections</b> from the login's options (<i class="fa fa-cog"></i>) menu.
|
<i class="fa fa-cubes"></i> <b>Collections</b> from the item's options (<i class="fa fa-cog"></i>) menu.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div ng-show="!collectionLogins.length && !collection.id">No unassigned logins.</div>
|
<div ng-show="!collectionCiphers.length && !collection.id">No unassigned items.</div>
|
||||||
<div class="table-responsive" ng-show="collectionLogins.length">
|
<div class="table-responsive" ng-show="collectionCiphers.length">
|
||||||
<table class="table table-striped table-hover table-vmiddle">
|
<table class="table table-striped table-hover table-vmiddle">
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr ng-repeat="login in collectionLogins = (logins | filter: filterByCollection(collection) |
|
<tr ng-repeat="cipher in collectionCiphers = (ciphers | filter: filterByCollection(collection) |
|
||||||
orderBy: ['name', 'username']) track by login.id">
|
orderBy: ['name', 'subTitle']) track by cipher.id">
|
||||||
<td style="width: 70px;">
|
<td style="width: 70px;">
|
||||||
<div class="btn-group" data-append-to="body">
|
<div class="btn-group" data-append-to="body">
|
||||||
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown">
|
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown">
|
||||||
|
@ -58,28 +58,28 @@
|
||||||
</button>
|
</button>
|
||||||
<ul class="dropdown-menu">
|
<ul class="dropdown-menu">
|
||||||
<li>
|
<li>
|
||||||
<a href="#" stop-click ng-click="editLogin(login)">
|
<a href="#" stop-click ng-click="editCipher(cipher)">
|
||||||
<i class="fa fa-fw fa-pencil"></i> Edit
|
<i class="fa fa-fw fa-pencil"></i> Edit
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<a href="#" stop-click ng-click="attachments(login)">
|
<a href="#" stop-click ng-click="attachments(cipher)">
|
||||||
<i class="fa fa-fw fa-paperclip"></i> Attachments
|
<i class="fa fa-fw fa-paperclip"></i> Attachments
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li ng-show="login.edit">
|
<li ng-show="cipher.edit">
|
||||||
<a href="#" stop-click ng-click="editCollections(login)">
|
<a href="#" stop-click ng-click="editCollections(cipher)">
|
||||||
<i class="fa fa-fw fa-cubes"></i> Collections
|
<i class="fa fa-fw fa-cubes"></i> Collections
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li ng-show="login.password">
|
<li ng-show="cipher.meta.password">
|
||||||
<a href="#" stop-click ngclipboard ngclipboard-error="clipboardError(e)"
|
<a href="#" stop-click ngclipboard ngclipboard-error="clipboardError(e)"
|
||||||
data-clipboard-text="{{login.password}}">
|
data-clipboard-text="{{cipher.meta.password}}">
|
||||||
<i class="fa fa-fw fa-clipboard"></i> Copy Password
|
<i class="fa fa-fw fa-clipboard"></i> Copy Password
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li ng-show="login.edit">
|
<li ng-show="cipher.edit">
|
||||||
<a href="#" stop-click ng-click="removeLogin(login, collection)"
|
<a href="#" stop-click ng-click="removeCipher(cipher, collection)"
|
||||||
ng-if="collection.id" class="text-red">
|
ng-if="collection.id" class="text-red">
|
||||||
<i class="fa fa-fw fa-remove"></i> Remove
|
<i class="fa fa-fw fa-remove"></i> Remove
|
||||||
</a>
|
</a>
|
||||||
|
@ -88,11 +88,11 @@
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<a href="#" stop-click ng-click="editLogin(login)">{{login.name}}</a>
|
<a href="#" stop-click ng-click="editCipher(cipher)">{{cipher.name}}</a>
|
||||||
<i class="fa fa-star text-muted" title="Favorite" ng-show="login.favorite"></i>
|
<i class="fa fa-star text-muted" title="Favorite" ng-show="cipher.favorite"></i>
|
||||||
<i class="fa fa-paperclip text-muted" title="Attachments" ng-if="login.hasAttachments"
|
<i class="fa fa-paperclip text-muted" title="Attachments" ng-if="cipher.hasAttachments"
|
||||||
stop-prop></i><br />
|
stop-prop></i><br />
|
||||||
<div class="text-sm text-muted">{{login.username}}</div>
|
<div class="text-sm text-muted">{{cipher.subTitle}}</div>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
|
|
Loading…
Reference in New Issue