Start with showing Credentials

This commit is contained in:
brantje 2016-09-14 21:12:10 +02:00
parent 6caf31a992
commit dee5ecda55
21 changed files with 517 additions and 295 deletions

View file

@ -110,9 +110,9 @@
</field> </field>
<field> <field>
<name>vault_id</name> <name>vault_id</name>
<type>text</type> <type>integer</type>
<notnull>true</notnull> <notnull>true</notnull>
<length>64</length> <length>8</length>
</field> </field>
<field> <field>

View file

@ -5,7 +5,7 @@
<description>A password manager for Nextcloud</description> <description>A password manager for Nextcloud</description>
<licence>AGPL</licence> <licence>AGPL</licence>
<author>Sander Brand</author> <author>Sander Brand</author>
<version>1.0.2.3</version> <version>1.0.2.4</version>
<namespace>Passman</namespace> <namespace>Passman</namespace>
<category>other</category> <category>other</category>
<website>https://github.com/nextcloud/passman/</website> <website>https://github.com/nextcloud/passman/</website>

View file

@ -20,10 +20,11 @@ use OCA\Passman\Service\CredentialService;
class CredentialController extends ApiController { class CredentialController extends ApiController {
private $userId; private $userId;
private $credentialService; private $credentialService;
public function __construct($AppName, public function __construct($AppName,
IRequest $request, IRequest $request,
$UserId, $UserId,
CredentialService $credentialService){ CredentialService $credentialService) {
parent::__construct($AppName, $request); parent::__construct($AppName, $request);
$this->userId = $UserId; $this->userId = $UserId;
$this->credentialService = $credentialService; $this->credentialService = $credentialService;
@ -75,8 +76,33 @@ class CredentialController extends ApiController {
/** /**
* @NoAdminRequired * @NoAdminRequired
*/ */
public function updateCredential($credential_id) { public function updateCredential($changed, $created,
return; $credential_id, $custom_fields, $delete_time,
$description, $email, $expire_time, $favicon, $files, $guid,
$hidden, $label, $otp, $password, $renew_interval,
$tags, $url, $username, $vault_id) {
$credential = array(
'credential_id' => $credential_id,
'guid' => $guid,
'user_id' => $this->userId,
'label' => $label,
'description' => $description,
'created' => $created,
'changed' => $changed,
'tags' => $tags,
'email' => $email,
'username' => $username,
'password' => $password,
'url' => $url,
'favicon' => $favicon,
'renew_interval' => $renew_interval,
'expire_time' => $expire_time,
'files' => $files,
'custom_fields' => $custom_fields,
'otp' => $otp,
);
$credential = $this->credentialService->updateCredential($credential);
return new JSONResponse($credential);
} }
/** /**

View file

@ -1,26 +1,3 @@
.actions.creatable {
padding-left: 10px; }
.actions.creatable .bubble {
position: relative;
width: 185px;
-webkit-border-radius: 5px;
border-radius: 5px;
background-clip: padding-box;
/* stops bg color from leaking outside the border: */
box-shadow: 0 1px 10px rgba(50, 50, 50, 0.7); }
.actions.creatable .bubble ul li {
padding-left: 10px; }
.actions.creatable .bubble ul .menuitem {
font-size: 12px;
display: inline; }
.actions.creatable .bubble:after {
right: inherit;
left: 10px;
top: -19px; }
#app-content-wrapper {
min-height: 95%; }
.button-geen { .button-geen {
background: #37ce02; background: #37ce02;
color: #fff; } color: #fff; }
@ -156,105 +133,147 @@
@media screen and (max-width: 768px) { @media screen and (max-width: 768px) {
.vault_wrapper { .vault_wrapper {
width: 90%; } } width: 90%; } }
.credential-table { #app-content {
width: 100%; overflow-x: hidden; }
margin-top: 44px; } #app-content #app-content-wrapper {
.credential-table tr:hover { min-height: 95%; }
background-color: whitesmoke; } #app-content #app-content-wrapper .actions.creatable {
.credential-table tr td { padding-left: 10px; }
cursor: pointer; #app-content #app-content-wrapper .actions.creatable .bubble {
padding: 5px; position: relative;
border-bottom: 1px solid #eeeeee; } width: 185px;
.credential-table tr td .label { -webkit-border-radius: 5px;
float: left; } border-radius: 5px;
.credential-table tr td .tags { background-clip: padding-box;
float: right; } /* stops bg color from leaking outside the border: */
.credential-table tr td .tags .tag { box-shadow: 0 1px 10px rgba(50, 50, 50, 0.7); }
background-color: rgba(240, 240, 240, 0.9); #app-content #app-content-wrapper .actions.creatable .bubble ul li {
padding: 4px; padding-left: 10px; }
font-size: 11px; } #app-content #app-content-wrapper .actions.creatable .bubble ul .menuitem {
.credential-table tr td .icon-more {
display: inline-block;
float: right;
margin-left: 5px;
margin-top: 1px;
opacity: 0.4;
height: 20px;
width: 32px;
cursor: pointer; }
.credential-table tr td .icon-more:hover {
opacity: 1; }
.credential-table tr td .popovermenu {
margin-top: 7px;
height: 100px;
width: 100px;
right: -2px !important;
box-shadow: 0 1px 10px rgba(50, 50, 50, 0.7); }
.credential-table tr td .popovermenu ul {
display: block;
width: 100px;
height: 75px; }
.credential-table tr td .popovermenu ul li {
padding: 0px; }
.credential-table tr td .popovermenu ul .menuitem {
font-size: 12px; font-size: 12px;
display: inline; } display: inline; }
.credential-table tr td .popovermenu .action { #app-content #app-content-wrapper .actions.creatable .bubble:after {
padding: 10px; right: inherit;
margin: -10px; } left: 10px;
top: -19px; }
.edit_credential { #app-content #app-content-wrapper .credential-table {
padding-top: 10px; } width: 100%;
.edit_credential label { margin-top: 44px; }
display: block; } #app-content #app-content-wrapper .credential-table tr:hover {
.edit_credential input[type="text"], .edit_credential input[type="password"] { background-color: whitesmoke; }
width: 100%; } #app-content #app-content-wrapper .credential-table tr.selected {
.edit_credential .tags { background-color: #f8f8f8; }
float: left; } #app-content #app-content-wrapper .credential-table tr td {
.edit_credential .tags .tag { cursor: pointer;
background-color: rgba(240, 240, 240, 0.9); padding: 5px;
padding: 4px; border-bottom: 1px solid #eeeeee; }
font-size: 11px; } #app-content #app-content-wrapper .credential-table tr td .label {
.edit_credential .credential_textarea { float: left; }
width: 100%; #app-content #app-content-wrapper .credential-table tr td .tags {
height: 100px; } float: right; }
.edit_credential .password_settings label { #app-content #app-content-wrapper .credential-table tr td .tags .tag {
overflow: hidden; } background-color: rgba(240, 240, 240, 0.9);
.edit_credential .password_settings label input[type="checkbox"] { padding: 4px;
width: auto !important; font-size: 11px; }
float: left; } #app-content #app-content-wrapper .credential-table tr td .icon-more {
.edit_credential .password_settings label .label { display: inline-block;
float: left; } float: right;
.edit_credential .password_settings label .label.sm { margin-left: 5px;
font-size: 12px; } margin-top: 1px;
.edit_credential .custom_fields, .edit_credential .files { opacity: 0.4;
margin-top: 10px; } height: 20px;
.edit_credential .custom_fields table, .edit_credential .files table { width: 32px;
width: 100%; }
.edit_credential .custom_fields table thead th, .edit_credential .files table thead th {
color: #fff; }
.edit_credential .custom_fields table thead th.field_actions, .edit_credential .files table thead th.field_actions {
width: 15%; }
.edit_credential .custom_fields table tr td.field_actions, .edit_credential .files table tr td.field_actions {
font-size: 13px;
width: 15%; }
.edit_credential .custom_fields table tr td.field_actions i, .edit_credential .files table tr td.field_actions i {
cursor: pointer; } cursor: pointer; }
.edit_credential .custom_fields table tr td, .edit_credential .custom_fields table tr th, .edit_credential .files table tr td, .edit_credential .files table tr th { #app-content #app-content-wrapper .credential-table tr td .icon-more:hover {
width: 20%; opacity: 1; }
padding: 5px; } #app-content #app-content-wrapper .credential-table tr td .popovermenu {
.edit_credential .custom_fields table tr td .editable-has-buttons.editable-input, .edit_credential .custom_fields table tr th .editable-has-buttons.editable-input, .edit_credential .files table tr td .editable-has-buttons.editable-input, .edit_credential .files table tr th .editable-has-buttons.editable-input { margin-top: 25px;
width: 55%; } height: 100px;
.edit_credential .custom_fields table tr td, .edit_credential .files table tr td { width: 100px;
height: 50px; right: -2px !important;
vertical-align: middle; } box-shadow: 0 1px 10px rgba(50, 50, 50, 0.7); }
.edit_credential .file_tab .progress { #app-content #app-content-wrapper .credential-table tr td .popovermenu ul {
margin-top: 10px; display: block;
height: 10px; } width: 100px;
.edit_credential .file_tab .progress .progress-bar { height: 75px; }
height: 10px; #app-content #app-content-wrapper .credential-table tr td .popovermenu ul li {
background-image: none; padding: 0px; }
background-color: #0082c9; } #app-content #app-content-wrapper .credential-table tr td .popovermenu ul .menuitem {
font-size: 12px;
display: inline; }
#app-content #app-content-wrapper .credential-table tr td .popovermenu .action {
padding: 10px;
margin: -10px; }
#app-content #app-content-wrapper .edit_credential {
padding-top: 10px; }
#app-content #app-content-wrapper .edit_credential label {
display: block; }
#app-content #app-content-wrapper .edit_credential input[type="text"], #app-content #app-content-wrapper .edit_credential input[type="password"] {
width: 100%; }
#app-content #app-content-wrapper .edit_credential .tags {
float: left; }
#app-content #app-content-wrapper .edit_credential .tags .tag {
background-color: rgba(240, 240, 240, 0.9);
padding: 4px;
font-size: 11px; }
#app-content #app-content-wrapper .edit_credential .credential_textarea {
width: 100%;
height: 100px; }
#app-content #app-content-wrapper .edit_credential .password_settings label {
overflow: hidden; }
#app-content #app-content-wrapper .edit_credential .password_settings label input[type="checkbox"] {
width: auto !important;
float: left; }
#app-content #app-content-wrapper .edit_credential .password_settings label .label {
float: left; }
#app-content #app-content-wrapper .edit_credential .password_settings label .label.sm {
font-size: 12px; }
#app-content #app-content-wrapper .edit_credential .custom_fields, #app-content #app-content-wrapper .edit_credential .files {
margin-top: 10px; }
#app-content #app-content-wrapper .edit_credential .custom_fields table, #app-content #app-content-wrapper .edit_credential .files table {
width: 100%; }
#app-content #app-content-wrapper .edit_credential .custom_fields table thead th, #app-content #app-content-wrapper .edit_credential .files table thead th {
color: #fff; }
#app-content #app-content-wrapper .edit_credential .custom_fields table thead th.field_actions, #app-content #app-content-wrapper .edit_credential .files table thead th.field_actions {
width: 15%; }
#app-content #app-content-wrapper .edit_credential .custom_fields table tr td.field_actions, #app-content #app-content-wrapper .edit_credential .files table tr td.field_actions {
font-size: 13px;
width: 15%; }
#app-content #app-content-wrapper .edit_credential .custom_fields table tr td.field_actions i, #app-content #app-content-wrapper .edit_credential .files table tr td.field_actions i {
cursor: pointer; }
#app-content #app-content-wrapper .edit_credential .custom_fields table tr td, #app-content #app-content-wrapper .edit_credential .custom_fields table tr th, #app-content #app-content-wrapper .edit_credential .files table tr td, #app-content #app-content-wrapper .edit_credential .files table tr th {
width: 20%;
padding: 5px; }
#app-content #app-content-wrapper .edit_credential .custom_fields table tr td .editable-has-buttons.editable-input, #app-content #app-content-wrapper .edit_credential .custom_fields table tr th .editable-has-buttons.editable-input, #app-content #app-content-wrapper .edit_credential .files table tr td .editable-has-buttons.editable-input, #app-content #app-content-wrapper .edit_credential .files table tr th .editable-has-buttons.editable-input {
width: 55%; }
#app-content #app-content-wrapper .edit_credential .custom_fields table tr td, #app-content #app-content-wrapper .edit_credential .files table tr td {
height: 50px;
vertical-align: middle; }
#app-content #app-content-wrapper .edit_credential .file_tab .progress {
margin-top: 10px;
height: 10px; }
#app-content #app-content-wrapper .edit_credential .file_tab .progress .progress-bar {
height: 10px;
background-image: none;
background-color: #0082c9; }
#app-content #app-content-wrapper .view_pane {
-webkit-box-shadow: 0px -4px 3px rgba(150, 150, 150, 0.75);
-moz-box-shadow: 0px -4px 3px rgba(150, 150, 150, 0.75);
box-shadow: 0px -4px 3px rgba(150, 150, 150, 0.75);
padding-top: 10px;
position: absolute;
bottom: 0;
background-color: #eee;
left: 0;
right: 0;
display: none;
overflow-y: auto; }
#app-content #app-content-wrapper .view_pane .row {
margin-left: 0;
margin-right: 0; }
#app-content #app-content-wrapper .view_pane.item_selected {
height: 20%;
display: inline-block; }
.settings-container div { .settings-container div {
padding-left: 15px; } padding-left: 15px; }

