diff options
author | WolFi <wolfi@wolfi.es> | 2021-05-17 01:43:40 +0300 |
---|---|---|
committer | WolFi <wolfi@wolfi.es> | 2021-05-17 01:43:53 +0300 |
commit | 7ec0ddd78895ef679d2a878c785f8f2a113415f9 (patch) | |
tree | fd3fe589ae6ad1f5a527fdb12b906d88a5ae32c7 | |
parent | e8410d1f5f171c802768e00a83cb25ec2a61fb75 (diff) | |
parent | b996e2dc69ae3e0759b134f29d27d56c5acd82c1 (diff) |
Merge branch 'migrations-2' of https://github.com/binsky08/passman into binsky08-migrations-2
47 files changed, 1409 insertions, 939 deletions
@@ -143,6 +143,7 @@ If you want a production-ready container, use the [Nextcloud Docker](https://hub ## Contributors Add yours when creating a [pull request](https://help.github.com/articles/creating-a-pull-request/)! * Newhinton + * [binsky](https://github.com/binsky08) ## FAQ **Are you adding something to check if malicious code is executing on the browser?** diff --git a/appinfo/info.xml b/appinfo/info.xml index 46d719ee..d0e0bd6e 100644 --- a/appinfo/info.xml +++ b/appinfo/info.xml @@ -37,7 +37,7 @@ For an demo of this app visit [https://demo.passman.cc](https://demo.passman.cc) <screenshot small-thumbnail="https://img.passman.cc/thumbs/share_credential.png">https://img.passman.cc/share_credential.png</screenshot> <screenshot small-thumbnail="https://img.passman.cc/thumbs/password_audit.png">https://img.passman.cc/password_audit.png</screenshot> <dependencies> - <php min-version="7.2"/> + <php min-version="7.4"/> <database>sqlite</database> <database>pgsql</database> <database min-version="5.5">mysql</database> @@ -55,4 +55,7 @@ For an demo of this app visit [https://demo.passman.cc](https://demo.passman.cc) </post-migration> </repair-steps> + <settings> + <admin>OCA\Passman\Settings\Admin</admin> + </settings> </info> diff --git a/controller/admincontroller.php b/controller/admincontroller.php index d7e47909..5d072f1b 100644 --- a/controller/admincontroller.php +++ b/controller/admincontroller.php @@ -24,6 +24,7 @@ use OCP\IRequest; use OCP\AppFramework\Http\JSONResponse; use OCP\AppFramework\ApiController; use OCA\Passman\Service\CredentialService; +use OCP\IUserManager; class AdminController extends ApiController { @@ -34,6 +35,7 @@ class AdminController extends ApiController { private $revisionService; private $deleteVaultRequestService; private $config; + private $userManager; public function __construct($AppName, IRequest $request, @@ -43,7 +45,8 @@ class AdminController extends ApiController { FileService $fileService, CredentialRevisionService $revisionService, DeleteVaultRequestService $deleteVaultRequestService, - IConfig $config + IConfig $config, + IUserManager $userManager ) { parent::__construct( $AppName, @@ -59,13 +62,13 @@ class AdminController extends ApiController { $this->deleteVaultRequestService = $deleteVaultRequestService; $this->config = $config; + $this->userManager = $userManager; } public function searchUser($term) { - $um = \OC::$server->getUserManager(); $results = array(); - $searchResult = $um->search($term); + $searchResult = $this->userManager->search($term); foreach ($searchResult as $user) { array_push($results, array( "value" => $user->getUID(), @@ -76,37 +79,43 @@ class AdminController extends ApiController { } public function moveCredentials($source_account, $destination_account) { - $vaults = $this->vaultService->getByUser($source_account); - foreach ($vaults as $vault) { - $credentials = $this->credentialService->getCredentialsByVaultId($vault->getId(), $source_account); - foreach ($credentials as $credential) { - $revisions = $this->revisionService->getRevisions($credential->getId()); - foreach ($revisions as $revision) { - $r = new CredentialRevision(); - $r->setId($revision['revision_id']); - $r->setGuid($revision['guid']); - $r->setCredentialId($credential->getId()); - $r->setUserId($destination_account); - $r->setCreated($revision['created']); - $r->setCredentialData(base64_encode(json_encode($revision['credential_data']))); - $r->setEditedBy($revision['edited_by']); - $this->revisionService->updateRevision($r); + $succeed = false; + if ($source_account != $destination_account){ + $vaults = $this->vaultService->getByUser($source_account); + foreach ($vaults as $vault) { + $credentials = $this->credentialService->getCredentialsByVaultId($vault->getId(), $source_account); + foreach ($credentials as $credential) { + $revisions = $this->revisionService->getRevisions($credential->getId()); + foreach ($revisions as $revision) { + $r = new CredentialRevision(); + $r->setId($revision['revision_id']); + $r->setGuid($revision['guid']); + $r->setCredentialId($credential->getId()); + $r->setUserId($destination_account); + $r->setCreated($revision['created']); + $r->setCredentialData(base64_encode(json_encode($revision['credential_data']))); + $r->setEditedBy($revision['edited_by']); + $this->revisionService->updateRevision($r); + } + + $c = $credential->jsonSerialize(); + $c['user_id'] = $destination_account; + $c['icon'] = json_encode($c['icon']); + $this->credentialService->updateCredential($c, true); } + $vault->setUserId($destination_account); + $this->vaultService->updateVault($vault); + } - $c = $credential->jsonSerialize(); - $c['user_id'] = $destination_account; - $this->credentialService->updateCredential($c, true); + $files = $this->fileService->getFilesFromUser($source_account); + foreach ($files as $file) { + $file->setUserId($destination_account); + $this->fileService->updateFile($file); } - $vault->setUserId($destination_account); - $this->vaultService->updateVault($vault); + $succeed = true; } - $files = $this->fileService->getFilesFromUser($source_account); - foreach ($files as $file) { - $file->setUserId($destination_account); - $this->fileService->updateFile($file); - } - return new JSONResponse(array('success' => true)); + return new JSONResponse(array('success' => $succeed)); } public function listRequests(){ @@ -114,7 +123,7 @@ class AdminController extends ApiController { $results = array(); foreach($requests as $request){ $r = $request->jsonSerialize(); - $r['displayName'] = Utils::getNameByUid($request->getRequestedBy()); + $r['displayName'] = Utils::getNameByUid($request->getRequestedBy(), $this->userManager); array_push($results, $r); } return new JSONResponse($results); @@ -188,4 +197,4 @@ class AdminController extends ApiController { } return new JSONResponse(array('result' => $result)); } -}
\ No newline at end of file +} diff --git a/controller/credentialcontroller.php b/controller/credentialcontroller.php index abc76a21..4984df6c 100644 --- a/controller/credentialcontroller.php +++ b/controller/credentialcontroller.php @@ -11,22 +11,20 @@ namespace OCA\Passman\Controller; +use OCA\Passman\Activity; use OCA\Passman\Db\Credential; use OCA\Passman\Db\SharingACL; -use OCA\Passman\Service\EncryptService; +use OCA\Passman\Service\ActivityService; +use OCA\Passman\Service\CredentialRevisionService; +use OCA\Passman\Service\CredentialService; use OCA\Passman\Service\SettingsService; +use OCA\Passman\Service\ShareService; use OCA\Passman\Utility\NotFoundJSONResponse; -use OCP\AppFramework\Db\DoesNotExistException; +use OCP\AppFramework\ApiController; use OCP\AppFramework\Http; use OCP\AppFramework\Http\DataResponse; -use OCP\IRequest; use OCP\AppFramework\Http\JSONResponse; -use OCP\AppFramework\ApiController; -use OCA\Passman\Service\CredentialService; -use OCA\Passman\Activity; -use OCA\Passman\Service\ActivityService; -use OCA\Passman\Service\CredentialRevisionService; -use OCA\Passman\Service\ShareService; +use OCP\IRequest; class CredentialController extends ApiController { @@ -38,13 +36,13 @@ class CredentialController extends ApiController { private $settings; public function __construct($AppName, - IRequest $request, - $userId, - CredentialService $credentialService, - ActivityService $activityService, - CredentialRevisionService $credentialRevisionService, - ShareService $sharingService, - SettingsService $settings + IRequest $request, + $userId, + CredentialService $credentialService, + ActivityService $activityService, + CredentialRevisionService $credentialRevisionService, + ShareService $sharingService, + SettingsService $settings ) { parent::__construct( @@ -67,10 +65,10 @@ class CredentialController extends ApiController { * @NoCSRFRequired */ public function createCredential($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, $compromised) { + $credential_id, $custom_fields, $delete_time, + $description, $email, $expire_time, $favicon, $files, $guid, + $hidden, $icon, $label, $otp, $password, $renew_interval, + $tags, $url, $username, $vault_id, $compromised) { $credential = array( 'credential_id' => $credential_id, 'guid' => $guid, @@ -85,7 +83,7 @@ class CredentialController extends ApiController { 'username' => $username, 'password' => $password, 'url' => $url, - 'icon' => $favicon, + 'icon' => json_encode($icon), 'favicon' => $favicon, 'renew_interval' => $renew_interval, 'expire_time' => $expire_time, @@ -106,7 +104,7 @@ class CredentialController extends ApiController { $link, $this->userId, Activity::TYPE_ITEM_ACTION); } - return new JSONResponse($this->credentialService->getCredentialByGUID($credential->getGuid())); + return new JSONResponse($this->credentialService->getCredentialByGUID($credential->getGuid())); } /** @@ -123,10 +121,10 @@ class CredentialController extends ApiController { * @NoCSRFRequired */ public function updateCredential($changed, $created, - $credential_id, $custom_fields, $delete_time, $credential_guid, - $description, $email, $expire_time, $icon, $files, $guid, - $hidden, $label, $otp, $password, $renew_interval, - $tags, $url, $username, $vault_id, $revision_created, $shared_key, $acl, $unshare_action, $set_share_key, $skip_revision, $compromised) { + $credential_id, $custom_fields, $delete_time, $credential_guid, + $description, $email, $expire_time, $icon, $files, $guid, + $hidden, $label, $otp, $password, $renew_interval, + $tags, $url, $username, $vault_id, $revision_created, $shared_key, $acl, $unshare_action, $set_share_key, $skip_revision, $compromised) { $storedCredential = $this->credentialService->getCredentialByGUID($credential_guid); @@ -261,7 +259,7 @@ class CredentialController extends ApiController { $credential = $this->credentialService->updateCredential($credential); - return new JSONResponse($this->credentialService->getCredentialByGUID($credential->getGuid())); + return new JSONResponse($this->credentialService->getCredentialByGUID($credential->getGuid())); } /** @@ -287,6 +285,7 @@ class CredentialController extends ApiController { /** * Delete leftovers from a credential * @param Credential $credential + * @throws \Exception */ private function deleteCredentialParts(Credential $credential) { $this->activityService->add( @@ -295,16 +294,17 @@ class CredentialController extends ApiController { '', $this->userId, Activity::TYPE_ITEM_ACTION); $this->sharingService->unshareCredential($credential->getGuid()); foreach ($this->credentialRevisionService->getRevisions($credential->getId()) as $revision) { - $id = $revision['revision_id']; - if(isset($id)){ - $this->credentialRevisionService->deleteRevision($id, $this->userId); - } + $id = $revision['revision_id']; + if (isset($id)) { + $this->credentialRevisionService->deleteRevision($id, $this->userId); + } } } /** * @NoAdminRequired * @NoCSRFRequired + * @throws \Exception */ public function getRevision($credential_guid) { try { diff --git a/controller/iconcontroller.php b/controller/iconcontroller.php index 97a24813..6be9a8a0 100644 --- a/controller/iconcontroller.php +++ b/controller/iconcontroller.php @@ -13,17 +13,14 @@ namespace OCA\Passman\Controller; use Doctrine\DBAL\Exception\DriverException; use OC\App\AppManager; +use OCA\Passman\Service\CredentialService; use OCA\Passman\Service\IconService; use OCA\Passman\Utility\Utils; +use OCP\AppFramework\ApiController; use OCP\AppFramework\Db\DoesNotExistException; use OCP\AppFramework\Http\DataDownloadResponse; -use OCP\AppFramework\Http\Response; -use OCP\IConfig; -use OCP\IRequest; use OCP\AppFramework\Http\JSONResponse; -use OCP\AppFramework\ApiController; -use OCA\Passman\Service\CredentialService; -use \OCP\App; +use OCP\IRequest; use OCP\IURLGenerator; class IconController extends ApiController { @@ -33,11 +30,11 @@ class IconController extends ApiController { private $urlGenerator; public function __construct($AppName, - IRequest $request, - $UserId, - CredentialService $credentialService, - AppManager $am, - IURLGenerator $urlGenerator + IRequest $request, + $UserId, + CredentialService $credentialService, + AppManager $am, + IURLGenerator $urlGenerator ) { parent::__construct( $AppName, @@ -57,7 +54,7 @@ class IconController extends ApiController { * @NoCSRFRequired */ public function getSingleIcon($base64Url) { - $url = base64_decode(str_replace('_','/', $base64Url)); + $url = base64_decode(str_replace('_', '/', $base64Url)); if (!preg_match("~^(?:f|ht)tps?://~i", $url)) { $url = "http://" . $url; } @@ -66,8 +63,8 @@ class IconController extends ApiController { $icon = new IconService($url); if ($icon->icoExists) { - $icon_json['type']= $icon->icoType; - $icon_json['content']= base64_encode($icon->icoData); + $icon_json['type'] = $icon->icoType; + $icon_json['content'] = base64_encode($icon->icoData); return new JSONResponse($icon_json); } @@ -79,13 +76,13 @@ class IconController extends ApiController { * @NoCSRFRequired */ public function getIcon($base64Url, $credentialId) { - $url = base64_decode(str_replace('_','/', $base64Url)); + $url = base64_decode(str_replace('_', '/', $base64Url)); - if($credentialId) { + if ($credentialId && $credentialId != "null") { try { $credential = $this->credentialService->getCredentialById($credentialId, $this->userId); $credential = $credential->jsonSerialize(); - } catch (DoesNotExistException $e){ + } catch (DoesNotExistException $e) { // Credential is not found, continue $credential = false; } @@ -95,15 +92,20 @@ class IconController extends ApiController { $url = "http://" . $url; } - $icon = new IconService($url); - $data = base64_decode("iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAMAAACdt4HsAAABHVBMVEUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADF3oJhAAAAXnRSTlMAAQIDBAUGBwgJCwwOEBITFBUWFxgaHB4hJCUnKissMDI0ODs9PkFCQ0RNUVJWV1lbXF1hY2Zna2xtcXh7f4KDhYmUm52lq62vsLW3ucHFyszO0dPV197i7/H3+fv9358zuQAAAWdJREFUWMPtldlWwjAURdPWogyKOKM4z0NRQRRHnAdE0QoI1eb/P8OnmzYlSZs+unIes+/ZbdOuFCFuBmc2Dk+qpe18EsVIptTGJJ3jrGR99B4H8jQlUTfOMSM3ZtT+SAsz8z0ZrZ//wZy4S1H6C1iQtfD+tCsS4EJYP9kV9rGTCRE0fMOfxZypITO7++5b/NCE/S3fx7PsLc9/eeuWqK/3vA9ngAJ3BPwmBIIdMnYbvNNLgo4Egg4MvelBpD0D6/F3YYJcJd0PEw7AWa6gCCNnLLoPtMoVPMJIikVNoE2uAN6BzcZ1MPA2wRA+AUIHwHkn1BAM7LH5OvBhjiAFA6tsXgCe4wjSMLDC5nPAx5Xg3wrGylfk1GlcM/MC/KFW6fvRVbBkLuj+omwf401KUJcXtCiBIy+gT4UYfawrgRIogRIogRLwBG4MAfVnsuX7XX8fWfKCU0qgvcr2mwaiDZYtsw/tMtnCP4F4Y01BhTeiAAAAAElFTkSuQmCC"); $type = 'png'; - - if ($icon->icoExists) { - $data = $icon->icoData; - $type = $icon->icoType; + + try { + $icon = new IconService($url); + if ($icon->icoExists) { + $data = $icon->icoData; + $type = $icon->icoType; + } + } catch (\InvalidArgumentException $e) { + //no need to do stuff in catch + //if IconService fails the predefined $data and $type are used } + if (isset($credential) && $credential['user_id'] == $this->userId) { $iconData = [ 'type' => ($type) ? $type : 'x-icon', @@ -111,7 +113,7 @@ class IconController extends ApiController { ]; $credential['icon'] = json_encode($iconData); try { - if($credential) { + if ($credential) { $this->credentialService->updateCredential($credential); } } catch (DriverException $exception) { @@ -152,12 +154,12 @@ class IconController extends ApiController { $pack = explode('/', $path[1])[2]; $mime = mime_content_type($iconPath); //print_r($path); - if($mime !== 'directory') { + if ($mime !== 'directory') { $icon = []; $icon['mimetype'] = mime_content_type($iconPath); $icon['url'] = $this->urlGenerator->linkTo('passman', $path[1]); $icon['pack'] = $pack; - if(!isset($icons[$pack])){ + if (!isset($icons[$pack])) { $icons[$pack] = []; } $icons[$pack][] = $icon; @@ -165,4 +167,4 @@ class IconController extends ApiController { } return new JSONResponse($icons); } -}
\ No newline at end of file +} diff --git a/controller/internalcontroller.php b/controller/internalcontroller.php index 6b92c698..79c9cf26 100644 --- a/controller/internalcontroller.php +++ b/controller/internalcontroller.php @@ -11,23 +11,28 @@ namespace OCA\Passman\Controller; +use OCA\Passman\Service\CredentialService; +use OCP\App\IAppManager; +use OCP\AppFramework\ApiController; +use OCP\AppFramework\Http\JSONResponse; use OCP\IConfig; use OCP\IRequest; -use OCP\AppFramework\Http\JSONResponse; -use OCP\AppFramework\ApiController; -use OCA\Passman\Service\CredentialService; -use \OCP\App; +use OCP\Notification\IManager; class InternalController extends ApiController { private $userId; private $credentialService; private $config; + private $manager; + private $appManager; public function __construct($AppName, - IRequest $request, - $UserId, - CredentialService $credentialService, - IConfig $config + IRequest $request, + $UserId, + CredentialService $credentialService, + IConfig $config, + IManager $IManager, + IAppManager $appManager ) { parent::__construct( $AppName, @@ -38,6 +43,8 @@ class InternalController extends ApiController { $this->userId = $UserId; $this->credentialService = $credentialService; $this->config = $config; + $this->manager = $IManager; + $this->appManager = $appManager; } /** @@ -45,16 +52,15 @@ class InternalController extends ApiController { */ public function remind($credential_id) { $credential = $this->credentialService->getCredentialById($credential_id, $this->userId); - if($credential) { + if ($credential) { $credential->setExpireTime(time() + (24 * 60 * 60)); $this->credentialService->upd($credential); - $manager = \OC::$server->getNotificationManager(); - $notification = $manager->createNotification(); + $notification = $this->manager->createNotification(); $notification->setApp('passman') ->setObject('credential', $credential_id) ->setUser($this->userId); - $manager->markProcessed($notification); + $this->manager->markProcessed($notification); } } @@ -62,18 +68,16 @@ class InternalController extends ApiController { * @NoAdminRequired */ public function read($credential_id) { - $credential = $this->credentialService->getCredentialById($credential_id, $this->userId); - if($credential) { + if ($credential) { $credential->setExpireTime(0); $this->credentialService->upd($credential); - $manager = \OC::$server->getNotificationManager(); - $notification = $manager->createNotification(); + $notification = $this->manager->createNotification(); $notification->setApp('passman') ->setObject('credential', $credential_id) ->setUser($this->userId); - $manager->markProcessed($notification); + $this->manager->markProcessed($notification); } } @@ -82,15 +86,14 @@ class InternalController extends ApiController { * @NoCSRFRequired */ public function getAppVersion() { - $AppInstance = new App(); - return new JSONResponse(array('version' => $AppInstance->getAppInfo("passman")["version"])); + return new JSONResponse(array('version' => $this->appManager->getAppInfo('passman')["version"])); } /** * @NoAdminRequired */ public function generatePerson() { - $context = [ 'http' => [ 'method' => 'GET' ], 'ssl' => [ 'verify_peer' => false, 'allow_self_signed'=> true ] ]; + $context = ['http' => ['method' => 'GET'], 'ssl' => ['verify_peer' => false, 'allow_self_signed' => true]]; $context = stream_context_create($context); $random_person = json_decode(file_get_contents('http://api.namefake.com/', false, $context)); return new JSONResponse($random_person); @@ -122,4 +125,4 @@ class InternalController extends ApiController { $this->config->setAppValue('passman', $key, $value); } -}
\ No newline at end of file +} diff --git a/controller/sharecontroller.php b/controller/sharecontroller.php index d27c185f..4b1f534e 100644 --- a/controller/sharecontroller.php +++ b/controller/sharecontroller.php @@ -11,26 +11,27 @@ namespace OCA\Passman\Controller; +use OCA\Passman\Activity; +use OCA\Passman\Db\File; use OCA\Passman\Db\SharingACL; -use OCA\Passman\Db\Vault; +use OCA\Passman\Service\ActivityService; use OCA\Passman\Service\CredentialService; use OCA\Passman\Service\FileService; use OCA\Passman\Service\NotificationService; use OCA\Passman\Service\SettingsService; use OCA\Passman\Service\ShareService; +use OCA\Passman\Service\VaultService; use OCA\Passman\Utility\NotFoundJSONResponse; use OCA\Passman\Utility\Utils; -use OCP\AppFramework\Http\NotFoundResponse; -use OCP\IRequest; -use OCP\AppFramework\Http\JSONResponse; use OCP\AppFramework\ApiController; - +use OCP\AppFramework\Db\DoesNotExistException; +use OCP\AppFramework\Db\MultipleObjectsReturnedException; +use OCP\AppFramework\Http\JSONResponse; +use OCP\AppFramework\Http\NotFoundResponse; use OCP\IGroupManager; +use OCP\IRequest; use OCP\IUserManager; - -use OCA\Passman\Service\VaultService; -use OCA\Passman\Service\ActivityService; -use OCA\Passman\Activity; +use OCP\Notification\IManager; class ShareController extends ApiController { @@ -44,22 +45,24 @@ class ShareController extends ApiController { private $notificationService; private $fileService; private $settings; + private $manager; private $limit = 50; private $offset = 0; public function __construct($AppName, - IRequest $request, - $UserId, - IGroupManager $groupManager, - IUserManager $userManager, - ActivityService $activityService, - VaultService $vaultService, - ShareService $shareService, - CredentialService $credentialService, - NotificationService $notificationService, - FileService $fileService, - SettingsService $config + IRequest $request, + $UserId, + IGroupManager $groupManager, + IUserManager $userManager, + ActivityService $activityService, + VaultService $vaultService, + ShareService $shareService, + CredentialService $credentialService, + NotificationService $notificationService, + FileService $fileService, + SettingsService $config, + IManager $IManager ) { parent::__construct( $AppName, @@ -78,6 +81,7 @@ class ShareController extends ApiController { $this->notificationService = $notificationService; $this->fileService = $fileService; $this->settings = $config; + $this->manager = $IManager; } @@ -222,7 +226,10 @@ class ShareController extends ApiController { return new JSONResponse(array('result' => true)); } - + /** + * @NoAdminRequired + * @NoCSRFRequired + */ public function unshareCredentialFromUser($item_guid, $user_id) { $acl = null; $sr = null; @@ -232,19 +239,19 @@ class ShareController extends ApiController { } try { - $sr = array_pop($this->shareService->getPendingShareRequestsForCredential($item_guid, $user_id)); + $shareRequests = $this->shareService->getPendingShareRequestsForCredential($item_guid, $user_id); + $sr = array_pop($shareRequests); } catch (\Exception $e) { // no need to catch this } if ($sr) { $this->shareService->cleanItemRequestsForUser($sr); - $manager = \OC::$server->getNotificationManager(); - $notification = $manager->createNotification(); + $notification = $this->manager->createNotification(); $notification->setApp('passman') ->setObject('passman_share_request', $sr->getId()) ->setUser($user_id); - $manager->markProcessed($notification); + $this->manager->markProcessed($notification); } if ($acl) { $this->shareService->deleteShareACL($acl); @@ -292,12 +299,11 @@ class ShareController extends ApiController { return new NotFoundResponse(); } - $manager = \OC::$server->getNotificationManager(); - $notification = $manager->createNotification(); + $notification = $this->manager->createNotification(); $notification->setApp('passman') ->setObject('passman_share_request', $sr->getId()) ->setUser($this->userId->getUID()); - $manager->markProcessed($notification); + $this->manager->markProcessed($notification); $notification = array( 'from_user' => ucfirst($this->userId->getDisplayName()), @@ -383,12 +389,11 @@ class ShareController extends ApiController { ); - $manager = \OC::$server->getNotificationManager(); - $notification = $manager->createNotification(); + $notification = $this->manager->createNotification(); $notification->setApp('passman') ->setObject('passman_share_request', $share_request_id) ->setUser($this->userId->getUID()); - $manager->markProcessed($notification); + $this->manager->markProcessed($notification); $this->shareService->cleanItemRequestsForUser($sr); return new JSONResponse(array('result' => true)); @@ -432,7 +437,8 @@ class ShareController extends ApiController { /** * @param $item_guid - * @return JSONResponse + * @return JSONResponse|NotFoundResponse + * @throws \OCP\DB\Exception * @NoAdminRequired * @NoCSRFRequired */ @@ -458,10 +464,11 @@ class ShareController extends ApiController { /** * @param $item_guid * @param $file_guid + * @return array|File|NotFoundJSONResponse + * @throws DoesNotExistException + * @throws MultipleObjectsReturnedException * @NoAdminRequired - * @PublicPage - * @return mixed - * @return NotFoundJSONResponse + * @NoCSRFRequired */ public function getFile($item_guid, $file_guid) { try { @@ -508,4 +515,4 @@ class ShareController extends ApiController { } } -}
\ No newline at end of file +} diff --git a/css/admin.css b/css/admin.css index f362cfb5..06ea9af9 100644 --- a/css/admin.css +++ b/css/admin.css @@ -2,6 +2,10 @@ padding: 5px; } #passwordSharingSettings #mover input[type="text"] { width: 350px; } +#passwordSharingSettings #mover .account_mover_selector { + width: 350px; } + #passwordSharingSettings #mover .account_mover_selector .select2-choice { + height: 34px; } #passwordSharingSettings #requests-table { width: 100%; } diff --git a/css/admin.css.map b/css/admin.css.map index 410bb786..df50b77a 100644 --- a/css/admin.css.map +++ b/css/admin.css.map @@ -1,6 +1,6 @@ { "version": 3, -"mappings": "AAGM,wCAAE;EACA,OAAO,EAAE,GAAG;AAGhB,kDAAkB;EAChB,KAAK,EAAE,KAAK;AAGhB,wCAAe;EACb,KAAK,EAAE,IAAI", +"mappings": "AAGM,wCAAE;EACA,OAAO,EAAE,GAAG;AAGhB,kDAAkB;EAChB,KAAK,EAAE,KAAK;AAEd,uDAAwB;EACtB,KAAK,EAAE,KAAK;EACZ,uEAAgB;IACd,MAAM,EAAE,IAAI;AAIlB,wCAAe;EACb,KAAK,EAAE,IAAI", "sources": ["../sass/admin.scss"], "names": [], "file": "admin.css" diff --git a/js/app/controllers/public_shared_credential.js b/js/app/controllers/public_shared_credential.js index 7f055002..b03aadc5 100644 --- a/js/app/controllers/public_shared_credential.js +++ b/js/app/controllers/public_shared_credential.js @@ -31,7 +31,7 @@ * Controller of the passmanApp */ angular.module('passmanApp') - .controller('PublicSharedCredential', ['$scope', 'ShareService', '$window', 'EncryptService', 'NotificationService', '$translate', function ($scope, ShareService, $window, EncryptService, NotificationService, $translate) { + .controller('PublicSharedCredential', ['$scope', 'ShareService', '$window', 'EncryptService', 'NotificationService', '$translate', 'escapeHTMLFilter', function ($scope, ShareService, $window, EncryptService, NotificationService, $translate, escapeHTMLFilter) { var _key; $scope.loading = false; $scope.loadSharedCredential = function () { @@ -58,7 +58,7 @@ return; } var file_data = EncryptService.decryptString(result.file_data, _key); - download(file_data, escapeHTML(file.filename), file.mimetype); + download(file_data, escapeHTMLFilter(file.filename), file.mimetype); }); }; }]); diff --git a/js/app/directives/credentialtemplate.js b/js/app/directives/credentialtemplate.js index 8c4f7a76..9b3e2d3e 100644 --- a/js/app/directives/credentialtemplate.js +++ b/js/app/directives/credentialtemplate.js @@ -29,8 +29,8 @@ * # passwordGen */ angular.module('passmanApp') - .directive('credentialTemplate', ['EncryptService', '$translate', 'FileService', 'ShareService', 'NotificationService', 'CredentialService', - function (EncryptService, $translate, FileService, ShareService, NotificationService, CredentialService) { + .directive('credentialTemplate', ['EncryptService', '$translate', 'FileService', 'ShareService', 'NotificationService', 'CredentialService', 'escapeHTMLFilter', + function (EncryptService, $translate, FileService, ShareService, NotificationService, CredentialService, escapeHTMLFilter) { return { templateUrl: 'views/partials/credential_template.html', replace: true, @@ -49,7 +49,7 @@ } var file_data = EncryptService.decryptString(result.file_data, key); - download(file_data, escapeHTML(file.filename), file.mimetype); + download(file_data, escapeHTMLFilter(file.filename), file.mimetype); }; @@ -65,4 +65,4 @@ } }; }]); -}());
\ No newline at end of file +}()); diff --git a/js/app/directives/iconpicker.js b/js/app/directives/iconpicker.js index 2cc60594..210dfacb 100644 --- a/js/app/directives/iconpicker.js +++ b/js/app/directives/iconpicker.js @@ -129,7 +129,9 @@ }; scope.useIcon = function() { - + if(!scope.credential.icon){ + scope.credential.icon = {}; + } if(scope.customIcon){ var data = scope.customIcon.data; scope.credential.icon.type = data.substring(data.lastIndexOf(":")+1,data.lastIndexOf(";")); @@ -138,9 +140,6 @@ $http.get(scope.selectedIcon.url).then(function(result) { var base64Data = window.btoa(result.data); var mimeType = 'svg+xml'; - if(!scope.credential.icon){ - scope.credential.icon = {}; - } scope.credential.icon.type = mimeType; scope.credential.icon.content = base64Data; }); diff --git a/js/app/filters/escapeHTML.js b/js/app/filters/escapeHTML.js new file mode 100644 index 00000000..88916dd7 --- /dev/null +++ b/js/app/filters/escapeHTML.js @@ -0,0 +1,38 @@ +/** + * 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 filter + * @name passmanApp.filter:escapeHTML + * @function + * @description Sanitizes a HTML string by replacing all potential dangerous characters with HTML entities + */ + angular.module('passmanApp') + .filter('escapeHTML', function () { + return function (s) { + return s.toString().split('&').join('&').split('<').join('<').split('>').join('>').split('"').join('"').split('\'').join('''); + }; + }); +}()); diff --git a/js/app/services/credentialservice.js b/js/app/services/credentialservice.js index 53fa67c0..e8bc2a41 100644 --- a/js/app/services/credentialservice.js +++ b/js/app/services/credentialservice.js @@ -41,10 +41,7 @@ 'changed': null, 'tags': [], 'email': null, - 'icon':{ - 'type': false, - 'content': '' - }, + 'icon': null, 'username': null, 'password': null, 'url': null, @@ -364,4 +361,4 @@ } }; }]); -}());
\ No newline at end of file +}()); diff --git a/js/app/services/shareservice.js b/js/app/services/shareservice.js index 195555cf..ff4a149c 100644 --- a/js/app/services/shareservice.js +++ b/js/app/services/shareservice.js @@ -313,4 +313,4 @@ } }; }]); -}());
\ No newline at end of file +}()); diff --git a/js/settings-admin.js b/js/settings-admin.js index b607e161..c9d4f32b 100644 --- a/js/settings-admin.js +++ b/js/settings-admin.js @@ -137,27 +137,54 @@ $(document).ready(function () { 'source_account': '', 'destination_account': '' }; - $(".username-autocomplete").autocomplete({ - source: OC.generateUrl('apps/passman/admin/search'), - minLength: 1, - select: function (event, ui) { - accountMover[$(this).attr('id')] = ui.item.value; - } + $('.account_mover_selector').select2({ + ajax: { + url: OC.generateUrl('apps/passman/admin/search'), + dataType: 'json', + delay: 50, + data: function (param) { + return { + term: param + }; + }, + results: function (data) { + var res = []; + for (var i = 0; i < data.length; i++) { + res.push({ + id: i, + text: data[i].value + }); + } + return { + results: res + }; + }, + cache: true + }, + placeholder: 'Search for a user', + minimumInputLength: 1 }); $('#move_credentials').click(function () { var self = this; + accountMover.source_account = $('#s2id_source_account a .select2-chosen').html(); + accountMover.destination_account = $('#s2id_destination_account a .select2-chosen').html(); $('#moveStatus').hide(); $(self).attr('disabled', 'disabled'); $(self).html('<i class="fa fa-spinner fa-spin"></i> ' + OC.L10N.translate('passman', 'Moving') + '...'); if (accountMover.source_account && accountMover.destination_account) { $.post(OC.generateUrl('apps/passman/admin/move'), accountMover, function (data) { + $(self).removeAttr('disabled'); + $(self).html('Move'); if (data.success) { - $(self).removeAttr('disabled'); - $(self).html('Move'); - $('#moveStatus').fadeIn(); + $('#moveStatusSucceeded').fadeIn(); + setTimeout(function () { + $('#moveStatusSucceeded').fadeOut(); + }, 3500); + } else { + $('#moveStatusFailed').fadeIn(); setTimeout(function () { - $('#moveStatus').fadeOut(); + $('#moveStatusFailed').fadeOut(); }, 3500); } }); diff --git a/js/templates.js b/js/templates.js index 07eed1ea..9096e60c 100644 --- a/js/templates.js +++ b/js/templates.js @@ -1,96 +1,96 @@ angular.module('templates-main', ['views/credential_revisions.html', 'views/edit_credential.html', 'views/partials/credential_template.html', 'views/partials/forms/edit_credential/basics.html', 'views/partials/forms/edit_credential/custom_fields.html', 'views/partials/forms/edit_credential/files.html', 'views/partials/forms/edit_credential/otp.html', 'views/partials/forms/edit_credential/password.html', 'views/partials/forms/settings/export.html', 'views/partials/forms/settings/general_settings.html', 'views/partials/forms/settings/generic_csv_import.html', 'views/partials/forms/settings/import.html', 'views/partials/forms/settings/password_settings.html', 'views/partials/forms/settings/sharing.html', 'views/partials/forms/settings/tool.html', 'views/partials/forms/share_credential/basics.html', 'views/partials/forms/share_credential/link_sharing.html', 'views/partials/icon-picker.html', 'views/partials/password-meter.html', 'views/settings.html', 'views/share_credential.html', 'views/show_vault.html', 'views/vault_req_deletion.html', 'views/vaults.html']); -angular.module('views/credential_revisions.html', []).run(['$templateCache', function ($templateCache) { +angular.module('views/credential_revisions.html', []).run(['$templateCache', function($templateCache) { 'use strict'; $templateCache.put('views/credential_revisions.html', '<div class="main_list" off-click-filter="\'.download-js-link, .sidebar-shown, #app-sidebar\'"><div id="passman-controls"><div class="actions creatable"><div class="breadcrumb"><div class="crumb svg ui-droppable"><a ng-click="logout()"><i class="fa fa-home"></i></a></div><div class="crumb svg"><a ng-click="cancelRevision()">{{active_vault.name}}</a></div><div class="crumb svg last"><a ng-if="storedCredential.credential_id">{{ \'showing.revisions\' | translate}} "{{revision.credential_data.label}}"</a></div></div></div></div><table class="credential-table" ng-init="menuOpen = false;"><tr ng-repeat="revision in revisions | orderBy:\'-created\'" ng-click="selectRevision(revision)" ng-class="{\'selected\': selectedRevision.revision_id == revision.revision_id}"><td><span class="icon"><i class="fa fa-lock"></i> </span><span class="label">{{ \'revision.of\' | translate}} {{revision.created * 1000 | date:\'dd-MM-yyyy @ HH:mm:ss\'}} ({{revision.credential_data.label}}) <span ng-if="revision.edited_by">{{ \'revision.edited.by\' | translate}} {{revision.edited_by}}</span></span></td></tr><tr ng-show="revisions.length == 0"><td>{{ \'no.revisions\' | translate}}</td></tr></table></div><div id="app-sidebar" class="detailsView scroll-container app_sidebar" off-click="closeSelected()" ng-show="selectedRevision"><span class="close icon-close" ng-click="closeSelected()" alt="Close"></span> <b ng-show="selectedRevision">{{ \'revision.of\' | translate}} {{selectedRevision.created * 1000 | date:\'dd-MM-yyyy @ HH:mm:ss\'}}</b><div class="credential-data"><div class="row" ng-show="selectedRevision.credential_data.label"><div class="col-xs-4 col-md-3 col-lg-3">{{ \'label\' | translate }}</div><div class="col-xs-8 col-md-9 col-lg-9"><span credential-field value="selectedRevision.credential_data.label"></span></div></div><div class="row" ng-show="selectedRevision.credential_data.username"><div class="col-xs-4 col-md-3 col-lg-3">{{ \'account\' | translate }}</div><div class="col-xs-8 col-md-9 col-lg-9"><span credential-field value="selectedRevision.credential_data.username"></span></div></div><div class="row" ng-show="selectedRevision.credential_data.password"><div class="col-xs-4 col-md-3 col-lg-3">{{ \'password\' | translate }}</div><div class="col-xs-8 col-md-9 col-lg-9"><span credential-field value="selectedRevision.credential_data.password" secret="\'true\'"></span></div></div><div class="row" ng-show="selectedRevision.credential_data.otp.secret"><div class="col-xs-4 col-md-3 col-lg-3">{{\'otp\' | translate}}</div><div class="col-xs-8 col-md-9 col-lg-9"><span otp-generator secret="selectedRevision.credential_data.otp.secret"></span></div></div><div class="row" ng-show="selectedRevision.credential_data.email"><div class="col-xs-4 col-md-3 col-lg-3">{{\'email\' | translate}}</div><div class="col-xs-8 col-md-9 col-lg-9"><span credential-field value="selectedRevision.credential_data.email"></span></div></div><div class="row" ng-show="selectedRevision.credential_data.url"><div class="col-xs-4 col-md-3 col-lg-3">{{ \'url\' | translate}}</div><div class="col-xs-8 col-md-9 col-lg-9"><span credential-field value="selectedRevision.credential_data.url"></span></div></div><div class="row" ng-show="selectedRevision.credential_data.description"><div class="col-xs-4 col-md-3 col-lg-3">{{\'notes\' | translate}}</div><div class="col-xs-8 col-md-9 col-lg-9"><span credential-field value="selectedRevision.credential_data.description_html"></span></div></div><div class="row" ng-show="selectedRevision.credential_data.files.length > 0"><div class="col-xs-4 col-md-3 col-lg-3">{{ \'files\' | translate}}</div><div class="col-xs-8 col-md-9 col-lg-9"><div ng-repeat="file in selectedRevision.credential_data.files" class="link" ng-click="downloadFile(selectedRevision.credential_data, file)">{{file.filename}} ({{file.size | bytes}})</div></div></div><div class="row" ng-repeat="field in selectedRevision.credential_data.custom_fields"><div class="col-xs-4 col-md-3 col-lg-3">{{field.label}}</div><div class="col-xs-8 col-md-9 col-lg-9"><span credential-field value="field.value" secret="field.secret" ng-if="field.field_type !== \'file\' || !field.field_type"></span> <span ng-if="field.field_type === \'file\'" class="link" ng-click="downloadFile(selectedCredential, field.value)">{{field.value.filename}} ({{field.value.size | bytes}})</span></div></div><div class="row" ng-show="selectedRevision.credential_data.expire_time > 0"><div class="col-xs-4 col-md-3 col-lg-3">{{ \'expire.time\' | translate }}</div><div class="col-xs-8 col-md-9 col-lg-9">{{selectedRevision.credential_data.expire_time * 1000 | date:\'dd-MM-yyyy @ HH:mm:ss\'}}</div></div><div class="row" ng-show="selectedRevision.credential_data.changed"><div class="col-xs-4 col-md-3 col-lg-3">{{ \'changed\' | translate}}</div><div class="col-xs-8 col-md-9 col-lg-9">{{selectedRevision.credential_data.changed * 1000 | date:\'dd-MM-yyyy @ HH:mm:ss\'}}</div></div><div class="row" ng-show="selectedRevision.credential_data.created"><div class="col-xs-4 col-md-3 col-lg-3">{{ \'created\' | translate}}</div><div class="col-xs-8 col-md-9 col-lg-9">{{selectedRevision.credential_data.created * 1000 | date:\'dd-MM-yyyy @ HH:mm:ss\'}}</div></div><div class="row"><div class="col-xs-12"><div class="tags"><span class="tag" ng-repeat="tag in selectedRevision.credential_data.tags">{{tag.text}}</span></div></div></div></div><div ng-show="selectedRevision"><button class="button" ng-click="restoreRevision(selectedRevision)"><span class="fa fa-edit"></span> {{ \'restore.revision\' | translate}}</button> <button class="button" ng-click="deleteRevision(selectedRevision)"><span class="fa fa-trash"></span> {{ \'delete.revision\' | translate}}</button></div></div>'); }]); -angular.module('views/edit_credential.html', []).run(['$templateCache', function ($templateCache) { +angular.module('views/edit_credential.html', []).run(['$templateCache', function($templateCache) { 'use strict'; $templateCache.put('views/edit_credential.html', '<div id="passman-controls"><div class="breadcrumb"><div class="breadcrumb"><div class="crumb svg ui-droppable" data-dir="/"><a ng-click="logout()"><i class="fa fa-home"></i></a></div><div class="crumb svg" data-dir="/Test"><a ng-click="cancel()">{{active_vault.name}}</a></div><div class="crumb svg last" data-dir="/Test"><a ng-if="storedCredential.credential_id">{{ \'edit.credential\' | translate}} "{{storedCredential.label}}"</a> <a ng-if="!storedCredential.credential_id">{{ \'create.credential\' | translate}}</a></div></div></div></div><div><ul class="tab_header"><li ng-repeat="tab in tabs track by $index" class="tab" ng-class="isActiveTab(tab)? \'active\' : \'inactive\'" ng-click="onClickTab(tab)" use-theme color="\'true\'">{{tab.title}}<div class="indicator" use-theme negative="\'true\'"></div></li></ul><div class="tab_container edit_credential" use-theme type="\'border-top-color\'"><div ng-include="currentTab.url"></div><button ng-click="saveCredential()" ng-disabled="saving"><i class="fa fa-spinner fa-spin" ng-show="saving"></i> {{ \'save\' | translate}}</button> <button ng-click="cancel()">{{ \'cancel\' | translate}}</button></div></div>'); }]); -angular.module('views/partials/credential_template.html', []).run(['$templateCache', function ($templateCache) { +angular.module('views/partials/credential_template.html', []).run(['$templateCache', function($templateCache) { 'use strict'; $templateCache.put('views/partials/credential_template.html', '<div class="credential-data"><div class="row" ng-show="credential.label && showLabel"><div class="col-xs-4 col-md-3 col-lg-3">{{ \'label\' | translate }}</div><div class="col-xs-8 col-md-9 col-lg-9"><span credential-field value="credential.label"></span></div></div><div class="compromised-details" ng-show="credential.compromised"><div class="icon-error-color icon"></div><div class="text">{{ \'compromised.warning\' | translate }}</div></div><div class="row" ng-show="credential.username"><div class="col-xs-4 col-md-3 col-lg-3">{{ \'account\' | translate }}</div><div class="col-xs-8 col-md-9 col-lg-9"><span credential-field value="credential.username"></span></div></div><div class="row" ng-show="credential.password"><div class="col-xs-4 col-md-3 col-lg-3">{{ \'password\' | translate }}</div><div class="col-xs-8 col-md-9 col-lg-9"><span credential-field value="credential.password" secret="\'true\'"></span></div></div><div class="row" ng-show="credential.otp.secret"><div class="col-xs-4 col-md-3 col-lg-3">{{\'otp\' | translate}}</div><div class="col-xs-8 col-md-9 col-lg-9"><span otp-generator secret="credential.otp.secret"></span></div></div><div class="row" ng-show="credential.email"><div class="col-xs-4 col-md-3 col-lg-3">{{\'email\' | translate}}</div><div class="col-xs-8 col-md-9 col-lg-9"><span credential-field value="credential.email"></span></div></div><div class="row" ng-show="credential.url"><div class="col-xs-4 col-md-3 col-lg-3">{{ \'url\' | translate}}</div><div class="col-xs-8 col-md-9 col-lg-9"><span credential-field value="credential.url" url="true"></span></div></div><div class="row" ng-show="credential.description"><div class="col-xs-4 col-md-3 col-lg-3">{{\'notes\' | translate}}</div><div class="col-xs-8 col-md-9 col-lg-9"><span credential-field value="credential.description_html"></span></div></div><div class="row" ng-show="credential.files.length > 0"><div class="col-xs-4 col-md-3 col-lg-3">{{ \'files\' | translate}}</div><div class="col-xs-8 col-md-9 col-lg-9"><div ng-repeat="file in credential.files"><a class="link" ng-click="downloadFile(credential, file)">{{file.filename}} ({{file.size | bytes}})</a><br></div></div></div><div class="row" ng-repeat="field in credential.custom_fields"><div class="col-xs-4 col-md-3 col-lg-3">{{field.label}}</div><div class="col-xs-8 col-md-9 col-lg-9"><span credential-field value="field.value" secret="field.secret" ng-if="field.field_type !== \'file\' || !field.field_type"></span> <span ng-if="field.field_type === \'file\'" class="link" ng-click="downloadFile(credential, field.value)">{{field.value.filename}} ({{field.value.size | bytes}})</span></div></div><div class="row" ng-show="credential.expire_time > 0"><div class="col-xs-4 col-md-3 col-lg-3">{{ \'expire.time\' | translate }}</div><div class="col-xs-8 col-md-9 col-lg-9">{{credential.expire_time * 1000 | date:\'dd-MM-yyyy @ HH:mm:ss\'}}</div></div><div class="row" ng-show="credential.changed"><div class="col-xs-4 col-md-3 col-lg-3">{{ \'changed\' | translate}}</div><div class="col-xs-8 col-md-9 col-lg-9">{{credential.changed * 1000 | date:\'dd-MM-yyyy @ HH:mm:ss\'}}</div></div><div class="row" ng-show="credential.created"><div class="col-xs-4 col-md-3 col-lg-3">{{ \'created\' | translate}}</div><div class="col-xs-8 col-md-9 col-lg-9">{{credential.created * 1000 | date:\'dd-MM-yyyy @ HH:mm:ss\'}}</div></div><div class="row"><div class="col-xs-12"><div class="tags"><span class="tag" ng-repeat="tag in credential.tags track by $index">{{tag.text}}</span></div></div></div></div>'); }]); -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'; $templateCache.put('views/partials/forms/edit_credential/basics.html', - '<div class="row"><div class="col-xs-12 col-md-6"><label>{{ \'label\' | translate}}</label><div class="icon-label"><div class="icon-picker" icon-picker="storedCredential"></div><input type="text" class="form-control" ng-model="storedCredential.label"></div><label>{{ \'username\' | translate}}</label><div><input type="text" ng-model="storedCredential.username"></div><label>{{ \'email\' | translate}}</label><div><input type="text" ng-model="storedCredential.email"></div><label>{{ \'password\' | translate}}</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>{{ \'password.r\' | translate}}</label><input type="password" ng-model="storedCredential.password_repeat"></div><label>{{ \'url\' | translate}}</label><div><input type="text" ng-model="storedCredential.url"></div></div><div class="col-xs-12 col-md-6"><label>{{ \'notes\' | translate}}</label><div><textarea class="credential_textarea" ng-model="storedCredential.description"></textarea></div><label>{{ \'add.tag\' | translate}}</label><div class="tags_input"><tags-input ng-model="storedCredential.tags" replace-spaces-with-dashes="false"><auto-complete source="getTags($query)" min-length="0"></auto-complete></tags-input></div></div><div class="col-xs-12 col-md-6"><button class="compromised-button" ng-click="compromise()">{{ \'compromised.label\' | translate}}</button><div class="compromised-details" ng-show="storedCredential.compromised"><div class="icon-error-color icon"></div><div class="text">{{ \'compromised.warning\' | translate }}</div></div></div></div>'); + '<div class="row"><div class="col-xs-12 col-md-6"><label>{{ \'label\' | translate}}</label><div class="icon-label"><div class="icon-picker" icon-picker="storedCredential"></div><input type="text" class="form-control" ng-model="storedCredential.label"></div><label>{{ \'username\' | translate}}</label><div><input type="text" ng-model="storedCredential.username"></div><label>{{ \'email\' | translate}}</label><div><input type="text" ng-model="storedCredential.email"></div><label>{{ \'password\' | translate}}</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>{{ \'password.r\' | translate}}</label> <input type="password" ng-model="storedCredential.password_repeat"></div><label>{{ \'url\' | translate}}</label><div><input type="text" ng-model="storedCredential.url"></div></div><div class="col-xs-12 col-md-6"><label>{{ \'notes\' | translate}}</label><div><textarea class="credential_textarea" ng-model="storedCredential.description"></textarea></div><label>{{ \'add.tag\' | translate}}</label><div class="tags_input"><tags-input ng-model="storedCredential.tags" replace-spaces-with-dashes="false"><auto-complete source="getTags($query)" min-length="0"></auto-complete></tags-input></div></div><div class="col-xs-12 col-md-6"><button class="compromised-button" ng-click="compromise()">{{ \'compromised.label\' | translate}}</button><div class="compromised-details" ng-show="storedCredential.compromised"><div class="icon-error-color icon"></div><div class="text">{{ \'compromised.warning\' | translate }}</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) { 'use strict'; $templateCache.put('views/partials/forms/edit_credential/custom_fields.html', - '<div class="row"><div class="col-xs-12 col-md-4"><label>{{ \'field.label\' | translate}}</label><input type="text" ng-model="new_custom_field.label"></div><div class="col-xs-10 col-md-6 field-value"><div class="row"><div class="col-xs-12"><label>{{ \'field.value\' | translate}}</label></div></div><div class="row"><div class="col-xs-8 valueInput"><input type="text" ng-model="new_custom_field.value" ng-show="new_custom_field.field_type === \'text\'"><password-gen ng-model="new_custom_field.value" ng-show="new_custom_field.field_type ===\'password\'" settings="{generateOnCreate: false }"></password-gen><span ng-show="new_custom_field.field_type ===\'file\'"><input id="custom_field_file" class="inputfile" type="file" file-select success="addFileToCustomField" error="fileLoadError" progress="fileSelectProgress"><label for="custom_field_file"><i class="fa fa-upload" aria-hidden="true"></i> {{ new_custom_field.value.filename || \'select.file\' | translate}}</label></span></div><div class="col-xs-4 selectType"><select class="form-control" ng-model="new_custom_field.field_type"><option value="text">{{ \'text\' | translate}}</option><option value="password">{{ \'password\' | translate}}</option><option value="file">{{ \'file\' | translate}}</option></select></div></div><div class="row"><div class="col-xs-12"><ng-password-meter ng-if="new_custom_field.field_type ===\'password\'" password="new_custom_field.value"></ng-password-meter></div></div></div><div class="col-xs-2 col-md-2"><label class="invisible">{{\'add\' | translate}}</label><button ng-click="addCustomField()">+</button></div></div><div class="row custom_fields" ng-if="storedCredential.custom_fields.length > 0"><div class="col-xs-12 table"><table><thead><tr use-theme><td class="dragger"></td><th class="field_label">{{ \'label\' | translate}}</th><th class="field_value">{{ \'value\' | translate}}</th><th class="field_secret">{{ \'type\' | translate}}</th><th class="field_actions">{{ \'actions\' | translate}}</th></tr></thead><tbody ui-sortable ng-model="storedCredential.custom_fields"><tr ng-repeat="field in storedCredential.custom_fields"><td class="dragger"><i class="fa fa-arrows-v"></i></td><td><a href="#" editable-text="field.label">{{ field.label || "empty" }}</a></td><td><span ng-if="field.field_type === \'text\'"><a href="#" editable-text="field.value">{{ field.value || \'empty\' | translate }}</a></span> <span ng-if="field.field_type === \'password\'"><a href="#" editable-password="field.value"><span ng-repeat="n in [] | range:field.value.length">*</span></a></span> <span ng-if="field.field_type === \'file\'">{{field.value.filename}} ({{field.value.size | bytes}})</span></td><td>{{ field.field_type }}</td><td class="field_actions"><i class="fa fa-trash" ng-click="deleteCustomField(field)"></i></td></tr></tbody></table></div></div>'); + '<div class="row"><div class="col-xs-12 col-md-4"><label>{{ \'field.label\' | translate}}</label> <input type="text" ng-model="new_custom_field.label"></div><div class="col-xs-10 col-md-6 field-value"><div class="row"><div class="col-xs-12"><label>{{ \'field.value\' | translate}}</label></div></div><div class="row"><div class="col-xs-8 valueInput"><input type="text" ng-model="new_custom_field.value" ng-show="new_custom_field.field_type === \'text\'"><password-gen ng-model="new_custom_field.value" ng-show="new_custom_field.field_type ===\'password\'" settings="{generateOnCreate: false }"></password-gen><span ng-show="new_custom_field.field_type ===\'file\'"><input id="custom_field_file" class="inputfile" type="file" file-select success="addFileToCustomField" error="fileLoadError" progress="fileSelectProgress"> <label for="custom_field_file"><i class="fa fa-upload" aria-hidden="true"></i> {{ new_custom_field.value.filename || \'select.file\' | translate}}</label></span></div><div class="col-xs-4 selectType"><select class="form-control" ng-model="new_custom_field.field_type"><option value="text">{{ \'text\' | translate}}</option><option value="password">{{ \'password\' | translate}}</option><option value="file">{{ \'file\' | translate}}</option></select></div></div><div class="row"><div class="col-xs-12"><ng-password-meter ng-if="new_custom_field.field_type ===\'password\'" password="new_custom_field.value"></ng-password-meter></div></div></div><div class="col-xs-2 col-md-2"><label class="invisible">{{\'add\' | translate}}</label> <button ng-click="addCustomField()">+</button></div></div><div class="row custom_fields" ng-if="storedCredential.custom_fields.length > 0"><div class="col-xs-12 table"><table><thead><tr use-theme><td class="dragger"></td><th class="field_label">{{ \'label\' | translate}}</th><th class="field_value">{{ \'value\' | translate}}</th><th class="field_secret">{{ \'type\' | translate}}</th><th class="field_actions">{{ \'actions\' | translate}}</th></tr></thead><tbody ui-sortable ng-model="storedCredential.custom_fields"><tr ng-repeat="field in storedCredential.custom_fields"><td class="dragger"><i class="fa fa-arrows-v"></i></td><td><a href="#" editable-text="field.label">{{ field.label || "empty" }}</a></td><td><span ng-if="field.field_type === \'text\'"><a href="#" editable-text="field.value">{{ field.value || \'empty\' | translate }}</a></span> <span ng-if="field.field_type === \'password\'"><a href="#" editable-password="field.value"><span ng-repeat="n in [] | range:field.value.length">*</span></a></span> <span ng-if="field.field_type === \'file\'">{{field.value.filename}} ({{field.value.size | bytes}})</span></td><td>{{ field.field_type }}</td><td class="field_actions"><i class="fa fa-trash" ng-click="deleteCustomField(field)"></i></td></tr></tbody></table></div></div>'); }]); -angular.module('views/partials/forms/edit_credential/files.html', []).run(['$templateCache', function ($templateCache) { +angular.module('views/partials/forms/edit_credential/files.html', []).run(['$templateCache', function($templateCache) { 'use strict'; $templateCache.put('views/partials/forms/edit_credential/files.html', - '<div class="row file_tab"><div class="col-xs-12 col-md-6"><input class="inputfile" id="file" type="file" file-select success="fileLoaded" error="fileLoadError" progress="fileSelectProgress"><label for="file"><i class="fa fa-upload" aria-hidden="true"></i> {{\'select.file\' | translate}}</label><span ng-if="fileprogress.file_percent > 0"><div progress-bar="fileprogress.file_percent"></div></span></div></div><div class="row files" ng-if="storedCredential.files.length > 0"><div class="col-xs-12 table"><table><thead use-theme><tr><th class="field_label">{{ \'file.name\' | translate }}</th><th class="field_value">{{ \'upload.date\' | translate}}</th><th class="field_secret">{{ \'size\' | translate}}</th><th class="field_actions">{{ \'actions\' | translate}}</th></tr></thead><tr ng-repeat="file in storedCredential.files"><td><a href="#" editable-text="file.filename">{{ file.filename || "empty" }}</a></td><td>{{file.created * 1000 | date:\'dd-MM-yyyy @ HH:mm:ss\'}}</td><td>{{file.size | bytes}}</td><td class="field_actions"><i class="fa fa-trash" ng-click="deleteFile(file)"></i></td></tr></table></div></div>'); + '<div class="row file_tab"><div class="col-xs-12 col-md-6"><input class="inputfile" id="file" type="file" file-select success="fileLoaded" error="fileLoadError" progress="fileSelectProgress"> <label for="file"><i class="fa fa-upload" aria-hidden="true"></i> {{\'select.file\' | translate}}</label> <span ng-if="fileprogress.file_percent > 0"><div progress-bar="fileprogress.file_percent"></div></span></div></div><div class="row files" ng-if="storedCredential.files.length > 0"><div class="col-xs-12 table"><table><thead use-theme><tr><th class="field_label">{{ \'file.name\' | translate }}</th><th class="field_value">{{ \'upload.date\' | translate}}</th><th class="field_secret">{{ \'size\' | translate}}</th><th class="field_actions">{{ \'actions\' | translate}}</th></tr></thead><tr ng-repeat="file in storedCredential.files"><td><a href="#" editable-text="file.filename">{{ file.filename || "empty" }}</a></td><td>{{file.created * 1000 | date:\'dd-MM-yyyy @ HH:mm:ss\'}}</td><td>{{file.size | bytes}}</td><td class="field_actions"><i class="fa fa-trash" ng-click="deleteFile(file)"></i></td></tr></table></div></div>'); }]); -angular.module('views/partials/forms/edit_credential/otp.html', []).run(['$templateCache', function ($templateCache) { +angular.module('views/partials/forms/edit_credential/otp.html', []).run(['$templateCache', function($templateCache) { 'use strict'; $templateCache.put('views/partials/forms/edit_credential/otp.html', - '<div class="row"><div class="col-xs-12"><div class="col-xs-4 nopadding"><span class="otpText">{{ \'upload.qr\' | translate}}</span><select ng-model="otpType"><option value="qrcode">Upload QR code</option><option value="secret">Enter secret</option></select></div><div class="col-xs-6 nopadding"><input type="file" qrread on-read="parseQR(qrdata)" class="input_secret" on-read="parseQR(qrdata)" ng-show="otpType === \'qrcode\'"> <input type="text" ng-model="storedCredential.otp.secret" ng-show="otpType === \'secret\'"></div></div></div><div class="row"><div class="col-xs-12" ng-if="storedCredential.otp"><b>{{ \'current.qr\' | translate}}</b></div></div><div class="row"><div class="col-xs-5 col-sm-4 col-md-2" ng-if="storedCredential.otp.qr_uri"><img ng-src="{{storedCredential.otp.qr_uri.image}}"></div><div class="col-sm-4 col-sm-5 col-md-5"><table ng-show="storedCredential.otp"><tr ng-show="storedCredential.otp.type"><td>{{ \'type\' | translate}}:</td><td>{{storedCredential.otp.type}}</td></tr><tr ng-show="storedCredential.otp.label"><td>{{ \'label\' | translate}}:</td><td>{{storedCredential.otp.label}}</td></tr><tr ng-show="storedCredential.otp.issuer"><td>{{ \'issuer\' | translate}}:</td><td>{{storedCredential.otp.issuer}}</td></tr><tr ng-show="storedCredential.otp.secret"><td>{{ \'secret\' | translate}}:</td><td>{{storedCredential.otp.secret}}</td></tr><tr ng-show="storedCredential.otp.secret"><td>{{ \'otp\' | translate}}:</td><td><span otp-generator secret="storedCredential.otp.secret"></span></td></tr></table></div></div>'); + '<div class="row"><div class="col-xs-12"><div class="col-xs-4 nopadding"><span class="otpText">{{ \'upload.qr\' | translate}}</span> <select ng-model="otpType"><option value="qrcode">Upload QR code</option><option value="secret">Enter secret</option></select></div><div class="col-xs-6 nopadding"><input type="file" qrread on-read="parseQR(qrdata)" class="input_secret" on-read="parseQR(qrdata)" ng-show="otpType === \'qrcode\'"> <input type="text" ng-model="storedCredential.otp.secret" ng-show="otpType === \'secret\'"></div></div></div><div class="row"><div class="col-xs-12" ng-if="storedCredential.otp"><b>{{ \'current.qr\' | translate}}</b></div></div><div class="row"><div class="col-xs-5 col-sm-4 col-md-2" ng-if="storedCredential.otp.qr_uri"><img ng-src="{{storedCredential.otp.qr_uri.image}}"></div><div class="col-sm-4 col-sm-5 col-md-5"><table ng-show="storedCredential.otp"><tr ng-show="storedCredential.otp.type"><td>{{ \'type\' | translate}}:</td><td>{{storedCredential.otp.type}}</td></tr><tr ng-show="storedCredential.otp.label"><td>{{ \'label\' | translate}}:</td><td>{{storedCredential.otp.label}}</td></tr><tr ng-show="storedCredential.otp.issuer"><td>{{ \'issuer\' | translate}}:</td><td>{{storedCredential.otp.issuer}}</td></tr><tr ng-show="storedCredential.otp.secret"><td>{{ \'secret\' | translate}}:</td><td>{{storedCredential.otp.secret}}</td></tr><tr ng-show="storedCredential.otp.secret"><td>{{ \'otp\' | translate}}:</td><td><span otp-generator secret="storedCredential.otp.secret"></span></td></tr></table></div></div>'); }]); -angular.module('views/partials/forms/edit_credential/password.html', []).run(['$templateCache', function ($templateCache) { +angular.module('views/partials/forms/edit_credential/password.html', []).run(['$templateCache', function($templateCache) { 'use strict'; $templateCache.put('views/partials/forms/edit_credential/password.html', - '<div class="row"><div class="col-xs-12 col-md-5 col-lg-5"><label>{{ \'password\' | translate}}</label><div><password-gen ng-model="storedCredential.password" settings="pwSettings" callback="pwGenerated"></password-gen><ng-password-meter password="storedCredential.password"></ng-password-meter></div><label>{{ \'password.r\' | translate}}</label><div><input type="password" ng-model="storedCredential.password_repeat"></div><label>{{ \'expire.date\' | translate}}</label><div><span datetime-picker ng-model="storedCredential.expire_time" class="link" future-only ng-show="storedCredential.expire_time == 0" close-on-select="false">{{\'no.expire.date\' | translate}}</span> <span datetime-picker ng-model="storedCredential.expire_time" class="link" future-only ng-show="storedCredential.expire_time != 0" close-on-select="false">{{ storedCredential.expire_time | date:\'dd-MM-yyyy @ HH:mm:ss\'}}</span></div><label>{{ \'renew.interval\' | translate}}</label><div><input type="number" ng-model="renewIntervalValue" min="0" ng-change="updateInterval(renewIntervalValue, renewIntervalModifier)"><select ng-model="renewIntervalModifier" ng-change="updateInterval(renewIntervalValue, renewIntervalModifier)"><option value="0">{{ \'disabled\' | translate}}</option><option value="86400">{{ \'days\' | translate }}</option><option value="604800">{{ \'weeks\' | translate}}</option><option value="2592000">{{ \'months\' | translate}}</option><option value="31622400">{{ \'years\' | translate}}</option></select></div></div><div class="col-xs-12 col-md-7 col-lg-7"><b>{{ \'generation.settings\' | translate}}</b><div class="row"><div class="password_settings"><div class="col-xs-12 col-sm-5 col-lg-4"><label><span class="label">{{ \'password.generation.length\' | translate}}</span><br><input type="number" ng-model="pwSettings.length" min="1"></label><label><span class="label">{{\'password.generation.min_digits\' | translate}}</span><br><input type="number" ng-model="pwSettings.minimumDigitCount" min="0"></label></div><div class="col-xs-12 col-sm-6 col-lg-6"><label><input type="checkbox" ng-model="pwSettings.useUppercase"> <span class="label sm">{{ \'password.generation.uppercase\' | translate}}</span></label><label><input ng-model="pwSettings.useLowercase" type="checkbox" id="lower"> <span class="label sm">{{ \'password.generation.lowercase\' | translate}}</span></label><label><input ng-model="pwSettings.useDigits" type="checkbox" id="digits"> <span class="label sm">{{ \'password.generation.digits\' | translate}}</span></label><label><input type="checkbox" id="special" ng-model="pwSettings.useSpecialChars"> <span class="label sm">{{ \'password.generation.special\' | translate}}</span></label><label><input type="checkbox" id="ambig" ng-model="pwSettings.avoidAmbiguousCharacters"> <span class="label sm">{{ \'password.generation.ambiguous\' | translate}}</span></label><label><input type="checkbox" ng-model="pwSettings.requireEveryCharType" id="reqevery"> <span class="label sm">{{ \'password.generation.require_same\' | translate}}</span></label></div></div></div></div></div>'); + '<div class="row"><div class="col-xs-12 col-md-5 col-lg-5"><label>{{ \'password\' | translate}}</label><div><password-gen ng-model="storedCredential.password" settings="pwSettings" callback="pwGenerated"></password-gen><ng-password-meter password="storedCredential.password"></ng-password-meter></div><label>{{ \'password.r\' | translate}}</label><div><input type="password" ng-model="storedCredential.password_repeat"></div><label>{{ \'expire.date\' | translate}}</label><div><span datetime-picker ng-model="storedCredential.expire_time" class="link" future-only ng-show="storedCredential.expire_time == 0" close-on-select="false">{{\'no.expire.date\' | translate}}</span> <span datetime-picker ng-model="storedCredential.expire_time" class="link" future-only ng-show="storedCredential.expire_time != 0" close-on-select="false">{{ storedCredential.expire_time | date:\'dd-MM-yyyy @ HH:mm:ss\'}}</span></div><label>{{ \'renew.interval\' | translate}}</label><div><input type="number" ng-model="renewIntervalValue" min="0" ng-change="updateInterval(renewIntervalValue, renewIntervalModifier)"> <select ng-model="renewIntervalModifier" ng-change="updateInterval(renewIntervalValue, renewIntervalModifier)"><option value="0">{{ \'disabled\' | translate}}</option><option value="86400">{{ \'days\' | translate }}</option><option value="604800">{{ \'weeks\' | translate}}</option><option value="2592000">{{ \'months\' | translate}}</option><option value="31622400">{{ \'years\' | translate}}</option></select></div></div><div class="col-xs-12 col-md-7 col-lg-7"><b>{{ \'generation.settings\' | translate}}</b><div class="row"><div class="password_settings"><div class="col-xs-12 col-sm-5 col-lg-4"><label><span class="label">{{ \'password.generation.length\' | translate}}</span><br><input type="number" ng-model="pwSettings.length" min="1"></label> <label><span class="label">{{\'password.generation.min_digits\' | translate}}</span><br><input type="number" ng-model="pwSettings.minimumDigitCount" min="0"></label></div><div class="col-xs-12 col-sm-6 col-lg-6"><label><input type="checkbox" ng-model="pwSettings.useUppercase"> <span class="label sm">{{ \'password.generation.uppercase\' | translate}}</span></label> <label><input ng-model="pwSettings.useLowercase" type="checkbox" id="lower"> <span class="label sm">{{ \'password.generation.lowercase\' | translate}}</span></label> <label><input ng-model="pwSettings.useDigits" type="checkbox" id="digits"> <span class="label sm">{{ \'password.generation.digits\' | translate}}</span></label> <label><input type="checkbox" id="special" ng-model="pwSettings.useSpecialChars"> <span class="label sm">{{ \'password.generation.special\' | translate}}</span></label> <label><input type="checkbox" id="ambig" ng-model="pwSettings.avoidAmbiguousCharacters"> <span class="label sm">{{ \'password.generation.ambiguous\' | translate}}</span></label> <label><input type="checkbox" ng-model="pwSettings.requireEveryCharType" id="reqevery"> <span class="label sm">{{ \'password.generation.require_same\' | translate}}</span></label></div></div></div></div></div>'); }]); -angular.module('views/partials/forms/settings/export.html', []).run(['$templateCache', function ($templateCache) { +angular.module('views/partials/forms/settings/export.html', []).run(['$templateCache', function($templateCache) { 'use strict'; $templateCache.put('views/partials/forms/settings/export.html', - '<div ng-controller="ExportCtrl"><div class="row"><div class="col-xs-6"><label>{{ \'export.type\' | translate}}<select ng-init="raw" ng-model="raw" ng-change="setExporter(raw)"><option ng-repeat="exporter in available_exporters" value="{{exporter}}">{{exporter.name}}</option></select></label><div><b>{{selectedExporter.description}}</b></div><div ng-show="selectedExporter" class="nopadding"><label>{{ \'export.confirm.text\' | translate }}</label><input type="password" ng-model="confirm_key"><br><div class="alert alert-warning" ng-show="error">{{error}}</div></div><div class="clearfix"><button class="button" ng-click="startExport()" ng-if="selectedExporter">{{ \'export\' | translate}}</button></div></div><div class="col-xs-6"><div ng-if="log" class="import_log"><textarea id="import_log" auto-scroll="log">{{log.join(\'\\n\')}}</textarea></div></div></div></div>'); + '<div ng-controller="ExportCtrl"><div class="row"><div class="col-xs-6"><label>{{ \'export.type\' | translate}} <select ng-init="raw" ng-model="raw" ng-change="setExporter(raw)"><option ng-repeat="exporter in available_exporters" value="{{exporter}}">{{exporter.name}}</option></select></label><div><b>{{selectedExporter.description}}</b></div><div ng-show="selectedExporter" class="nopadding"><label>{{ \'export.confirm.text\' | translate }}</label> <input type="password" ng-model="confirm_key"><br><div class="alert alert-warning" ng-show="error">{{error}}</div></div><div class="clearfix"><button class="button" ng-click="startExport()" ng-if="selectedExporter">{{ \'export\' | translate}}</button></div></div><div class="col-xs-6"><div ng-if="log" class="import_log"><textarea id="import_log" auto-scroll="log">{{log.join(\'\\n\')}}</textarea></div></div></div></div>'); }]); -angular.module('views/partials/forms/settings/general_settings.html', []).run(['$templateCache', function ($templateCache) { +angular.module('views/partials/forms/settings/general_settings.html', []).run(['$templateCache', function($templateCache) { 'use strict'; $templateCache.put('views/partials/forms/settings/general_settings.html', - '<div class="row"><div class="col-xs-12 col-md-6"><h3>{{ \'rename.vault\' | translate}}</h3><label>{{ \'rename.vault.name\' | translate}}</label><input type="text" ng-model="$parent.new_vault_name"> <button ng-click="saveVaultSettings()">{{ \'change\' | translate}}</button><h3>{{ \'change.vault.key\' | translate}}</h3><label>{{ \'old.vault.password\' | translate}}</label><input type="password" ng-model="oldVaultPass"><label>{{ \'new.vault.password\' | translate}}</label><input type="password" ng-model="newVaultPass"><ng-password-meter password="newVaultPass" score="vault_key_score"></ng-password-meter><label>{{ \'new.vault.pw.r\' | translate}}</label><input type="password" ng-model="newVaultPass2"><div ng-show="error || vault_key_score.score < minimal_value_key_strength" class="error"><ul><li>{{error}}</li><li ng-show="vault_key_score.score < minimal_value_key_strength">{{\'min.vault.key.strength\' | translate:required_score}}</li></ul></div><button ng-click="changeVaultPassword(oldVaultPass,newVaultPass,newVaultPass2)" ng-disabled="vault_key_score.score < minimal_value_key_strength">{{ \'change\' | translate}}</button><div ng-show="change_pw.total > 0">{{\'warning.leave\' | translate}}<br>{{ \'processing\' | translate}} {{cur_state.process}}<div progress-bar="cur_state.calculated" index="cur_state.current" total="cur_state.total"></div>{{ \'total.progress\' | translate}}<div progress-bar="change_pw.percent" index="change_pw.done" total="change_pw.total"></div></div><h3>{{\'delete.vault\' | translate}}</h3><b>{{ \'vault.remove.notice\' | translate }}</b><label>{{\'vault.password\' | translate}}</label><input type="password" ng-model="$parent.delete_vault_password"> <input type="checkbox" ng-model="$parent.confirm_vault_delete"> {{\'delete.vault.checkbox\' | translate}}<br><button class="btn btn-danger" ng-click="delete_vault()">{{\'delete.vault.confirm\' | translate}}</button><div ng-show="remove_pw">{{\'deleting.pw\' | translate:translationData}}<div progress-bar="remove_pw.percent" index="remove_pw.done" total="remove_pw.total"></div></div></div><div class="col-xs-12 col-md-6"><h3>{{ \'about.passman\' | translate}}</h3><p>{{ \'version\' | translate}}: <b>{{passman_version}}</b><br><br><a href="https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=6YS8F97PETVU2" target="_blank" class="link">{{ \'donate.support\' | translate}}</a><br></p><h3>{{ \'bookmarklet\' | translate}}</h3><div><p>{{ \'bookmarklet.info1\' | translate}}<br>{{ \'bookmarklet.info2\' | translate}}<br></p></div><div><p ng-bind-html="bookmarklet" style="margin-top: 5px"></p></div></div></div>'); + '<div class="row"><div class="col-xs-12 col-md-6"><h3>{{ \'rename.vault\' | translate}}</h3><label>{{ \'rename.vault.name\' | translate}}</label> <input type="text" ng-model="$parent.new_vault_name"> <button ng-click="saveVaultSettings()">{{ \'change\' | translate}}</button><h3>{{ \'change.vault.key\' | translate}}</h3><label>{{ \'old.vault.password\' | translate}}</label> <input type="password" ng-model="oldVaultPass"> <label>{{ \'new.vault.password\' | translate}}</label> <input type="password" ng-model="newVaultPass"><ng-password-meter password="newVaultPass" score="vault_key_score"></ng-password-meter><label>{{ \'new.vault.pw.r\' | translate}}</label> <input type="password" ng-model="newVaultPass2"><div ng-show="error || vault_key_score.score < minimal_value_key_strength" class="error"><ul><li>{{error}}</li><li ng-show="vault_key_score.score < minimal_value_key_strength">{{\'min.vault.key.strength\' | translate:required_score}}</li></ul></div><button ng-click="changeVaultPassword(oldVaultPass,newVaultPass,newVaultPass2)" ng-disabled="vault_key_score.score < minimal_value_key_strength">{{ \'change\' | translate}}</button><div ng-show="change_pw.total > 0">{{\'warning.leave\' | translate}}<br>{{ \'processing\' | translate}} {{cur_state.process}}<div progress-bar="cur_state.calculated" index="cur_state.current" total="cur_state.total"></div>{{ \'total.progress\' | translate}}<div progress-bar="change_pw.percent" index="change_pw.done" total="change_pw.total"></div></div><h3>{{\'delete.vault\' | translate}}</h3><b>{{ \'vault.remove.notice\' | translate }}</b> <label>{{\'vault.password\' | translate}}</label> <input type="password" ng-model="$parent.delete_vault_password"> <input type="checkbox" ng-model="$parent.confirm_vault_delete"> {{\'delete.vault.checkbox\' | translate}}<br><button class="btn btn-danger" ng-click="delete_vault()">{{\'delete.vault.confirm\' | translate}}</button><div ng-show="remove_pw">{{\'deleting.pw\' | translate:translationData}}<div progress-bar="remove_pw.percent" index="remove_pw.done" total="remove_pw.total"></div></div></div><div class="col-xs-12 col-md-6"><h3>{{ \'about.passman\' | translate}}</h3><p>{{ \'version\' | translate}}: <b>{{passman_version}}</b><br><br><a href="https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=6YS8F97PETVU2" target="_blank" class="link">{{ \'donate.support\' | translate}}</a><br></p><h3>{{ \'bookmarklet\' | translate}}</h3><div><p>{{ \'bookmarklet.info1\' | translate}}<br>{{ \'bookmarklet.info2\' | translate}}<br></p></div><div><p ng-bind-html="bookmarklet" style="margin-top: 5px"></p></div></div></div>'); }]); -angular.module('views/partials/forms/settings/generic_csv_import.html', []).run(['$templateCache', function ($templateCache) { +angular.module('views/partials/forms/settings/generic_csv_import.html', []).run(['$templateCache', function($templateCache) { 'use strict'; $templateCache.put('views/partials/forms/settings/generic_csv_import.html', '<div ng-controller="GenericCsvImportCtrl"><div class="row"><div class="col-xs-12 col-md-3"><div>{{ \'select.csv\' | translate}} <input type="file" file-select accept=".csv" success="csvLoaded"></div><div ng-show="parsed_csv"><span translate="parsed.csv.rows" translate-value-rows="{{ parsed_csv.length }}"></span></div><div ng-show="parsed_csv"><input type="checkbox" ng-model="skipFirstRow" ng-checked="matched"> {{ \'skip.first.row\' | translate}}</div><div ng-show="import_fields.indexOf(\'label\') === -1 && parsed_csv"><b>{{ \'import.csv.label.req\' | translate}}</b></div><div ng-show="import_fields.indexOf(\'label\') !== -1 && parsed_csv"><button class="btn btn-success" ng-disabled="importing" ng-click="startCSVImport()"><i class="fa fa-spinner fa-spin" ng-show="importing"></i> {{ (importing) ? (\'import.importing\' | translate) : (\'import.start\' | translate) }}</button></div><div><div ng-if="import_progress.progress > 0">{{ \'upload.progress\' | translate}}<div progress-bar="import_progress.progress" index="import_progress.loaded" total="import_progress.total"></div></div></div><div><div ng-if="log" class="import_log"><textarea id="import_log" auto-scroll="log">{{log.join(\'\\n\')}}</textarea></div></div></div><div class="col-xs-12 col-md-9" ng-show="parsed_csv"><b>{{ \'first.five.lines\' | translate }}</b><br>{{ \'assign.column\' | translate }}<div class="import-table-outter"><table class="import-table"><tr ng-repeat="line in parsed_csv | limitTo:5"><td class="inspect"><i class="fa fa-search" ng-click="inspectCredential(line)" ng-if="($index > 0 && matched && import_fields.length > 0) || ($index >= 0 && !matched && import_fields.length > 0)"></i></td><td ng-repeat="prop in line track by $index">{{line[$index]}}</td></tr><tr ng-repeat="line in parsed_csv | limitTo:1"><td></td><td ng-repeat="prop in line track by $index"><select ng-model="import_fields[$index]" ng-change="updateExample()" ng-options="property.prop as property.label for property in credentialProperties"></select></td></tr></table></div><div ng-show="inspected_credential && import_fields.length > 0"><b>{{ \'example.credential\' | translate}}</b><div credential-template="inspected_credential" show-label></div></div></div></div></div>'); }]); -angular.module('views/partials/forms/settings/import.html', []).run(['$templateCache', function ($templateCache) { +angular.module('views/partials/forms/settings/import.html', []).run(['$templateCache', function($templateCache) { 'use strict'; $templateCache.put('views/partials/forms/settings/import.html', - '<div><div ng-click="showGenericImport = !showGenericImport;" class="link"><span ng-show="!showGenericImport">{{\'missing.importer\' | translate}}</span> <span ng-show="showGenericImport">{{\'missing.importer.back\' | translate}}</span></div></div><div ng-controller="ImportCtrl" ng-show="!showGenericImport"><div class="row"><div class="col-xs-6"><div class="import-selection"><label>{{ \'import.type\' | translate}}<select ng-init="importerType" ng-model="importerType" ng-change="setImporter(importerType)"><option ng-repeat="importer in available_importers" value="{{importer}}">{{importer.name}}</option></select></label></div><div ng-show="selectedImporter"><b>{{ \'import.steps\' | translate }}</b><ul class="import-steps"><li ng-repeat="step in selectedImporter.exportSteps">{{step}}</li></ul></div><input ng-if="selectedImporter" type="file" file-select success="fileLoaded" error="fileLoadError" progress="fileSelectProgress"><br><button class="button" ng-click="startImport()" ng-if="selectedImporter">{{ \'import\' | translate}}</button><div ng-if="file_read_progress.percent > 0">{{ \'read.progress\' | translate}}<div progress-bar="file_read_progress.percent" index="file_read_progress.loaded" total="file_read_progress.total"></div></div><div ng-if="import_progress.progress > 0">{{ \'upload.progress\' | translate}}<div progress-bar="import_progress.progress" index="import_progress.loaded" total="import_progress.total"></div></div></div><div class="col-xs-6"><div ng-if="log" class="import_log"><textarea id="import_log" auto-scroll="log">{{log.join(\'\\n\')}}</textarea></div></div></div></div><div ng-include="\'views/partials/forms/settings/generic_csv_import.html\'" ng-show="showGenericImport"></div>'); + '<div><div ng-click="showGenericImport = !showGenericImport;" class="link"><span ng-show="!showGenericImport">{{\'missing.importer\' | translate}}</span> <span ng-show="showGenericImport">{{\'missing.importer.back\' | translate}}</span></div></div><div ng-controller="ImportCtrl" ng-show="!showGenericImport"><div class="row"><div class="col-xs-6"><div class="import-selection"><label>{{ \'import.type\' | translate}} <select ng-init="importerType" ng-model="importerType" ng-change="setImporter(importerType)"><option ng-repeat="importer in available_importers" value="{{importer}}">{{importer.name}}</option></select></label></div><div ng-show="selectedImporter"><b>{{ \'import.steps\' | translate }}</b><ul class="import-steps"><li ng-repeat="step in selectedImporter.exportSteps">{{step}}</li></ul></div><input ng-if="selectedImporter" type="file" file-select success="fileLoaded" error="fileLoadError" progress="fileSelectProgress"><br><button class="button" ng-click="startImport()" ng-if="selectedImporter">{{ \'import\' | translate}}</button><div ng-if="file_read_progress.percent > 0">{{ \'read.progress\' | translate}}<div progress-bar="file_read_progress.percent" index="file_read_progress.loaded" total="file_read_progress.total"></div></div><div ng-if="import_progress.progress > 0">{{ \'upload.progress\' | translate}}<div progress-bar="import_progress.progress" index="import_progress.loaded" total="import_progress.total"></div></div></div><div class="col-xs-6"><div ng-if="log" class="import_log"><textarea id="import_log" auto-scroll="log">{{log.join(\'\\n\')}}</textarea></div></div></div></div><div ng-include="\'views/partials/forms/settings/generic_csv_import.html\'" ng-show="showGenericImport"></div>'); }]); -angular.module('views/partials/forms/settings/password_settings.html', []).run(['$templateCache', function ($templateCache) { +angular.module('views/partials/forms/settings/password_settings.html', []).run(['$templateCache', function($templateCache) { 'use strict'; $templateCache.put('views/partials/forms/settings/password_settings.html', - '<div class="password_settings"><div class="col-xs-12 col-sm-5 col-lg-4 password-settings-padding-left-fix"><label><span class="label">{{ \'password.generation.length\' | translate}}</span><br><input type="number" ng-model="vault_settings.pwSettings.length" min="1"></label><label><span class="label">{{ \'password.generation.min_digits\' | translate}}</span><br><input type="number" ng-model="vault_settings.pwSettings.minimumDigitCount" min="0"></label><label><span class="label">Generate password on creation</span><br><input type="checkbox" ng-model="vault_settings.pwSettings.generateOnCreate" min="0"></label></div><div class="col-xs-12 col-sm-6 col-lg-6"><label><input type="checkbox" ng-model="vault_settings.pwSettings.useUppercase"> <span class="label sm">{{ \'password.generation.uppercase\' | translate}}</span></label><label><input ng-model="vault_settings.pwSettings.useLowercase" type="checkbox" id="lower"> <span class="label sm">{{ \'password.generation.lowercase\' | translate}}</span></label><label><input ng-model="vault_settings.pwSettings.useDigits" type="checkbox" id="digits"> <span class="label sm">{{ \'password.generation.digits\' | translate}}</span></label><label><input type="checkbox" id="special" ng-model="vault_settings.pwSettings.useSpecialChars"> <span class="label sm">{{ \'password.generation.special\' | translate}}</span></label><label><input type="checkbox" id="ambig" ng-model="vault_settings.pwSettings.avoidAmbiguousCharacters"> <span class="label sm">{{ \'password.generation.ambiguous\' | translate}}</span></label><label><input type="checkbox" ng-model="vault_settings.pwSettings.requireEveryCharType" id="reqevery"> <span class="label sm">{{ \'password.generation.require_same\' | translate}}</span></label></div></div><div class="row"><div class="col-xs-12"><button class="button" ng-click="saveVaultSettings()">{{ \'save\' | translate}}</button></div></div>'); + '<div class="password_settings"><div class="col-xs-12 col-sm-5 col-lg-4 password-settings-padding-left-fix"><label><span class="label">{{ \'password.generation.length\' | translate}}</span><br><input type="number" ng-model="vault_settings.pwSettings.length" min="1"></label> <label><span class="label">{{ \'password.generation.min_digits\' | translate}}</span><br><input type="number" ng-model="vault_settings.pwSettings.minimumDigitCount" min="0"></label> <label><span class="label">Generate password on creation</span><br><input type="checkbox" ng-model="vault_settings.pwSettings.generateOnCreate" min="0"></label></div><div class="col-xs-12 col-sm-6 col-lg-6"><label><input type="checkbox" ng-model="vault_settings.pwSettings.useUppercase"> <span class="label sm">{{ \'password.generation.uppercase\' | translate}}</span></label> <label><input ng-model="vault_settings.pwSettings.useLowercase" type="checkbox" id="lower"> <span class="label sm">{{ \'password.generation.lowercase\' | translate}}</span></label> <label><input ng-model="vault_settings.pwSettings.useDigits" type="checkbox" id="digits"> <span class="label sm">{{ \'password.generation.digits\' | translate}}</span></label> <label><input type="checkbox" id="special" ng-model="vault_settings.pwSettings.useSpecialChars"> <span class="label sm">{{ \'password.generation.special\' | translate}}</span></label> <label><input type="checkbox" id="ambig" ng-model="vault_settings.pwSettings.avoidAmbiguousCharacters"> <span class="label sm">{{ \'password.generation.ambiguous\' | translate}}</span></label> <label><input type="checkbox" ng-model="vault_settings.pwSettings.requireEveryCharType" id="reqevery"> <span class="label sm">{{ \'password.generation.require_same\' | translate}}</span></label></div></div><div class="row"><div class="col-xs-12"><button class="button" ng-click="saveVaultSettings()">{{ \'save\' | translate}}</button></div></div>'); }]); -angular.module('views/partials/forms/settings/sharing.html', []).run(['$templateCache', function ($templateCache) { +angular.module('views/partials/forms/settings/sharing.html', []).run(['$templateCache', function($templateCache) { 'use strict'; $templateCache.put('views/partials/forms/settings/sharing.html', - '<div ng-controller="SharingSettingsCtrl"><div class="row"><div class="col-md-6"><label>{{ \'priv.key\' | translate}}</label><textarea class="col-md-12">{{sharing_keys.private_sharing_key}}</textarea></div><div class="col-md-6"><label>{{ \'pub.key\' | translate}}</label><textarea class="col-md-12">{{sharing_keys.public_sharing_key}}</textarea></div></div><div class="row"><div class="col-md-12"><label>{{ \'key.size\' | translate}}<select ng-model="key_size" ng-options="size.name for size in available_sizes"></select><button ng-click="updateSharingKeys()"><i class="fa fa-fa-floppy-o"></i> {{ \'save.keys\' | translate}}</button> <button ng-if="!generating" ng-click="generateKeys(key_size.size)">{{ \'gen.keys\' | translate}}</button> <button ng-if="generating"><i class="fa fa-spinner fa-spin"></i> {{ \'generating.keys\' | translate}} ({{progress}}/2)</button></label></div></div></div>'); + '<div ng-controller="SharingSettingsCtrl"><div class="row"><div class="col-md-6"><label>{{ \'priv.key\' | translate}}</label> <textarea class="col-md-12">{{sharing_keys.private_sharing_key}}</textarea></div><div class="col-md-6"><label>{{ \'pub.key\' | translate}}</label> <textarea class="col-md-12">{{sharing_keys.public_sharing_key}}</textarea></div></div><div class="row"><div class="col-md-12"><label>{{ \'key.size\' | translate}} <select ng-model="key_size" ng-options="size.name for size in available_sizes"></select> <button ng-click="updateSharingKeys()"><i class="fa fa-fa-floppy-o"></i> {{ \'save.keys\' | translate}}</button> <button ng-if="!generating" ng-click="generateKeys(key_size.size)">{{ \'gen.keys\' | translate}}</button> <button ng-if="generating"><i class="fa fa-spinner fa-spin"></i> {{ \'generating.keys\' | translate}} ({{progress}}/2)</button></label></div></div></div>'); }]); -angular.module('views/partials/forms/settings/tool.html', []).run(['$templateCache', function ($templateCache) { +angular.module('views/partials/forms/settings/tool.html', []).run(['$templateCache', function($templateCache) { 'use strict'; $templateCache.put('views/partials/forms/settings/tool.html', '<div class="row"><div class="col-xs-12"><p>{{ \'tool.intro\' | translate}}</p></div><div class="col-xs-12" ng-init="minStrength = 3;">{{ \'min.strength\' | translate}} <input type="number" min="1" max="4" value="3" ng-model="minStrength"> <button ng-click="startScan(minStrength)">{{ \'scan.start\' | translate}}</button></div></div><div class="row" ng-show="scan_result"><div class="col-xs-12"><p class="spacer-top-30"><b>{{ \'scan.result.msg\' | translate}}</b><br><span translate="scan.result" translate-values="{ scan_result: scan_result.length}"></span><br></p><table class="table scan-result-table spacer-top-30"><thead><tr><td><b>{{ \'label\' | translate}}</b></td><td><b>{{ \'score\' | translate}}</b></td><td><b>{{ \'password\' | translate}}</b></td><td><b>{{ \'action\' | translate}}</b></td></tr></thead><tbody><tr ng-repeat="result in scan_result | orderBy:\'password_zxcvbn_result.score\'"><td class="label-audit">{{result.label}}</td><td class="score"><ng-password-meter password="result.password"></ng-password-meter></td><td><span credential-field value="result.password" secret="\'true\'"></span></td><td><div><a href="#/vault/{{ active_vault.guid }}/edit/{{result.guid}}" class="link"><i class="fa fa-edit"></i></a></div></td></tr></tbody></table></div></div>'); }]); -angular.module('views/partials/forms/share_credential/basics.html', []).run(['$templateCache', function ($templateCache) { +angular.module('views/partials/forms/share_credential/basics.html', []).run(['$templateCache', function($templateCache) { 'use strict'; $templateCache.put('views/partials/forms/share_credential/basics.html', '<div class="row"><div class="col-xs-12 col-md-6"><div><table class="table sharing_table"><thead><tr><td><tags-input ng-model="inputSharedWith" replace-spaces-with-dashes="false" add-from-autocomplete-only="true" placeholder="{{ \'search.u.g\' | translate}}"><auto-complete source="searchUsers($query)" min-length="0" template="autocomplete-template"></auto-complete></tags-input></td><td><button class="button" ng-click="shareWith(inputSharedWith)">+</button></td></tr><tr><td colspan="2"><small>{{ \'search.result.missing\' | translate}}</small></td></tr></thead></table><div ng-if="share_settings.cypher_progress.done > 0">{{\'cyphering\' | translate}}...<div progress-bar="share_settings.cypher_progress.percent" index="share_settings.cypher_progress.done" total="share_settings.cypher_progress.total"></div></div><div ng-if="share_settings.upload_progress.done > 0">{{ \'uploading\' | translate}}...<div progress-bar="share_settings.upload_progress.percent" index="share_settings.upload_progress.done" total="share_settings.upload_progress.total"></div></div></div></div><div class="col-xs-12 col-md-6" ng-show="share_settings.cypher_progress.times.length > 0"><table class="table"><thead><tr><td>{{ \'user\' | translate}}</td><td>{{ \'crypto.time\' | translate}}</td></tr></thead><tr ng-repeat="user in share_settings.cypher_progress.times"><td><i class="fa fa-cogs"></i> {{user.user}}</td><td>{{user.time}} s</td></tr></table>{{ \'crypto.total.time\' | translate}}: {{ calculate_total_time() }}</div></div><div class="row"><div class="col-xs-12 col-md-6"><table class="table shared_table" ng-show="share_settings.credentialSharedWithUserAndGroup.length > 0"><thead><tr><td>{{\'user\' | translate}}</td><td>{{ \'perm.read\' | translate}}</td><td>{{ \'perm.write\' | translate}}</td><td>{{ \'perm.files\' | translate}}</td><td>{{ \'perm.revisions\' | translate}}</td><td></td></tr></thead><tr ng-repeat="user in share_settings.credentialSharedWithUserAndGroup"><td><i class="fa fa-user" ng-if="user.pending === false"></i> <i class="fa fa-user-times" ng-if="user.pending === true"></i> {{user.userId}} <small ng-if="user.pending === true" class="pull-right pending">{{ \'pending\' | translate}}</small></td><td><input type="checkbox" ng-click="setPermission(user.acl, default_permissions.permissions.READ)" ng-checked="hasPermission(user.acl, default_permissions.permissions.READ)"></td><td><input type="checkbox" ng-click="setPermission(user.acl, default_permissions.permissions.WRITE)" ng-checked="hasPermission(user.acl, default_permissions.permissions.WRITE)"></td><td><input type="checkbox" ng-click="setPermission(user.acl, default_permissions.permissions.FILES)" ng-checked="hasPermission(user.acl, default_permissions.permissions.FILES)"></td><td><input type="checkbox" ng-click="setPermission(user.acl, default_permissions.permissions.HISTORY)" ng-checked="hasPermission(user.acl, default_permissions.permissions.HISTORY)"></td><td><i class="fa fa-trash" ng-click="unshareUser(user)"></i></td></tr></table></div></div><script type="text/ng-template" id="autocomplete-template"><i class="fa fa-user" ng-if="data.type === \'user\'"></i>\n' + @@ -98,51 +98,51 @@ angular.module('views/partials/forms/share_credential/basics.html', []).run(['$t ' {{data.text}}</script>'); }]); -angular.module('views/partials/forms/share_credential/link_sharing.html', []).run(['$templateCache', function ($templateCache) { +angular.module('views/partials/forms/share_credential/link_sharing.html', []).run(['$templateCache', function($templateCache) { 'use strict'; $templateCache.put('views/partials/forms/share_credential/link_sharing.html', '<div class="row"><div class="col-xs-12 col-md-6"><label><input type="checkbox" ng-model="share_settings.linkSharing.enabled"> {{ \'enable.link.sharing\' | translate}}.</label><br><div class="pull-left col-xs-6 nopadding"><span credential-field value="share_link" secret="false" use-input="true" input-placeholder="\'click.share\' | translate"></span></div><div ng-show="share_settings.linkSharing.enabled" class="clearfix">{{ \'share.until.date\' | translate}} <span datetime-picker ng-model="share_settings.linkSharing.settings.expire_time" class="link" future-only close-on-select="false" timestamp="true">{{ share_settings.linkSharing.settings.expire_time | date:\'dd-MM-yyyy @ HH:mm:ss\' }}</span></div><div ng-show="share_settings.linkSharing.enabled">{{ \'expire.views\' | translate}}<br><input type="number" ng-model="share_settings.linkSharing.settings.expire_views"></div><div ng-if="share_settings.linkSharing.enabled"><table><tr><td><input type="checkbox" ng-click="setPermission(share_settings.linkSharing.settings.acl, default_permissions.permissions.FILES)" ng-checked="hasPermission(share_settings.linkSharing.settings.acl, default_permissions.permissions.FILES)"></td><td>{{ \'show.files\' | translate}}</td></tr></table></div></div></div>'); }]); -angular.module('views/partials/icon-picker.html', []).run(['$templateCache', function ($templateCache) { +angular.module('views/partials/icon-picker.html', []).run(['$templateCache', function($templateCache) { 'use strict'; $templateCache.put('views/partials/icon-picker.html', - '<div class="cell icon-category-auth" ng-if="!credential.url && !credential.icon"></div><div class="cell" ng-if="credential.url || credential.icon"><span class="icon"><credential-icon credential="credential"></credential-icon></span></div><div style="display: none" id="iconPicker" title="{{ \'pick.icon\' | translate }}"><div class="iconList"><div ng-repeat="(groupName, icons) in iconGroups"><div ng-click="expanded = !expanded" ng-init="expanded=true"><div class="icon-triangle-s arrow" ng-class="{ \'icon-triangle-e\': !expanded , \'icon-triangle-s\': expanded }"></div><div class="collapsible" id="{{groupName}}">{{groupName}}</div></div><div ng-class="{ \'content_show\': expanded , \'content\': !expanded }"><div class="icon" ng-repeat="icon in icons" ng-click="selectIcon(icon)"><img ng-src="{{icon.url}}" height="32"></div></div></div></div><div class="iconModifier"><input id="iconPicker-Search" class="iconSearch" type="text" placeholder="{{ \'pick.icon.search\' | translate }}"><label for="iconPicker-CustomIcon">{{ \'pick.icon.custom.label\' | translate }}</label><input id="iconPicker-CustomIcon" class="iconSearch" type="file"><div ng-if="selectedIcon || customIcon">{{ \'selected.icon\' | translate}}:<br><img ng-src="{{selectedIcon.url}}" height="32" ng-if="!customIcon"> <img src="{{customIcon.data}}" height="32" ng-if="customIcon"><br><button ng-click="useIcon()">{{ \'use.icon\' | translate}}</button></div><div><button ng-click="deleteIcon()" ng-if="credential.icon">{{ \'use.icon.delete\' | translate}}</button> <button ng-click="refreshUrlIcon()">{{ \'use.icon.refresh\' | translate}}</button></div></div></div>'); + '<div class="cell fa fa-lock" ng-if="!credential.url && !credential.icon"></div><div class="cell" ng-if="credential.url || credential.icon"><span class="icon"><credential-icon credential="credential"></credential-icon></span></div><div style="display: none" id="iconPicker" title="{{ \'pick.icon\' | translate }}"><div class="iconList"><div ng-repeat="(groupName, icons) in iconGroups"><div ng-click="expanded = !expanded" ng-init="expanded=true"><div class="icon-triangle-s arrow" ng-class="{ \'icon-triangle-e\': !expanded , \'icon-triangle-s\': expanded }"></div><div class="collapsible" id="{{groupName}}">{{groupName}}</div></div><div ng-class="{ \'content_show\': expanded , \'content\': !expanded }"><div class="icon" ng-repeat="icon in icons" ng-click="selectIcon(icon)"><img ng-src="{{icon.url}}" height="32"></div></div></div></div><div class="iconModifier"><input id="iconPicker-Search" class="iconSearch" type="text" placeholder="{{ \'pick.icon.search\' | translate }}"> <label for="iconPicker-CustomIcon">{{ \'pick.icon.custom.label\' | translate }}</label> <input id="iconPicker-CustomIcon" class="iconSearch" type="file"><div ng-if="selectedIcon || customIcon">{{ \'selected.icon\' | translate}}:<br><img ng-src="{{selectedIcon.url}}" height="32" ng-if="!customIcon"> <img src="{{customIcon.data}}" height="32" ng-if="customIcon"><br><button ng-click="useIcon()">{{ \'use.icon\' | translate}}</button></div><div><button ng-click="deleteIcon()" ng-if="credential.icon">{{ \'use.icon.delete\' | translate}}</button> <button ng-click="refreshUrlIcon()">{{ \'use.icon.refresh\' | translate}}</button></div></div></div>'); }]); -angular.module('views/partials/password-meter.html', []).run(['$templateCache', function ($templateCache) { +angular.module('views/partials/password-meter.html', []).run(['$templateCache', function($templateCache) { 'use strict'; $templateCache.put('views/partials/password-meter.html', '<div class="pass-meter {{masterClass}}" off-click="matchBreakdown = false;"><div class="{{colClass}} pass-meter-col {{first}}"><div class="indicator"></div></div><div class="{{colClass}} pass-meter-col {{second}}"><div class="indicator"></div></div><div class="{{colClass}} pass-meter-col {{third}}"><div class="indicator"></div></div><div class="{{colClass}} pass-meter-col {{fourth}}"><div class="indicator"></div></div><div class="details" ng-click="toggleScore()"><span ng-show="!scoreShown">{{ \'details\' | translate }}</span> <span ng-show="scoreShown">{{ \'hide.details\' | translate}}</span></div><div class="pass-meter-message">{{message}}</div><div class="detail_box" ng-show="scoreShown"><div class="row"><div class="col-xs-6">{{ \'password.score\' | translate}}:</div><div class="col-xs-6">{{score.score}}</div></div><div><b>{{ \'cracking.times\' | translate}}</b></div><div class="row"><div class="col-xs-6">{{ \'cracking.time.100h\' | translate}}<br><small>{{ \'cracking.time.100h.desc\' | translate}}</small></div><div class="col-xs-6">{{score.crack_times_display.online_throttling_100_per_hour}}</div></div><div class="row"><div class="col-xs-6">{{ \'cracking.time.10s\' | translate}}<br><small>{{ \'cracking.time.10s.desc\' | translate}}</small></div><div class="col-xs-6">{{score.crack_times_display.online_no_throttling_10_per_second}}</div></div><div class="row"><div class="col-xs-6">{{ \'cracking.time.10ks\' | translate}}<br><small>{{ \'cracking.time.10ks.desc\' | translate}}</small></div><div class="col-xs-6">{{score.crack_times_display.offline_slow_hashing_1e4_per_second}}</div></div><div class="row"><div class="col-xs-6">{{ \'cracking.time.10Bs\' | translate}}<br><small>{{ \'cracking.time.10Bs.desc\' | translate}}</small></div><div class="col-xs-6">{{score.crack_times_display.offline_fast_hashing_1e10_per_second}}</div></div><div class="row"><div class="col-xs-6">{{ \'match.sequence\' | translate}}:</div><div class="col-xs-6"><span class="link" ng-click="toggleMatchBreakdown()">{{ \'match.sequence.link\' | translate}}</span></div></div></div></div><div class="match-sequence"><div class="sequence_container" ng-style="{\'width\': score.sequence.length * 210 }"><div class="sequence" ng-repeat="sequence in score.sequence"><table><tr><td colspan="2" class="token"><code>{{sequence.token}}</code></td></tr><tr ng-if="sequence.pattern"><td>{{ \'pattern\' | translate}}</td><td>{{sequence.pattern}}</td></tr><tr ng-if="sequence.matched_word"><td>{{ \'matched.word\' | translate}}</td><td>{{sequence.matched_word}}</td></tr><tr ng-if="sequence.dictionary_name"><td>{{ \'dictionary.name\' | translate}}</td><td>{{sequence.dictionary_name}}</td></tr><tr ng-if="sequence.rank"><td>{{ \'rank\' | translate}}</td><td>{{sequence.rank}}</td></tr><tr ng-if="sequence.reversed"><td>{{ \'reversed\' | translate}}</td><td>{{sequence.reversed}}</td></tr><tr ng-if="sequence.guesses"><td>{{ \'guesses\' | translate}}</td><td>{{sequence.guesses}}</td></tr><tr ng-if="sequence.base_guesses"><td>{{ \'base.guesses\' | translate}}</td><td>{{sequence.base_guesses}}</td></tr><tr ng-if="sequence.uppercase_variations"><td>{{ \'uppercase.variations\' | translate}}</td><td>{{sequence.uppercase_variations}}</td></tr><tr ng-if="sequence.l33t_variations"><td>{{ \'leet.variations\' | translate}}</td><td>{{sequence.l33t_variations}}</td></tr></table></div></div></div>'); }]); -angular.module('views/settings.html', []).run(['$templateCache', function ($templateCache) { +angular.module('views/settings.html', []).run(['$templateCache', function($templateCache) { 'use strict'; $templateCache.put('views/settings.html', '<div id="passman-controls"><div class="breadcrumb"><div class="breadcrumb"><div class="crumb svg ui-droppable" data-dir="/"><a ng-click="logout()"><i class="fa fa-home"></i></a></div><div class="crumb svg"><a ng-click="cancel()">{{active_vault.name}}</a></div><div class="crumb svg last"><a>{{ \'settings\' | translate}}</a></div></div></div></div><div><ul class="tab_header"><li ng-repeat="tab in tabs track by $index" class="tab" ng-class="isActiveTab(tab)? \'active\' : \'inactive\'" ng-click="onClickTab(tab)" use-theme color="\'true\'">{{tab.title | translate}}<div class="indicator" use-theme negative="\'true\'"></div></li></ul><div class="tab_container settings edit_credential" use-theme type="\'border-top-color\'"><div ng-include="currentTab.url"></div></div></div>'); }]); -angular.module('views/share_credential.html', []).run(['$templateCache', function ($templateCache) { +angular.module('views/share_credential.html', []).run(['$templateCache', function($templateCache) { 'use strict'; $templateCache.put('views/share_credential.html', '<div class="main_list.share"><div id="passman-controls"><div class="actions creatable"><div class="breadcrumb"><div class="crumb svg ui-droppable" data-dir="/"><a ng-click="logout()"><i class="fa fa-home"></i></a></div><div class="crumb svg" data-dir="/Test"><a ng-click="cancel()">{{active_vault.name}}</a></div><div class="crumb svg last" data-dir="/Test"><a ng-if="storedCredential.credential_id">{{ \'share.credential\' | translate}} {{storedCredential.label}}</a></div></div></div></div><ul class="tab_header"><li ng-repeat="tab in tabs track by $index" class="tab" ng-class="{active:isActiveTab(tab)}" ng-click="onClickTab(tab)" use-theme color="\'true\'">{{tab.title | translate}}<div class="indicator" use-theme negative="\'true\'"></div></li></ul><div class="tab_container share_credential" ng-show="currentTab"><div ng-include="currentTab.url"></div><button ng-click="applyShare()" ng-disabled="share_settings.linkSharing.enabled === false && share_settings.credentialSharedWithUserAndGroup.length === 0">{{ \'share\' | translate}}</button> <button ng-click="cancel()">{{ \'cancel\' | translate}}</button> <button class="btn btn-danger" ng-disabled="!storedCredential.shared_key" ng-click="unshareCredential(storedCredential)">{{ \'unshare\' | translate}}</button></div></div>'); }]); -angular.module('views/show_vault.html', []).run(['$templateCache', function ($templateCache) { +angular.module('views/show_vault.html', []).run(['$templateCache', function($templateCache) { 'use strict'; $templateCache.put('views/show_vault.html', - '<div class="main_list" off-click-filter="\'.download-js-link, .sidebar-shown, #app-sidebar\'"><div id="passman-controls" ng-class="{ \'sidebar-shown\': selectedCredential }"><div class="breadcrumb"><div class="breadcrumb"><div class="crumb svg ui-droppable" data-dir="/"><a ng-click="logout()"><i class="fa fa-home"></i></a></div><div class="crumb svg" ng-click="clearState()"><a>{{active_vault.name}}</a></div></div><div class="addCredential" ng-hide="delete_time>0"><button ng-click="addCredential()">+</button></div></div><div class="title" credential-counter="filtered_credentials" vault="active_vault" delete-time="delete_time" filters="filterOptions"></div><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;"><div class="searchOptions" ng-show="filterOptionShown"><input type="checkbox" ng-model="filterOptions.useRegex"> {{ \'use.regex\' | translate }}</div></div><div class="viewModes"><div class="view-mode" ng-class="{\'active\': view_mode === \'list\' }" ng-click="switchViewMode(\'list\')"><i class="fa fa-list"></i></div><div class="view-mode" ng-class="{\'active\': view_mode === \'grid\' }" ng-click="switchViewMode(\'grid\')"><i class="fa fa-th-large"></i></div></div></div><div class="loaderContainer" ng-if="show_spinner"><div class="loader" use-theme type="\'border-bottom-color\'"></div></div><div ng-init="menuOpen = false;"><table class="credential-table" ng-if="view_mode === \'list\'"><tr ng-repeat="credential in filtered_credentials | orderBy:\'label\'" ng-if="showCredentialRow(credential)" ng-click="selectCredential(credential)" ng-dblclick="editCredential(credential)" ng-class="{\'selected\': selectedCredential.credential_id == credential.credential_id}"><td ng-class="{\'compromised\': credential.compromised }"><span class="tags"><span class="tag" ng-repeat="tag in credential.tags_raw">{{ ::tag.text}}</span> </span><span class="icon" ng-if="credential.url || credential.icon"><credential-icon credential="credential"></credential-icon></span><span class="icon" ng-if="!credential.url && !credential.icon"><i class="fa fa-lock" ng-if="!credential.acl && !credential.shared_key"></i> <i class="fa fa-share-alt" ng-if="credential.acl"></i> <i class="fa fa-share-alt-square" ng-if="credential.shared_key"></i> </span><a class="label">{{ ::credential.label}}</a> <span ng-if="credential.compromised" class="compromised-list"><i class="icon-error icon"></i> <span class="text">{{ \'compromised.warning.list\' | translate}}</span></span></td></tr></table><ul class="grid-view" ng-if="view_mode === \'grid\'"><li class="credential" ng-repeat="credential in filtered_credentials | orderBy:\'label\'" ng-if="credential.hidden == 0 && showCredentialRow(credential)" ng-click="selectCredential(credential)" use-theme type="\'border-color\'"><div class="credential_content"><div><span class="icon" ng-if="credential.url"><credential-icon credential="credential"></credential-icon></span><span class="icon" ng-if="!credential.url"><i class="fa fa-lock" ng-if="!credential.acl && !credential.shared_key"></i> <i class="fa fa-share-alt" ng-if="credential.acl"></i> <i class="fa fa-share-alt-square" ng-if="credential.shared_key"></i></span><div class="label">{{ ::credential.label}}</div></div><div class="tags"><div class="tag" ng-repeat="tag in credential.tags_raw">{{ ::tag.text}}</div></div></div></li></ul><div ng-if="getListSizes().listsize_wout_deleted==0 && no_credentials_label.all && !show_spinner && selectedtags.length==0 && filterOptions.filterText==\'\'" class="nopasswords" ng-hide="delete_time>0"><b>{{\'vault.hint.hello\' | translate}}</b><br><div>{{\'vault.hint.hello.add\' | translate}}</div><div class=""><button ng-click="addCredential()">+</button></div></div><div ng-if="getListSizes().listsize_wout_deleted==0 && no_credentials_label.all && !show_spinner && selectedtags.length>0" class="nopasswords" ng-hide="delete_time>0"><div>{{ \'vault.hint.list.notags\' | translate}}</div></div><div ng-if="getListSizes().listsize_wout_deleted==0 && no_credentials_label.all && !show_spinner && selectedtags.length==0 && filterOptions.filterText!=\'\'" class="nopasswords" ng-hide="delete_time>0"><div>{{ \'vault.hint.list.nosearch\' | translate}} <b>\'{{filterOptions.filterText}}\'</b></div></div><div class="nopasswords" ng-if="no_credentials_label.s_good" ng-hide="getListSizes().listsize_wout_deleted>0"><div>{{ \'vault.hint.list.nogood\' | translate}}</div></div><div class="nopasswords" ng-if="no_credentials_label.s_medium" ng-hide="getListSizes().listsize_wout_deleted>0"><div>{{ \'vault.hint.list.nomedium\' | translate}}</div></div><div class="nopasswords" ng-if="no_credentials_label.s_low" ng-hide="getListSizes().listsize_wout_deleted>0"><div>{{ \'vault.hint.list.nobad\' | translate}}</div></div><div class="nopasswords" ng-if="no_credentials_label.expired" ng-hide="getListSizes().listsize_wout_deleted>0"><div>{{ \'vault.hint.list.noexpired\' | translate}}</div></div><div class="nopasswords" ng-if="getListSizes().listsize_deleted==0" ng-hide="delete_time==0"><div>{{ \'vault.hint.list.nodeleted\' | translate}}</div></div></div></div><div id="app-sidebar" class="app_sidebar" ng-show="selectedCredential" off-click="closeSelected()"><span class="close icon-close" ng-click="closeSelected()" alt="Close"></span><div class="sidebar"><span class="icon sidebar-icon" ng-if="selectedCredential.url || credential.icon"><credential-icon credential="selectedCredential"></credential-icon></span><span class="icon sidebar-icon" ng-if="!selectedCredential.url && !credential.icon"><credential-icon credential="selectedCredential"></credential-icon></span><h2 class="sidebar-label">{{selectedCredential.label}}</h2></div><div credential-template="selectedCredential"></div><div ng-show="selectedCredential"><div><button class="button" ng-click="editCredential(selectedCredential)" ng-if="selectedCredential.delete_time == 0 && hasPermission(selectedCredential.acl.permissions, permissions.permissions.WRITE)"><span class="fa fa-edit"></span> {{ \'edit\' | translate}}</button> <button class="button" ng-click="deleteCredential(selectedCredential)" ng-if="selectedCredential.delete_time == 0 && hasPermission(selectedCredential.acl.permissions, permissions.permissions.WRITE)"><span class="fa fa-trash"></span> {{ \'delete\' | translate}}</button> <button class="button" ng-click="shareCredential(selectedCredential)" ng-if="selectedCredential.delete_time == 0 && selectedCredential.acl === undefined &&\n' + + '<div class="main_list" off-click-filter="\'.download-js-link, .sidebar-shown, #app-sidebar\'"><div id="passman-controls" ng-class="{ \'sidebar-shown\': selectedCredential }"><div class="breadcrumb"><div class="breadcrumb"><div class="crumb svg ui-droppable" data-dir="/"><a ng-click="logout()"><i class="fa fa-home"></i></a></div><div class="crumb svg" ng-click="clearState()"><a>{{active_vault.name}}</a></div></div><div class="addCredential" ng-hide="delete_time>0"><button ng-click="addCredential()">+</button></div></div><div class="title" credential-counter="filtered_credentials" vault="active_vault" delete-time="delete_time" filters="filterOptions"></div><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;"><div class="searchOptions" ng-show="filterOptionShown"><input type="checkbox" ng-model="filterOptions.useRegex"> {{ \'use.regex\' | translate }}</div></div><div class="viewModes"><div class="view-mode" ng-class="{\'active\': view_mode === \'list\' }" ng-click="switchViewMode(\'list\')"><i class="fa fa-list"></i></div><div class="view-mode" ng-class="{\'active\': view_mode === \'grid\' }" ng-click="switchViewMode(\'grid\')"><i class="fa fa-th-large"></i></div></div></div><div class="loaderContainer" ng-if="show_spinner"><div class="loader" use-theme type="\'border-bottom-color\'"></div></div><div ng-init="menuOpen = false;"><table class="credential-table" ng-if="view_mode === \'list\'"><tr ng-repeat="credential in filtered_credentials | orderBy:\'label\'" ng-if="showCredentialRow(credential)" ng-click="selectCredential(credential)" ng-dblclick="editCredential(credential)" ng-class="{\'selected\': selectedCredential.credential_id == credential.credential_id}"><td ng-class="{\'compromised\': credential.compromised }"><span class="tags"><span class="tag" ng-repeat="tag in credential.tags_raw">{{ ::tag.text}}</span> </span><span class="icon" ng-if="credential.url || credential.icon"><credential-icon credential="credential"></credential-icon></span><span class="icon" ng-if="!credential.url && !credential.icon"><i class="fa fa-lock" ng-if="!credential.acl && !credential.shared_key"></i> <i class="fa fa-share-alt" ng-if="credential.acl"></i> <i class="fa fa-share-alt-square" ng-if="credential.shared_key"></i> </span><a class="label">{{ ::credential.label}}</a> <span ng-if="credential.compromised" class="compromised-list"><i class="icon-error icon"></i> <span class="text">{{ \'compromised.warning.list\' | translate}}</span></span></td></tr></table><ul class="grid-view" ng-if="view_mode === \'grid\'"><li class="credential" ng-repeat="credential in filtered_credentials | orderBy:\'label\'" ng-if="credential.hidden == 0 && showCredentialRow(credential)" ng-click="selectCredential(credential)" use-theme type="\'border-color\'"><div class="credential_content"><div><span class="icon" ng-if="credential.url"><credential-icon credential="credential"></credential-icon></span><span class="icon" ng-if="!credential.url"><i class="fa fa-lock" ng-if="!credential.acl && !credential.shared_key"></i> <i class="fa fa-share-alt" ng-if="credential.acl"></i> <i class="fa fa-share-alt-square" ng-if="credential.shared_key"></i></span><div class="label">{{ ::credential.label}}</div></div><div class="tags"><div class="tag" ng-repeat="tag in credential.tags_raw">{{ ::tag.text}}</div></div></div></li></ul><div ng-if="getListSizes().listsize_wout_deleted==0 && no_credentials_label.all && !show_spinner && selectedtags.length==0 && filterOptions.filterText==\'\'" class="nopasswords" ng-hide="delete_time>0"><b>{{\'vault.hint.hello\' | translate}}</b><br><div>{{\'vault.hint.hello.add\' | translate}}</div><div class=""><button ng-click="addCredential()">+</button></div></div><div ng-if="getListSizes().listsize_wout_deleted==0 && no_credentials_label.all && !show_spinner && selectedtags.length>0" class="nopasswords" ng-hide="delete_time>0"><div>{{ \'vault.hint.list.notags\' | translate}}</div></div><div ng-if="getListSizes().listsize_wout_deleted==0 && no_credentials_label.all && !show_spinner && selectedtags.length==0 && filterOptions.filterText!=\'\'" class="nopasswords" ng-hide="delete_time>0"><div>{{ \'vault.hint.list.nosearch\' | translate}} <b>\'{{filterOptions.filterText}}\'</b></div></div><div class="nopasswords" ng-if="no_credentials_label.s_good" ng-hide="getListSizes().listsize_wout_deleted>0"><div>{{ \'vault.hint.list.nogood\' | translate}}</div></div><div class="nopasswords" ng-if="no_credentials_label.s_medium" ng-hide="getListSizes().listsize_wout_deleted>0"><div>{{ \'vault.hint.list.nomedium\' | translate}}</div></div><div class="nopasswords" ng-if="no_credentials_label.s_low" ng-hide="getListSizes().listsize_wout_deleted>0"><div>{{ \'vault.hint.list.nobad\' | translate}}</div></div><div class="nopasswords" ng-if="no_credentials_label.expired" ng-hide="getListSizes().listsize_wout_deleted>0"><div>{{ \'vault.hint.list.noexpired\' | translate}}</div></div><div class="nopasswords" ng-if="getListSizes().listsize_deleted==0" ng-hide="delete_time==0"><div>{{ \'vault.hint.list.nodeleted\' | translate}}</div></div></div></div><div id="app-sidebar" class="app_sidebar" ng-show="selectedCredential" off-click="closeSelected()"><span class="close icon-close" ng-click="closeSelected()" alt="Close"></span><div class="sidebar"><span class="icon sidebar-icon" ng-if="selectedCredential.url || selectedCredential.icon"><credential-icon credential="selectedCredential"></credential-icon></span><span class="icon sidebar-icon" ng-if="!selectedCredential.url && !selectedCredential.icon"><i class="fa fa-lock fa-3x icon-image"></i></span><h2 class="sidebar-label">{{selectedCredential.label}}</h2></div><div credential-template="selectedCredential"></div><div ng-show="selectedCredential"><div><button class="button" ng-click="editCredential(selectedCredential)" ng-if="selectedCredential.delete_time == 0 && hasPermission(selectedCredential.acl.permissions, permissions.permissions.WRITE)"><span class="fa fa-edit"></span> {{ \'edit\' | translate}}</button> <button class="button" ng-click="deleteCredential(selectedCredential)" ng-if="selectedCredential.delete_time == 0 && hasPermission(selectedCredential.acl.permissions, permissions.permissions.WRITE)"><span class="fa fa-trash"></span> {{ \'delete\' | translate}}</button> <button class="button" ng-click="shareCredential(selectedCredential)" ng-if="selectedCredential.delete_time == 0 && selectedCredential.acl === undefined &&\n' + ' (settings.user_sharing_enabled === 1 || settings.user_sharing_enabled === \'1\' || settings.link_sharing_enabled === 1 || settings.link_sharing_enabled === \'1\')"><span class="fa fa-share"></span> {{ \'share\' | translate}}</button> <button class="button" ng-click="getRevisions(selectedCredential)" ng-if="selectedCredential.delete_time == 0 && hasPermission(selectedCredential.acl.permissions, permissions.permissions.HISTORY)"><span class="fa fa-undo"></span> {{ \'revisions\' | translate}}</button> <button class="button" ng-if="selectedCredential.delete_time > 0" ng-click="recoverCredential(selectedCredential) && hasPermission(selectedCredential.acl.permissions, permissions.permissions.WRITE)"><span class="fa fa-recycle"></span> {{\'recover\' | translate}}</button> <button class="button" ng-if="selectedCredential.delete_time > 0" ng-click="destroyCredential(selectedCredential)"><span class="fa fa-bomb"></span> {{\'destroy\' | translate}}</button></div></div></div><div class="share_popup" style="display: none" title="{{ \'sharereq.title\' | translate }}"><p>{{ \'sharereq.line1\' | translate}} {{ \'sharereq.line2\' | translate}}</p><br><table class="table"><thead><tr><td><b>{{ \'label\' | translate}}</b></td><td><b>{{ \'permissions\' | translate}}</b></td><td><b>{{ \'received.from\' | translate}}</b></td><td><b>{{ \'date\' | translate}}</b></td></tr></thead><tr ng-repeat="share_request in incoming_share_requests" ng-if="share_request.target_vault_id == active_vault.vault_id"><td>{{share_request.credential_label}}</td><td>{{share_request.permissions}}</td><td>{{share_request.from_user_id}}</td><td>{{share_request.created * 1000 | date:\'dd-MM-yyyy @ HH:mm:ss\'}}</td><td><span class="link" ng-click="acceptShareRequest(share_request)"><b>{{ \'accept\' | translate}}</b></span> | <span class="link" ng-click="declineShareRequest(share_request)">{{ \'decline\' | translate}}</span></td></tr></table></div>'); }]); -angular.module('views/vault_req_deletion.html', []).run(['$templateCache', function ($templateCache) { +angular.module('views/vault_req_deletion.html', []).run(['$templateCache', function($templateCache) { 'use strict'; $templateCache.put('views/vault_req_deletion.html', - '<div class="vault_wrapper"><div class="reset_form" ng-show="!pending_deletion">{{ \'req.intro1\' | translate }}<br>{{ \'req.intro2\' | translate }}<br>{{ \'req.intro3\' | translate }}<br><br><b>{{ \'request.deletion.warning\' | translate}}</b><label>{{ \'request.deletion.reason\' | translate }}</label><input type="text" ng-model="reason" class="form-control"> <button class="button button-red" ng-click="requestDeletion()">{{ \'request.deletion.accept\' | translate }}</button> <a class="pull-right button button-geen" ng-href="#/">{{ \'cancel\' | translate}}</a></div><div class="reset_form" ng-show="pending_deletion"><button class="button button-red" ng-click="removeRequestDeletion()">Cancel destruction request</button> <a class="pull-right button button-geen" ng-href="#/">Cancel</a></div></div>'); + '<div class="vault_wrapper"><div class="reset_form" ng-show="!pending_deletion">{{ \'req.intro1\' | translate }}<br>{{ \'req.intro2\' | translate }}<br>{{ \'req.intro3\' | translate }}<br><br><b>{{ \'request.deletion.warning\' | translate}}</b> <label>{{ \'request.deletion.reason\' | translate }}</label> <input type="text" ng-model="reason" class="form-control"> <button class="button button-red" ng-click="requestDeletion()">{{ \'request.deletion.accept\' | translate }}</button> <a class="pull-right button button-geen" ng-href="#/">{{ \'cancel\' | translate}}</a></div><div class="reset_form" ng-show="pending_deletion"><button class="button button-red" ng-click="removeRequestDeletion()">Cancel destruction request</button> <a class="pull-right button button-geen" ng-href="#/">Cancel</a></div></div>'); }]); -angular.module('views/vaults.html', []).run(['$templateCache', function ($templateCache) { +angular.module('views/vaults.html', []).run(['$templateCache', function($templateCache) { 'use strict'; $templateCache.put('views/vaults.html', - '<div class="vault_wrapper"><div class="vaults" ng-if="!list_selected_vault && !creating_vault"><div class="ui-select-container ui-select-bootstrap vaultlist"><ul><li ng-click="newVault()">+ Create a new vault</li><li ng-repeat="vault in vaults" ng-class="{\'selected\': vault == list_selected_vault }" ng-click="selectVault(vault)"><div><span class="ui-select-choices-row-inner"><div class="ng-binding ng-scope">{{vault.name}} <span class="pull-right" style="color: #ce3702" ng-show="vault.delete_request_pending">{{ \'delete.request.pending\' | translate}}</span></div><small class="ng-binding ng-scope">{{ \'created\' | translate}}: {{vault.created * 1000 | date:\'dd-MM-yyyy @ HH:mm:ss\'}} | {{ \'last.access\' | translate}}: <span ng-if="vault.last_access > 0">{{vault.last_access * 1000 | date:\'dd-MM-yyyy @ HH:mm:ss\'}}</span> <span ng-if="vault.last_access === 0">{{\'never\' | translate}}</span></small></span></div></li><li ng-if="vaults.length === 0">{{ \'no.vaults\' | translate}}</li></ul></div></div><div ng-if="creating_vault"><div class="login_form" ng-init="vault_name = \'\'; vault_key=\'\'; ">{{\'new.vault.name\' | translate}}<div><input type="text" ng-model="vault_name" required></div><div>{{ \'new.vault.pass\' | translate}} <input type="password" ng-model="vault_key" required><ng-password-meter password="vault_key" score="vault_key_score"></ng-password-meter></div><div>{{ \'new.vault.passr\' | translate}} <input type="password" ng-model="vault_key2" required></div><div ng-show="error || vault_key_score.score < minimal_value_key_strength" class="error"><ul><li ng-show="error">{{error}}</li><li ng-show="vault_key_score.score < minimal_value_key_strength">{{\'min.vault.key.strength\' | translate:required_score}}</li></ul></div><div><small>{{\'new.vault.sharing_key_notice\' | translate}}</small></div><div class="button_wrapper"><button class="button button-geen" ng-if="!creating_keys" click-disable ng-click="createVault(vault_name, vault_key, vault_key2)" ng-disabled="vault_key_score.score < minimal_value_key_strength || vault_key !== vault_key2 || vault_key === \'\'">{{ \'new.vault.create\' | translate }}</button><div class="button" ng-if="creating_keys"><span><i class="fa fa-spinner fa-spin"></i> {{creating_keys}}</span></div><div class="button button-red" ng-click="clearState()">{{ \'cancel\' | translate}}</div><div class="template-hidden">{{sharing_keys}}</div></div></div></div><div ng-if="list_selected_vault != false"><div class="vaultlist"><ul><li ng-click="clearState()">{{ \'go.back.vaults\' | translate }}</li></ul></div><div class="login_form"><div ng-show="error" class="error"><ul><li>{{error}}</li></ul></div>{{ \'input.vault.password\' | translate}} {{list_selected_vault.name}}<div class="pw-input"><input type="password" ng-model="vault_key" ng-enter="loginToVault(list_selected_vault, vault_key)"> <small class="last_access">{{\'last.access\' | translate}}: <span ng-if="list_selected_vault.last_access > 0">{{list_selected_vault.last_access * 1000 | date:\'dd-MM-yyyy @ HH:mm:ss\'}}</span> <span ng-if="list_selected_vault.last_access === 0">Never</span></small></div><div class="login_opts"><div><label><input type="checkbox" ng-checked="default_vault" ng-click="toggleDefaultVault()"> {{ \'vault.default\' | translate}}</label></div><div><label><input type="checkbox" ng-checked="remember_vault_password" ng-click="toggleRememberPassword()"> {{ \'vault.auto.login\' | translate}}</label></div><div><label><input type="checkbox" ng-checked="auto_logout_timer" ng-click="toggleAutoLogout()"> {{ \'auto.logout\' | translate}}</label><select ng-model="logout_timer" ng-change="selectLogoutTimer(logout_timer)"><option value="0">Never</option><option value="30">30 minutes</option><option value="60">60 minutes</option><option value="90">90 minutes</option><option value="180">3 hour</option><option value="480">8 hour</option></select></div></div><div class="alert alert-danger" ng-show="vault_tries[list_selected_vault.guid].timeout !== 0" translate="vault.locked" translate-value-tries="{{ vault_tries[list_selected_vault.guid].tries }}" translate-value-time="{{ vault_tries[list_selected_vault.guid].timeout | toHHMMSS }}"></div><button class="button button-geen" ng-click="loginToVault(list_selected_vault, vault_key)" ng-disabled="vault_tries[list_selected_vault.guid].timeout !== 0">{{ \'vault.decrypt\' | translate}}</button> <span ng-click="forgottenPassword = true;" style="margin-top: 10px; padding: 6px 12px" class="link pull-right" ng-show="!forgottenPassword">Forgot password?</span> <button ng-show="forgottenPassword" class="pull-right button button-red" ng-click="requestDeletion(list_selected_vault)"><span ng-show="list_selected_vault.delete_request_pending">{{ \'cancel.request.deletion\' | translate }}</span> <span ng-show="!list_selected_vault.delete_request_pending">{{ \'request.deletion\' | translate }}</span></button></div></div></div>'); + '<div class="vault_wrapper"><div class="vaults" ng-if="!list_selected_vault && !creating_vault"><div class="ui-select-container ui-select-bootstrap vaultlist"><ul><li ng-click="newVault()">+ Create a new vault</li><li ng-repeat="vault in vaults" ng-class="{\'selected\': vault == list_selected_vault }" ng-click="selectVault(vault)"><div><span class="ui-select-choices-row-inner"><div class="ng-binding ng-scope">{{vault.name}} <span class="pull-right" style="color: #ce3702;" ng-show="vault.delete_request_pending">{{ \'delete.request.pending\' | translate}}</span></div><small class="ng-binding ng-scope">{{ \'created\' | translate}}: {{vault.created * 1000 | date:\'dd-MM-yyyy @ HH:mm:ss\'}} | {{ \'last.access\' | translate}}: <span ng-if="vault.last_access > 0">{{vault.last_access * 1000 | date:\'dd-MM-yyyy @ HH:mm:ss\'}}</span> <span ng-if="vault.last_access === 0">{{\'never\' | translate}}</span></small></span></div></li><li ng-if="vaults.length === 0">{{ \'no.vaults\' | translate}}</li></ul></div></div><div ng-if="creating_vault"><div class="login_form" ng-init="vault_name = \'\'; vault_key=\'\'; ">{{\'new.vault.name\' | translate}}<div><input type="text" ng-model="vault_name" required></div><div>{{ \'new.vault.pass\' | translate}} <input type="password" ng-model="vault_key" required><ng-password-meter password="vault_key" score="vault_key_score"></ng-password-meter></div><div>{{ \'new.vault.passr\' | translate}} <input type="password" ng-model="vault_key2" required></div><div ng-show="error || vault_key_score.score < minimal_value_key_strength" class="error"><ul><li ng-show="error">{{error}}</li><li ng-show="vault_key_score.score < minimal_value_key_strength">{{\'min.vault.key.strength\' | translate:required_score}}</li></ul></div><div><small>{{\'new.vault.sharing_key_notice\' | translate}}</small></div><div class="button_wrapper"><button class="button button-geen" ng-if="!creating_keys" click-disable ng-click="createVault(vault_name, vault_key, vault_key2)" ng-disabled="vault_key_score.score < minimal_value_key_strength || vault_key !== vault_key2 || vault_key === \'\'">{{ \'new.vault.create\' | translate }}</button><div class="button" ng-if="creating_keys"><span><i class="fa fa-spinner fa-spin"></i> {{creating_keys}}</span></div><div class="button button-red" ng-click="clearState()">{{ \'cancel\' | translate}}</div><div class="template-hidden">{{sharing_keys}}</div></div></div></div><div ng-if="list_selected_vault != false"><div class="vaultlist"><ul><li ng-click="clearState()">{{ \'go.back.vaults\' | translate }}</li></ul></div><div class="login_form"><div ng-show="error" class="error"><ul><li>{{error}}</li></ul></div>{{ \'input.vault.password\' | translate}} {{list_selected_vault.name}}<div class="pw-input"><input type="password" ng-model="vault_key" ng-enter="loginToVault(list_selected_vault, vault_key)"> <small class="last_access">{{\'last.access\' | translate}}: <span ng-if="list_selected_vault.last_access > 0">{{list_selected_vault.last_access * 1000 | date:\'dd-MM-yyyy @ HH:mm:ss\'}}</span> <span ng-if="list_selected_vault.last_access === 0">Never</span></small></div><div class="login_opts"><div><label><input type="checkbox" ng-checked="default_vault" ng-click="toggleDefaultVault()"> {{ \'vault.default\' | translate}}</label></div><div><label><input type="checkbox" ng-checked="remember_vault_password" ng-click="toggleRememberPassword()"> {{ \'vault.auto.login\' | translate}}</label></div><div><label><input type="checkbox" ng-checked="auto_logout_timer" ng-click="toggleAutoLogout()"> {{ \'auto.logout\' | translate}}</label> <select ng-model="logout_timer" ng-change="selectLogoutTimer(logout_timer)"><option value="0">Never</option><option value="30">30 minutes</option><option value="60">60 minutes</option><option value="90">90 minutes</option><option value="180">3 hour</option><option value="480">8 hour</option></select></div></div><div class="alert alert-danger" ng-show="vault_tries[list_selected_vault.guid].timeout !== 0" translate="vault.locked" translate-value-tries="{{ vault_tries[list_selected_vault.guid].tries }}" translate-value-time="{{ vault_tries[list_selected_vault.guid].timeout | toHHMMSS }}"></div><button class="button button-geen" ng-click="loginToVault(list_selected_vault, vault_key)" ng-disabled="vault_tries[list_selected_vault.guid].timeout !== 0">{{ \'vault.decrypt\' | translate}}</button> <span ng-click="forgottenPassword = true;" style="margin-top: 10px; padding: 6px 12px;" class="link pull-right" ng-show="!forgottenPassword">Forgot password?</span> <button ng-show="forgottenPassword" class="pull-right button button-red" ng-click="requestDeletion(list_selected_vault)"><span ng-show="list_selected_vault.delete_request_pending">{{ \'cancel.request.deletion\' | translate }}</span> <span ng-show="!list_selected_vault.delete_request_pending">{{ \'request.deletion\' | translate }}</span></button></div></div></div>'); }]); diff --git a/lib/Activity.php b/lib/Activity.php index 96c1afaf..61f6fc33 100644 --- a/lib/Activity.php +++ b/lib/Activity.php @@ -24,6 +24,7 @@ namespace OCA\Passman; use OCP\IURLGenerator; +use OCP\L10N\IFactory; class Activity implements \OCP\Activity\IExtension { const FILTER_PASSMAN = 'passman'; @@ -54,9 +55,11 @@ class Activity implements \OCP\Activity\IExtension { protected $URLGenerator; + protected $factory; - public function __construct( IURLGenerator $URLGenerator) { + public function __construct(IURLGenerator $URLGenerator, IFactory $factory) { $this->URLGenerator = $URLGenerator; + $this->factory = $factory; } @@ -67,8 +70,8 @@ class Activity implements \OCP\Activity\IExtension { * @param string $languageCode * @return array|false */ - public function getNotificationTypes($languageCode) { - $l = \OC::$server->getL10N(self::APP_NAME, $languageCode); + public function getNotificationTypes(string $languageCode) { + $l = $this->factory->get(self::APP_NAME, $languageCode); return array( self::TYPE_ITEM_ACTION => $l->t('A Passman item has been created, modified or deleted'), self::TYPE_ITEM_EXPIRED => $l->t('A Passman item has expired'), @@ -127,7 +130,7 @@ class Activity implements \OCP\Activity\IExtension { * @return string|false */ public function translate($app, $text, $params, $stripPath, $highlightParams, $languageCode) { - $l = \OC::$server->getL10NFactory()->get(self::APP_NAME, $languageCode); + $l = $this->factory->get(self::APP_NAME, $languageCode); if ($app === self::APP_NAME) { switch ($text) { case self::SUBJECT_ITEM_CREATED: @@ -258,13 +261,13 @@ class Activity implements \OCP\Activity\IExtension { * @return array|false */ public function getNavigation() { - $l = \OC::$server->getL10N(self::APP_NAME); + $l = $this->factory->get(self::APP_NAME); return array( 'top' => array(), - 'apps' => array( self::FILTER_PASSMAN => + 'apps' => array(self::FILTER_PASSMAN => array( 'id' => 'passman', - 'name' => (string) $l->t('Passwords'), + 'name' => (string)$l->t('Passwords'), 'url' => $this->URLGenerator->linkToRoute('activity.Activities.showList', ['filter' => self::FILTER_PASSMAN]), ), ), @@ -278,7 +281,7 @@ class Activity implements \OCP\Activity\IExtension { * @return boolean */ public function isFilterValid($filterValue) { - return $filterValue === self::FILTER_PASSMAN; + return $filterValue === self::FILTER_PASSMAN; } /** @@ -300,4 +303,4 @@ class Activity implements \OCP\Activity\IExtension { return false; } -}
\ No newline at end of file +} diff --git a/lib/AppInfo/Application.php b/lib/AppInfo/Application.php index f83dbcbd..2849dc99 100644 --- a/lib/AppInfo/Application.php +++ b/lib/AppInfo/Application.php @@ -39,16 +39,23 @@ use OCA\Passman\Service\SettingsService; use OCA\Passman\Service\ShareService; use OCA\Passman\Service\VaultService; use OCA\Passman\Utility\Utils; +use OCA\UserStatus\Listener\UserDeletedListener; use OCP\AppFramework\App; use OCP\AppFramework\Bootstrap\IBootContext; use OCP\AppFramework\Bootstrap\IBootstrap; use OCP\AppFramework\Bootstrap\IRegistrationContext; use OCP\IDBConnection; +use OCP\IGroupManager; use OCP\IL10N; -use OCP\ILogger; +use OCP\INavigationManager; +use OCP\IURLGenerator; +use OCP\IUserManager; +use OCP\IUserSession; use OCP\Notification\IManager; +use OCP\User\Events\BeforeUserDeletedEvent; use OCP\Util; use Psr\Container\ContainerInterface; +use Psr\Log\LoggerInterface; class Application extends App implements IBootstrap { public const APP_ID = 'passman'; @@ -59,7 +66,6 @@ class Application extends App implements IBootstrap { public function register(IRegistrationContext $context): void { $this->registerNavigationEntry(); - // $this->registerPersonalPage(); $context->registerEventListener( BeforeUserDeletedEvent::class, @@ -80,20 +86,27 @@ class Application extends App implements IBootstrap { $context->registerMiddleware(APIMiddleware::class); $context->registerService('ShareController', function (ContainerInterface $c) { - $server = $this->getContainer()->getServer(); + /** @var IUserManager $userManager */ + $userManager = $c->get(IUserManager::class); + /** @var IGroupManager $groupManager */ + $groupManager = $c->get(IGroupManager::class); + /** @var IUserSession $userSession */ + $userSession = $c->get(IUserSession::class); + return new ShareController( $c->get('AppName'), $c->get('Request'), - $server->getUserSession()->getUser(), - $server->getGroupManager(), - $server->getUserManager(), + $userSession->getUser(), + $groupManager, + $userManager, $c->get(ActivityService::class), $c->get(VaultService::class), $c->get(ShareService::class), $c->get(CredentialService::class), $c->get(NotificationService::class), $c->get(FileService::class), - $c->get(SettingsService::class) + $c->get(SettingsService::class), + $c->get(IManager::class) ); }); @@ -101,7 +114,7 @@ class Application extends App implements IBootstrap { $context->registerService('CronService', function (ContainerInterface $c) { return new CronService( $c->get(CredentialService::class), - $c->get(ILogger::class), + $c->get(LoggerInterface::class), $c->get(Utils::class), $c->get(NotificationService::class), $c->get(ActivityService::class), @@ -115,14 +128,11 @@ class Application extends App implements IBootstrap { } public function boot(IBootContext $context): void { - $l = \OC::$server->getL10N(self::APP_ID); - /** @var IManager $manager */ $manager = $context->getAppContainer()->get(IManager::class); $manager->registerNotifierService(Notifier::class); Util::addTranslations(self::APP_ID); - \OCP\App::registerAdmin(self::APP_ID, 'templates/admin.settings'); } /** @@ -130,23 +140,20 @@ class Application extends App implements IBootstrap { */ public function registerNavigationEntry() { $c = $this->getContainer(); - $server = $c->getServer(); - $navigationEntry = function () use ($c, $server) { + /** @var INavigationManager $navigationManager */ + $navigationManager = $c->get(INavigationManager::class); + + $navigationEntry = function () use ($c) { + /** @var IURLGenerator $urlGenerator */ + $urlGenerator = $c->get(IURLGenerator::class); return [ 'id' => $c->getAppName(), 'order' => 10, - 'name' => $c->query(IL10N::class)->t('Passwords'), - 'href' => $server->getURLGenerator()->linkToRoute('passman.page.index'), - 'icon' => $server->getURLGenerator()->imagePath($c->getAppName(), 'app.svg'), + 'name' => $c->get(IL10N::class)->t('Passwords'), + 'href' => $urlGenerator->linkToRoute('passman.page.index'), + 'icon' => $urlGenerator->imagePath($c->getAppName(), 'app.svg'), ]; }; - $server->getNavigationManager()->add($navigationEntry); - } - - /** - * Register personal settings for notifications and emails - */ - public function registerPersonalPage() { - \OCP\App::registerPersonal($this->getContainer()->getAppName(), 'personal'); + $navigationManager->add($navigationEntry); } } diff --git a/lib/BackgroundJob/ExpireCredentials.php b/lib/BackgroundJob/ExpireCredentials.php index e1b06f95..a911775e 100644 --- a/lib/BackgroundJob/ExpireCredentials.php +++ b/lib/BackgroundJob/ExpireCredentials.php @@ -24,7 +24,7 @@ namespace OCA\Passman\BackgroundJob; use OC\BackgroundJob\TimedJob; -use \OCA\Passman\AppInfo\Application; +use OCA\Passman\Service\CronService; use OCP\IConfig; /** @@ -33,21 +33,23 @@ use OCP\IConfig; * @package OCA\Passman\BackgroundJob */ class ExpireCredentials extends TimedJob { - /** @var IConfig */ - protected $config; + + protected IConfig $config; + private CronService $cronService; /** + * ExpireCredentials constructor. * @param IConfig $config + * @param CronService $cronService */ - public function __construct(IConfig $config) { + public function __construct(IConfig $config, CronService $cronService) { // Run once per minute $this->setInterval(60); $this->config = $config; + $this->cronService = $cronService; } protected function run($argument) { - $app = new Application(); - $container = $app->getContainer(); - $container->query('CronService')->expireCredentials(); + $this->cronService->expireCredentials(); } } diff --git a/lib/Db/CredentialMapper.php b/lib/Db/CredentialMapper.php index 2ae6e8e3..e39146bc 100644 --- a/lib/Db/CredentialMapper.php +++ b/lib/Db/CredentialMapper.php @@ -24,14 +24,19 @@ namespace OCA\Passman\Db; use OCA\Passman\Utility\Utils; +use OCP\AppFramework\Db\DoesNotExistException; +use OCP\AppFramework\Db\Entity; +use OCP\AppFramework\Db\MultipleObjectsReturnedException; +use OCP\AppFramework\Db\QBMapper; +use OCP\DB\QueryBuilder\IQueryBuilder; use OCP\IDBConnection; -use OCP\AppFramework\Db\Mapper; -class CredentialMapper extends Mapper { - private $utils; +class CredentialMapper extends QBMapper { + const TABLE_NAME = 'passman_credentials'; + private Utils $utils; public function __construct(IDBConnection $db, Utils $utils) { - parent::__construct($db, 'passman_credentials'); + parent::__construct($db, self::TABLE_NAME); $this->utils = $utils; } @@ -39,74 +44,98 @@ class CredentialMapper extends Mapper { /** * Obtains the credentials by vault id (not guid) * - * @throws \OCP\AppFramework\Db\DoesNotExistException if not found - * @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException if more than one result - * @return Credential[] + * @param string $vault_id + * @param string $user_id + * @return Entity[] */ - public function getCredentialsByVaultId($vault_id, $user_id) { - $sql = 'SELECT * FROM `*PREFIX*passman_credentials` ' . - 'WHERE `user_id` = ? and vault_id = ?'; - return $this->findEntities($sql, [$user_id, $vault_id]); + public function getCredentialsByVaultId(string $vault_id, string $user_id) { + $qb = $this->db->getQueryBuilder(); + $qb->select('*') + ->from(self::TABLE_NAME) + ->where($qb->expr()->eq('user_id', $qb->createNamedParameter($user_id, IQueryBuilder::PARAM_STR))) + ->andWhere($qb->expr()->eq('vault_id', $qb->createNamedParameter($vault_id, IQueryBuilder::PARAM_STR))); + + return $this->findEntities($qb); } /** - * Get a random credentail from a vault + * Get a random credential from a vault * - * @param $vault_id - * @param $user_id - * @return Credential + * @param string $vault_id + * @param string $user_id + * @return Credential[] */ - public function getRandomCredentialByVaultId($vault_id, $user_id) { - $sql = 'SELECT * FROM `*PREFIX*passman_credentials` ' . - 'WHERE `user_id` = ? and vault_id = ? AND shared_key is NULL LIMIT 20'; - $entities = $this->findEntities($sql, [$user_id, $vault_id]); + public function getRandomCredentialByVaultId(string $vault_id, string $user_id) { + $qb = $this->db->getQueryBuilder(); + $qb->select('*') + ->from(self::TABLE_NAME) + ->where($qb->expr()->eq('user_id', $qb->createNamedParameter($user_id, IQueryBuilder::PARAM_STR))) + ->andWhere($qb->expr()->eq('vault_id', $qb->createNamedParameter($vault_id, IQueryBuilder::PARAM_STR))) + ->andWhere($qb->expr()->isNull('shared_key')) + ->setMaxResults(20); + + $entities = $this->findEntities($qb); $count = count($entities) - 1; - $entities = array_splice($entities, rand(0, $count), 1); - return $entities; + + /** @var Credential[] $entity */ + $entity = array_splice($entities, rand(0, $count), 1); + return $entity; } /** * Get expired credentials * - * @param $timestamp - * @return Credential[] + * @param int $timestamp + * @return Entity[] */ - public function getExpiredCredentials($timestamp) { - $sql = 'SELECT * FROM `*PREFIX*passman_credentials` ' . - 'WHERE `expire_time` > 0 AND `expire_time` < ?'; - return $this->findEntities($sql, [$timestamp]); + public function getExpiredCredentials(int $timestamp) { + $qb = $this->db->getQueryBuilder(); + $qb->select('*') + ->from(self::TABLE_NAME) + ->where($qb->expr()->gt('expire_time', $qb->createNamedParameter(0, IQueryBuilder::PARAM_INT))) + ->andWhere($qb->expr()->lt('expire_time', $qb->createNamedParameter($timestamp, IQueryBuilder::PARAM_INT))); + + return $this->findEntities($qb); } /** * Get an credential by id. * Optional user id * - * @param $credential_id - * @param null $user_id - * @return Credential + * @param int $credential_id + * @param string|null $user_id + * @return Entity + * @throws DoesNotExistException + * @throws MultipleObjectsReturnedException */ - public function getCredentialById($credential_id, $user_id = null) { - $sql = 'SELECT * FROM `*PREFIX*passman_credentials` ' . - 'WHERE `id` = ?'; - // If we want to check the owner, add it to the query - $params = [$credential_id]; + public function getCredentialById(int $credential_id, string $user_id = null) { + $qb = $this->db->getQueryBuilder(); + $qb->select('*') + ->from(self::TABLE_NAME) + ->where($qb->expr()->eq('id', $qb->createNamedParameter($credential_id, IQueryBuilder::PARAM_INT))); + if ($user_id !== null) { - $sql .= ' and `user_id` = ? '; - array_push($params, $user_id); + $qb->andWhere($qb->expr()->eq('user_id', $qb->createNamedParameter($user_id, IQueryBuilder::PARAM_STR))); } - return $this->findEntity($sql, $params); + + return $this->findEntity($qb); } /** * Get credential label by id * - * @param $credential_id - * @return Credential + * @param int $credential_id + * @return Entity + * @throws DoesNotExistException + * @throws MultipleObjectsReturnedException */ - public function getCredentialLabelById($credential_id) { - $sql = 'SELECT id, label FROM `*PREFIX*passman_credentials` ' . - 'WHERE `id` = ? '; - return $this->findEntity($sql, [$credential_id]); + public function getCredentialLabelById(int $credential_id) { + $qb = $this->db->getQueryBuilder(); + $qb->select(['id', 'label']) + ->from(self::TABLE_NAME) + ->where($qb->expr()->eq('id', $qb->createNamedParameter($credential_id, IQueryBuilder::PARAM_INT))); + + return $this->findEntity($qb); } /** @@ -130,7 +159,7 @@ class CredentialMapper extends Mapper { $credential->setUsername($raw_credential['username']); $credential->setPassword($raw_credential['password']); $credential->setUrl($raw_credential['url']); - $credential->setIcon($raw_credential['favicon']); + $credential->setIcon($raw_credential['icon']); $credential->setRenewInterval($raw_credential['renew_interval']); $credential->setExpireTime($raw_credential['expire_time']); $credential->setDeleteTime($raw_credential['delete_time']); @@ -146,13 +175,13 @@ class CredentialMapper extends Mapper { } /** - * Update a credential - * * @param $raw_credential array An array containing all the credential fields * @param $useRawUser bool - * @return Credential The updated credential + * @return Credential|Entity The updated credential + * @throws DoesNotExistException + * @throws MultipleObjectsReturnedException */ - public function updateCredential($raw_credential, $useRawUser) { + public function updateCredential($raw_credential, bool $useRawUser) { $original = $this->getCredentialByGUID($raw_credential['guid']); $uid = ($useRawUser) ? $raw_credential['user_id'] : $original->getUserId(); @@ -197,16 +226,22 @@ class CredentialMapper extends Mapper { /** * Finds a credential by the given guid * - * @param $credential_guid - * @return Credential + * @param string $credential_guid + * @param string|null $user_id + * @return Entity + * @throws DoesNotExistException + * @throws MultipleObjectsReturnedException */ - public function getCredentialByGUID($credential_guid, $user_id = null) { - $q = 'SELECT * FROM `*PREFIX*passman_credentials` WHERE guid = ? '; - $params = [$credential_guid]; + public function getCredentialByGUID(string $credential_guid, string $user_id = null) { + $qb = $this->db->getQueryBuilder(); + $qb->select('*') + ->from(self::TABLE_NAME) + ->where($qb->expr()->eq('guid', $qb->createNamedParameter($credential_guid, IQueryBuilder::PARAM_STR))); + if ($user_id !== null) { - $q .= ' and `user_id` = ? '; - array_push($params, $user_id); + $qb->andWhere($qb->expr()->eq('user_id', $qb->createNamedParameter($user_id, IQueryBuilder::PARAM_STR))); } - return $this->findEntity($q, $params); + + return $this->findEntity($qb); } -}
\ No newline at end of file +} diff --git a/lib/Db/CredentialRevisionMapper.php b/lib/Db/CredentialRevisionMapper.php index a22f5d1b..001e4374 100644 --- a/lib/Db/CredentialRevisionMapper.php +++ b/lib/Db/CredentialRevisionMapper.php @@ -24,49 +24,61 @@ namespace OCA\Passman\Db; use OCA\Passman\Utility\Utils; +use OCP\AppFramework\Db\DoesNotExistException; +use OCP\AppFramework\Db\Entity; +use OCP\AppFramework\Db\MultipleObjectsReturnedException; +use OCP\AppFramework\Db\QBMapper; +use OCP\DB\QueryBuilder\IQueryBuilder; use OCP\IDBConnection; -use OCP\AppFramework\Db\Mapper; -class CredentialRevisionMapper extends Mapper { - private $utils; +class CredentialRevisionMapper extends QBMapper { + const TABLE_NAME = 'passman_revisions'; + private Utils $utils; public function __construct(IDBConnection $db, Utils $utils) { - parent::__construct($db, 'passman_revisions'); + parent::__construct($db, self::TABLE_NAME); $this->utils = $utils; } /** * Get revisions from a credential - * @throws \OCP\AppFramework\Db\DoesNotExistException if not found - * @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException if more than one result - * @return CredentialRevision[] + * + * @param int $credential_id + * @param string|null $user_id + * @return Entity[] */ - public function getRevisions($credential_id, $user_id = null) { - $sql = 'SELECT * FROM `*PREFIX*passman_revisions` ' . - 'WHERE `credential_id` = ?'; - $params = [$credential_id]; - if ($user_id !== null) { - $sql.= ' and `user_id` = ? '; - $params[] = $user_id; - } - return $this->findEntities($sql, $params); + public function getRevisions(int $credential_id, string $user_id = null) { + $qb = $this->db->getQueryBuilder(); + $qb->select('*') + ->from(self::TABLE_NAME) + ->where($qb->expr()->eq('credential_id', $qb->createNamedParameter($credential_id, IQueryBuilder::PARAM_INT))); + + if ($user_id !== null) { + $qb->andWhere($qb->expr()->eq('user_id', $qb->createNamedParameter($user_id, IQueryBuilder::PARAM_STR))); + } + + return $this->findEntities($qb); } /** - * @throws \OCP\AppFramework\Db\DoesNotExistException if not found - * @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException if more than one result - * @return CredentialRevision + * @param int $revision_id + * @param string|null $user_id + * @return Entity + * @throws DoesNotExistException + * @throws MultipleObjectsReturnedException */ - public function getRevision($revision_id, $user_id = null) { - $sql = 'SELECT * FROM `*PREFIX*passman_revisions` ' . - 'WHERE `id` = ?'; - $params = [$revision_id]; - if ($user_id !== null) { - $sql.= ' and `user_id` = ? '; - $params[] = $user_id; - } - return $this->findEntity($sql, $params); + public function getRevision(int $revision_id, string $user_id = null) { + $qb = $this->db->getQueryBuilder(); + $qb->select('*') + ->from(self::TABLE_NAME) + ->where($qb->expr()->eq('id', $qb->createNamedParameter($revision_id, IQueryBuilder::PARAM_INT))); + + if ($user_id !== null) { + $qb->andWhere($qb->expr()->eq('user_id', $qb->createNamedParameter($user_id, IQueryBuilder::PARAM_STR))); + } + + return $this->findEntity($qb); } /** @@ -101,4 +113,4 @@ class CredentialRevisionMapper extends Mapper { $revision->setUserId($user_id); return $this->delete($revision); } -}
\ No newline at end of file +} diff --git a/lib/Db/DeleteVaultRequestMapper.php b/lib/Db/DeleteVaultRequestMapper.php index a43fe78f..585780d4 100644 --- a/lib/Db/DeleteVaultRequestMapper.php +++ b/lib/Db/DeleteVaultRequestMapper.php @@ -24,13 +24,14 @@ namespace OCA\Passman\Db; -use Icewind\SMB\Share; -use OCA\Passman\Utility\Utils; use OCP\AppFramework\Db\DoesNotExistException; -use OCP\AppFramework\Db\Mapper; +use OCP\AppFramework\Db\Entity; +use OCP\AppFramework\Db\MultipleObjectsReturnedException; +use OCP\AppFramework\Db\QBMapper; +use OCP\DB\QueryBuilder\IQueryBuilder; use OCP\IDBConnection; -class DeleteVaultRequestMapper extends Mapper { +class DeleteVaultRequestMapper extends QBMapper { const TABLE_NAME = 'passman_delete_vault_request'; public function __construct(IDBConnection $db) { @@ -40,38 +41,47 @@ class DeleteVaultRequestMapper extends Mapper { /** * Create a new enty in the db * @param DeleteVaultRequest $request - * @return \OCP\AppFramework\Db\Entity + * @return Entity */ - public function createRequest(DeleteVaultRequest $request){ + public function createRequest(DeleteVaultRequest $request) { return $this->insert($request); } /** * Get all delete requests - * @return \OCP\AppFramework\Db\Entity + * @return Entity[] */ - public function getDeleteRequests(){ - $q = "SELECT * FROM *PREFIX*" . self::TABLE_NAME; - return $this->findEntities($q); + public function getDeleteRequests() { + $qb = $this->db->getQueryBuilder(); + $qb->select('*') + ->from(self::TABLE_NAME); + + return $this->findEntities($qb); } /** - * Get request for an vault id - * @param $vault_id integer The vault id - * @return \OCP\AppFramework\Db\Entity + * Get request for a vault guid + * @param string $vault_guid + * @return Entity + * @throws DoesNotExistException + * @throws MultipleObjectsReturnedException */ - public function getDeleteRequestsForVault($vault_guid){ - $q = "SELECT * FROM *PREFIX*" . self::TABLE_NAME .' WHERE `vault_guid` = ?'; - return $this->findEntity($q, [$vault_guid]); + public function getDeleteRequestsForVault(string $vault_guid) { + $qb = $this->db->getQueryBuilder(); + $qb->select('*') + ->from(self::TABLE_NAME) + ->where($qb->expr()->eq('vault_guid', $qb->createNamedParameter($vault_guid, IQueryBuilder::PARAM_STR))); + + return $this->findEntity($qb); } /** * Deletes the given delete request - * @param DeleteVaultRequest $request Request to delete - * @return DeleteVaultRequest The deleted request + * @param DeleteVaultRequest $request Request to delete + * @return DeleteVaultRequest The deleted request */ - public function removeDeleteVaultRequest(DeleteVaultRequest $request){ + public function removeDeleteVaultRequest(DeleteVaultRequest $request) { return $this->delete($request); } -}
\ No newline at end of file +} diff --git a/lib/Db/FileMapper.php b/lib/Db/FileMapper.php index b1e044d3..eb7bb029 100644 --- a/lib/Db/FileMapper.php +++ b/lib/Db/FileMapper.php @@ -25,51 +25,61 @@ namespace OCA\Passman\Db; use OCA\Passman\Utility\Utils; +use OCP\AppFramework\Db\DoesNotExistException; +use OCP\AppFramework\Db\Entity; +use OCP\AppFramework\Db\MultipleObjectsReturnedException; +use OCP\AppFramework\Db\QBMapper; +use OCP\DB\QueryBuilder\IQueryBuilder; use OCP\IDBConnection; -use OCP\AppFramework\Db\Mapper; -class FileMapper extends Mapper { - private $utils; +class FileMapper extends QBMapper { + const TABLE_NAME = 'passman_files'; + private Utils $utils; public function __construct(IDBConnection $db, Utils $utils) { - parent::__construct($db, 'passman_files'); + parent::__construct($db, self::TABLE_NAME); $this->utils = $utils; } /** - * @param $file_id - * @param null $user_id - * @return File - * @throws \OCP\AppFramework\Db\DoesNotExistException if not found - * @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException if more than one result + * @param int $file_id + * @param string|null $user_id + * @return Entity + * @throws DoesNotExistException + * @throws MultipleObjectsReturnedException */ - public function getFile($file_id, $user_id = null) { - $sql = 'SELECT * FROM `*PREFIX*passman_files` ' . - 'WHERE `id` = ?'; - $params = [$file_id]; + public function getFile(int $file_id, string $user_id = null) { + $qb = $this->db->getQueryBuilder(); + $qb->select('*') + ->from(self::TABLE_NAME) + ->where($qb->expr()->eq('id', $qb->createNamedParameter($file_id, IQueryBuilder::PARAM_INT))); + if ($user_id !== null) { - $sql .= ' and `user_id` = ? '; - array_push($params, $user_id); + $qb->andWhere($qb->expr()->eq('user_id', $qb->createNamedParameter($user_id, IQueryBuilder::PARAM_STR))); } - return $this->findEntity($sql, $params); + + return $this->findEntity($qb); } + /** - * @param $file_id - * @param null $user_id - * @return File - * @throws \OCP\AppFramework\Db\DoesNotExistException if not found - * @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException if more than one result + * @param string $file_guid + * @param string|null $user_id + * @return Entity + * @throws DoesNotExistException + * @throws MultipleObjectsReturnedException */ - public function getFileByGuid($file_guid, $user_id = null) { - $sql = 'SELECT * FROM `*PREFIX*passman_files` ' . - 'WHERE `guid` = ?'; - $params = [$file_guid]; + public function getFileByGuid(string $file_guid, string $user_id = null) { + $qb = $this->db->getQueryBuilder(); + $qb->select('*') + ->from(self::TABLE_NAME) + ->where($qb->expr()->eq('guid', $qb->createNamedParameter($file_guid, IQueryBuilder::PARAM_STR))); + if ($user_id !== null) { - $sql .= ' and `user_id` = ? '; - array_push($params, $user_id); + $qb->andWhere($qb->expr()->eq('user_id', $qb->createNamedParameter($user_id, IQueryBuilder::PARAM_STR))); } - return $this->findEntity($sql, $params); + + return $this->findEntity($qb); } /** @@ -87,21 +97,21 @@ class FileMapper extends Mapper { $file->setFileData($file_raw['file_data']); $file->setMimetype($file_raw['mimetype']); - return $this->insert($file); } /** * Delete a file by file_id and user id - * @param $file_id - * @param $userId - * @return File + * + * @param int $file_id + * @param string $userId + * @return File|Entity */ - public function deleteFile($file_id, $userId) { + public function deleteFile(int $file_id, string $userId) { $file = new File(); $file->setId($file_id); $file->setUserId($userId); - $this->delete($file); + return $this->delete($file); } /** @@ -115,16 +125,15 @@ class FileMapper extends Mapper { /** - * @param $user_id - * @return File[] - * @throws \OCP\AppFramework\Db\DoesNotExistException if not found - * @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException if more than one result + * @param string $user_id + * @return Entity[] */ - public function getFilesFromUser($user_id) { - $sql = 'SELECT * FROM `*PREFIX*passman_files` ' . - 'WHERE `user_id` = ?'; - $params = [$user_id]; + public function getFilesFromUser(string $user_id) { + $qb = $this->db->getQueryBuilder(); + $qb->select('*') + ->from(self::TABLE_NAME) + ->where($qb->expr()->eq('user_id', $qb->createNamedParameter($user_id, IQueryBuilder::PARAM_STR))); - return $this->findEntities($sql, $params); + return $this->findEntities($qb); } -}
\ No newline at end of file +} diff --git a/lib/Db/ShareRequestMapper.php b/lib/Db/ShareRequestMapper.php index 0660be0f..a836fd2f 100644 --- a/lib/Db/ShareRequestMapper.php +++ b/lib/Db/ShareRequestMapper.php @@ -24,129 +24,182 @@ namespace OCA\Passman\Db; -use Icewind\SMB\Share; -use OCA\Passman\Utility\Utils; use OCP\AppFramework\Db\DoesNotExistException; -use OCP\AppFramework\Db\Mapper; +use OCP\AppFramework\Db\Entity; +use OCP\AppFramework\Db\MultipleObjectsReturnedException; +use OCP\AppFramework\Db\QBMapper; +use OCP\DB\Exception; +use OCP\DB\IResult; +use OCP\DB\QueryBuilder\IQueryBuilder; use OCP\IDBConnection; -class ShareRequestMapper extends Mapper { - const TABLE_NAME = 'passman_share_request'; - - public function __construct(IDBConnection $db) { - parent::__construct($db, self::TABLE_NAME); - } - - public function createRequest(ShareRequest $request){ - return $this->insert($request); - } - - /** - * Obtains a request by the given item and vault GUID pair - * @param $item_guid - * @param $target_vault_guid - * @return ShareRequest - */ - public function getRequestByItemAndVaultGuid($item_guid, $target_vault_guid){ - $q = "SELECT * FROM *PREFIX*" . self::TABLE_NAME . " WHERE item_guid = ? AND target_vault_guid = ?"; - return $this->findEntity($q, [$item_guid, $target_vault_guid]); - } - - /** - * Get shared items for the given item_guid - * @param $item_guid - * @return ShareRequest[] - */ - public function getRequestsByItemGuidGroupedByUser($item_guid){ - if (strtolower($this->db->getDatabasePlatform()->getName()) === 'mysql'){ - $this->db->executeQuery("SET sql_mode = '';"); +class ShareRequestMapper extends QBMapper { + const TABLE_NAME = 'passman_share_request'; + + public function __construct(IDBConnection $db) { + parent::__construct($db, self::TABLE_NAME); + } + + /** + * @param ShareRequest $request + * @return ShareRequest|Entity + */ + public function createRequest(ShareRequest $request) { + return $this->insert($request); + } + + /** + * Obtains a request by the given item and vault GUID pair + * + * @param string $item_guid + * @param string $target_vault_guid + * @return Entity + * @throws DoesNotExistException + * @throws MultipleObjectsReturnedException + */ + public function getRequestByItemAndVaultGuid(string $item_guid, string $target_vault_guid) { + $qb = $this->db->getQueryBuilder(); + $qb->select('*') + ->from(self::TABLE_NAME) + ->where($qb->expr()->eq('item_guid', $qb->createNamedParameter($item_guid, IQueryBuilder::PARAM_STR))) + ->andWhere($qb->expr()->eq('target_vault_guid', $qb->createNamedParameter($target_vault_guid, IQueryBuilder::PARAM_STR))); + + return $this->findEntity($qb); + } + + /** + * Get shared items for the given item_guid + * + * @param string $item_guid + * @return Entity[] + * @throws Exception + */ + public function getRequestsByItemGuidGroupedByUser(string $item_guid) { + if (strtolower($this->db->getDatabasePlatform()->getName()) === 'mysql') { + $this->db->executeQuery("SET sql_mode = '';"); } - $q = "SELECT *, target_user_id FROM *PREFIX*" . self::TABLE_NAME . " WHERE item_guid = ? GROUP BY target_user_id;"; - return $this->findEntities($q, [$item_guid]); - } - - /** - * Deletes all pending requests for the given user to the given item - * @param $item_id The item ID - * @param $target_user_id The target user - * @return \PDOStatement The result of running the db query - */ - public function cleanItemRequestsForUser($item_id, $target_user_id){ - $q = "DELETE FROM *PREFIX*" . self::TABLE_NAME . " WHERE item_id = ? AND target_user_id = ?"; - $this->execute($q, [$item_id, $target_user_id]); - return $this->execute($q, [$item_id, $target_user_id]); - } - - /** - * Obtains all pending share requests for the given user ID - * @param $user_id - * @return ShareRequest[] - */ - public function getUserPendingRequests($user_id){ - $q = "SELECT * FROM *PREFIX*". self::TABLE_NAME ." WHERE target_user_id = ?"; - return $this->findEntities($q, [$user_id]); - } - - /** - * Deletes the given share request - * @param ShareRequest $shareRequest Request to delete - * @return ShareRequest The deleted request - */ - public function deleteShareRequest(ShareRequest $shareRequest){ - return $this->delete($shareRequest); + $qb = $this->db->getQueryBuilder(); + $qb->select('*') + ->from(self::TABLE_NAME) + ->where($qb->expr()->eq('item_guid', $qb->createNamedParameter($item_guid, IQueryBuilder::PARAM_STR))) + ->groupBy('target_user_id'); + + return $this->findEntities($qb); + } + + /** + * Deletes all pending requests for the given user to the given item + * + * @param int $item_id + * @param string $target_user_id + * @return int|IResult + * @throws Exception + */ + public function cleanItemRequestsForUser(int $item_id, string $target_user_id) { + $qb = $this->db->getQueryBuilder(); + return $qb->delete(self::TABLE_NAME) + ->where($qb->expr()->eq('item_id', $qb->createNamedParameter($item_id, IQueryBuilder::PARAM_INT))) + ->andWhere($qb->expr()->eq('target_user_id', $qb->createNamedParameter($target_user_id, IQueryBuilder::PARAM_STR))) + ->execute(); + } + + /** + * Obtains all pending share requests for the given user ID + * + * @param string $user_id + * @return Entity[] + */ + public function getUserPendingRequests(string $user_id) { + $qb = $this->db->getQueryBuilder(); + $qb->select('*') + ->from(self::TABLE_NAME) + ->where($qb->expr()->eq('target_user_id', $qb->createNamedParameter($user_id, IQueryBuilder::PARAM_STR))); + + return $this->findEntities($qb); + } + + /** + * Deletes the given share request + * @param ShareRequest $shareRequest Request to delete + * @return ShareRequest The deleted request + */ + public function deleteShareRequest(ShareRequest $shareRequest) { + return $this->delete($shareRequest); } - /** - * Gets a share request by it's unique incremental id - * @param $id - * @return ShareRequest + /** + * Gets a share request by it's unique incremental id + * + * @param int $id + * @return Entity * @throws DoesNotExistException - */ - public function getShareRequestById($id){ - $q = "SELECT * FROM *PREFIX*" . self::TABLE_NAME . " WHERE id = ?"; - return $this->findEntity($q, [$id]); + * @throws MultipleObjectsReturnedException + */ + public function getShareRequestById(int $id) { + $qb = $this->db->getQueryBuilder(); + $qb->select('*') + ->from(self::TABLE_NAME) + ->where($qb->expr()->eq('id', $qb->createNamedParameter($id, IQueryBuilder::PARAM_INT))); + + return $this->findEntity($qb); } - /** - * Gets all share requests by a given item GUID - * @param $item_guid - * @return ShareRequest[] - */ - public function getShareRequestsByItemGuid($item_guid){ - $q = "SELECT * FROM *PREFIX*" . self::TABLE_NAME . " WHERE item_guid = ?"; - return $this->findEntities($q, [$item_guid]); + /** + * Gets all share requests by a given item GUID + * + * @param string $item_guid + * @return Entity[] + */ + public function getShareRequestsByItemGuid(string $item_guid) { + $qb = $this->db->getQueryBuilder(); + $qb->select('*') + ->from(self::TABLE_NAME) + ->where($qb->expr()->eq('item_guid', $qb->createNamedParameter($item_guid, IQueryBuilder::PARAM_STR))); + + return $this->findEntities($qb); } - /** - * Updates the given share request, - * @param ShareRequest $shareRequest - * @return ShareRequest - */ - public function updateShareRequest(ShareRequest $shareRequest){ + /** + * Updates the given share request, + * @param ShareRequest $shareRequest + * @return ShareRequest + */ + public function updateShareRequest(ShareRequest $shareRequest) { return $this->update($shareRequest); } - /** - * Finds pending requests sent to the given user to the given item. - * @param $item_guid - * @param $user_id - * @return ShareRequest[] - */ - public function getPendingShareRequests($item_guid, $user_id){ - $q = "SELECT * FROM *PREFIX*" . self::TABLE_NAME . " WHERE item_guid = ? and target_user_id= ?"; - return $this->findEntities($q, [$item_guid, $user_id]); + /** + * Finds pending requests sent to the given user to the given item. + * + * @param string $item_guid + * @param string $user_id + * @return Entity[] + */ + public function getPendingShareRequests(string $item_guid, string $user_id) { + $qb = $this->db->getQueryBuilder(); + $qb->select('*') + ->from(self::TABLE_NAME) + ->where($qb->expr()->eq('item_guid', $qb->createNamedParameter($item_guid, IQueryBuilder::PARAM_STR))) + ->andWhere($qb->expr()->eq('target_user_id', $qb->createNamedParameter($user_id, IQueryBuilder::PARAM_STR))); + + return $this->findEntities($qb); } - /** - * Updates all pending requests with the given permissions - * @param $item_guid The item for which to update the requests - * @param $user_id The user for which to update the requests - * @param $permissions The new permissions to apply - * @return \PDOStatement The result of the operation - */ - public function updatePendingRequestPermissions($item_guid, $user_id, $permissions){ - $q = "UPDATE *PREFIX*" . self::TABLE_NAME . " SET permissions = ? WHERE item_guid = ? AND target_user_id = ?"; - return $this->execute($q, [$permissions, $item_guid, $user_id]); - } - -}
\ No newline at end of file + /** + * Updates all pending requests with the given permissions + * + * @param string $item_guid The item for which to update the requests + * @param string $user_id The user for which to update the requests + * @param int $permissions The new permissions to apply + * @return int|IResult + * @throws Exception + */ + public function updatePendingRequestPermissions(string $item_guid, string $user_id, int $permissions) { + $qb = $this->db->getQueryBuilder(); + return $qb->update(self::TABLE_NAME) + ->set('permissions', $qb->createNamedParameter($permissions, IQueryBuilder::PARAM_INT)) + ->where($qb->expr()->eq('item_guid', $qb->createNamedParameter($item_guid, IQueryBuilder::PARAM_STR))) + ->andWhere($qb->expr()->eq('target_user_id', $qb->createNamedParameter($user_id, IQueryBuilder::PARAM_STR))) + ->execute(); + } +} diff --git a/lib/Db/SharingACLMapper.php b/lib/Db/SharingACLMapper.php index e251a0c4..f03b9d9f 100644 --- a/lib/Db/SharingACLMapper.php +++ b/lib/Db/SharingACLMapper.php @@ -24,72 +24,99 @@ namespace OCA\Passman\Db; -use OCP\AppFramework\Db\Mapper; +use OCP\AppFramework\Db\DoesNotExistException; +use OCP\AppFramework\Db\Entity; +use OCP\AppFramework\Db\MultipleObjectsReturnedException; +use OCP\AppFramework\Db\QBMapper; +use OCP\DB\QueryBuilder\IQueryBuilder; use OCP\IDBConnection; -use OCP\IUser; -use OCA\Passman\Utility\Utils; -class SharingACLMapper extends Mapper { - const TABLE_NAME = '*PREFIX*passman_sharing_acl'; +class SharingACLMapper extends QBMapper { + const TABLE_NAME = 'passman_sharing_acl'; - public function __construct(IDBConnection $db) { - parent::__construct($db, 'passman_sharing_acl'); - } + public function __construct(IDBConnection $db) { + parent::__construct($db, 'passman_sharing_acl'); + } - public function createACLEntry(SharingACL $acl){ - return $this->insert($acl); - } + /** + * @param SharingACL $acl + * @return SharingACL|Entity + */ + public function createACLEntry(SharingACL $acl) { + return $this->insert($acl); + } - /** - * Gets the currently accepted share requests from the given user for the given vault guid - * @param $user_id - * @param $vault_guid - * @return SharingACL[] - */ - public function getVaultEntries($user_id, $vault_guid) { - $q = "SELECT * FROM ". self::TABLE_NAME ." WHERE user_id = ? AND vault_guid = ?"; - return $this->findEntities($q, [$user_id, $vault_guid]); - } + /** + * Gets the currently accepted share requests from the given user for the given vault guid + * + * @param string $user_id + * @param string $vault_guid + * @return Entity[] + */ + public function getVaultEntries(string $user_id, string $vault_guid) { + $qb = $this->db->getQueryBuilder(); + $qb->select('*') + ->from(self::TABLE_NAME) + ->where($qb->expr()->eq('user_id', $qb->createNamedParameter($user_id, IQueryBuilder::PARAM_STR))) + ->andWhere($qb->expr()->eq('vault_guid', $qb->createNamedParameter($vault_guid, IQueryBuilder::PARAM_STR))); - /** - * Gets the acl for a given item guid - * @param $user_id - * @param $item_guid - * @return SharingACL - */ - public function getItemACL($user_id, $item_guid) { - $q = "SELECT * FROM " . self::TABLE_NAME . " WHERE item_guid = ? AND "; - $filter = [$item_guid]; - $q .= ($user_id === null) ? 'user_id is null' : 'user_id = ? '; - if ($user_id !== null){ - $filter[] = $user_id; - } + return $this->findEntities($qb); + } - return $this->findEntity($q, $filter); - } + /** + * Gets the acl for a given item guid + * + * @param string $user_id + * @param string $item_guid + * @return Entity + * @throws DoesNotExistException + * @throws MultipleObjectsReturnedException + */ + public function getItemACL(string $user_id, string $item_guid) { + $qb = $this->db->getQueryBuilder(); + $qb->select('*') + ->from(self::TABLE_NAME) + ->where($qb->expr()->eq('item_guid', $qb->createNamedParameter($item_guid, IQueryBuilder::PARAM_STR))); - /** - * Update the acl for a given item guid - * @param $user_id - * @param $item_guid - * @return SharingACL - */ - public function updateCredentialACL(SharingACL $sharingACL) { - return $this->update($sharingACL); - } + if ($user_id === null) { + $qb->andWhere($qb->expr()->isNull('user_id')); + } else { + $qb->andWhere($qb->expr()->eq('user_id', $qb->createNamedParameter($user_id, IQueryBuilder::PARAM_STR))); + } + + return $this->findEntity($qb); + } - /** - * Gets the currently accepted share requests from the given user for the given vault guid - * @param $user_id - * @param $vault_id - * @return SharingACL[] - */ - public function getCredentialAclList($item_guid) { - $q = "SELECT * FROM ". self::TABLE_NAME ." WHERE item_guid = ?"; - return $this->findEntities($q, [$item_guid]); - } + /** + * Update an acl + * + * @param SharingACL $sharingACL + * @return SharingACL|Entity + */ + public function updateCredentialACL(SharingACL $sharingACL) { + return $this->update($sharingACL); + } + + /** + * Gets the currently accepted share requests from the given user for the given vault guid + * + * @param string $item_guid + * @return Entity[] + */ + public function getCredentialAclList(string $item_guid) { + $qb = $this->db->getQueryBuilder(); + $qb->select('*') + ->from(self::TABLE_NAME) + ->where($qb->expr()->eq('item_guid', $qb->createNamedParameter($item_guid, IQueryBuilder::PARAM_STR))); + + return $this->findEntities($qb); + } - public function deleteShareACL(SharingACL $ACL){ - return $this->delete($ACL); + /** + * @param SharingACL $ACL + * @return SharingACL|Entity + */ + public function deleteShareACL(SharingACL $ACL) { + return $this->delete($ACL); } -}
\ No newline at end of file +} diff --git a/lib/Db/VaultMapper.php b/lib/Db/VaultMapper.php index 6844458c..37fb942c 100644 --- a/lib/Db/VaultMapper.php +++ b/lib/Db/VaultMapper.php @@ -24,61 +24,80 @@ namespace OCA\Passman\Db; use OCA\Passman\Utility\Utils; +use OCP\AppFramework\Db\DoesNotExistException; +use OCP\AppFramework\Db\Entity; +use OCP\AppFramework\Db\MultipleObjectsReturnedException; +use OCP\AppFramework\Db\QBMapper; +use OCP\DB\QueryBuilder\IQueryBuilder; use OCP\IDBConnection; -use OCP\AppFramework\Db\Mapper; -class VaultMapper extends Mapper { - private $utils; +class VaultMapper extends QBMapper { + const TABLE_NAME = 'passman_vaults'; + private Utils $utils; + public function __construct(IDBConnection $db, Utils $utils) { - parent::__construct($db, 'passman_vaults'); + parent::__construct($db, self::TABLE_NAME); $this->utils = $utils; } /** - * @throws \OCP\AppFramework\Db\DoesNotExistException if not found - * @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException if more than one result - * @return Vault[] + * @param int $vault_id + * @param string $user_id + * @return Entity[] */ - public function find($vault_id, $user_id) { - $sql = 'SELECT * FROM `*PREFIX*passman_vaults` ' . - 'WHERE `id`= ? and `user_id` = ?'; - return $this->findEntities($sql, [$vault_id, $user_id]); + public function find(int $vault_id, string $user_id) { + $qb = $this->db->getQueryBuilder(); + $qb->select('*') + ->from(self::TABLE_NAME) + ->where($qb->expr()->eq('id', $qb->createNamedParameter($vault_id, IQueryBuilder::PARAM_INT))) + ->andWhere($qb->expr()->eq('user_id', $qb->createNamedParameter($user_id, IQueryBuilder::PARAM_STR))); + + return $this->findEntities($qb); } + /** - * @throws \OCP\AppFramework\Db\DoesNotExistException if not found - * @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException if more than one result - * @return Vault + * @param string $vault_guid + * @param string $user_id + * @return Entity + * @throws DoesNotExistException + * @throws MultipleObjectsReturnedException */ - public function findByGuid($vault_guid, $user_id) { - $sql = 'SELECT * FROM `*PREFIX*passman_vaults` ' . - 'WHERE `guid`= ? and `user_id` = ?'; - return $this->findEntity($sql, [$vault_guid, $user_id]); + public function findByGuid(string $vault_guid, string $user_id) { + $qb = $this->db->getQueryBuilder(); + $qb->select('*') + ->from(self::TABLE_NAME) + ->where($qb->expr()->eq('guid', $qb->createNamedParameter($vault_guid, IQueryBuilder::PARAM_STR))) + ->andWhere($qb->expr()->eq('user_id', $qb->createNamedParameter($user_id, IQueryBuilder::PARAM_STR))); + + return $this->findEntity($qb); } /** - * @throws \OCP\AppFramework\Db\DoesNotExistException if not found - * @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException if more than one result - * @return Vault[] + * @param string $user_id + * @return Entity[] */ - public function findVaultsFromUser($userId){ - $sql = 'SELECT * FROM `*PREFIX*passman_vaults` ' . - 'WHERE `user_id` = ? '; - $params = [$userId]; - return $this->findEntities($sql, $params); + public function findVaultsFromUser(string $user_id) { + $qb = $this->db->getQueryBuilder(); + $qb->select('*') + ->from(self::TABLE_NAME) + ->where($qb->expr()->eq('user_id', $qb->createNamedParameter($user_id, IQueryBuilder::PARAM_STR))); + + return $this->findEntities($qb); } /** * Creates a vault - * @param $vault_name - * @param $userId - * @return Vault + * + * @param string $vault_name + * @param string $user_id + * @return Vault|Entity */ - public function create($vault_name, $userId){ + public function create(string $vault_name, string $user_id) { $vault = new Vault(); $vault->setName($vault_name); - $vault->setUserId($userId); + $vault->setUserId($user_id); $vault->setGuid($this->utils->GUID()); $vault->setCreated($this->utils->getTime()); $vault->setLastAccess(0); @@ -87,45 +106,52 @@ class VaultMapper extends Mapper { /** * Update last access time of a vault - * @param $vault_id - * @param $user_id + * + * @param int $vault_id + * @param string $user_id + * @return Vault|Entity */ - public function setLastAccess($vault_id, $user_id){ + public function setLastAccess(int $vault_id, string $user_id) { $vault = new Vault(); $vault->setId($vault_id); $vault->setUserId($user_id); $vault->setLastAccess(Utils::getTime()); - $this->update($vault); + return $this->update($vault); } /** * Update vault + * * @param Vault $vault + * @return Vault|Entity */ - public function updateVault(Vault $vault){ - $this->update($vault); + public function updateVault(Vault $vault) { + return $this->update($vault); } /** * Update the sharing key's - * @param $vault_id - * @param $privateKey - * @param $publicKey + * + * @param int $vault_id + * @param string $privateKey + * @param string $publicKey + * @return Vault|Entity */ - public function updateSharingKeys($vault_id, $privateKey, $publicKey){ + public function updateSharingKeys(int $vault_id, string $privateKey, string $publicKey) { $vault = new Vault(); $vault->setId($vault_id); $vault->setPrivateSharingKey($privateKey); $vault->setPublicSharingKey($publicKey); $vault->setSharingKeysGenerated($this->utils->getTime()); - $this->update($vault); + return $this->update($vault); } /** * Delete a vault + * * @param Vault $vault */ - public function deleteVault(Vault $vault){ + public function deleteVault(Vault $vault) { $this->delete($vault); } -}
\ No newline at end of file +} diff --git a/lib/Notifier.php b/lib/Notifier.php index c1a1c000..38b3a8a8 100644 --- a/lib/Notifier.php +++ b/lib/Notifier.php @@ -22,14 +22,16 @@ */ namespace OCA\Passman; + +use OCP\L10N\IFactory; use OCP\Notification\INotification; use OCP\Notification\INotifier; class Notifier implements INotifier { - protected $factory; + protected IFactory $factory; - public function __construct(\OCP\L10N\IFactory $factory) { + public function __construct(IFactory $factory) { $this->factory = $factory; } @@ -37,7 +39,7 @@ class Notifier implements INotifier { * @param INotification $notification * @param string $languageCode The code of the language that should be used to prepare the notification */ -public function prepare(INotification $notification, string $languageCode): INotification { + public function prepare(INotification $notification, string $languageCode): INotification { if ($notification->getApp() !== 'passman') { // Not my app => throw throw new \InvalidArgumentException(); @@ -50,7 +52,7 @@ public function prepare(INotification $notification, string $languageCode): INot // Deal with known subjects case 'credential_expired': $notification->setParsedSubject( - (string) $l->t('Your credential "%s" expired, click here to update the credential.', $notification->getSubjectParameters()) + (string)$l->t('Your credential "%s" expired, click here to update the credential.', $notification->getSubjectParameters()) ); // Deal with the actions for a known subject @@ -58,13 +60,13 @@ public function prepare(INotification $notification, string $languageCode): INot switch ($action->getLabel()) { case 'remind': $action->setParsedLabel( - (string) $l->t('Remind me later') + (string)$l->t('Remind me later') ); break; case 'ignore': $action->setParsedLabel( - (string) $l->t('Ignore') + (string)$l->t('Ignore') ); break; } @@ -76,7 +78,7 @@ public function prepare(INotification $notification, string $languageCode): INot case 'credential_shared': $notification->setParsedSubject( - (string) $l->t('%s shared "%s" with you. Click here to accept', $notification->getSubjectParameters()) + (string)$l->t('%s shared "%s" with you. Click here to accept', $notification->getSubjectParameters()) ); // Deal with the actions for a known subject @@ -84,7 +86,7 @@ public function prepare(INotification $notification, string $languageCode): INot switch ($action->getLabel()) { case 'decline': $action->setParsedLabel( - (string) $l->t('Decline') + (string)$l->t('Decline') ); break; } @@ -95,13 +97,13 @@ public function prepare(INotification $notification, string $languageCode): INot case 'credential_share_denied': $notification->setParsedSubject( - (string) $l->t('%s has declined your share request for "%s".', $notification->getSubjectParameters()) + (string)$l->t('%s has declined your share request for "%s".', $notification->getSubjectParameters()) ); return $notification; case 'credential_share_accepted': $notification->setParsedSubject( - (string) $l->t('%s has accepted your share request for "%s".', $notification->getSubjectParameters()) + (string)$l->t('%s has accepted your share request for "%s".', $notification->getSubjectParameters()) ); return $notification; default: @@ -118,6 +120,7 @@ public function prepare(INotification $notification, string $languageCode): INot public function getID(): string { return 'passman'; } + /** * Human readable name describing the notifier * diff --git a/lib/Search/Provider.php b/lib/Search/Provider.php index 098d9400..45c13151 100644 --- a/lib/Search/Provider.php +++ b/lib/Search/Provider.php @@ -42,10 +42,10 @@ use OCP\Search\SearchResultEntry; class Provider implements IProvider { - private $l10n; - private $urlGenerator; - private $db; - private $settings; + private IL10N $l10n; + private IURLGenerator $urlGenerator; + private IDBConnection $db; + private SettingsService $settings; public function __construct(IL10N $l10n, IURLGenerator $urlGenerator, IDBConnection $db, SettingsService $settings) { $this->l10n = $l10n; diff --git a/lib/Service/CredentialRevisionService.php b/lib/Service/CredentialRevisionService.php index 284fff74..035c4dd1 100644 --- a/lib/Service/CredentialRevisionService.php +++ b/lib/Service/CredentialRevisionService.php @@ -24,22 +24,23 @@ namespace OCA\Passman\Service; use OCA\Passman\Db\CredentialRevision; -use OCP\IConfig; -use OCP\AppFramework\Db\DoesNotExistException; - use OCA\Passman\Db\CredentialRevisionMapper; +use OCP\AppFramework\Db\DoesNotExistException; +use OCP\AppFramework\Db\Entity; +use OCP\AppFramework\Db\MultipleObjectsReturnedException; +use OCP\IConfig; class CredentialRevisionService { - private $credentialRevisionMapper; - private $encryptService; + private CredentialRevisionMapper $credentialRevisionMapper; + private EncryptService $encryptService; private $server_key; - public function __construct(CredentialRevisionMapper $credentialRevisionMapper, EncryptService $encryptService) { + public function __construct(CredentialRevisionMapper $credentialRevisionMapper, EncryptService $encryptService, IConfig $config) { $this->credentialRevisionMapper = $credentialRevisionMapper; $this->encryptService = $encryptService; - $this->server_key = \OC::$server->getConfig()->getSystemValue('passwordsalt', ''); + $this->server_key = $config->getSystemValue('passwordsalt', ''); } /** @@ -50,6 +51,7 @@ class CredentialRevisionService { * @param $credential_id * @param $edited_by * @return CredentialRevision + * @throws \Exception */ public function createRevision($credential, $userId, $credential_id, $edited_by) { $credential = $this->encryptService->encryptCredential($credential); @@ -59,11 +61,12 @@ class CredentialRevisionService { /** * Get revisions of a credential * - * @param $credential_id - * @param null $user_id - * @return CredentialRevision[] + * @param int $credential_id + * @param string|null $user_id + * @return Entity[] + * @throws \Exception */ - public function getRevisions($credential_id, $user_id = null) { + public function getRevisions(int $credential_id, string $user_id = null) { $result = $this->credentialRevisionMapper->getRevisions($credential_id, $user_id); foreach ($result as $index => $revision) { $c = json_decode(base64_decode($revision->getCredentialData()), true); @@ -74,12 +77,14 @@ class CredentialRevisionService { } /** - * - * @param $credential_id - * @param null $user_id - * @return CredentialRevision + * @param int $credential_id + * @param string|null $user_id + * @return Entity + * @throws DoesNotExistException + * @throws MultipleObjectsReturnedException + * @throws \Exception */ - public function getRevision($credential_id, $user_id = null) { + public function getRevision(int $credential_id, string $user_id = null) { $revision = $this->credentialRevisionMapper->getRevision($credential_id, $user_id); $c = json_decode(base64_decode($revision->getCredentialData()), true); $revision->setCredentialData($this->encryptService->decryptCredential($c)); @@ -89,11 +94,11 @@ class CredentialRevisionService { /** * Delete a revision * - * @param $revision_id - * @param $user_id + * @param int $revision_id + * @param string $user_id * @return CredentialRevision */ - public function deleteRevision($revision_id, $user_id) { + public function deleteRevision(int $revision_id, string $user_id) { return $this->credentialRevisionMapper->deleteRevision($revision_id, $user_id); } @@ -101,7 +106,8 @@ class CredentialRevisionService { * Update revision * * @param CredentialRevision $credentialRevision - * @return CredentialRevision + * @return CredentialRevision|Entity + * @throws \Exception */ public function updateRevision(CredentialRevision $credentialRevision) { $credential_data = $credentialRevision->getCredentialData(); @@ -110,4 +116,4 @@ class CredentialRevisionService { $credentialRevision->setCredentialData($credential_data); return $this->credentialRevisionMapper->update($credentialRevision); } -}
\ No newline at end of file +} diff --git a/lib/Service/CredentialService.php b/lib/Service/CredentialService.php index 7bd45917..6ba3b0d9 100644 --- a/lib/Service/CredentialService.php +++ b/lib/Service/CredentialService.php @@ -24,27 +24,29 @@ namespace OCA\Passman\Service; use OCA\Passman\Db\Credential; -use OCA\Passman\Db\CredentialRevision; +use OCA\Passman\Db\CredentialMapper; use OCA\Passman\Db\SharingACL; use OCA\Passman\Db\SharingACLMapper; -use OCP\IConfig; use OCP\AppFramework\Db\DoesNotExistException; - -use OCA\Passman\Db\CredentialMapper; +use OCP\AppFramework\Db\Entity; +use OCP\AppFramework\Db\MultipleObjectsReturnedException; +use OCP\IConfig; class CredentialService { - private $credentialMapper; - private $sharingACL; - private $encryptService; + private CredentialMapper $credentialMapper; + private SharingACLMapper $sharingACL; + private ShareService $shareService; + private EncryptService $encryptService; private $server_key; - public function __construct(CredentialMapper $credentialMapper, SharingACLMapper $sharingACL, EncryptService $encryptService) { + public function __construct(CredentialMapper $credentialMapper, SharingACLMapper $sharingACL, ShareService $shareService, EncryptService $encryptService, IConfig $config) { $this->credentialMapper = $credentialMapper; $this->sharingACL = $sharingACL; + $this->shareService = $shareService; $this->encryptService = $encryptService; - $this->server_key = \OC::$server->getConfig()->getSystemValue('passwordsalt', ''); + $this->server_key = $config->getSystemValue('passwordsalt', ''); } /** @@ -52,8 +54,9 @@ class CredentialService { * * @param array $credential * @return Credential + * @throws \Exception */ - public function createCredential($credential) { + public function createCredential(array $credential) { $credential = $this->encryptService->encryptCredential($credential); return $this->credentialMapper->create($credential); } @@ -61,11 +64,13 @@ class CredentialService { /** * Update credential * - * @param $credential array | Credential - * @param $useRawUser bool - * @return Credential + * @param array $credential + * @param false $useRawUser + * @return Credential|Entity + * @throws DoesNotExistException + * @throws MultipleObjectsReturnedException */ - public function updateCredential($credential, $useRawUser = false) { + public function updateCredential(array $credential, $useRawUser = false) { $credential = $this->encryptService->encryptCredential($credential); return $this->credentialMapper->updateCredential($credential, $useRawUser); } @@ -73,32 +78,36 @@ class CredentialService { /** * Update credential * - * @param $credential Credential - * @return Credential + * @param Credential $credential + * @return Credential|Entity + * @throws DoesNotExistException + * @throws MultipleObjectsReturnedException */ public function upd(Credential $credential) { $credential = $this->encryptService->encryptCredential($credential); - return $this->credentialMapper->updateCredential($credential); + return $this->credentialMapper->updateCredential($credential->jsonSerialize(), false); } /** * Delete credential * * @param Credential $credential - * @return \OCP\AppFramework\Db\Entity + * @return Entity */ public function deleteCredential(Credential $credential) { + $this->shareService->unshareCredential($credential->getGuid()); return $this->credentialMapper->deleteCredential($credential); } /** * Get credentials by vault id * - * @param $vault_id - * @param $user_id - * @return \OCA\Passman\Db\Credential[] + * @param int $vault_id + * @param string $user_id + * @return Entity[] + * @throws \Exception */ - public function getCredentialsByVaultId($vault_id, $user_id) { + public function getCredentialsByVaultId(int $vault_id, string $user_id) { $credentials = $this->credentialMapper->getCredentialsByVaultId($vault_id, $user_id); foreach ($credentials as $index => $credential) { $credentials[$index] = $this->encryptService->decryptCredential($credential); @@ -109,11 +118,11 @@ class CredentialService { /** * Get a random credential from given vault * - * @param $vault_id - * @param $user_id + * @param int $vault_id + * @param string $user_id * @return mixed */ - public function getRandomCredentialByVaultId($vault_id, $user_id) { + public function getRandomCredentialByVaultId(int $vault_id, string $user_id) { $credentials = $this->credentialMapper->getRandomCredentialByVaultId($vault_id, $user_id); foreach ($credentials as $index => $credential) { $credentials[$index] = $this->encryptService->decryptCredential($credential); @@ -124,10 +133,11 @@ class CredentialService { /** * Get expired credentials. * - * @param $timestamp - * @return \OCA\Passman\Db\Credential[] + * @param int $timestamp + * @return Entity[] + * @throws \Exception */ - public function getExpiredCredentials($timestamp) { + public function getExpiredCredentials(int $timestamp) { $credentials = $this->credentialMapper->getExpiredCredentials($timestamp); foreach ($credentials as $index => $credential) { $credentials[$index] = $this->encryptService->decryptCredential($credential); @@ -138,12 +148,13 @@ class CredentialService { /** * Get a single credential. * - * @param $credential_id - * @param $user_id - * @return Credential + * @param int $credential_id + * @param string $user_id + * @return array|Credential * @throws DoesNotExistException + * @throws MultipleObjectsReturnedException */ - public function getCredentialById($credential_id, $user_id) { + public function getCredentialById(int $credential_id, string $user_id) { $credential = $this->credentialMapper->getCredentialById($credential_id); if ($credential->getUserId() === $user_id) { return $this->encryptService->decryptCredential($credential); @@ -160,10 +171,12 @@ class CredentialService { /** * Get credential label by credential id. * - * @param $credential_id - * @return Credential + * @param int $credential_id + * @return array|Credential + * @throws DoesNotExistException + * @throws MultipleObjectsReturnedException */ - public function getCredentialLabelById($credential_id) { + public function getCredentialLabelById(int $credential_id) { $credential = $this->credentialMapper->getCredentialLabelById($credential_id); return $this->encryptService->decryptCredential($credential); } @@ -171,12 +184,14 @@ class CredentialService { /** * Get credential by guid * - * @param $credential_guid - * @param null $user_id - * @return Credential + * @param string $credential_guid + * @param string|null $user_id + * @return array|Credential + * @throws DoesNotExistException + * @throws MultipleObjectsReturnedException */ - public function getCredentialByGUID($credential_guid, $user_id = null) { + public function getCredentialByGUID(string $credential_guid, string $user_id = null) { $credential = $this->credentialMapper->getCredentialByGUID($credential_guid, $user_id); return $this->encryptService->decryptCredential($credential); } -}
\ No newline at end of file +} diff --git a/lib/Service/CronService.php b/lib/Service/CronService.php index d84deffb..84ff65f5 100644 --- a/lib/Service/CronService.php +++ b/lib/Service/CronService.php @@ -23,21 +23,23 @@ namespace OCA\Passman\Service; -use OCP\IConfig; -use OCP\AppFramework\Db\DoesNotExistException; -use OCP\ILogger; -use OCA\Passman\Utility\Utils; use OCA\Passman\Activity; +use OCA\Passman\Utility\Utils; +use OCP\DB\Exception; +use OCP\DB\QueryBuilder\IQueryBuilder; use OCP\IDBConnection; +use Psr\Log\LoggerInterface; + class CronService { - private $credentialService; - private $logger; - private $utils; - private $notificationService; - private $activityService; - private $db; - public function __construct(CredentialService $credentialService, ILogger $logger, Utils $utils, NotificationService $notificationService, ActivityService $activityService, IDBConnection $db) { + private CredentialService $credentialService; + private LoggerInterface $logger; + private Utils $utils; + private NotificationService $notificationService; + private ActivityService $activityService; + private IDBConnection $db; + + public function __construct(CredentialService $credentialService, LoggerInterface $logger, Utils $utils, NotificationService $notificationService, ActivityService $activityService, IDBConnection $db) { $this->credentialService = $credentialService; $this->logger = $logger; $this->utils = $utils; @@ -46,24 +48,29 @@ class CronService { $this->db = $db; } - public function expireCredentials() { $expired_credentials = $this->credentialService->getExpiredCredentials($this->utils->getTime()); - foreach($expired_credentials as $credential){ + foreach ($expired_credentials as $credential) { $link = ''; // @TODO create direct link to credential + $qb = $this->db->getQueryBuilder(); + $qb->select('*') + ->from('notifications') + ->where($qb->expr()->eq('object_id', $qb->createNamedParameter($credential->getId(), IQueryBuilder::PARAM_INT))) + ->andWhere($qb->expr()->eq('subject', $qb->createNamedParameter('credential_expired', IQueryBuilder::PARAM_STR))); - $sql = 'SELECT count(*) as `rows` from `*PREFIX*notifications` WHERE `subject`= \'credential_expired\' AND object_id=?'; - $id = $credential->getId(); - $result = $this->db->executeQuery($sql, array($id)); - $this->logger->debug($credential->getLabel() .' is expired, checking notifications!', array('app' => 'passman')); - $notifications = intval($result->fetch()['rows']); - if($notifications === 0) { - $this->logger->debug($credential->getLabel() .' is expired, adding notification!', array('app' => 'passman')); - $this->activityService->add( - Activity::SUBJECT_ITEM_EXPIRED, array($credential->getLabel(), $credential->getUserId()), - '', array(), - $link, $credential->getUserId(), Activity::TYPE_ITEM_EXPIRED); - $this->notificationService->credentialExpiredNotification($credential); + try { + $this->logger->debug($credential->getLabel() . ' is expired, checking notifications!', array('app' => 'passman')); + $notificationCount = $qb->execute()->rowCount(); + if ($notificationCount === 0) { + $this->logger->debug($credential->getLabel() . ' is expired, adding notification!', array('app' => 'passman')); + $this->activityService->add( + Activity::SUBJECT_ITEM_EXPIRED, array($credential->getLabel(), $credential->getUserId()), + '', array(), + $link, $credential->getUserId(), Activity::TYPE_ITEM_EXPIRED); + $this->notificationService->credentialExpiredNotification($credential); + } + } catch (Exception $exception) { + $this->logger->error('Error while creating a notification: ' . $exception->getMessage(), array('app' => 'passman')); } } } diff --git a/lib/Service/DeleteVaultRequestService.php b/lib/Service/DeleteVaultRequestService.php index 82820722..872111c5 100644 --- a/lib/Service/DeleteVaultRequestService.php +++ b/lib/Service/DeleteVaultRequestService.php @@ -25,13 +25,12 @@ namespace OCA\Passman\Service; use OCA\Passman\Db\DeleteVaultRequest; use OCA\Passman\Db\DeleteVaultRequestMapper; - -use OCP\AppFramework\Db\DoesNotExistException; +use OCP\AppFramework\Db\Entity; class DeleteVaultRequestService { - private $deleteVaultRequestMapper; + private DeleteVaultRequestMapper $deleteVaultRequestMapper; public function __construct(DeleteVaultRequestMapper $deleteVaultRequestMapper) { $this->deleteVaultRequestMapper = $deleteVaultRequestMapper; @@ -41,16 +40,16 @@ class DeleteVaultRequestService { * Create a new DeleteVaultRequest * * @param $request DeleteVaultRequest - * @return \OCA\Passman\Db\DeleteVaultRequest + * @return DeleteVaultRequest */ public function createRequest(DeleteVaultRequest $request) { return $this->deleteVaultRequestMapper->insert($request); } /** - * Create a new DeleteVaultRequest + * Create a new DeleteVaultRequest * - * @return \OCA\Passman\Db\DeleteVaultRequest[] + * @return Entity[] */ public function getDeleteRequests() { return $this->deleteVaultRequestMapper->getDeleteRequests(); @@ -59,13 +58,12 @@ class DeleteVaultRequestService { /** * Create a new DeleteVaultRequest * - * @param $vault_id integer The vault id - * @return bool | DeleteVaultRequest + * @param $vault_guid string The vault guid + * @return bool | Entity */ - public function getDeleteRequestForVault($vault_guid) { + public function getDeleteRequestForVault(string $vault_guid) { try { - $result = $this->deleteVaultRequestMapper->getDeleteRequestsForVault($vault_guid); - return $result; + return $this->deleteVaultRequestMapper->getDeleteRequestsForVault($vault_guid); } catch (\Exception $e) { return false; } @@ -75,11 +73,8 @@ class DeleteVaultRequestService { * Create a new DeleteVaultRequest * * @param $req DeleteVaultRequest - * @return bool | DeleteVaultRequest */ public function removeDeleteRequestForVault(DeleteVaultRequest $req) { $this->deleteVaultRequestMapper->removeDeleteVaultRequest($req); } - - -}
\ No newline at end of file +} diff --git a/lib/Service/EncryptService.php b/lib/Service/EncryptService.php index 64284c4f..9c4f3063 100644 --- a/lib/Service/EncryptService.php +++ b/lib/Service/EncryptService.php @@ -26,9 +26,10 @@ namespace OCA\Passman\Service; // Class copied from http://stackoverflow.com/questions/5089841/two-way-encryption-i-need-to-store-passwords-that-can-be-retrieved?answertab=votes#tab-top // Upgraded to use openssl -use Icewind\SMB\Exception\Exception; use OCA\Passman\Db\Credential; use OCA\Passman\Db\File; +use OCP\AppFramework\Db\Entity; +use OCP\IConfig; /** * A class to handle secure encryption and decryption of arbitrary data @@ -84,14 +85,14 @@ class EncryptService { protected $rounds = 100; /** - * Constructor! - * + * EncryptService constructor. * @param SettingsService $settings + * @param IConfig $config */ - public function __construct(SettingsService $settings) { + public function __construct(SettingsService $settings, IConfig $config) { $this->cipher = $settings->getAppSetting('server_side_encryption', 'aes-256-cbc'); - $password_salt = \OC::$server->getConfig()->getSystemValue('passwordsalt', ''); - $secret = \OC::$server->getConfig()->getSystemValue('secret', ''); + $password_salt = $config->getSystemValue('passwordsalt', ''); + $secret = $config->getSystemValue('secret', ''); $this->server_key = $password_salt . $secret; $this->rounds = $settings->getAppSetting('rounds_pbkdf2_stretching', 100); } @@ -279,8 +280,9 @@ class EncryptService { /** * Encrypt a credential * - * @param Credential|array $credential the credential to decrypt + * @param Credential|Entity|array $credential the credential to decrypt * @return Credential|array + * @throws \Exception */ public function decryptCredential($credential) { return $this->handleCredential($credential, EncryptService::OP_DECRYPT); @@ -342,10 +344,10 @@ class EncryptService { /** * Encrypt a file * - * @param File|array $file + * @param File|array $file * @return File|array + * @throws \Exception */ - public function encryptFile($file) { return $this->handleFile($file, EncryptService::OP_ENCRYPT); } @@ -353,10 +355,10 @@ class EncryptService { /** * Decrypt a file * - * @param File|array $file - * @return File|array + * @param File|Entity|array $file + * @return array|File + * @throws \Exception */ - public function decryptFile($file) { return $this->handleFile($file, EncryptService::OP_DECRYPT); } @@ -396,4 +398,4 @@ class EncryptService { return $file; } -}
\ No newline at end of file +} diff --git a/lib/Service/FileService.php b/lib/Service/FileService.php index 829b7927..6663797c 100644 --- a/lib/Service/FileService.php +++ b/lib/Service/FileService.php @@ -23,33 +23,38 @@ namespace OCA\Passman\Service; +use Exception; use OCA\Passman\Db\File; -use OCP\IConfig; -use OCP\AppFramework\Db\DoesNotExistException; - use OCA\Passman\Db\FileMapper; +use OCP\AppFramework\Db\DoesNotExistException; +use OCP\AppFramework\Db\Entity; +use OCP\AppFramework\Db\MultipleObjectsReturnedException; +use OCP\IConfig; class FileService { - private $fileMapper; - private $encryptService; + private FileMapper $fileMapper; + private EncryptService $encryptService; private $server_key; - public function __construct(FileMapper $fileMapper, EncryptService $encryptService) { + public function __construct(FileMapper $fileMapper, EncryptService $encryptService, IConfig $config) { $this->fileMapper = $fileMapper; $this->encryptService = $encryptService; - $this->server_key = \OC::$server->getConfig()->getSystemValue('passwordsalt', ''); + $this->server_key = $config->getSystemValue('passwordsalt', ''); } /** * Get a single file. This function also returns the file content. * - * @param $fileId - * @param null $userId - * @return \OCA\Passman\Db\File + * @param int $fileId + * @param string|null $userId + * @return array|File + * @throws DoesNotExistException + * @throws MultipleObjectsReturnedException + * @throws Exception */ - public function getFile($fileId, $userId = null) { + public function getFile(int $fileId, string $userId = null) { $file = $this->fileMapper->getFile($fileId, $userId); return $this->encryptService->decryptFile($file); } @@ -57,11 +62,14 @@ class FileService { /** * Get a single file. This function also returns the file content. * - * @param $file_guid - * @param null $userId - * @return \OCA\Passman\Db\File + * @param string $file_guid + * @param string|null $userId + * @return array|File + * @throws DoesNotExistException + * @throws MultipleObjectsReturnedException + * @throws Exception */ - public function getFileByGuid($file_guid, $userId = null) { + public function getFileByGuid(string $file_guid, string $userId = null) { $file = $this->fileMapper->getFileByGuid($file_guid, $userId); return $this->encryptService->decryptFile($file); } @@ -69,11 +77,14 @@ class FileService { /** * Upload a new file, * - * @param $file array - * @param $userId - * @return \OCA\Passman\Db\File + * @param array $file + * @param string $userId + * @return array|File + * @throws DoesNotExistException + * @throws MultipleObjectsReturnedException + * @throws Exception */ - public function createFile($file, $userId) { + public function createFile(array $file, string $userId) { $file = $this->encryptService->encryptFile($file); $file = $this->fileMapper->create($file, $userId); return $this->getFile($file->getId()); @@ -82,11 +93,11 @@ class FileService { /** * Delete file * - * @param $file_id - * @param $userId - * @return \OCA\Passman\Db\File + * @param int $file_id + * @param string $userId + * @return File|Entity */ - public function deleteFile($file_id, $userId) { + public function deleteFile(int $file_id, string $userId) { return $this->fileMapper->deleteFile($file_id, $userId); } @@ -94,9 +105,10 @@ class FileService { * Update file * * @param File $file - * @return \OCA\Passman\Db\File + * @return File + * @throws Exception */ - public function updateFile($file) { + public function updateFile(File $file) { $file = $this->encryptService->encryptFile($file); return $this->fileMapper->updateFile($file); } @@ -106,13 +118,14 @@ class FileService { * * @param string $userId * @return File[] + * @throws Exception */ - public function getFilesFromUser($userId){ + public function getFilesFromUser(string $userId) { $files = $this->fileMapper->getFilesFromUser($userId); $results = array(); - foreach ($files as $file){ + foreach ($files as $file) { array_push($results, $this->encryptService->decryptFile($file)); } return $results; } -}
\ No newline at end of file +} diff --git a/lib/Service/NotificationService.php b/lib/Service/NotificationService.php index 61b251bb..5b0d2d8d 100644 --- a/lib/Service/NotificationService.php +++ b/lib/Service/NotificationService.php @@ -23,32 +23,31 @@ namespace OCA\Passman\Service; -use OCP\IConfig; -use OCP\AppFramework\Db\DoesNotExistException; - -use OCA\Passman\Db\FileMapper; +use OCP\IURLGenerator; +use OCP\Notification\IManager; class NotificationService { - private $manager; + private IManager $manager; + private IURLGenerator $urlGenerator; - public function __construct() { - $this->manager = \OC::$server->getNotificationManager(); + public function __construct(IManager $IManager, IURLGenerator $urlGenerator) { + $this->manager = $IManager; + $this->urlGenerator = $urlGenerator; } - function credentialExpiredNotification($credential){ - $urlGenerator = \OC::$server->getURLGenerator(); - $link = $urlGenerator->getAbsoluteURL($urlGenerator->linkTo('','index.php/apps/passman/#/vault/'. $credential->getVaultId() .'/edit/'. $credential->getId())); - $api = $urlGenerator->getAbsoluteURL($urlGenerator->linkTo('', 'index.php/apps/passman')); + function credentialExpiredNotification($credential) { + $link = $this->urlGenerator->getAbsoluteURL($this->urlGenerator->linkTo('', 'index.php/apps/passman/#/vault/' . $credential->getVaultId() . '/edit/' . $credential->getId())); + $api = $this->urlGenerator->getAbsoluteURL($this->urlGenerator->linkTo('', 'index.php/apps/passman')); $notification = $this->manager->createNotification(); $remindAction = $notification->createAction(); $remindAction->setLabel('remind') - ->setLink($api. '/api/internal/notifications/remind/'. $credential->getId() , 'POST'); + ->setLink($api . '/api/internal/notifications/remind/' . $credential->getId(), 'POST'); $declineAction = $notification->createAction(); $declineAction->setLabel('ignore') - ->setLink($api . '/api/internal/notifications/read/'. $credential->getId(), 'DELETE'); + ->setLink($api . '/api/internal/notifications/read/' . $credential->getId(), 'DELETE'); $notification->setApp('passman') ->setUser($credential->getUserId()) @@ -63,15 +62,14 @@ class NotificationService { } - function credentialSharedNotification($data){ - $urlGenerator = \OC::$server->getURLGenerator(); - $link = $urlGenerator->getAbsoluteURL($urlGenerator->linkTo('','index.php/apps/passman/#/')); - $api = $urlGenerator->getAbsoluteURL($urlGenerator->linkTo('', 'index.php/apps/passman')); + function credentialSharedNotification($data) { + $link = $this->urlGenerator->getAbsoluteURL($this->urlGenerator->linkTo('', 'index.php/apps/passman/#/')); + $api = $this->urlGenerator->getAbsoluteURL($this->urlGenerator->linkTo('', 'index.php/apps/passman')); $notification = $this->manager->createNotification(); $declineAction = $notification->createAction(); $declineAction->setLabel('decline') - ->setLink($api . '/api/v2/sharing/decline/'. $data['req_id'], 'DELETE'); + ->setLink($api . '/api/v2/sharing/decline/' . $data['req_id'], 'DELETE'); $notification->setApp('passman') ->setUser($data['target_user']) @@ -85,7 +83,7 @@ class NotificationService { } - function credentialDeclinedSharedNotification($data){ + function credentialDeclinedSharedNotification($data) { $notification = $this->manager->createNotification(); $notification->setApp('passman') ->setUser($data['target_user']) @@ -96,7 +94,7 @@ class NotificationService { } - function credentialAcceptedSharedNotification($data){ + function credentialAcceptedSharedNotification($data) { $notification = $this->manager->createNotification(); $notification->setApp('passman') ->setUser($data['target_user']) @@ -106,4 +104,4 @@ class NotificationService { $this->manager->notify($notification); } -}
\ No newline at end of file +} diff --git a/lib/Service/ShareService.php b/lib/Service/ShareService.php index 8dec01db..922cb5c7 100644 --- a/lib/Service/ShareService.php +++ b/lib/Service/ShareService.php @@ -24,22 +24,26 @@ namespace OCA\Passman\Service; -use Icewind\SMB\Share; use OCA\Passman\Db\CredentialMapper; -use OCA\Passman\Db\CredentialRevision; use OCA\Passman\Db\ShareRequest; use OCA\Passman\Db\ShareRequestMapper; use OCA\Passman\Db\SharingACL; use OCA\Passman\Db\SharingACLMapper; use OCA\Passman\Utility\Utils; use OCP\AppFramework\Db\DoesNotExistException; +use OCP\AppFramework\Db\Entity; +use OCP\AppFramework\Db\MultipleObjectsReturnedException; +use OCP\DB\Exception; +use OCP\DB\IResult; +use OCP\Notification\IManager; class ShareService { - private $sharingACL; - private $shareRequest; - private $credential; - private $revisions; - private $encryptService; + private SharingACLMapper $sharingACL; + private ShareRequestMapper $shareRequest; + private CredentialMapper $credential; + private CredentialRevisionService $revisions; + private EncryptService $encryptService; + private IManager $IManager; public function __construct( @@ -47,13 +51,15 @@ class ShareService { ShareRequestMapper $shareRequest, CredentialMapper $credentials, CredentialRevisionService $revisions, - EncryptService $encryptService + EncryptService $encryptService, + IManager $IManager ) { $this->sharingACL = $sharingACL; $this->shareRequest = $shareRequest; $this->credential = $credentials; $this->revisions = $revisions; $this->encryptService = $encryptService; + $this->IManager = $IManager; } /** @@ -89,6 +95,10 @@ class ShareService { return $requests; } + /** + * @param SharingACL $acl + * @return Entity + */ public function createACLEntry(SharingACL $acl) { if ($acl->getCreated() === null) $acl->setCreated((new \DateTime())->getTimestamp()); return $this->sharingACL->createACLEntry($acl); @@ -97,11 +107,14 @@ class ShareService { /** * Applies the given share, defaults to no expire * - * @param $item_guid - * @param $target_vault_guid - * @param $final_shared_key + * @param string $item_guid + * @param string $target_vault_guid + * @param string $final_shared_key + * @throws DoesNotExistException + * @throws Exception + * @throws MultipleObjectsReturnedException */ - public function applyShare($item_guid, $target_vault_guid, $final_shared_key) { + public function applyShare(string $item_guid, string $target_vault_guid, string $final_shared_key) { $request = $this->shareRequest->getRequestByItemAndVaultGuid($item_guid, $target_vault_guid); $permissions = $request->getPermissions(); @@ -123,21 +136,23 @@ class ShareService { /** * Obtains pending requests for the given user ID * - * @param $user_id - * @return \OCA\Passman\Db\ShareRequest[] + * @param string $user_id + * @return Entity[] */ - public function getUserPendingRequests($user_id) { + public function getUserPendingRequests(string $user_id) { return $this->shareRequest->getUserPendingRequests($user_id); } /** * Get shared credentials from a user * - * @param $user_id - * @param $vault_guid - * @return \OCA\Passman\Db\SharingACL[] + * @param string $user_id + * @param string $vault_guid + * @return array + * @throws DoesNotExistException + * @throws MultipleObjectsReturnedException */ - public function getSharedItems($user_id, $vault_guid) { + public function getSharedItems(string $user_id, string $vault_guid) { $entries = $this->sharingACL->getVaultEntries($user_id, $vault_guid); $return = []; @@ -159,15 +174,24 @@ class ShareService { /** * Gets the acl for a given item guid * - * @param $user_id - * @param $item_guid - * @return SharingACL + * @param string $user_id + * @param string $item_guid + * @return Entity + * @throws DoesNotExistException + * @throws MultipleObjectsReturnedException */ - public function getACL($user_id, $item_guid) { + public function getACL(string $user_id, string $item_guid) { return $this->sharingACL->getItemACL($user_id, $item_guid); } - public function getSharedItem($user_id, $item_guid) { + /** + * @param string $user_id + * @param string $item_guid + * @return array|mixed + * @throws DoesNotExistException + * @throws MultipleObjectsReturnedException + */ + public function getSharedItem(string $user_id, string $item_guid) { $acl = $this->sharingACL->getItemACL($user_id, $item_guid); // Check if the user can read the credential, probably unnecesary, but just to be sure @@ -188,11 +212,14 @@ class ShareService { /** * Gets history from the given item checking the user's permissions to access it * - * @param $user_id - * @param $item_guid - * @return CredentialRevision[] + * @param string $user_id + * @param string $item_guid + * @return array|Entity[] + * @throws DoesNotExistException + * @throws MultipleObjectsReturnedException + * @throws \Exception */ - public function getItemHistory($user_id, $item_guid) { + public function getItemHistory(string $user_id, string $item_guid) { $acl = $this->sharingACL->getItemACL($user_id, $item_guid); if (!$acl->hasPermission(SharingACL::READ | SharingACL::HISTORY)) return []; @@ -204,7 +231,8 @@ class ShareService { * Deletes a share request by the item ID * * @param ShareRequest $request - * @return \PDOStatement + * @return int|IResult + * @throws Exception */ public function cleanItemRequestsForUser(ShareRequest $request) { return $this->shareRequest->cleanItemRequestsForUser($request->getItemId(), $request->getTargetUserId()); @@ -213,21 +241,25 @@ class ShareService { /** * Get an share request by id * - * @param $id - * @return ShareRequest + * @param int $id + * @return Entity + * @throws DoesNotExistException + * @throws MultipleObjectsReturnedException */ - public function getShareRequestById($id) { + public function getShareRequestById(int $id) { return $this->shareRequest->getShareRequestById($id); } /** * Get an share request by $item_guid and $target_vault_guid * - * @param $item_guid - * @param $target_vault_guid - * @return ShareRequest + * @param string $item_guid + * @param string $target_vault_guid + * @return Entity + * @throws DoesNotExistException + * @throws MultipleObjectsReturnedException */ - public function getRequestByGuid($item_guid, $target_vault_guid) { + public function getRequestByGuid(string $item_guid, string $target_vault_guid) { return $this->shareRequest->getRequestByItemAndVaultGuid($item_guid, $target_vault_guid); } @@ -235,41 +267,48 @@ class ShareService { * Get the access control list by item guid * * @param string $item_guid - * @return \OCA\Passman\Db\SharingACL[] + * @return Entity[] */ - public function getCredentialAclList($item_guid) { + public function getCredentialAclList(string $item_guid) { return $this->sharingACL->getCredentialAclList($item_guid); } - public function getCredentialPendingAclList($item_guid) { + /** + * @param string $item_guid + * @return Entity[] + * @throws Exception + */ + public function getCredentialPendingAclList(string $item_guid) { return $this->shareRequest->getRequestsByItemGuidGroupedByUser($item_guid); } /** * Gets the ACL on the credential for the user * - * @param $user_id - * @param $item_guid - * @return SharingACL + * @param string $user_id + * @param string $item_guid + * @return Entity + * @throws DoesNotExistException + * @throws MultipleObjectsReturnedException */ - public function getCredentialAclForUser($user_id, $item_guid) { + public function getCredentialAclForUser(string $user_id, string $item_guid) { return $this->sharingACL->getItemACL($user_id, $item_guid); } /** * Get pending share requests by guid * - * @param string $item_guid - * @return \OCA\Passman\Db\ShareRequest[] + * @param string $item_guid + * @return Entity[] */ - public function getShareRequestsByGuid($item_guid) { + public function getShareRequestsByGuid(string $item_guid) { return $this->shareRequest->getShareRequestsByItemGuid($item_guid); } /** * Get pending share requests by guid * - * @param ShareRequest $request + * @param ShareRequest $request * @return ShareRequest */ public function deleteShareRequest(ShareRequest $request) { @@ -279,8 +318,8 @@ class ShareService { /** * Delete ACL * - * @param ShareRequest $request - * @return \OCA\Passman\Db\ShareRequest[] + * @param SharingACL|Entity $ACL + * @return SharingACL|Entity */ public function deleteShareACL(SharingACL $ACL) { return $this->sharingACL->deleteShareACL($ACL); @@ -290,12 +329,16 @@ class ShareService { * Updates the given ACL entry * * @param SharingACL $sharingACL - * @return SharingACL + * @return SharingACL|Entity */ public function updateCredentialACL(SharingACL $sharingACL) { return $this->sharingACL->updateCredentialACL($sharingACL); } + /** + * @param ShareRequest $shareRequest + * @return ShareRequest + */ public function updateCredentialShareRequest(ShareRequest $shareRequest) { return $this->shareRequest->updateShareRequest($shareRequest); } @@ -304,15 +347,22 @@ class ShareService { /** * Get pending share requests by guid and uid * - * @param ShareRequest $request - * @return \OCA\Passman\Db\ShareRequest[] + * @param string $item_guid + * @param string $user_id + * @return Entity[] */ - public function getPendingShareRequestsForCredential($item_guid, $user_id) { + public function getPendingShareRequestsForCredential(string $item_guid, string $user_id) { return $this->shareRequest->getPendingShareRequests($item_guid, $user_id); } - - public function updatePendingShareRequestsForCredential($item_guid, $user_id, $permissions) { + /** + * @param string $item_guid + * @param string $user_id + * @param int $permissions + * @return int|IResult + * @throws Exception + */ + public function updatePendingShareRequestsForCredential(string $item_guid, string $user_id, int $permissions) { return $this->shareRequest->updatePendingRequestPermissions($item_guid, $user_id, $permissions); } @@ -321,8 +371,7 @@ class ShareService { * This will delete all ACL's and share requests. * @param string $item_guid */ - - public function unshareCredential($item_guid) { + public function unshareCredential(string $item_guid) { $acl_list = $this->getCredentialAclList($item_guid); $request_list = $this->getShareRequestsByGuid($item_guid); foreach ($acl_list as $ACL) { @@ -330,12 +379,11 @@ class ShareService { } foreach ($request_list as $request) { $this->deleteShareRequest($request); - $manager = \OC::$server->getNotificationManager(); - $notification = $manager->createNotification(); + $notification = $this->IManager->createNotification(); $notification->setApp('passman') ->setObject('passman_share_request', $request->getId()) ->setUser($request->getTargetUserId()); - $manager->markProcessed($notification); + $this->IManager->markProcessed($notification); } } -}
\ No newline at end of file +} diff --git a/lib/Service/VaultService.php b/lib/Service/VaultService.php index 43e3a519..4c0d5c20 100644 --- a/lib/Service/VaultService.php +++ b/lib/Service/VaultService.php @@ -24,10 +24,10 @@ namespace OCA\Passman\Service; use OCA\Passman\Db\Vault; -use OCP\IConfig; -use OCP\AppFramework\Db\DoesNotExistException; - use OCA\Passman\Db\VaultMapper; +use OCP\AppFramework\Db\DoesNotExistException; +use OCP\AppFramework\Db\Entity; +use OCP\AppFramework\Db\MultipleObjectsReturnedException; class VaultService { @@ -41,7 +41,7 @@ class VaultService { /** * Get vaults from a user. * @param $userId - * @return \OCA\Passman\Db\Vault[] + * @return Entity[] */ public function getByUser($userId) { return $this->vaultMapper->findVaultsFromUser($userId); @@ -51,29 +51,29 @@ class VaultService { * Get a single vault * @param $vault_id * @param $user_id - * @return \OCA\Passman\Db\Vault[] + * @return Entity[] */ public function getById($vault_id, $user_id) { - $vault = $this->vaultMapper->find($vault_id, $user_id); - return $vault; + return $this->vaultMapper->find($vault_id, $user_id); } /** * Get a single vault. * @param $vault_guid * @param $user_id - * @return \OCA\Passman\Db\Vault + * @return Entity + * @throws DoesNotExistException + * @throws MultipleObjectsReturnedException */ public function getByGuid($vault_guid, $user_id) { - $vault = $this->vaultMapper->findByGuid($vault_guid, $user_id); - return $vault; + return $this->vaultMapper->findByGuid($vault_guid, $user_id); } /** * Create a new vault. * @param $vault_name * @param $userId - * @return \OCA\Passman\Db\Vault + * @return Vault */ public function createVault($vault_name, $userId) { return $this->vaultMapper->create($vault_name, $userId); @@ -82,6 +82,7 @@ class VaultService { /** * Update vault * @param $vault + * @return Vault|Entity */ public function updateVault($vault) { return $this->vaultMapper->updateVault($vault); @@ -91,30 +92,34 @@ class VaultService { * Update last access time of a vault. * @param $vault_id * @param $user_id + * @return Vault|Entity */ - public function setLastAccess($vault_id, $user_id){ + public function setLastAccess($vault_id, $user_id) { return $this->vaultMapper->setLastAccess($vault_id, $user_id); } /** - * Uodate sharing keys of a vault. + * Update sharing keys of a vault. * @param $vault_id * @param $privateKey * @param $publicKey + * @return Vault|Entity */ - public function updateSharingKeys($vault_id, $privateKey, $publicKey){ + public function updateSharingKeys($vault_id, $privateKey, $publicKey) { return $this->vaultMapper->updateSharingKeys($vault_id, $privateKey, $publicKey); } /** * Delete a vault from user - * @param string $vault_guid - * @param string $user_id + * @param $vault_guid + * @param $user_id + * @throws DoesNotExistException + * @throws MultipleObjectsReturnedException */ - public function deleteVault($vault_guid, $user_id){ + public function deleteVault($vault_guid, $user_id) { $vault = $this->getByGuid($vault_guid, $user_id); - if($vault instanceof Vault) { + if ($vault instanceof Vault) { $this->vaultMapper->deleteVault($vault); } } -}
\ No newline at end of file +} diff --git a/lib/Settings/Admin.php b/lib/Settings/Admin.php new file mode 100644 index 00000000..2196dbb6 --- /dev/null +++ b/lib/Settings/Admin.php @@ -0,0 +1,115 @@ +<?php +/** + * 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/>. + * + */ + +namespace OCA\Passman\Settings; + +use GuzzleHttp\Client; +use GuzzleHttp\Exception\GuzzleException; +use OCP\App\IAppManager; +use OCP\AppFramework\Http\TemplateResponse; +use OCP\IConfig; +use OCP\IL10N; +use OCP\Settings\ISettings; + +class Admin implements ISettings { + + protected IConfig $config; + private IL10N $l; + private IAppManager $appManager; + + /** + * Admin constructor. + * @param IConfig $config + * @param IL10N $l + * @param IAppManager $appManager + */ + public function __construct(IConfig $config, IL10N $l, IAppManager $appManager) { + $this->config = $config; + $this->l = $l; + $this->appManager = $appManager; + } + + /** + * @return TemplateResponse + */ + public function getForm(): TemplateResponse { + $checkVersion = $this->config->getAppValue('passman', 'check_version', '1') === '1'; + $localVersion = $this->appManager->getAppInfo('passman')["version"]; + $githubVersion = $this->l->t('Unable to get version info'); + if ($checkVersion) { + // get latest master version + $version = false; + + $url = 'https://raw.githubusercontent.com/nextcloud/passman/dist/appinfo/info.xml'; + try { + $httpClient = new Client(); + $response = $httpClient->request('get', $url); + $xml = $response->getBody()->getContents(); + } catch (GuzzleException $e) { + $xml = false; + } + + if ($xml) { + $data = simplexml_load_string($xml); + + // libxml_disable_entity_loader is deprecated with php8, the vulnerability is disabled by default by libxml with php8 + if (\PHP_VERSION_ID < 80000) { + $loadEntities = libxml_disable_entity_loader(true); + $data = simplexml_load_string($xml); + libxml_disable_entity_loader($loadEntities); + } + + if ($data !== false) { + $version = (string)$data->version; + } else { + libxml_clear_errors(); + } + } + + if ($version !== false) { + $githubVersion = $version; + } + } + // $ciphers = openssl_get_cipher_methods(); + + return new TemplateResponse('passman', 'admin', [ + 'localVersion' => $localVersion, + 'githubVersion' => $githubVersion, + 'checkVersion' => $checkVersion, + ], 'blank'); + } + + /** + * @return string + */ + public function getSection(): string { + return 'additional'; + } + + /** + * @return int + */ + public function getPriority(): int { + return 100; + } +} diff --git a/lib/Utility/Utils.php b/lib/Utility/Utils.php index 095d6ac6..327af271 100644 --- a/lib/Utility/Utils.php +++ b/lib/Utility/Utils.php @@ -23,6 +23,8 @@ namespace OCA\Passman\Utility; +use OCP\IUserManager; + class Utils { /** * Gets the unix epoch UTC timestamp @@ -52,16 +54,21 @@ class Utils { } /** - * @param $uid + * @param string $uid + * @param IUserManager $userManager * @return string */ - public static function getNameByUid($uid){ - $um = \OC::$server->getUserManager(); - $u = $um->get($uid); + public static function getNameByUid(string $uid, IUserManager $userManager){ + $u = $userManager->get($uid); return $u->getDisplayName(); } - public static function getDirContents($dir, &$results = array()){ + /** + * @param string $dir + * @param array $results + * @return array|mixed + */ + public static function getDirContents(string $dir, &$results = array()){ $files = scandir($dir); foreach($files as $value){ @@ -75,4 +82,4 @@ class Utils { } return $results; } -}
\ No newline at end of file +} diff --git a/migration/serversideencryption.php b/migration/serversideencryption.php index 7ecc4371..a41e7c0c 100644 --- a/migration/serversideencryption.php +++ b/migration/serversideencryption.php @@ -29,10 +29,12 @@ use OCA\Passman\Service\CredentialRevisionService; use OCA\Passman\Service\CredentialService; use OCA\Passman\Service\EncryptService; use OCA\Passman\Service\FileService; +use OCP\DB\Exception; +use OCP\IConfig; use OCP\IDBConnection; -use OCP\ILogger; use OCP\Migration\IOutput; use OCP\Migration\IRepairStep; +use Psr\Log\LoggerInterface; class ServerSideEncryption implements IRepairStep { @@ -46,7 +48,7 @@ class ServerSideEncryption implements IRepairStep { /** @var string */ private $installedVersion; - /** @var ILogger */ + /** @var LoggerInterface */ private $logger; /** @var CredentialService */ @@ -58,15 +60,15 @@ class ServerSideEncryption implements IRepairStep { /** @var FileService */ private $fileService; - public function __construct(EncryptService $encryptService, IDBConnection $db, ILogger $logger, CredentialService $credentialService, CredentialRevisionService $revisionService, - FileService $fileService) { + public function __construct(EncryptService $encryptService, IDBConnection $db, LoggerInterface $logger, CredentialService $credentialService, CredentialRevisionService $revisionService, + FileService $fileService, IConfig $config) { $this->encryptService = $encryptService; $this->db = $db; $this->logger = $logger; $this->credentialService = $credentialService; $this->revisionService = $revisionService; $this->fileService = $fileService; - $this->installedVersion = \OC::$server->getConfig()->getAppValue('passman', 'installed_version'); + $this->installedVersion = $config->getAppValue('passman', 'installed_version'); } public function getName() { @@ -83,19 +85,30 @@ class ServerSideEncryption implements IRepairStep { } } - private function fetchAll($sql){ - return $this->db->executeQuery($sql)->fetchAll(); + /** + * KEEP THIS METHOD PRIVATE!!! + * + * @param string $table + * @return mixed[] + * @throws Exception + */ + private function fetchAll(string $table) { + $qb = $this->db->getQueryBuilder(); + $result = $qb->select('*') + ->from($table) + ->execute(); + return $result->fetchAll(); } private function encryptCredentials() { - $credentials = $this->fetchAll('SELECT * FROM `*PREFIX*passman_credentials`'); + $credentials = $this->fetchAll('passman_credentials'); foreach ($credentials as $credential) { $this->credentialService->updateCredential($credential); } } private function encryptRevisions() { - $revisions = $this->fetchAll('SELECT * FROM `*PREFIX*passman_revisions`'); + $revisions = $this->fetchAll('passman_revisions'); foreach ($revisions as $_revision) { $revision = new CredentialRevision(); $revision->setId($_revision['id']); @@ -110,7 +123,7 @@ class ServerSideEncryption implements IRepairStep { } private function encryptFiles() { - $files = $this->fetchAll('SELECT * FROM `*PREFIX*passman_files`'); + $files = $this->fetchAll('passman_files'); foreach ($files as $_file) { $file = new File(); $file->setId($_file['id']); diff --git a/sass/admin.scss b/sass/admin.scss index 2eae188d..b15ba68a 100644 --- a/sass/admin.scss +++ b/sass/admin.scss @@ -8,8 +8,14 @@ input[type="text"]{ width: 350px; } + .account_mover_selector { + width: 350px; + .select2-choice { + height: 34px; + } + } } #requests-table{ width: 100%; } -}
\ No newline at end of file +} diff --git a/templates/part.admin.php b/templates/admin.php index 1f583cf3..71b38e9d 100644 --- a/templates/part.admin.php +++ b/templates/admin.php @@ -1,58 +1,23 @@ <?php /** @var \OCP\IL10N $l */ /** @var array $_ */ -use \OCP\App; script('passman', 'settings-admin'); style('passman', 'admin'); style('passman', 'vendor/font-awesome/font-awesome.min'); - -$checkVersion = OC::$server->getConfig()->getAppValue('passman', 'check_version', '1') === '1'; -$AppInstance = new App(); -$localVersion = $AppInstance->getAppInfo("passman")["version"]; -$githubVersion = $l->t('Unable to get version info'); -if ($checkVersion) { - // get latest master version - $version = false; - - $url = 'https://raw.githubusercontent.com/nextcloud/passman/master/appinfo/info.xml'; - try { - $client = OC::$server->getHTTPClientService()->newClient(); - $response = $client->get($url); - $xml = $response->getBody(); - } catch (\Exception $e) { - $xml = false; - } - - if ($xml) { - $loadEntities = libxml_disable_entity_loader(true); - $data = @simplexml_load_string($xml); - libxml_disable_entity_loader($loadEntities); - if ($data !== false) { - $version = (string)$data->version; - } else { - libxml_clear_errors(); - } - } - - if ($version !== false) { - $githubVersion = $version; - } -} -$ciphers = openssl_get_cipher_methods(); ?> <div id="passwordSharingSettings" class="followup section"> <h2><?php p($l->t('Passman Settings')); ?></h2> <?php - if ($checkVersion) { - p($l->t('GitHub version:') . ' ' . $githubVersion); + if ($_['checkVersion']) { + p($l->t('GitHub version:') . ' ' . $_['githubVersion']); print '<br />'; } ?> - Local version: <?php p($localVersion); ?><br/> + Local version: <?php p($_['localVersion']); ?><br/> <?php - if ($checkVersion && version_compare($githubVersion, $localVersion) === 1) { + if ($_['checkVersion'] && version_compare($_['githubVersion'], $_['localVersion']) === 1) { p($l->t('A newer version of Passman is available')); } ?> @@ -158,15 +123,16 @@ $ciphers = openssl_get_cipher_methods(); <table class="table"> <tr> <td><?php p($l->t('Source account')); ?> </td> - <td><input class="username-autocomplete" type="text" id="source_account" name="source_account"></td> + <td><input type="hidden" class="form-control account_mover_selector" id="source_account"></td> </tr> <tr> <td><?php p($l->t('Destination account')); ?> </td> - <td><input class="username-autocomplete" type="text" id="destination_account" name="destination_account"></td> + <td><input type="hidden" class="form-control account_mover_selector" id="destination_account"></td> </tr> </table> <button class="success" id="move_credentials">Move</button> - <span id="moveStatus" style="display: none;"><?php p($l->t('Credentials moved!')); ?></span> + <span id="moveStatusSucceeded" style="display: none;"><?php p($l->t('Credentials moved!')); ?></span> + <span id="moveStatusFailed" style="display: none;"><?php p($l->t('An error occurred!')); ?></span> </div> <div id="tabs-3"> diff --git a/templates/admin.settings.php b/templates/admin.settings.php deleted file mode 100644 index b5280153..00000000 --- a/templates/admin.settings.php +++ /dev/null @@ -1,4 +0,0 @@ -<?php -namespace OCA\Passman; -$tmpl = new \OCP\Template('passman', 'part.admin'); -return $tmpl->fetchPage();
\ No newline at end of file diff --git a/templates/main.php b/templates/main.php index 4bc649a3..7300e4c1 100644 --- a/templates/main.php +++ b/templates/main.php @@ -51,6 +51,7 @@ script('passman', 'app/filters/range'); script('passman', 'app/filters/propsfilter'); script('passman', 'app/filters/byte'); script('passman', 'app/filters/tagfilter'); +script('passman', 'app/filters/escapeHTML'); script('passman', 'app/filters/as'); script('passman', 'app/filters/credentialsearch'); script('passman', 'app/filters/toHHMMSS'); diff --git a/templates/views/partials/icon-picker.html b/templates/views/partials/icon-picker.html index 318c0fe4..6373a1df 100644 --- a/templates/views/partials/icon-picker.html +++ b/templates/views/partials/icon-picker.html @@ -1,4 +1,4 @@ -<div class="cell icon-category-auth" ng-if="!credential.url && !credential.icon"></div> +<div class="cell fa fa-lock" ng-if="!credential.url && !credential.icon"></div> <div class="cell" ng-if="credential.url || credential.icon"> <span class="icon"> diff --git a/templates/views/show_vault.html b/templates/views/show_vault.html index 9b5893e2..75c97869 100644 --- a/templates/views/show_vault.html +++ b/templates/views/show_vault.html @@ -145,11 +145,11 @@ <span class="close icon-close" ng-click="closeSelected()" alt="Close"></span> <div class="sidebar"> - <span class="icon sidebar-icon" ng-if="selectedCredential.url || credential.icon"> + <span class="icon sidebar-icon" ng-if="selectedCredential.url || selectedCredential.icon"> <credential-icon credential="selectedCredential"></credential-icon> </span> - <span class="icon sidebar-icon" ng-if="!selectedCredential.url && !credential.icon"> - <credential-icon credential="selectedCredential"></credential-icon> + <span class="icon sidebar-icon" ng-if="!selectedCredential.url && !selectedCredential.icon"> + <i class="fa fa-lock fa-3x icon-image"></i> </span> <h2 class="sidebar-label">{{selectedCredential.label}}</h2> </div> |