From c6a5c07041d2e5d20771409aede8b755d28372ac Mon Sep 17 00:00:00 2001 From: Cyrille Bollu Date: Sat, 5 Feb 2022 20:49:17 +0100 Subject: Adds a "Request password" button to the public share authentication page for shares of type TYPE_EMAIL, when the "video verification" checkbox isn't checked. Users accessing non-anonymous public shares (TYPE_EMAIL shares) can now request a temporary password themselves. - Creates a migration step for the files_sharing app to add the 'password_expiration_time' attribute to the oc_shares table. - Makes share temporary passwords' expiration time configurable via a system value. - Adds a system config value to allow permanent share passwords -Fixes a typo in a comment in apps/files_sharing/src/components/SharingEntryLink.vue See https://github.com/nextcloud/server/issues/31005 Signed-off-by: Cyrille Bollu --- lib/private/Share20/Manager.php | 6 +++ lib/private/Share20/ProviderFactory.php | 1 + lib/private/Share20/Share.php | 16 ++++++++ .../AppFramework/AuthPublicShareController.php | 47 ++++++++++++++++++++-- lib/public/Share/IShare.php | 13 ++++++ 5 files changed, 80 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/private/Share20/Manager.php b/lib/private/Share20/Manager.php index 3fca9e3fe14..4e87c37fedb 100644 --- a/lib/private/Share20/Manager.php +++ b/lib/private/Share20/Manager.php @@ -1552,6 +1552,12 @@ class Manager implements IManager { return false; } + // Makes sure password hasn't expired + $expirationTime = $share->getPasswordExpirationTime(); + if ($expirationTime !== null && $expirationTime < new \DateTime()) { + return false; + } + $newHash = ''; if (!$this->hasher->verify($password, $share->getPassword(), $newHash)) { return false; diff --git a/lib/private/Share20/ProviderFactory.php b/lib/private/Share20/ProviderFactory.php index 42677d6bcf7..434c0017d21 100644 --- a/lib/private/Share20/ProviderFactory.php +++ b/lib/private/Share20/ProviderFactory.php @@ -185,6 +185,7 @@ class ProviderFactory implements IProviderFactory { $settingsManager = new SettingsManager($this->serverContainer->getConfig()); $this->shareByMailProvider = new ShareByMailProvider( + $this->serverContainer->getConfig(), $this->serverContainer->getDatabaseConnection(), $this->serverContainer->getSecureRandom(), $this->serverContainer->getUserManager(), diff --git a/lib/private/Share20/Share.php b/lib/private/Share20/Share.php index f1df71b1143..7ed03832e4c 100644 --- a/lib/private/Share20/Share.php +++ b/lib/private/Share20/Share.php @@ -73,6 +73,7 @@ class Share implements IShare { private $expireDate; /** @var string */ private $password; + private ?\DateTimeInterface $passwordExpirationTime = null; /** @var bool */ private $sendPasswordByTalk = false; /** @var string */ @@ -461,6 +462,21 @@ class Share implements IShare { return $this->password; } + /** + * @inheritdoc + */ + public function setPasswordExpirationTime(?\DateTimeInterface $passwordExpirationTime = null): IShare { + $this->passwordExpirationTime = $passwordExpirationTime; + return $this; + } + + /** + * @inheritdoc + */ + public function getPasswordExpirationTime(): ?\DateTimeInterface { + return $this->passwordExpirationTime; + } + /** * @inheritdoc */ diff --git a/lib/public/AppFramework/AuthPublicShareController.php b/lib/public/AppFramework/AuthPublicShareController.php index 33adf7b5fe4..bd0e32f566d 100644 --- a/lib/public/AppFramework/AuthPublicShareController.php +++ b/lib/public/AppFramework/AuthPublicShareController.php @@ -84,12 +84,40 @@ abstract class AuthPublicShareController extends PublicShareController { return new TemplateResponse('core', 'publicshareauth', ['wrongpw' => true], 'guest'); } + /** + * The template to show after user identification + * + * @since 24.0.0 + */ + protected function showIdentificationResult(bool $success): TemplateResponse { + return new TemplateResponse('core', 'publicshareauth', ['identityOk' => $success], 'guest'); + } + + /** + * Validates that the provided identity is allowed to receive a temporary password + * + * @since 24.0.0 + */ + protected function validateIdentity(?string $identityToken = null): bool { + return false; + } + + /** + * Generates a password + * + * @since 24.0.0 + */ + protected function generatePassword(): void { + } + /** * Verify the password * - * @since 14.0.0 + * @since 24.0.0 */ - abstract protected function verifyPassword(string $password): bool; + protected function verifyPassword(string $password): bool { + return false; + } /** * Function called after failed authentication @@ -120,12 +148,25 @@ abstract class AuthPublicShareController extends PublicShareController { * * @since 14.0.0 */ - final public function authenticate(string $password = '') { + final public function authenticate(string $password = '', string $passwordRequest = 'no', string $identityToken = '') { // Already authenticated if ($this->isAuthenticated()) { return $this->getRedirect(); } + // Is user requesting a temporary password? + if ($passwordRequest == '') { + if ($this->validateIdentity($identityToken)) { + $this->generatePassword(); + $response = $this->showIdentificationResult(true); + return $response; + } else { + $response = $this->showIdentificationResult(false); + $response->throttle(); + return $response; + } + } + if (!$this->verifyPassword($password)) { $this->authFailed(); $response = $this->showAuthFailed(); diff --git a/lib/public/Share/IShare.php b/lib/public/Share/IShare.php index 8ff3f5f0394..1d3cf9bbbdf 100644 --- a/lib/public/Share/IShare.php +++ b/lib/public/Share/IShare.php @@ -448,6 +448,19 @@ interface IShare { */ public function getPassword(); + /** + * Set the password's expiration time of this share. + * + * @return self The modified object + * @since 24.0.0 + */ + public function setPasswordExpirationTime(?\DateTimeInterface $passwordExpirationTime = null): IShare; + + /** + * Get the password's expiration time of this share. + * @since 24.0.0 + */ + public function getPasswordExpirationTime(): ?\DateTimeInterface; /** * Set if the recipient can start a conversation with the owner to get the -- cgit v1.2.3