Remove server side encryption setting at admin page.

Fix counting credentials (Fixes #235)

Fix for deleting shared credental (Fixes #232)

Fix for empty sharing keys in vaults (Fixes #230)

Fix removed shared credential leaves tags

Fix for lastpass import #233

Disable share button when link sharing is disabled.
Or when it's not shared with a user.

Add issue template

Bump version
This commit is contained in:
brantje 2017-02-10 11:18:31 +01:00
parent 053a364d88
commit 0a386d77ce
No known key found for this signature in database
GPG key ID: 5FF1D117F918687F
12 changed files with 175 additions and 58 deletions

44
ISSUE_TEMPLATE.md Normal file
View file

@ -0,0 +1,44 @@
<!--
Thanks for reporting issues back to us!
This is the bug tracker for the Passman. Find passman-webextension at https://github.com/nextcloud/passman-webextension
To make it possible for us to help you please fill out below information carefully.
-->
### Steps to reproduce
1.
2.
3.
### Expected behaviour
Tell us what should happen
### Actual behaviour
Tell us what happens instead
### Configuration
**Operating system**:
**Browser**:
**Extensions that might cause interference**:
**Passman version**:
**Nextcloud version**:
#### Browser log
<details>
<summary>Browser log</summary>
```
Insert your browser log here, this could for example include:
a) The javascript console log
b) The network log
c) ...
```
</details>

View file

@ -18,7 +18,7 @@ For an demo of this app visit [https://demo.passman.cc](https://demo.passman.cc)
]]></description>
<licence>AGPL</licence>
<version>2.0.1</version>
<version>2.0.2</version>
<author homepage="https://github.com/brantje">Sander Brand</author>
<author homepage="https://github.com/animalillo">Marcos Zuriaga</author>
<namespace>Passman</namespace>

View file

@ -79,9 +79,6 @@
//$location.path('/')
}
if (_credential.tags) {
TagService.addTags(_credential.tags);
}
_credentials[i] = _credential;
}
@ -100,14 +97,23 @@
_shared_credential_data.acl = _shared_credential;
_shared_credential_data.acl.permissions = new SharingACL(_shared_credential_data.acl.permissions);
_shared_credential_data.tags_raw = _shared_credential_data.tags;
if (_shared_credential_data.tags) {
TagService.addTags(_shared_credential_data.tags);
}
_credentials.push(_shared_credential_data);
}
}
angular.merge($scope.active_vault.credentials, _credentials);
$scope.show_spinner = false;
if(!vault.private_sharing_key){
var key_size = 1024;
ShareService.generateRSAKeys(key_size).then(function (kp) {
var pem = ShareService.rsaKeyPairToPEM(kp);
$scope.creating_keys = false;
$scope.active_vault.private_sharing_key = pem.privateKey;
$scope.active_vault.public_sharing_key = pem.publicKey;
$scope.$digest();
VaultService.updateSharingKeys($scope.active_vault);
});
}
});
});
};
@ -125,6 +131,7 @@
};
var refresh_data_interval = null;
if ($scope.active_vault) {
$scope.$parent.selectedVault = true;
@ -257,7 +264,8 @@
}
notification = NotificationService.showNotification($translate.instant('credential.deleted'), 5000,
function () {
CredentialService.updateCredential(_credential).then(function (result) {
var key = CredentialService.getSharedKeyFromCredential(_credential);
CredentialService.updateCredential(_credential, false, key).then(function (result) {
if (result.delete_time > 0) {
notification = false;
@ -286,7 +294,8 @@
}
NotificationService.showNotification($translate.instant('credential.recovered'), 5000,
function () {
CredentialService.updateCredential(_credential).then(function () {
var key = CredentialService.getSharedKeyFromCredential(_credential);
CredentialService.updateCredential(_credential, false, key).then(function () {
notification = false;
});
@ -329,7 +338,15 @@
filtered_credentials = $filter('tagFilter')(filtered_credentials, $scope.selectedtags);
filtered_credentials = $filter('filter')(filtered_credentials, {hidden: 0});
$scope.filtered_credentials = filtered_credentials;
$scope.filterOptions.selectedtags = angular.copy($scope.selectedtags);
for (var i = 0; i < $scope.active_vault.credentials.length; i++) {
var _credential = $scope.active_vault.credentials[i];
if (_credential.tags) {
TagService.addTags(_credential.tags);
}
}
}
}, true);
$scope.selectedtags = [];
@ -406,21 +423,13 @@
$scope.downloadFile = function (credential, file) {
var callback = function (result) {
var key = null;
var key = EncryptService.getSharedKeyFromCredential(credential);
if (!result.hasOwnProperty('file_data')) {
NotificationService.showNotification($translate.instant('error.loading.file.perm'), 5000);
return;
}
if (!credential.hasOwnProperty('acl') && credential.hasOwnProperty('shared_key')) {
if (credential.shared_key) {
key = EncryptService.decryptString(angular.copy(credential.shared_key));
}
}
if (credential.hasOwnProperty('acl')) {
key = EncryptService.decryptString(angular.copy(credential.acl.shared_key));
}
var file_data = EncryptService.decryptString(result.file_data, key);
download(file_data, escapeHTML(file.filename), file.mimetype);

View file

@ -237,19 +237,23 @@
};
$scope.unshareCredential = function (credential) {
ShareService.unshareCredential(credential);
var _credential = angular.copy(credential);
var old_key = EncryptService.decryptString(angular.copy(_credential.shared_key));
var new_key = VaultService.getActiveVault().vaultKey;
_credential.shared_key = null;
_credential.unshare_action = true;
_credential.skip_revision = true;
_credential = CredentialService.encryptCredential(_credential, old_key);
CredentialService.updateCredential(_credential, true).then(function () {
NotificationService.showNotification($translate.instant('credential.unshared'), 4000);
CredentialService.reencryptCredential(_credential.guid, old_key, new_key).then(function () {
getAcl();
CredentialService.reencryptCredential(_credential.guid, old_key, new_key, true).then(function (data) {
getAcl();
var c = data.cryptogram;
c.shared_key = null;
c.unshare_action = true;
c.skip_revision = true;
ShareService.unshareCredential(c);
CredentialService.updateCredential(c, true).then(function () {
NotificationService.showNotification($translate.instant('credential.unshared'), 4000);
$scope.sharing_complete = true;
});
});
};

View file

@ -0,0 +1,63 @@
/**
* Nextcloud - passman
*
* @copyright Copyright (c) 2016, Sander Brand (brantje@gmail.com)
* @copyright Copyright (c) 2016, Marcos Zuriaga Miguel (wolfi@wolfi.es)
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
(function () {
'use strict';
/**
* @ngdoc directive
* @name passmanApp.directive:passwordGen
* @description
* # passwordGen
*/
angular.module('passmanApp')
.directive('credentialCounter', [function () {
return {
template: '<div ng-show="counter" translate="number.filtered" translate-values="{number_filtered: counter, credential_number: total}"></div>',
replace: false,
restrict: 'A',
scope: {
credentials: '=credentialCounter',
deleteTime: '=',
vault: '=',
filters: '='
},
link: function (scope) {
function countCredentials() {
var countedCredentials = 0;
var total = 0;
angular.forEach(scope.credentials, function (credential) {
total = (credential.hidden !== 1) ? total + 1 : total;
if(credential.delete_time >= scope.deleteTime && credential.hidden === 0){
countedCredentials = countedCredentials+1;
}
});
scope.counter = countedCredentials;
scope.total = total;
}
scope.$watch('[credentials, deleteTime, filters]', function () {
countCredentials();
}, true);
}
};
}]);
}());

View file

@ -82,13 +82,13 @@
getEncryptedFields: function () {
return _encryptedFields;
},
updateCredential: function (credential, skipEncyption) {
updateCredential: function (credential, skipEncryption, key) {
var _credential = angular.copy(credential);
if (!skipEncyption) {
if (!skipEncryption) {
for (var i = 0; i < _encryptedFields.length; i++) {
var field = _encryptedFields[i];
var fieldValue = angular.copy(credential[field]);
_credential[field] = EncryptService.encryptString(JSON.stringify(fieldValue));
_credential[field] = EncryptService.encryptString(JSON.stringify(fieldValue), key);
}
}
_credential.expire_time = new Date(angular.copy(credential.expire_time)).getTime() / 1000;
@ -150,6 +150,18 @@
}
return credential;
},
getSharedKeyFromCredential: function (credential) {
var key = null;
if (!credential.hasOwnProperty('acl') && credential.hasOwnProperty('shared_key')) {
if (credential.shared_key) {
key = EncryptService.decryptString(angular.copy(credential.shared_key));
}
}
if (credential.hasOwnProperty('acl')) {
key = EncryptService.decryptString(angular.copy(credential.acl.shared_key));
}
return key;
},
getRevisions: function (guid) {
var queryUrl = OC.generateUrl('apps/passman/api/v2/credentials/' + guid + '/revision');
return $http.get(queryUrl).then(function (response) {
@ -182,7 +194,7 @@
}
});
},
reencryptCredential: function (credential_guid, old_password, new_password) {
reencryptCredential: function (credential_guid, old_password, new_password, skipSharingKey) {
var service = this;
@ -198,8 +210,7 @@
this.parent.plain_credential = service.decryptCredential(credential, this.parent.old_password);
var tmp = angular.copy(this.parent.plain_credential);
//@FIXME Your shared credentials are not updated properly
if (tmp.hasOwnProperty('shared_key') && tmp.shared_key !== null) {
if (tmp.hasOwnProperty('shared_key') && tmp.shared_key !== null && !skipSharingKey) {
var shared_key = EncryptService.decryptString(angular.copy(tmp.shared_key)).trim();
tmp.shared_key = EncryptService.encryptString(angular.copy(shared_key), this.parent.new_password);
tmp.set_share_key = true;

View file

@ -48,7 +48,7 @@ var PassmanImporter = PassmanImporter || {};
_credential.url = row.url;
_credential.tags = (row.grouping) ? [{text: row.grouping}] : [];
_credential.description = row.extra;
if(_credential.label){
if(_credential.label && _credential.label !== "undefined"){
credential_list.push(_credential);
}
var progress = {
@ -58,7 +58,7 @@ var PassmanImporter = PassmanImporter || {};
};
this.call_progress(progress);
}
this.call_then(credential_list)
this.call_then(credential_list);
});
};
})(window, $, PassmanImporter);

File diff suppressed because one or more lines are too long

View file

@ -74,6 +74,7 @@ script('passman', 'app/directives/ngenter');
script('passman', 'app/directives/autoscroll');
script('passman', 'app/directives/clickselect');
script('passman', 'app/directives/colorfromstring');
script('passman', 'app/directives/credentialcounter');
script('passman', 'app/directives/clearbutton2');
script('passman', 'importers/import-main');
script('passman', 'importers/importer-keepasscsv');

View file

@ -108,17 +108,5 @@ $ciphers = openssl_get_cipher_methods();
</option>
</select>
</p>
<p>
<label for="server_side_encryption">Server side encryption
method:</label>
<select name="server_side_encryption2" id="server_side_encryption2">
<?php
foreach ($ciphers as $cipher) {
print '<option value="' . $cipher . '">' . $cipher . '</option>';
}
?>
</select> (Not working atm. OpenSSL has no equivalent of <code>mcrypt_get_key_size()</code>)
</p>
</form>
</div>

View file

@ -27,7 +27,7 @@
<div class="tab_container share_credential" ng-show="currentTab">
<div ng-include="currentTab.url"></div>
<button ng-click="applyShare()">{{ 'share' | translate}}</button>
<button ng-click="applyShare()" ng-disabled="!share_settings.linkSharing.enabled || share_settings.credentialSharedWithUserAndGroup.length > 0">{{ 'share' | translate}}</button>
<button ng-click="cancel()">{{ 'cancel' | translate}}</button>
<button class="btn btn-danger" ng-click="unshareCredential(storedCredential)">{{ 'unshare' | translate}}</button>
</div>

View file

@ -10,21 +10,18 @@
</div>
</div>
</div>
<span class="title" ng-if="delete_time">
{{ 'deleted.since' | translate }}:
<span ng-if="delete_time == 1">All time</span>
<span ng-if="delete_time > 1">{{delete_time | date:'dd-MM-yyyy @ HH:mm:ss'}}</span>
</span>
<div class="actions creatable">
<span ng-click="addCredential()" class="button new">
<span >+</span></span>
</div>
<div class="title" ng-show="filtered_credentials.length > 0" translate="number.filtered"
translate-values="{number_filtered: filtered_credentials.length, credential_number: active_vault.credentials.length - 1}"
>
<div class="title" credential-counter="filtered_credentials" vault="active_vault" delete-time="delete_time" filters="filterOptions"></div>
<!--<span class="title" ng-if="delete_time"><br />
{{ 'deleted.since' | translate }}:
<span ng-if="delete_time == 1">All time</span>
<span ng-if="delete_time > 1">{{delete_time | date:'dd-MM-yyyy @ HH:mm:ss'}}</span>
</div>
</span> -->
<div class="searchboxContainer" ng-init="filterOptionShown = false;" off-click="filterOptionShown = false;">
<input type="text" ng-model="filterOptions.filterText" class="searchbox" id="searchBox"
placeholder="{{'search.credential' | translate}}" select-on-click clear-btn ng-click="filterOptionShown = true;">