converting logins to ciphers on vault lists

This commit is contained in:
Kyle Spearrin 2017-10-14 16:31:35 -04:00
parent 355a58f67c
commit 884bce4ec4
5 changed files with 120 additions and 123 deletions

View File

@ -72,7 +72,7 @@
};
_service.logOut = function (callback) {
$rootScope.vaultLogins = null;
$rootScope.vaultCiphers = null;
$rootScope.vaultFolders = null;
callback();
};

View File

@ -22,8 +22,8 @@
var delayLoad = true;
$scope.loaded = true;
if (!$rootScope.vaultLogins) {
$rootScope.vaultLogins = [];
if (!$rootScope.vaultCiphers) {
$rootScope.vaultCiphers = [];
delayLoad = false;
}
if (!$rootScope.vaultFolders) {
@ -42,32 +42,30 @@
function loadVault() {
var decFolders = [];
var decLogins = [];
var decCiphers = [];
var promises = [];
var folderPromise = $q.when(folderService.getAllDecrypted());
folderPromise.then(function (folders) {
var folderPromise = folderService.getAllDecrypted().then(function (folders) {
decFolders = folders;
});
promises.push(folderPromise);
var cipherPromise = loginService.getAllDecrypted();
cipherPromise.then(function (ciphers) {
decLogins = ciphers;
var cipherPromise = loginService.getAllDecrypted().then(function (ciphers) {
decCiphers = ciphers;
});
promises.push(cipherPromise);
$q.all(promises).then(function () {
$scope.loaded = true;
$rootScope.vaultFolders = decFolders;
$rootScope.vaultLogins = decLogins;
$rootScope.vaultCiphers = decCiphers;
if ($scope.showFolderCounts) {
// compute item count for each folder
for (var i = 0; i < decFolders.length; i++) {
var itemCount = 0;
for (var j = 0; j < decLogins.length; j++) {
if (decLogins[j].folderId === decFolders[i].id) {
for (var j = 0; j < decCiphers.length; j++) {
if (decCiphers[j].folderId === decFolders[i].id) {
itemCount++;
}
}
@ -95,30 +93,30 @@
return item.name.toLowerCase();
};
$scope.searchLogins = function () {
$scope.searchCiphers = function () {
if (!$scope.searchText || $scope.searchText.length < 2) {
return;
}
return searchLogin;
return searchCipher;
};
function searchLogin(login) {
function searchCipher(cipher) {
var searchTerm = $scope.searchText.toLowerCase();
if (login.name && login.name.toLowerCase().indexOf(searchTerm) !== -1) {
if (cipher.name && cipher.name.toLowerCase().indexOf(searchTerm) !== -1) {
return true;
}
if (login.username && login.username.toLowerCase().indexOf(searchTerm) !== -1) {
if (cipher.username && cipher.username.toLowerCase().indexOf(searchTerm) !== -1) {
return true;
}
if (login.uri && login.uri.toLowerCase().indexOf(searchTerm) !== -1) {
if (cipher.login && cipher.login.uri && cipher.login.uri.toLowerCase().indexOf(searchTerm) !== -1) {
return true;
}
return false;
}
$scope.addLogin = function () {
$scope.addCipher = function () {
storeState();
$state.go('addLogin', {
animation: 'in-slide-up',
@ -126,32 +124,32 @@
});
};
$scope.viewLogin = function (login) {
if (login.clicked) {
login.cancelClick = true;
$scope.launchWebsite(login);
$scope.viewCipher = function (cipher) {
if (cipher.clicked) {
cipher.cancelClick = true;
$scope.launchWebsite(cipher);
return;
}
login.clicked = true;
cipher.clicked = true;
$timeout(function () {
if (login.cancelClick) {
login.cancelClick = false;
login.clicked = false;
if (cipher.cancelClick) {
cipher.cancelClick = false;
cipher.clicked = false;
return;
}
storeState();
$state.go('viewLogin', {
loginId: login.id,
loginId: cipher.id,
animation: 'in-slide-up',
from: 'vault'
});
// clean up
login.cancelClick = false;
login.clicked = false;
cipher.cancelClick = false;
cipher.clicked = false;
}, 200);
};
@ -173,11 +171,11 @@
toastr.info(type + i18nService.valueCopied);
};
$scope.launchWebsite = function (login) {
$scope.launchWebsite = function (cipher) {
$timeout(function () {
if (login.uri.startsWith('http://') || login.uri.startsWith('https://')) {
if (cipher.uri.startsWith('http://') || cipher.uri.startsWith('https://')) {
$analytics.eventTrack('Launched Website From Listing');
chrome.tabs.create({ url: login.uri });
chrome.tabs.create({ url: cipher.uri });
if (utilsService.inPopup($window)) {
$window.close();
}

View File

@ -10,7 +10,7 @@
var pageSize = 100,
decFolder = null,
decLogins = [];
decCiphers = [];
$scope.folder = {
id: !state.folderId || state.folderId === '0' ? null : state.folderId,
@ -20,8 +20,8 @@
$('#search').focus();
$scope.loaded = false;
$scope.vaultLogins = [];
$scope.pagedVaultLogins = [];
$scope.vaultCiphers = [];
$scope.pagedVaultCiphers = [];
$scope.searchText = null;
loadVault();
@ -31,7 +31,7 @@
if ($scope.folder.id) {
var folderDeferred = $q.defer();
folderService.get($scope.folder.id, function (folder) {
$q.when(folder.decrypt()).then(function (model) {
folder.decrypt().then(function (model) {
decFolder = model;
folderDeferred.resolve();
});
@ -39,21 +39,20 @@
promises.push(folderDeferred.promise);
}
var cipherPromise = loginService.getAllDecryptedForFolder($scope.folder.id);
cipherPromise.then(function (ciphers) {
var cipherPromise = loginService.getAllDecryptedForFolder($scope.folder.id).then(function (ciphers) {
if (utilsService.isEdge()) {
// Edge is super slow at sorting
decLogins = ciphers;
decCiphers = ciphers;
}
else {
decLogins = ciphers.sort(cipherSort);
decCiphers = ciphers.sort(cipherSort);
}
});
promises.push(cipherPromise);
$q.all(promises).then(function () {
$scope.loaded = true;
$scope.vaultLogins = decLogins;
$scope.vaultCiphers = decCiphers;
if (decFolder) {
$scope.folder.name = decFolder.name;
@ -61,7 +60,7 @@
if (state.searchText) {
$scope.searchText = state.searchText;
$scope.searchLogins();
$scope.searchCiphers();
}
$timeout(setScrollY, 200);
@ -106,36 +105,36 @@
}
$scope.loadMore = function () {
var pagedLength = $scope.pagedVaultLogins.length;
if ($scope.vaultLogins.length > pagedLength) {
$scope.pagedVaultLogins =
$scope.pagedVaultLogins.concat($scope.vaultLogins.slice(pagedLength, pagedLength + pageSize));
var pagedLength = $scope.pagedVaultCiphers.length;
if ($scope.vaultCiphers.length > pagedLength) {
$scope.pagedVaultCiphers =
$scope.pagedVaultCiphers.concat($scope.vaultCiphers.slice(pagedLength, pagedLength + pageSize));
}
};
$scope.searchLogins = function () {
$scope.searchCiphers = function () {
if (!$scope.searchText || $scope.searchText.length < 2) {
if ($scope.vaultLogins.length !== decLogins.length) {
resetList(decLogins);
if ($scope.vaultCiphers.length !== decCiphers.length) {
resetList(decCiphers);
}
return;
}
var matchedLogins = [];
for (var i = 0; i < decLogins.length; i++) {
if (searchCipher(decLogins[i])) {
matchedLogins.push(decLogins[i]);
var matchedCiphers = [];
for (var i = 0; i < decCiphers.length; i++) {
if (searchCipher(decCiphers[i])) {
matchedCiphers.push(decCiphers[i]);
}
}
resetList(matchedLogins);
resetList(matchedCiphers);
};
$scope.launchWebsite = function (login) {
$scope.launchWebsite = function (cipher) {
$timeout(function () {
if (login.uri.startsWith('http://') || login.uri.startsWith('https://')) {
if (cipher.uri.startsWith('http://') || cipher.uri.startsWith('https://')) {
$analytics.eventTrack('Launched Website From Listing');
chrome.tabs.create({ url: login.uri });
chrome.tabs.create({ url: cipher.uri });
if (utilsService.inPopup($window)) {
$window.close();
}
@ -143,9 +142,9 @@
});
};
function resetList(logins) {
$scope.vaultLogins = logins;
$scope.pagedVaultLogins = [];
function resetList(ciphers) {
$scope.vaultCiphers = ciphers;
$scope.pagedVaultCiphers = [];
$scope.loadMore();
}
@ -164,7 +163,7 @@
return false;
}
$scope.addLogin = function () {
$scope.addCipher = function () {
storeState();
$state.go('addLogin', {
animation: 'in-slide-up',
@ -173,32 +172,32 @@
});
};
$scope.viewLogin = function (login) {
if (login.clicked) {
login.cancelClick = true;
$scope.launchWebsite(login);
$scope.viewCipher = function (cipher) {
if (cipher.clicked) {
cipher.cancelClick = true;
$scope.launchWebsite(cipher);
return;
}
login.clicked = true;
cipher.clicked = true;
$timeout(function () {
if (login.cancelClick) {
login.cancelClick = false;
login.clicked = false;
if (cipher.cancelClick) {
cipher.cancelClick = false;
cipher.clicked = false;
return;
}
storeState();
$state.go('viewLogin', {
loginId: login.id,
loginId: cipher.id,
animation: 'in-slide-up',
from: 'folder'
});
// clean up
login.cancelClick = false;
login.clicked = false;
cipher.cancelClick = false;
cipher.clicked = false;
}, 200);
};

View File

@ -7,12 +7,12 @@
<i class="fa fa-search"></i>
</div>
<div class="right">
<a href="" ng-click="addLogin()"><i class="fa fa-plus fa-lg"></i></a>
<a href="" ng-click="addCipher()"><i class="fa fa-plus fa-lg"></i></a>
</div>
</div>
<div class="content content-tabs">
<!-- Folder List -->
<div ng-if="vaultLogins.length && (showOnlyFolderView || vaultLogins.length >= 100) && vaultFolders.length && (!searchText || searchText.length < 2)">
<div ng-if="vaultCiphers.length && (showOnlyFolderView || vaultCiphers.length >= 100) && vaultFolders.length && (!searchText || searchText.length < 2)">
<div class="list">
<div class="list-section" style="padding-bottom: 0;">
<div class="list-section-header">
@ -29,80 +29,80 @@
</div>
</div>
<!-- Grouped List -->
<div ng-if="vaultLogins.length && !showOnlyFolderView && vaultLogins.length < 100 && (!searchText || searchText.length < 2)">
<div ng-if="vaultCiphers.length && !showOnlyFolderView && vaultCiphers.length < 100 && (!searchText || searchText.length < 2)">
<div class="list">
<div class="list-grouped" ng-repeat="folder in vaultFolders | orderBy: folderSort track by $index"
ng-show="vaultFolderLogins.length">
ng-show="vaultFolderCiphers.length">
<div class="list-grouped-header">
<small>{{vaultFolderLogins.length}}</small>
<small>{{vaultFolderCiphers.length}}</small>
<i class="fa fa-folder-open"></i> {{folder.name}}
</div>
<a href="#" stop-click ng-click="viewLogin(login)"
class="list-grouped-item condensed" title="{{i18n.edit}} {{login.name}}"
ng-repeat="login in vaultFolderLogins = (vaultLogins | filter: { folderId: folder.id }
| filter: searchLogins() | orderBy: ['name', 'subTitle']) track by $index">
<a href="#" stop-click ng-click="viewCipher(cipher)"
class="list-grouped-item condensed" title="{{i18n.edit}} {{cipher.name}}"
ng-repeat="cipher in vaultFolderCiphers = (vaultCiphers | filter: { folderId: folder.id }
| filter: searchCiphers() | orderBy: ['name', 'subTitle']) track by $index">
<span class="btn-list" stop-prop stop-click title="{{i18n.copyPassword}}" ngclipboard
ngclipboard-error="clipboardError(e)" ngclipboard-success="clipboardSuccess(e, i18n.password)"
data-clipboard-text="{{login.password}}" ng-class="{'disabled': !login.password}">
data-clipboard-text="{{cipher.password}}" ng-class="{'disabled': !cipher.password}">
<i class="fa fa-lg fa-key"></i>
</span>
<span class="btn-list" stop-prop stop-click title="{{i18n.copyUsername}}" ngclipboard
ngclipboard-error="clipboardError(e)" ngclipboard-success="clipboardSuccess(e, i18n.username)"
data-clipboard-text="{{login.username}}" ng-class="{'disabled': !login.username}">
data-clipboard-text="{{cipher.username}}" ng-class="{'disabled': !cipher.username}">
<i class="fa fa-lg fa-user"></i>
</span>
<span class="btn-list" stop-prop stop-click title="{{i18n.launchWebsite}}" ng-click="launchWebsite(login)"
ng-class="{'disabled': !login.uri}">
<span class="btn-list" stop-prop stop-click title="{{i18n.launchWebsite}}" ng-click="launchWebsite(cipher)"
ng-class="{'disabled': !cipher.uri}">
<i class="fa fa-lg fa-share-square-o"></i>
</span>
<icon uri="login.uri"></icon>
<icon uri="cipher.uri"></icon>
<span class="text">
{{login.name}}
<i class="fa fa-share-alt text-muted" ng-if="login.organizationId" title="{{i18n.shared}}"></i>
<i class="fa fa-paperclip text-muted" ng-if="login.attachments" title="{{i18n.attachments}}"></i>
{{cipher.name}}
<i class="fa fa-share-alt text-muted" ng-if="cipher.organizationId" title="{{i18n.shared}}"></i>
<i class="fa fa-paperclip text-muted" ng-if="cipher.attachments" title="{{i18n.attachments}}"></i>
</span>
<span class="detail">{{login.subTitle}}</span>
<span class="detail">{{cipher.subTitle}}</span>
</a>
</div>
</div>
</div>
<!-- Search Results List -->
<div ng-if="vaultLogins.length && searchText && searchText.length >= 2">
<div ng-if="vaultCiphers.length && searchText && searchText.length >= 2">
<div class="list">
<div class="list-section" style="padding-top: 0; padding-bottom: 0;">
<a href="#" stop-click ng-click="viewLogin(login)"
class="list-section-item condensed" title="{{i18n.edit}} {{login.name}}"
ng-repeat="login in searchResults = (vaultLogins | filter: searchLogins() | orderBy: ['name', 'subTitle'])
<a href="#" stop-click ng-click="viewCipher(cipher)"
class="list-section-item condensed" title="{{i18n.edit}} {{cipher.name}}"
ng-repeat="cipher in searchResults = (vaultCiphers | filter: searchCiphers() | orderBy: ['name', 'subTitle'])
track by $index">
<span class="btn-list" stop-prop stop-click title="{{i18n.copyPassword}}" ngclipboard
ngclipboard-error="clipboardError(e)" ngclipboard-success="clipboardSuccess(e, i18n.password)"
data-clipboard-text="{{login.password}}" ng-class="{'disabled': !login.password}">
data-clipboard-text="{{cipher.password}}" ng-class="{'disabled': !cipher.password}">
<i class="fa fa-lg fa-key"></i>
</span>
<span class="btn-list" stop-prop stop-click title="{{i18n.copyUsername}}" ngclipboard
ngclipboard-error="clipboardError(e)" ngclipboard-success="clipboardSuccess(e, i18n.username)"
data-clipboard-text="{{login.username}}" ng-class="{'disabled': !login.username}">
data-clipboard-text="{{cipher.username}}" ng-class="{'disabled': !cipher.username}">
<i class="fa fa-lg fa-user"></i>
</span>
<span class="btn-list" stop-prop stop-click title="{{i18n.launchWebsite}}" ng-click="launchWebsite(login)"
ng-class="{'disabled': !login.uri}">
<span class="btn-list" stop-prop stop-click title="{{i18n.launchWebsite}}" ng-click="launchWebsite(cipher)"
ng-class="{'disabled': !cipher.uri}">
<i class="fa fa-lg fa-share-square-o"></i>
</span>
<icon uri="login.uri"></icon>
<icon uri="cipher.uri"></icon>
<span class="text">
{{login.name}}
<i class="fa fa-share-alt text-muted" ng-if="login.organizationId" title="{{i18n.shared}}"></i>
<i class="fa fa-paperclip text-muted" ng-if="login.attachments" title="{{i18n.attachments}}"></i>
{{cipher.name}}
<i class="fa fa-share-alt text-muted" ng-if="cipher.organizationId" title="{{i18n.shared}}"></i>
<i class="fa fa-paperclip text-muted" ng-if="cipher.attachments" title="{{i18n.attachments}}"></i>
</span>
<span class="detail">{{login.subTitle}}</span>
<span class="detail">{{cipher.subTitle}}</span>
</a>
</div>
</div>
</div>
<div class="centered-message" ng-if="loaded && !vaultLogins.length">
<div class="centered-message" ng-if="loaded && !vaultCiphers.length">
<p>
{{i18n.noLoginsInList}}
<button ng-click="addLogin()" style="margin-top: 20px;" class="btn btn-link btn-block">{{i18n.addLogin}}</button>
<button ng-click="addCipher()" style="margin-top: 20px;" class="btn btn-link btn-block">{{i18n.addLogin}}</button>
</p>
</div>
<div class="page-loading" ng-if="!loaded">

View File

@ -3,53 +3,53 @@
<a ui-sref="tabs.vault({animation: 'out-slide-right'})"><i class="fa fa-chevron-left"></i> {{i18n.myVault}}</a>
</div>
<div class="search">
<input type="search" placeholder="{{i18n.searchFolder}}" ng-model="searchText" ng-change="searchLogins()" id="search" />
<input type="search" placeholder="{{i18n.searchFolder}}" ng-model="searchText" ng-change="searchCiphers()" id="search" />
<i class="fa fa-search"></i>
</div>
<div class="right">
<a href="" ng-click="addLogin()"><i class="fa fa-plus fa-lg"></i></a>
<a href="" ng-click="addCipher()"><i class="fa fa-plus fa-lg"></i></a>
</div>
</div>
<div class="content">
<div ng-if="vaultLogins.length" infinite-scroll="loadMore()" infinite-scroll-distance="1" infinite-scroll-parent="true"
<div ng-if="vaultCiphers.length" infinite-scroll="loadMore()" infinite-scroll-distance="1" infinite-scroll-parent="true"
infinite-scroll-immediate-check="true">
<div class="list">
<div class="list-section" style="padding-bottom: 0;">
<div class="list-section-header">
{{folder.name}}
<span>{{vaultLogins.length}}</span>
<span>{{vaultCiphers.length}}</span>
</div>
<a href="#" stop-click ng-click="viewLogin(login)"
class="list-section-item condensed" title="{{i18n.edit}} {{login.name}}"
ng-repeat="login in pagedVaultLogins track by $index">
<a href="#" stop-click ng-click="viewCipher(cipher)"
class="list-section-item condensed" title="{{i18n.edit}} {{cipher.name}}"
ng-repeat="cipher in pagedVaultCiphers track by $index">
<span class="btn-list" stop-prop stop-click title="{{i18n.copyPassword}}" ngclipboard
ngclipboard-error="clipboardError(e)" ngclipboard-success="clipboardSuccess(e, i18n.password)"
data-clipboard-text="{{login.password}}" ng-class="{'disabled': !login.password}">
data-clipboard-text="{{cipher.password}}" ng-class="{'disabled': !cipher.password}">
<i class="fa fa-lg fa-key"></i>
</span>
<span class="btn-list" stop-prop stop-click title="{{i18n.copyUsername}}" ngclipboard
ngclipboard-error="clipboardError(e)" ngclipboard-success="clipboardSuccess(e, i18n.username)"
data-clipboard-text="{{login.username}}" ng-class="{'disabled': !login.username}">
data-clipboard-text="{{cipher.username}}" ng-class="{'disabled': !cipher.username}">
<i class="fa fa-lg fa-user"></i>
</span>
<span class="btn-list" stop-prop stop-click title="{{i18n.launchWebsite}}" ng-click="launchWebsite(login)"
ng-class="{'disabled': !login.uri}">
<span class="btn-list" stop-prop stop-click title="{{i18n.launchWebsite}}" ng-click="launchWebsite(cipher)"
ng-class="{'disabled': !cipher.uri}">
<i class="fa fa-lg fa-share-square-o"></i>
</span>
<span class="text">
{{login.name}}
<i class="fa fa-share-alt text-muted" ng-if="login.organizationId" title="{{i18n.shared}}"></i>
<i class="fa fa-paperclip text-muted" ng-if="login.attachments" title="{{i18n.attachments}}"></i>
{{cipher.name}}
<i class="fa fa-share-alt text-muted" ng-if="cipher.organizationId" title="{{i18n.shared}}"></i>
<i class="fa fa-paperclip text-muted" ng-if="cipher.attachments" title="{{i18n.attachments}}"></i>
</span>
<span class="detail">{{login.username}}</span>
<span class="detail">{{cipher.username}}</span>
</a>
</div>
</div>
</div>
<div class="centered-message" ng-if="loaded && !vaultLogins.length">
<div class="centered-message" ng-if="loaded && !vaultCiphers.length">
<p>
{{i18n.noLoginsInList}}
<button ng-click="addLogin()" style="margin-top: 20px;" class="btn btn-link btn-block">{{i18n.addLogin}}</button>
<button ng-click="addCipher()" style="margin-top: 20px;" class="btn btn-link btn-block">{{i18n.addLogin}}</button>
</p>
</div>
<div class="page-loading" ng-if="!loaded">