diff options
author | skjnldsv <skjnldsv@protonmail.com> | 2024-07-05 14:02:53 +0200 |
---|---|---|
committer | John Molakvoæ <skjnldsv@users.noreply.github.com> | 2024-07-12 20:14:30 +0200 |
commit | c253112cf77411ee374ea29a9566cdd28d3e544d (patch) | |
tree | e78bde64bbe1746105bb244141036d745ac31971 | |
parent | d388370c3b4bd50d1ad7668aef9000bd54a8c442 (diff) | |
download | nextcloud-server-c253112cf77411ee374ea29a9566cdd28d3e544d.tar.gz nextcloud-server-c253112cf77411ee374ea29a9566cdd28d3e544d.zip |
chore(files_sharing): refactor mail handling
Signed-off-by: skjnldsv <skjnldsv@protonmail.com>
-rw-r--r-- | apps/files_sharing/lib/Controller/ShareAPIController.php | 33 | ||||
-rw-r--r-- | apps/sharebymail/lib/ShareByMailProvider.php | 45 | ||||
-rw-r--r-- | lib/private/Share20/DefaultShareProvider.php | 46 |
3 files changed, 86 insertions, 38 deletions
diff --git a/apps/files_sharing/lib/Controller/ShareAPIController.php b/apps/files_sharing/lib/Controller/ShareAPIController.php index 5e7e2b9c872..72ebd39ea07 100644 --- a/apps/files_sharing/lib/Controller/ShareAPIController.php +++ b/apps/files_sharing/lib/Controller/ShareAPIController.php @@ -2040,18 +2040,49 @@ class ShareAPIController extends OCSController { */ #[NoAdminRequired] #[BruteForceProtection(action: 'sendShareEmail')] - public function sendShareEmail(string $id, $emails = []) { + public function sendShareEmail(string $id, $password = '') { try { $share = $this->getShareById($id); + if (!$this->canAccessShare($share, false)) { + throw new OCSNotFoundException($this->l->t('Wrong share ID, share does not exist')); + } + + if (!$this->canEditShare($share)) { + throw new OCSForbiddenException('You are not allowed to send mail notifications'); + } + + // For mail and link shares, the user must be + // the owner of the share, not only the file owner. + if ($share->getShareType() === IShare::TYPE_EMAIL + || $share->getShareType() === IShare::TYPE_LINK){ + if ($share->getSharedBy() !== $this->currentUser) { + throw new OCSForbiddenException('You are not allowed to send mail notifications'); + } + } + try { $provider = $this->factory->getProviderForType($share->getShareType()); if (!($provider instanceof IShareProviderWithNotification)) { throw new OCSBadRequestException($this->l->t('No mail notification configured for this share type')); } + // Circumvent the password encrypted data by + // setting the password clear. We're not storing + // the password clear, it is just a temporary + // object manipulation. The password will stay + // encrypted in the database. + if ($share->getPassword() && $share->getPassword() !== $password) { + if (!$this->shareManager->checkPassword($share, $password)) { + throw new OCSBadRequestException($this->l->t('Wrong password')); + } + $share = $share->setPassword($password); + } + $provider->sendMailNotification($share); return new JSONResponse(['message' => 'ok']); + } catch(OCSBadRequestException $e) { + throw $e; } catch (Exception $e) { throw new OCSException($this->l->t('Error while sending mail notification')); } diff --git a/apps/sharebymail/lib/ShareByMailProvider.php b/apps/sharebymail/lib/ShareByMailProvider.php index 3ff4f3db82e..63f80f5db5f 100644 --- a/apps/sharebymail/lib/ShareByMailProvider.php +++ b/apps/sharebymail/lib/ShareByMailProvider.php @@ -101,18 +101,12 @@ class ShareByMailProvider implements IShareProviderWithNotification { $shareId = $this->createMailShare($share); - // Sends share password to receiver when it's a permanent one (otherwise she will have to request it via the showShare UI) - // or to owner when the password shall be given during a Talk session - if ($this->config->getSystemValue('sharing.enable_mail_link_password_expiration', false) === false || $share->getSendPasswordByTalk()) { - $send = $this->sendPassword($share, $password); - if ($passwordEnforced && $send === false) { - $this->sendPasswordToOwner($share, $password); - } - } - $this->createShareActivity($share); $data = $this->getRawShare($shareId); + // Temporary set the clear password again to send it by mail + $data['password'] = $password; + return $this->createShareObject($data); } @@ -260,6 +254,21 @@ class ShareByMailProvider implements IShareProviderWithNotification { $share->getExpirationDate(), $share->getNote() ); + + // If we have a password set, we send it to the recipient + if ($share->getPassword()) { + // Sends share password to receiver when it's a permanent one (otherwise she will have to request it via the showShare UI) + // or to owner when the password shall be given during a Talk session + $passwordExpire = $this->config->getSystemValue('sharing.enable_mail_link_password_expiration', false); + $passwordEnforced = $this->shareManager->shareApiLinkEnforcePassword(); + if ($passwordExpire === false || $share->getSendPasswordByTalk()) { + $send = $this->sendPassword($share, $share->getPassword()); + if ($passwordEnforced && $send === false) { + $this->sendPasswordToOwner($share, $share->getPassword()); + } + } + } + return true; } catch (HintException $hintException) { $this->logger->error('Failed to send share by mail.', [ @@ -289,7 +298,7 @@ class ShareByMailProvider implements IShareProviderWithNotification { * @param string $note note * @throws \Exception If mail couldn't be sent */ - public function sendEmail( + protected function sendEmail( string $filename, string $link, string $initiator, @@ -318,6 +327,7 @@ class ShareByMailProvider implements IShareProviderWithNotification { if ($note !== '') { $emailTemplate->addBodyText(htmlspecialchars($note), $note); } + $emailTemplate->addBodyText( htmlspecialchars($text . ' ' . $this->l->t('Click the button below to open it.')), $text @@ -354,13 +364,21 @@ class ShareByMailProvider implements IShareProviderWithNotification { } $message->useTemplate($emailTemplate); - $this->mailer->send($message); + $failedRecipients = $this->mailer->send($message); + if (!empty($failedRecipients)) { + $this->logger->error('Share notification mail could not be sent to: ' . implode(', ', $failedRecipients)); + return; + } } /** - * send password to recipient of a mail share + * Send password to recipient of a mail share + * Will return false if + * 1. the password is empty + * 2. the setting to send the password by mail is disabled + * 3. the share is set to send the password by talk */ - public function sendPassword(IShare $share, string $password): bool { + protected function sendPassword(IShare $share, string $password): bool { $filename = $share->getNode()->getName(); $initiator = $share->getSharedBy(); $shareWith = $share->getSharedWith(); @@ -660,6 +678,7 @@ class ShareByMailProvider implements IShareProviderWithNotification { ->set('expiration', $qb->createNamedParameter($share->getExpirationDate(), IQueryBuilder::PARAM_DATE)) ->set('note', $qb->createNamedParameter($share->getNote())) ->set('hide_download', $qb->createNamedParameter((int)$share->getHideDownload(), IQueryBuilder::PARAM_INT)) + ->set('mail_send', $qb->createNamedParameter(1)) ->executeStatement(); if ($originalShare->getNote() !== $share->getNote() && $share->getNote() !== '') { diff --git a/lib/private/Share20/DefaultShareProvider.php b/lib/private/Share20/DefaultShareProvider.php index 1d529a65626..875c2a85188 100644 --- a/lib/private/Share20/DefaultShareProvider.php +++ b/lib/private/Share20/DefaultShareProvider.php @@ -1384,36 +1384,34 @@ class DefaultShareProvider implements IShareProviderWithNotification { public function sendMailNotification(IShare $share): true { try { + // Check user + $user = $this->userManager->get($share->getSharedWith()); + if ($user === null) { + $this->logger->debug('Share notification not sent to ' . $share->getSharedWith() . ' because user could not be found.', ['app' => 'share']); + return false; + } + // Handle user shares if ($share->getShareType() === IShare::TYPE_USER) { - $user = $this->userManager->get($share->getSharedWith()); - if ($user !== null) { - $emailAddress = $user->getEMailAddress(); - if ($emailAddress !== null && $emailAddress !== '') { - $userLang = $this->l10nFactory->getUserLanguage($user); - $l = $this->l10nFactory->get('lib', $userLang); - $this->sendUserShareMail( - $l, - $share->getNode()->getName(), - $this->urlGenerator->linkToRouteAbsolute('files_sharing.Accept.accept', ['shareId' => $share->getFullId()]), - $share->getSharedBy(), - $emailAddress, - $share->getExpirationDate(), - $share->getNote() - ); - $this->logger->debug('Sent share notification to ' . $emailAddress . ' for share with ID ' . $share->getId() . '.', ['app' => 'share']); - return true; - - } + // Check email address + $emailAddress = $user->getEMailAddress(); + if ($emailAddress === null || $emailAddress === '') { $this->logger->debug('Share notification not sent to ' . $share->getSharedWith() . ' because email address is not set.', ['app' => 'share']); return false; } - $this->logger->debug('Share notification not sent to ' . $share->getSharedWith() . ' because user could not be found.', ['app' => 'share']); - return false; - } - // Handle link shares - if ($share->getShareType() === IShare::TYPE_LINK) { + $userLang = $this->l10nFactory->getUserLanguage($user); + $l = $this->l10nFactory->get('lib', $userLang); + $this->sendUserShareMail( + $l, + $share->getNode()->getName(), + $this->urlGenerator->linkToRouteAbsolute('files_sharing.Accept.accept', ['shareId' => $share->getFullId()]), + $share->getSharedBy(), + $emailAddress, + $share->getExpirationDate(), + $share->getNote() + ); + $this->logger->debug('Sent share notification to ' . $emailAddress . ' for share with ID ' . $share->getId() . '.', ['app' => 'share']); return true; } } catch (\Exception $e) { |