File diff suppressed because one or more lines are too long

View file

@ -31,6 +31,18 @@ angular.module('passmanApp')
$location.path('/vault/'+ $scope.active_vault.vault_id +'/new') $location.path('/vault/'+ $scope.active_vault.vault_id +'/new')
}; };
$scope.editCredential = function(credential){
var credential = angular.copy(credential);
SettingsService.setSetting('edit_credential',credential);
$location.path('/vault/'+ $scope.active_vault.vault_id +'/edit/'+ credential.credential_id)
};
$scope.selectedCredential = false;
$scope.selectCredential = function (credential) {
console.log(credential);
$scope.selectedCredential = credential
}
$rootScope.$on('logout', function () { $rootScope.$on('logout', function () {
console.log('Logout received, clean up'); console.log('Logout received, clean up');
$scope.credentials = []; $scope.credentials = [];

View file

@ -8,7 +8,7 @@
* Controller of the passmanApp * Controller of the passmanApp
*/ */
angular.module('passmanApp') angular.module('passmanApp')
.controller('CredentialEditCtrl', ['$scope', 'VaultService', 'CredentialService', 'SettingsService', '$location', '$routeParams', 'FileService', function ($scope, VaultService, CredentialService, SettingsService, $location, $routeParams, FileService) { .controller('CredentialEditCtrl', ['$scope', 'VaultService', 'CredentialService', 'SettingsService', '$location', '$routeParams', 'FileService', 'EncryptService', function ($scope, VaultService, CredentialService, SettingsService, $location, $routeParams, FileService, EncryptService) {
$scope.active_vault = VaultService.getActiveVault(); $scope.active_vault = VaultService.getActiveVault();
@ -143,6 +143,7 @@ angular.module('passmanApp')
}; };
FileService.uploadFile(_file).then(function (result) { FileService.uploadFile(_file).then(function (result) {
delete result.file_data; delete result.file_data;
result.filename = EncryptService.decryptString(result.filename);
$scope.storedCredential.files.push(result); $scope.storedCredential.files.push(result);
}); });
@ -177,5 +178,27 @@ angular.module('passmanApp')
qrInfo[parsedQR[5]] = parsedQR[6]; qrInfo[parsedQR[5]] = parsedQR[6];
$scope.storedCredential.otp = qrInfo; $scope.storedCredential.otp = qrInfo;
$scope.$apply() $scope.$apply()
};
$scope.saveCredential = function () {
delete $scope.storedCredential.password_repeat;
if(!$scope.storedCredential.credential_id){
$scope.storedCredential.vault_id = $scope.active_vault.vault_id;
CredentialService.createCredential($scope.storedCredential).then(function (result) {
$location.path('/vault/' + $routeParams.vault_id);
//@TODO Show notification
})
} else {
CredentialService.updateCredential($scope.storedCredential).then(function (result) {
SettingsService.setSetting('edit_credential', null);
$location.path('/vault/' + $routeParams.vault_id);
//@TODO Show notification
})
}
};
$scope.cancel = function(){
$location.path('/vault/' + $routeParams.vault_id);
} }
}]); }]);

