aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorskjnldsv <skjnldsv@protonmail.com>2024-07-05 14:02:53 +0200
committerJohn Molakvoæ <skjnldsv@users.noreply.github.com>2024-07-12 20:14:30 +0200
commitc253112cf77411ee374ea29a9566cdd28d3e544d (patch)
treee78bde64bbe1746105bb244141036d745ac31971
parentd388370c3b4bd50d1ad7668aef9000bd54a8c442 (diff)
downloadnextcloud-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.php33
-rw-r--r--apps/sharebymail/lib/ShareByMailProvider.php45
-rw-r--r--lib/private/Share20/DefaultShareProvider.php46
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) {