chore(files_sharing): refactor mail handling

Signed-off-by: skjnldsv <skjnldsv@protonmail.com>
This commit is contained in:
skjnldsv 2024-07-05 14:02:53 +02:00 committed by John Molakvoæ
parent d388370c3b
commit c253112cf7
3 changed files with 88 additions and 40 deletions

View file

@ -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'));
}

View file

@ -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() !== '') {

View file

@ -1384,36 +1384,34 @@ class DefaultShareProvider implements IShareProviderWithNotification {
public function sendMailNotification(IShare $share): true {
try {
// 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;
}
$this->logger->debug('Share notification not sent to ' . $share->getSharedWith() . ' because email address is not set.', ['app' => 'share']);
return false;
}
// 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 link shares
if ($share->getShareType() === IShare::TYPE_LINK) {
// Handle user shares
if ($share->getShareType() === IShare::TYPE_USER) {
// 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;
}
$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) {