18
js/app/filters/decrypt.js Normal file
View file

@ -0,0 +1,18 @@
'use strict';
/**
* @ngdoc filter
* @name passmanApp.filter:decrypt
* @function
* @description
* # decrypt
* Filter in the passmanApp.
*/
angular.module('passmanApp')
.filter('decrypt',['EncryptService', function (EncryptService) {
return function (input) {
if(input) {
return EncryptService.decryptString(input);
}
};
}]);

View file

@ -24,28 +24,31 @@ angular.module('passmanApp')
'url': null, 'url': null,
'favicon': null, 'favicon': null,
'renew_interval': null, 'renew_interval': null,
'expire_time': null, 'expire_time': 0,
'delete_time': 0, 'delete_time': 0,
'files': [], 'files': [],
'custom_fields': [], 'custom_fields': [],
'otp': {}, 'otp': {},
'hidden': false 'hidden': false
}; };
var _encryptedFields = ['description','username','password','files','custom_fields','otp']; var _encryptedFields = ['description', 'username', 'password', 'files', 'custom_fields', 'otp', 'email', 'tags', 'url'];
return { return {
newCredential: function () { newCredential: function () {
return angular.copy(credential); return angular.copy(credential);
}, },
createCredential: function (credential) { createCredential: function (credential) {
for(var i = 0; i < _encryptedFields.length; i++){ var _credential = angular.copy(credential);
for (var i = 0; i < _encryptedFields.length; i++) {
var field = _encryptedFields[i]; var field = _encryptedFields[i];
var fieldValue = angular.copy(credential[field]); var fieldValue = angular.copy(credential[field]);
credential[field] = EncryptService.encryptString(JSON.stringify(fieldValue)); _credential[field] = EncryptService.encryptString(JSON.stringify(fieldValue));
} }
var queryUrl = OC.generateUrl('apps/passman/api/v2/credentials'); var queryUrl = OC.generateUrl('apps/passman/api/v2/credentials');
return $http.post(queryUrl, credential).then(function (response) { return $http.post(queryUrl, _credential).then(function (response) {
if(response.data){ if (response.data) {
return response.data; return response.data;
} else { } else {
return response; return response;
@ -53,15 +56,16 @@ angular.module('passmanApp')
}); });
}, },
updateCredential: function (credential) { updateCredential: function (credential) {
for(var i = 0; i < _encryptedFields.length; i++){ var _credential = angular.copy(credential);
for (var i = 0; i < _encryptedFields.length; i++) {
var field = _encryptedFields[i]; var field = _encryptedFields[i];
var fieldValue = angular.copy(credential[field]); var fieldValue = angular.copy(credential[field]);
credential[field] = EncryptService.encryptString(JSON.stringify(fieldValue)); _credential[field] = EncryptService.encryptString(JSON.stringify(fieldValue));
} }
var queryUrl = OC.generateUrl('apps/passman/api/v2/credentials/'+ credential.credential_id); var queryUrl = OC.generateUrl('apps/passman/api/v2/credentials/' + credential.credential_id);
return $http.post(queryUrl, credential).then(function (response) { return $http.patch(queryUrl, _credential).then(function (response) {
if(response.data){ if (response.data) {
return response.data; return response.data;
} else { } else {
return response; return response;
@ -69,7 +73,7 @@ angular.module('passmanApp')
}); });
}, },
encryptCredential: function (credential) { encryptCredential: function (credential) {
for(var i = 0; i < _encryptedFields.length; i++){ for (var i = 0; i < _encryptedFields.length; i++) {
var field = _encryptedFields[i]; var field = _encryptedFields[i];
var fieldValue = angular.copy(credential[field]); var fieldValue = angular.copy(credential[field]);
credential[field] = EncryptService.encryptString(JSON.stringify(fieldValue)); credential[field] = EncryptService.encryptString(JSON.stringify(fieldValue));
@ -77,7 +81,7 @@ angular.module('passmanApp')
return credential; return credential;
}, },
decryptCredential: function (credential) { decryptCredential: function (credential) {
for(var i = 0; i < _encryptedFields.length; i++){ for (var i = 0; i < _encryptedFields.length; i++) {
var field = _encryptedFields[i]; var field = _encryptedFields[i];
var fieldValue = angular.copy(credential[field]); var fieldValue = angular.copy(credential[field]);
credential[field] = JSON.parse(EncryptService.decryptString(fieldValue)); credential[field] = JSON.parse(EncryptService.decryptString(fieldValue));

View file

@ -13,6 +13,7 @@ angular.module('passmanApp')
uploadFile: function (file) { uploadFile: function (file) {
var queryUrl = OC.generateUrl('apps/passman/api/v2/file'); var queryUrl = OC.generateUrl('apps/passman/api/v2/file');
var _file = angular.copy(file); var _file = angular.copy(file);
_file.filename = EncryptService.encryptString(_file.filename);
var data = EncryptService.encryptString(angular.copy(file.data)); var data = EncryptService.encryptString(angular.copy(file.data));
_file.data = data; _file.data = data;
return $http.post(queryUrl, _file).then(function (response) { return $http.post(queryUrl, _file).then(function (response) {

View file

@ -3,7 +3,7 @@ angular.module('templates-main', ['views/edit_credential.html', 'views/partials/
angular.module('views/edit_credential.html', []).run(['$templateCache', function($templateCache) { angular.module('views/edit_credential.html', []).run(['$templateCache', function($templateCache) {
'use strict'; 'use strict';
$templateCache.put('views/edit_credential.html', $templateCache.put('views/edit_credential.html',
'<ul class="tab_header"><li ng-repeat="tab in tabs track by $index" class="tab" ng-class="{active:isActiveTab(tab)}" ng-click="onClickTab(tab)">{{tab.title}}</li></ul><div class="tab_container edit_credential"><div ng-include="currentTab.url"></div></div><textarea>\n' + '<ul class="tab_header"><li ng-repeat="tab in tabs track by $index" class="tab" ng-class="{active:isActiveTab(tab)}" ng-click="onClickTab(tab)">{{tab.title}}</li></ul><div class="tab_container edit_credential"><div ng-include="currentTab.url"></div></div><button ng-click="saveCredential()">Save</button> <button ng-click="cancel()">Cancel</button><textarea>\n' +
'{{storedCredential}}\n' + '{{storedCredential}}\n' +
' </textarea>'); ' </textarea>');
}]); }]);
@ -11,7 +11,7 @@ angular.module('views/edit_credential.html', []).run(['$templateCache', function
angular.module('views/partials/forms/edit_credential/basics.html', []).run(['$templateCache', function($templateCache) { angular.module('views/partials/forms/edit_credential/basics.html', []).run(['$templateCache', function($templateCache) {
'use strict'; 'use strict';
$templateCache.put('views/partials/forms/edit_credential/basics.html', $templateCache.put('views/partials/forms/edit_credential/basics.html',
'<div class="row"><div class="col-xs-12 col-md-6"><label>Label</label><div><input type="text" ng-model="storedCredential.label"></div><label>Usermame</label><div><input type="text" ng-model="storedCredential.username"></div><label>E-mail</label><div><input type="text" ng-model="storedCredential.email"></div><label>Password</label><div><password-gen ng-model="storedCredential.password" settings="pwSettings" callback="pwGenerated"></password-gen><ng-password-meter password="storedCredential.password"></ng-password-meter></div><div><label>Repeat password</label><input type="password" ng-model="storedCredential.password_repeat"></div><label>URL</label><div><input type="text" ng-model="storedCredential.url"></div></div><div class="col-xs-12 col-md-6"><label>Description</label><div><textarea class="credential_textarea"></textarea></div><label>Add Tag</label><div><input type="text" placeholder="Add a tag"></div><label>Tags</label><div><div class="tags"><div class="tag">test</div></div></div></div></div>'); '<div class="row"><div class="col-xs-12 col-md-6"><label>Label</label><div><input type="text" ng-model="storedCredential.label"></div><label>Usermame</label><div><input type="text" ng-model="storedCredential.username"></div><label>E-mail</label><div><input type="text" ng-model="storedCredential.email"></div><label>Password</label><div><password-gen ng-model="storedCredential.password" settings="pwSettings" callback="pwGenerated"></password-gen><ng-password-meter password="storedCredential.password"></ng-password-meter></div><div><label>Repeat password</label><input type="password" ng-model="storedCredential.password_repeat"></div><label>URL</label><div><input type="text" ng-model="storedCredential.url"></div></div><div class="col-xs-12 col-md-6"><label>Description</label><div><textarea class="credential_textarea" ng-model="storedCredential.description"></textarea></div><label>Add Tag</label><div><input type="text" placeholder="Add a tag"></div><label>Tags</label><div><div class="tags"><div class="tag">test</div></div></div></div></div>');
}]); }]);
angular.module('views/partials/forms/edit_credential/custom_fields.html', []).run(['$templateCache', function($templateCache) { angular.module('views/partials/forms/edit_credential/custom_fields.html', []).run(['$templateCache', function($templateCache) {
@ -47,7 +47,7 @@ angular.module('views/partials/password-meter.html', []).run(['$templateCache',
angular.module('views/show_vault.html', []).run(['$templateCache', function($templateCache) { angular.module('views/show_vault.html', []).run(['$templateCache', function($templateCache) {
'use strict'; 'use strict';
$templateCache.put('views/show_vault.html', $templateCache.put('views/show_vault.html',
'<div id="controls"><div class="breadcrumb"></div><div class="actions creatable"><span ng-click="menuOpen = !menuOpen" class="button new" ng-init="menuOpen = false" off-click="menuOpen = false;"><span>New</span></span><div class="actionList popovermenu bubble menu" ng-show="menuOpen"><ul><li><span ng-click="addCredential()" class="menuitem action"><span class="icon icon-rename"></span> <span>New credential</span></span></li><li><span href="#" class="menuitem action"><span class="icon icon-shared"></span> <span>New shared credential</span></span></li></ul></div></div></div><table class="credential-table" ng-init="menuOpen = false"><tr ng-repeat="credential in credentials"><td><span class="label">{{credential.label}}</span> <span class="icon icon-more" ng-click="menuOpen = !menuOpen" off-click="menuOpen = false;"></span> <span class="tags"><span class="tag">Tag 1</span> <span class="tag">Tag 2</span> <span class="tag">Tag 4</span> <span class="tag">Tag 4</span> <span class="tag">Long tag xD</span></span><div class="actionList popovermenu bubble menu" ng-show="menuOpen"><ul><li><span class="menuitem action"><span class="icon icon-rename"></span><span>Edit</span></span></li><li><span href="#" class="menuitem action"><span class="icon icon-share"></span><span>Share</span></span></li><li><span class="menuitem action" data-action="Delete"><span class="icon icon-delete"></span><span>Delete</span></span></li></ul></div></td></tr></table>'); '<div id="controls"><div class="breadcrumb"></div><div class="actions creatable"><span ng-click="menuOpen = !menuOpen" class="button new" ng-init="menuOpen = false" off-click="menuOpen = false;"><span>New</span></span><div class="actionList popovermenu bubble menu" ng-show="menuOpen"><ul><li><span ng-click="addCredential()" class="menuitem action"><span class="icon icon-rename"></span> <span>New credential</span></span></li><li><span href="#" class="menuitem action"><span class="icon icon-shared"></span> <span>New shared credential</span></span></li></ul></div></div></div><table class="credential-table" ng-init="menuOpen = false;"><tr ng-repeat="credential in credentials" ng-if="credential.hidden == 0 && credential.delete_time == 0" ng-click="selectCredential(credential)" ng-class="{\'selected\': selectedCredential.credential_id == credential.credential_id}"><td><span class="label">{{credential.label}}</span> <span class="icon icon-more" ng-click="menuOpen = !menuOpen" off-click="menuOpen = false;"></span> <span class="tags"><span class="tag">Tag 1</span> <span class="tag">Tag 2</span> <span class="tag">Tag 4</span> <span class="tag">Tag 4</span> <span class="tag">Long tag xD</span></span><div class="actionList popovermenu bubble menu" ng-show="menuOpen"><ul><li ng-click="editCredential(credential)"><span class="menuitem action"><span class="icon icon-rename"></span><span>Edit</span></span></li><li><span href="#" class="menuitem action"><span class="icon icon-share"></span><span>Share</span></span></li><li><span class="menuitem action" data-action="Delete"><span class="icon icon-delete"></span><span>Delete</span></span></li></ul></div></td></tr></table><div class="view_pane" ng-class="{\'item_selected\': selectedCredential}"><div class="row"><div class="col-xs-2 col-sm-2 col-md-1">Label</div><div class="col-xs-6 col-sm-4 col-md-4">{{selectedCredential.label}}</div></div><div class="row"><div class="col-xs-2 col-sm-2 col-md-1">Account</div><div class="col-xs-6 col-sm-4 col-md-4">{{selectedCredential.label}}</div></div><div class="row"><div class="col-xs-2 col-sm-2 col-md-1">Password</div><div class="col-xs-6 col-sm-4 col-md-4">{{selectedCredential.label}}</div></div><div class="row"><div class="col-xs-2 col-sm-2 col-md-1">Files</div><div class="col-xs-6 col-sm-4 col-md-4">{{selectedCredential.label}}</div></div><div class="row"><div class="col-xs-2 col-sm-2 col-md-1">Custom fields</div><div class="col-xs-6 col-sm-4 col-md-4">{{selectedCredential.label}}</div></div><div class="row"><div class="col-xs-2 col-sm-2 col-md-1">Changed</div><div class="col-xs-6 col-sm-4 col-md-4">{{selectedCredential.label}}</div></div><div class="row"><div class="col-xs-2 col-sm-2 col-md-1">Created</div><div class="col-xs-6 col-sm-4 col-md-4">{{selectedCredential.label}}</div></div></div>');
}]); }]);
angular.module('views/vaults.html', []).run(['$templateCache', function($templateCache) { angular.module('views/vaults.html', []).run(['$templateCache', function($templateCache) {

View file

@ -93,6 +93,8 @@ class Credential extends Entity implements \JsonSerializable{
$this->addType('renewInterval', 'integer'); $this->addType('renewInterval', 'integer');
$this->addType('expireTime', 'integer'); $this->addType('expireTime', 'integer');
$this->addType('deleteTime', 'integer'); $this->addType('deleteTime', 'integer');
$this->addType('vault_id', 'integer');
$this->addType('credential_id', 'integer');
} }

View file

@ -58,4 +58,26 @@ class CredentialMapper extends Mapper {
return parent::insert($credential); return parent::insert($credential);
} }
public function update($raw_credential){
$credential = new Credential();
$credential->setId($raw_credential['credential_id']);
$credential->setUserId($raw_credential['user_id']);
$credential->setLabel($raw_credential['label']);
$credential->setDescription($raw_credential['description']);
$credential->setChanged($this->utils->getTime());
$credential->setTags($raw_credential['tags']);
$credential->setEmail($raw_credential['email']);
$credential->setUsername($raw_credential['username']);
$credential->setPassword($raw_credential['password']);
$credential->setUrl($raw_credential['url']);
$credential->setFavicon($raw_credential['favicon']);
$credential->setRenewInterval($raw_credential['renew_interval']);
$credential->setExpireTime($raw_credential['expire_time']);
$credential->setFiles($raw_credential['files']);
$credential->setCustomFields($raw_credential['custom_fields']);
$credential->setOtp($raw_credential['otp']);
$credential->setHidden($raw_credential['hidden']);
return parent::update($credential);
}
} }

View file

@ -29,6 +29,10 @@ class CredentialService {
return $this->credentialMapper->create($credential); return $this->credentialMapper->create($credential);
} }
public function updateCredential($credential) {
return $this->credentialMapper->update($credential);
}
public function getCredentialsByVaultId($vault_id, $user_id){ public function getCredentialsByVaultId($vault_id, $user_id){
return $this->credentialMapper->getCredentialsByVaultId($vault_id, $user_id); return $this->credentialMapper->getCredentialsByVaultId($vault_id, $user_id);
} }

View file

@ -1,7 +1,6 @@
@import 'variables'; @import 'variables';
@import 'mixins'; @import 'mixins';
@import 'container';
@import 'partials/button'; @import 'partials/button';
@import 'partials/popovermenu'; @import 'partials/popovermenu';
@import 'partials/tabs'; @import 'partials/tabs';

View file

@ -1,26 +0,0 @@
.actions.creatable{
padding-left: 10px;
.bubble{
position: relative;
width: 185px;
@include border-radius(5px);
box-shadow: 0 1px 10px rgba(50, 50, 50, .7);
ul{
li{
padding-left: 10px;
}
.menuitem{
font-size: 12px;
display: inline;
}
}
}
.bubble:after{
right: inherit;
left: 10px;
top: -19px;
}
}
#app-content-wrapper{
min-height: 95%;
}

View file

@ -1,143 +1,196 @@
.credential-table { #app-content {
width: 100%; overflow-x: hidden;
margin-top: 44px; #app-content-wrapper {
tr:hover { min-height: 95%;
background-color: darken(#fff, 4%); .actions.creatable {
} padding-left: 10px;
tr { .bubble {
td { position: relative;
cursor: pointer; width: 185px;
padding: 5px; @include border-radius(5px);
border-bottom: 1px solid #eeeeee;
.label {
float: left;
}
.tags {
float: right;
.tag {
background-color: rgba(240, 240, 240, .9);
padding: 4px;
font-size: 11px;
}
}
.icon-more {
display: inline-block;
float: right;
margin-left: 5px;
margin-top: 1px;
opacity: 0.4;
height: 20px;
width: 32px;
cursor: pointer;
}
.icon-more:hover {
opacity: 1;
}
.popovermenu {
margin-top: 7px;
height: 100px;
width: 100px;
right: -2px !important;
box-shadow: 0 1px 10px rgba(50, 50, 50, .7); box-shadow: 0 1px 10px rgba(50, 50, 50, .7);
ul { ul {
display: block;
width: 100px;
height: 75px;
li { li {
padding: 0px; padding-left: 10px;
} }
.menuitem { .menuitem {
font-size: 12px; font-size: 12px;
display: inline; display: inline;
} }
} }
.action { }
padding: 10px; .bubble:after {
margin: -10px; right: inherit;
} left: 10px;
top: -19px;
} }
} }
} .credential-table {
}
.edit_credential {
padding-top: 10px;
label {
display: block;
}
input[type="text"], input[type="password"] {
width: 100%;
}
.tags {
float: left;
.tag {
background-color: rgba(240, 240, 240, .9);
padding: 4px;
font-size: 11px;
}
}
.credential_textarea {
width: 100%;
height: 100px;
}
.password_settings {
label {
overflow: hidden;
input[type="checkbox"] {
width: auto !important;
float: left;
}
.label {
&.sm{
font-size: 12px;
}
float: left;
}
}
}
.custom_fields, .files {
margin-top: 10px;
table {
width: 100%; width: 100%;
thead { margin-top: 44px;
th { tr:hover {
color: #fff; background-color: darken(#fff, 4%);
}
th.field_actions {
width: 15%;
}
} }
tr { tr {
td.field_actions { &.selected {
font-size: 13px; background-color: #f8f8f8;
width: 15%; }
i{ td {
cursor: pointer;
padding: 5px;
border-bottom: 1px solid #eeeeee;
.label {
float: left;
}
.tags {
float: right;
.tag {
background-color: rgba(240, 240, 240, .9);
padding: 4px;
font-size: 11px;
}
}
.icon-more {
display: inline-block;
float: right;
margin-left: 5px;
margin-top: 1px;
opacity: 0.4;
height: 20px;
width: 32px;
cursor: pointer; cursor: pointer;
} }
} .icon-more:hover {
td, th { opacity: 1;
width: 20%; }
padding: 5px; .popovermenu {
.editable-has-buttons.editable-input { margin-top: 25px;
width: 55%; height: 100px;
width: 100px;
right: -2px !important;
box-shadow: 0 1px 10px rgba(50, 50, 50, .7);
ul {
display: block;
width: 100px;
height: 75px;
li {
padding: 0px;
}
.menuitem {
font-size: 12px;
display: inline;
}
}
.action {
padding: 10px;
margin: -10px;
}
} }
}
td{
height: 50px;
vertical-align: middle;
} }
} }
} }
}
.file_tab{ .edit_credential {
.progress{ padding-top: 10px;
margin-top: 10px; label {
height: 10px; display: block;
.progress-bar{
height: 10px;
background-image: none;
background-color: #0082c9;
} }
input[type="text"], input[type="password"] {
width: 100%;
}
.tags {
float: left;
.tag {
background-color: rgba(240, 240, 240, .9);
padding: 4px;
font-size: 11px;
}
}
.credential_textarea {
width: 100%;
height: 100px;
}
.password_settings {
label {
overflow: hidden;
input[type="checkbox"] {
width: auto !important;
float: left;
}
.label {
&.sm {
font-size: 12px;
}
float: left;
}
}
}
.custom_fields, .files {
margin-top: 10px;
table {
width: 100%;
thead {
th {
color: #fff;
}
th.field_actions {
width: 15%;
}
}
tr {
td.field_actions {
font-size: 13px;
width: 15%;
i {
cursor: pointer;
}
}
td, th {
width: 20%;
padding: 5px;
.editable-has-buttons.editable-input {
width: 55%;
}
}
td {
height: 50px;
vertical-align: middle;
}
}
}
}
.file_tab {
.progress {
margin-top: 10px;
height: 10px;
.progress-bar {
height: 10px;
background-image: none;
background-color: #0082c9;
}
}
}
}
.view_pane {
-webkit-box-shadow: 0px -4px 3px rgba(150, 150, 150, 0.75);
-moz-box-shadow: 0px -4px 3px rgba(150, 150, 150, 0.75);
box-shadow: 0px -4px 3px rgba(150, 150, 150, 0.75);
padding-top: 10px;
.row {
margin-left: 0;
margin-right: 0;
}
&.item_selected {
height: 20%;
display: inline-block;
}
position: absolute;
bottom: 0;
background-color: #eee;
left: 0;
right: 0;
display: none;
overflow-y: auto;
} }
} }
} }

View file

@ -30,6 +30,7 @@ script('passman', 'app/controllers/credential');
script('passman', 'app/controllers/edit_credential'); script('passman', 'app/controllers/edit_credential');
script('passman', 'app/filters/range'); script('passman', 'app/filters/range');
script('passman', 'app/filters/propsfilter'); script('passman', 'app/filters/propsfilter');
script('passman', 'app/filters/decrypt');
script('passman', 'app/services/cacheservice'); script('passman', 'app/services/cacheservice');
script('passman', 'app/services/vaultservice'); script('passman', 'app/services/vaultservice');
script('passman', 'app/services/credentialservice'); script('passman', 'app/services/credentialservice');

View file

@ -7,6 +7,8 @@
<div class="tab_container edit_credential"> <div class="tab_container edit_credential">
<div ng-include="currentTab.url"></div> <div ng-include="currentTab.url"></div>
</div> </div>
<button ng-click="saveCredential()">Save</button>
<button ng-click="cancel()">Cancel</button>
<textarea> <textarea>
{{storedCredential}} {{storedCredential}}
</textarea> </textarea>

View file

@ -30,7 +30,7 @@
<div class="col-xs-12 col-md-6"> <div class="col-xs-12 col-md-6">
<label>Description</label> <label>Description</label>
<div> <div>
<textarea class="credential_textarea"></textarea> <textarea class="credential_textarea" ng-model="storedCredential.description"></textarea>
</div> </div>
<label>Add Tag</label> <label>Add Tag</label>
<div> <div>

View file

@ -29,8 +29,8 @@
</div> </div>
</div> </div>
</div> </div>
<table class="credential-table" ng-init="menuOpen = false"> <table class="credential-table" ng-init="menuOpen = false;">
<tr ng-repeat="credential in credentials"> <tr ng-repeat="credential in credentials" ng-if="credential.hidden == 0 && credential.delete_time == 0" ng-click="selectCredential(credential)" ng-class="{'selected': selectedCredential.credential_id == credential.credential_id}">
<td> <td>
<span class="label">{{credential.label}}</span> <span class="label">{{credential.label}}</span>
<span class="icon icon-more" ng-click="menuOpen = !menuOpen" <span class="icon icon-more" ng-click="menuOpen = !menuOpen"
@ -44,7 +44,7 @@
</span> </span>
<div class="actionList popovermenu bubble menu" ng-show="menuOpen"> <div class="actionList popovermenu bubble menu" ng-show="menuOpen">
<ul> <ul>
<li><span <li ng-click="editCredential(credential)"><span
class="menuitem action" class="menuitem action"
><span ><span
class="icon icon-rename"></span><span>Edit</span></span> class="icon icon-rename"></span><span>Edit</span></span>
@ -64,3 +64,65 @@
</td> </td>
</tr> </tr>
</table> </table>
<div class="view_pane" ng-class="{'item_selected': selectedCredential}" >
<div class="row">
<div class="col-xs-2 col-sm-2 col-md-1">
Label
</div>
<div class="col-xs-6 col-sm-4 col-md-4">
{{selectedCredential.label}}
</div>
</div>
<div class="row">
<div class="col-xs-2 col-sm-2 col-md-1">
Account
</div>
<div class="col-xs-6 col-sm-4 col-md-4">
{{selectedCredential.label}}
</div>
</div>
<div class="row">
<div class="col-xs-2 col-sm-2 col-md-1">
Password
</div>
<div class="col-xs-6 col-sm-4 col-md-4">
{{selectedCredential.label}}
</div>
</div>
<div class="row">
<div class="col-xs-2 col-sm-2 col-md-1">
Files
</div>
<div class="col-xs-6 col-sm-4 col-md-4">
{{selectedCredential.label}}
</div>
</div>
<div class="row">
<div class="col-xs-2 col-sm-2 col-md-1">
Custom fields
</div>
<div class="col-xs-6 col-sm-4 col-md-4">
{{selectedCredential.label}}
</div>
</div>
<div class="row">
<div class="col-xs-2 col-sm-2 col-md-1">
Changed
</div>
<div class="col-xs-6 col-sm-4 col-md-4">
{{selectedCredential.label}}
</div>
</div>
<div class="row">
<div class="col-xs-2 col-sm-2 col-md-1">
Created
</div>
<div class="col-xs-6 col-sm-4 col-md-4">
{{selectedCredential.label}}
</div>
</div>
</div>