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>
<name>vault_id</name>
<type>text</type>
<type>integer</type>
<notnull>true</notnull>
<length>64</length>
<length>8</length>
</field>
<field>

View file

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

View file

@ -20,10 +20,11 @@ use OCA\Passman\Service\CredentialService;
class CredentialController extends ApiController {
private $userId;
private $credentialService;
public function __construct($AppName,
IRequest $request,
$UserId,
CredentialService $credentialService){
CredentialService $credentialService) {
parent::__construct($AppName, $request);
$this->userId = $UserId;
$this->credentialService = $credentialService;
@ -75,8 +76,33 @@ class CredentialController extends ApiController {
/**
* @NoAdminRequired
*/
public function updateCredential($credential_id) {
return;
public function updateCredential($changed, $created,
$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 {
background: #37ce02;
color: #fff; }
@ -156,105 +133,147 @@
@media screen and (max-width: 768px) {
.vault_wrapper {
width: 90%; } }
.credential-table {
width: 100%;
margin-top: 44px; }
.credential-table tr:hover {
background-color: whitesmoke; }
.credential-table tr td {
cursor: pointer;
padding: 5px;
border-bottom: 1px solid #eeeeee; }
.credential-table tr td .label {
float: left; }
.credential-table tr td .tags {
float: right; }
.credential-table tr td .tags .tag {
background-color: rgba(240, 240, 240, 0.9);
padding: 4px;
font-size: 11px; }
.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 {
#app-content {
overflow-x: hidden; }
#app-content #app-content-wrapper {
min-height: 95%; }
#app-content #app-content-wrapper .actions.creatable {
padding-left: 10px; }
#app-content #app-content-wrapper .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); }
#app-content #app-content-wrapper .actions.creatable .bubble ul li {
padding-left: 10px; }
#app-content #app-content-wrapper .actions.creatable .bubble ul .menuitem {
font-size: 12px;
display: inline; }
.credential-table tr td .popovermenu .action {
padding: 10px;
margin: -10px; }
.edit_credential {
padding-top: 10px; }
.edit_credential label {
display: block; }
.edit_credential input[type="text"], .edit_credential input[type="password"] {
width: 100%; }
.edit_credential .tags {
float: left; }
.edit_credential .tags .tag {
background-color: rgba(240, 240, 240, 0.9);
padding: 4px;
font-size: 11px; }
.edit_credential .credential_textarea {
width: 100%;
height: 100px; }
.edit_credential .password_settings label {
overflow: hidden; }
.edit_credential .password_settings label input[type="checkbox"] {
width: auto !important;
float: left; }
.edit_credential .password_settings label .label {
float: left; }
.edit_credential .password_settings label .label.sm {
font-size: 12px; }
.edit_credential .custom_fields, .edit_credential .files {
margin-top: 10px; }
.edit_credential .custom_fields table, .edit_credential .files table {
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 {
#app-content #app-content-wrapper .actions.creatable .bubble:after {
right: inherit;
left: 10px;
top: -19px; }
#app-content #app-content-wrapper .credential-table {
width: 100%;
margin-top: 44px; }
#app-content #app-content-wrapper .credential-table tr:hover {
background-color: whitesmoke; }
#app-content #app-content-wrapper .credential-table tr.selected {
background-color: #f8f8f8; }
#app-content #app-content-wrapper .credential-table tr td {
cursor: pointer;
padding: 5px;
border-bottom: 1px solid #eeeeee; }
#app-content #app-content-wrapper .credential-table tr td .label {
float: left; }
#app-content #app-content-wrapper .credential-table tr td .tags {
float: right; }
#app-content #app-content-wrapper .credential-table tr td .tags .tag {
background-color: rgba(240, 240, 240, 0.9);
padding: 4px;
font-size: 11px; }
#app-content #app-content-wrapper .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; }
.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 {
width: 20%;
padding: 5px; }
.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 {
width: 55%; }
.edit_credential .custom_fields table tr td, .edit_credential .files table tr td {
height: 50px;
vertical-align: middle; }
.edit_credential .file_tab .progress {
margin-top: 10px;
height: 10px; }
.edit_credential .file_tab .progress .progress-bar {
height: 10px;
background-image: none;
background-color: #0082c9; }
#app-content #app-content-wrapper .credential-table tr td .icon-more:hover {
opacity: 1; }
#app-content #app-content-wrapper .credential-table tr td .popovermenu {
margin-top: 25px;
height: 100px;
width: 100px;
right: -2px !important;
box-shadow: 0 1px 10px rgba(50, 50, 50, 0.7); }
#app-content #app-content-wrapper .credential-table tr td .popovermenu ul {
display: block;
width: 100px;
height: 75px; }
#app-content #app-content-wrapper .credential-table tr td .popovermenu ul li {
padding: 0px; }
#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 {
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')
};
$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 () {
console.log('Logout received, clean up');
$scope.credentials = [];

View file

@ -8,7 +8,7 @@
* Controller of the 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();
@ -143,6 +143,7 @@ angular.module('passmanApp')
};
FileService.uploadFile(_file).then(function (result) {
delete result.file_data;
result.filename = EncryptService.decryptString(result.filename);
$scope.storedCredential.files.push(result);
});
@ -177,5 +178,27 @@ angular.module('passmanApp')
qrInfo[parsedQR[5]] = parsedQR[6];
$scope.storedCredential.otp = qrInfo;
$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,
'favicon': null,
'renew_interval': null,
'expire_time': null,
'expire_time': 0,
'delete_time': 0,
'files': [],
'custom_fields': [],
'otp': {},
'hidden': false
};
var _encryptedFields = ['description','username','password','files','custom_fields','otp'];
var _encryptedFields = ['description', 'username', 'password', 'files', 'custom_fields', 'otp', 'email', 'tags', 'url'];
return {
newCredential: function () {
return angular.copy(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 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');
return $http.post(queryUrl, credential).then(function (response) {
if(response.data){
return $http.post(queryUrl, _credential).then(function (response) {
if (response.data) {
return response.data;
} else {
return response;
@ -53,15 +56,16 @@ angular.module('passmanApp')
});
},
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 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);
return $http.post(queryUrl, credential).then(function (response) {
if(response.data){
var queryUrl = OC.generateUrl('apps/passman/api/v2/credentials/' + credential.credential_id);
return $http.patch(queryUrl, _credential).then(function (response) {
if (response.data) {
return response.data;
} else {
return response;
@ -69,7 +73,7 @@ angular.module('passmanApp')
});
},
encryptCredential: function (credential) {
for(var i = 0; i < _encryptedFields.length; i++){
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));
@ -77,7 +81,7 @@ angular.module('passmanApp')
return 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 fieldValue = angular.copy(credential[field]);
credential[field] = JSON.parse(EncryptService.decryptString(fieldValue));

View file

@ -13,6 +13,7 @@ angular.module('passmanApp')
uploadFile: function (file) {
var queryUrl = OC.generateUrl('apps/passman/api/v2/file');
var _file = angular.copy(file);
_file.filename = EncryptService.encryptString(_file.filename);
var data = EncryptService.encryptString(angular.copy(file.data));
_file.data = data;
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) {
'use strict';
$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' +
' </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) {
'use strict';
$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) {
@ -47,7 +47,7 @@ angular.module('views/partials/password-meter.html', []).run(['$templateCache',
angular.module('views/show_vault.html', []).run(['$templateCache', function($templateCache) {
'use strict';
$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) {

View file

@ -93,6 +93,8 @@ class Credential extends Entity implements \JsonSerializable{
$this->addType('renewInterval', 'integer');
$this->addType('expireTime', '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);
}
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);
}
public function updateCredential($credential) {
return $this->credentialMapper->update($credential);
}
public function getCredentialsByVaultId($vault_id, $user_id){
return $this->credentialMapper->getCredentialsByVaultId($vault_id, $user_id);
}

View file

@ -1,7 +1,6 @@
@import 'variables';
@import 'mixins';
@import 'container';
@import 'partials/button';
@import 'partials/popovermenu';
@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 {
width: 100%;
margin-top: 44px;
tr:hover {
background-color: darken(#fff, 4%);
}
tr {
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;
}
.icon-more:hover {
opacity: 1;
}
.popovermenu {
margin-top: 7px;
height: 100px;
width: 100px;
right: -2px !important;
#app-content {
overflow-x: hidden;
#app-content-wrapper {
min-height: 95%;
.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 {
display: block;
width: 100px;
height: 75px;
li {
padding: 0px;
padding-left: 10px;
}
.menuitem {
font-size: 12px;
display: inline;
}
}
.action {
padding: 10px;
margin: -10px;
}
}
.bubble:after {
right: inherit;
left: 10px;
top: -19px;
}
}
}
}
.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 {
.credential-table {
width: 100%;
thead {
th {
color: #fff;
}
th.field_actions {
width: 15%;
}
margin-top: 44px;
tr:hover {
background-color: darken(#fff, 4%);
}
tr {
td.field_actions {
font-size: 13px;
width: 15%;
i{
&.selected {
background-color: #f8f8f8;
}
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;
}
}
td, th {
width: 20%;
padding: 5px;
.editable-has-buttons.editable-input {
width: 55%;
.icon-more:hover {
opacity: 1;
}
.popovermenu {
margin-top: 25px;
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{
.progress{
margin-top: 10px;
height: 10px;
.progress-bar{
height: 10px;
background-image: none;
background-color: #0082c9;
.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%;
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/filters/range');
script('passman', 'app/filters/propsfilter');
script('passman', 'app/filters/decrypt');
script('passman', 'app/services/cacheservice');
script('passman', 'app/services/vaultservice');
script('passman', 'app/services/credentialservice');

View file

@ -7,6 +7,8 @@
<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>
{{storedCredential}}
</textarea>

View file

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

View file

@ -29,8 +29,8 @@
</div>
</div>
</div>
<table class="credential-table" ng-init="menuOpen = false">
<tr ng-repeat="credential in credentials">
<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"
@ -44,7 +44,7 @@
</span>
<div class="actionList popovermenu bubble menu" ng-show="menuOpen">
<ul>
<li><span
<li ng-click="editCredential(credential)"><span
class="menuitem action"
><span
class="icon icon-rename"></span><span>Edit</span></span>
@ -63,4 +63,66 @@
</div>
</td>
</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>