ShareByMailProvider.php 39 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258
  1. <?php
  2. /**
  3. * @copyright Copyright (c) 2016 Bjoern Schiessle <bjoern@schiessle.org>
  4. *
  5. * @author Arthur Schiwon <blizzz@arthur-schiwon.de>
  6. * @author Bjoern Schiessle <bjoern@schiessle.org>
  7. * @author Christoph Wurst <christoph@winzerhof-wurst.at>
  8. * @author comradekingu <epost@anotheragency.no>
  9. * @author Daniel Calviño Sánchez <danxuliu@gmail.com>
  10. * @author Daniel Kesselberg <mail@danielkesselberg.de>
  11. * @author exner104 <59639860+exner104@users.noreply.github.com>
  12. * @author Frederic Werner <frederic-github@werner-net.work>
  13. * @author Joas Schilling <coding@schilljs.com>
  14. * @author John Molakvoæ <skjnldsv@protonmail.com>
  15. * @author Lukas Reschke <lukas@statuscode.ch>
  16. * @author Morris Jobke <hey@morrisjobke.de>
  17. * @author Nicolas SIMIDE <2083596+dems54@users.noreply.github.com>
  18. * @author Robin Appelman <robin@icewind.nl>
  19. * @author robottod <83244577+robottod@users.noreply.github.com>
  20. * @author Roeland Jago Douma <roeland@famdouma.nl>
  21. * @author rubo77 <github@r.z11.de>
  22. * @author Stephan Müller <mail@stephanmueller.eu>
  23. * @author Valdnet <47037905+Valdnet@users.noreply.github.com>
  24. *
  25. * @license GNU AGPL version 3 or any later version
  26. *
  27. * This program is free software: you can redistribute it and/or modify
  28. * it under the terms of the GNU Affero General Public License as
  29. * published by the Free Software Foundation, either version 3 of the
  30. * License, or (at your option) any later version.
  31. *
  32. * This program is distributed in the hope that it will be useful,
  33. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  34. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  35. * GNU Affero General Public License for more details.
  36. *
  37. * You should have received a copy of the GNU Affero General Public License
  38. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  39. *
  40. */
  41. namespace OCA\ShareByMail;
  42. use OC\Share20\Exception\InvalidShare;
  43. use OC\Share20\Share;
  44. use OC\User\NoUserException;
  45. use OCA\ShareByMail\Settings\SettingsManager;
  46. use OCP\Activity\IManager;
  47. use OCP\DB\QueryBuilder\IQueryBuilder;
  48. use OCP\Defaults;
  49. use OCP\EventDispatcher\IEventDispatcher;
  50. use OCP\Files\Folder;
  51. use OCP\Files\IRootFolder;
  52. use OCP\Files\Node;
  53. use OCP\HintException;
  54. use OCP\IConfig;
  55. use OCP\IDBConnection;
  56. use OCP\IL10N;
  57. use OCP\ILogger;
  58. use OCP\IURLGenerator;
  59. use OCP\IUser;
  60. use OCP\IUserManager;
  61. use OCP\Mail\IMailer;
  62. use OCP\Security\Events\GenerateSecurePasswordEvent;
  63. use OCP\Security\IHasher;
  64. use OCP\Security\ISecureRandom;
  65. use OCP\Share\Exceptions\GenericShareException;
  66. use OCP\Share\Exceptions\ShareNotFound;
  67. use OCP\Share\IManager as IShareManager;
  68. use OCP\Share\IShare;
  69. use OCP\Share\IShareProvider;
  70. /**
  71. * Class ShareByMail
  72. *
  73. * @package OCA\ShareByMail
  74. */
  75. class ShareByMailProvider implements IShareProvider {
  76. private IConfig $config;
  77. /** @var IDBConnection */
  78. private $dbConnection;
  79. /** @var ILogger */
  80. private $logger;
  81. /** @var ISecureRandom */
  82. private $secureRandom;
  83. /** @var IUserManager */
  84. private $userManager;
  85. /** @var IRootFolder */
  86. private $rootFolder;
  87. /** @var IL10N */
  88. private $l;
  89. /** @var IMailer */
  90. private $mailer;
  91. /** @var IURLGenerator */
  92. private $urlGenerator;
  93. /** @var IManager */
  94. private $activityManager;
  95. /** @var SettingsManager */
  96. private $settingsManager;
  97. /** @var Defaults */
  98. private $defaults;
  99. /** @var IHasher */
  100. private $hasher;
  101. /** @var IEventDispatcher */
  102. private $eventDispatcher;
  103. /** @var IShareManager */
  104. private $shareManager;
  105. /**
  106. * Return the identifier of this provider.
  107. *
  108. * @return string Containing only [a-zA-Z0-9]
  109. */
  110. public function identifier() {
  111. return 'ocMailShare';
  112. }
  113. public function __construct(IConfig $config,
  114. IDBConnection $connection,
  115. ISecureRandom $secureRandom,
  116. IUserManager $userManager,
  117. IRootFolder $rootFolder,
  118. IL10N $l,
  119. ILogger $logger,
  120. IMailer $mailer,
  121. IURLGenerator $urlGenerator,
  122. IManager $activityManager,
  123. SettingsManager $settingsManager,
  124. Defaults $defaults,
  125. IHasher $hasher,
  126. IEventDispatcher $eventDispatcher,
  127. IShareManager $shareManager) {
  128. $this->config = $config;
  129. $this->dbConnection = $connection;
  130. $this->secureRandom = $secureRandom;
  131. $this->userManager = $userManager;
  132. $this->rootFolder = $rootFolder;
  133. $this->l = $l;
  134. $this->logger = $logger;
  135. $this->mailer = $mailer;
  136. $this->urlGenerator = $urlGenerator;
  137. $this->activityManager = $activityManager;
  138. $this->settingsManager = $settingsManager;
  139. $this->defaults = $defaults;
  140. $this->hasher = $hasher;
  141. $this->eventDispatcher = $eventDispatcher;
  142. $this->shareManager = $shareManager;
  143. }
  144. /**
  145. * Share a path
  146. *
  147. * @param IShare $share
  148. * @return IShare The share object
  149. * @throws ShareNotFound
  150. * @throws \Exception
  151. */
  152. public function create(IShare $share) {
  153. $shareWith = $share->getSharedWith();
  154. /*
  155. * Check if file is not already shared with the remote user
  156. */
  157. $alreadyShared = $this->getSharedWith($shareWith, IShare::TYPE_EMAIL, $share->getNode(), 1, 0);
  158. if (!empty($alreadyShared)) {
  159. $message = 'Sharing %1$s failed, because this item is already shared with user %2$s';
  160. $message_t = $this->l->t('Sharing %1$s failed, because this item is already shared with user %2$s', [$share->getNode()->getName(), $shareWith]);
  161. $this->logger->debug(sprintf($message, $share->getNode()->getName(), $shareWith), ['app' => 'Federated File Sharing']);
  162. throw new \Exception($message_t);
  163. }
  164. // if the admin enforces a password for all mail shares we create a
  165. // random password and send it to the recipient
  166. $password = $share->getPassword() ?: '';
  167. $passwordEnforced = $this->shareManager->shareApiLinkEnforcePassword();
  168. if ($passwordEnforced && empty($password)) {
  169. $password = $this->autoGeneratePassword($share);
  170. }
  171. if (!empty($password)) {
  172. $share->setPassword($this->hasher->hash($password));
  173. }
  174. $shareId = $this->createMailShare($share);
  175. // Sends share password to receiver when it's a permanent one (otherwise she will have to request it via the showShare UI)
  176. // or to owner when the password shall be given during a Talk session
  177. if ($this->config->getSystemValue('sharing.enable_mail_link_password_expiration', false) === false || $share->getSendPasswordByTalk()) {
  178. $send = $this->sendPassword($share, $password);
  179. if ($passwordEnforced && $send === false) {
  180. $this->sendPasswordToOwner($share, $password);
  181. }
  182. }
  183. $this->createShareActivity($share);
  184. $data = $this->getRawShare($shareId);
  185. return $this->createShareObject($data);
  186. }
  187. /**
  188. * auto generate password in case of password enforcement on mail shares
  189. *
  190. * @param IShare $share
  191. * @return string
  192. * @throws \Exception
  193. */
  194. protected function autoGeneratePassword($share) {
  195. $initiatorUser = $this->userManager->get($share->getSharedBy());
  196. $initiatorEMailAddress = ($initiatorUser instanceof IUser) ? $initiatorUser->getEMailAddress() : null;
  197. $allowPasswordByMail = $this->settingsManager->sendPasswordByMail();
  198. if ($initiatorEMailAddress === null && !$allowPasswordByMail) {
  199. throw new \Exception(
  200. $this->l->t("We cannot send you the auto-generated password. Please set a valid email address in your personal settings and try again.")
  201. );
  202. }
  203. $passwordEvent = new GenerateSecurePasswordEvent();
  204. $this->eventDispatcher->dispatchTyped($passwordEvent);
  205. $password = $passwordEvent->getPassword();
  206. if ($password === null) {
  207. $password = $this->secureRandom->generate(8, ISecureRandom::CHAR_HUMAN_READABLE);
  208. }
  209. return $password;
  210. }
  211. /**
  212. * create activity if a file/folder was shared by mail
  213. *
  214. * @param IShare $share
  215. * @param string $type
  216. */
  217. protected function createShareActivity(IShare $share, string $type = 'share') {
  218. $userFolder = $this->rootFolder->getUserFolder($share->getSharedBy());
  219. $this->publishActivity(
  220. $type === 'share' ? Activity::SUBJECT_SHARED_EMAIL_SELF : Activity::SUBJECT_UNSHARED_EMAIL_SELF,
  221. [$userFolder->getRelativePath($share->getNode()->getPath()), $share->getSharedWith()],
  222. $share->getSharedBy(),
  223. $share->getNode()->getId(),
  224. (string) $userFolder->getRelativePath($share->getNode()->getPath())
  225. );
  226. if ($share->getShareOwner() !== $share->getSharedBy()) {
  227. $ownerFolder = $this->rootFolder->getUserFolder($share->getShareOwner());
  228. $fileId = $share->getNode()->getId();
  229. $nodes = $ownerFolder->getById($fileId);
  230. $ownerPath = $nodes[0]->getPath();
  231. $this->publishActivity(
  232. $type === 'share' ? Activity::SUBJECT_SHARED_EMAIL_BY : Activity::SUBJECT_UNSHARED_EMAIL_BY,
  233. [$ownerFolder->getRelativePath($ownerPath), $share->getSharedWith(), $share->getSharedBy()],
  234. $share->getShareOwner(),
  235. $fileId,
  236. (string) $ownerFolder->getRelativePath($ownerPath)
  237. );
  238. }
  239. }
  240. /**
  241. * create activity if a file/folder was shared by mail
  242. *
  243. * @param IShare $share
  244. * @param string $sharedWith
  245. * @param bool $sendToSelf
  246. */
  247. protected function createPasswordSendActivity(IShare $share, $sharedWith, $sendToSelf) {
  248. $userFolder = $this->rootFolder->getUserFolder($share->getSharedBy());
  249. if ($sendToSelf) {
  250. $this->publishActivity(
  251. Activity::SUBJECT_SHARED_EMAIL_PASSWORD_SEND_SELF,
  252. [$userFolder->getRelativePath($share->getNode()->getPath())],
  253. $share->getSharedBy(),
  254. $share->getNode()->getId(),
  255. (string) $userFolder->getRelativePath($share->getNode()->getPath())
  256. );
  257. } else {
  258. $this->publishActivity(
  259. Activity::SUBJECT_SHARED_EMAIL_PASSWORD_SEND,
  260. [$userFolder->getRelativePath($share->getNode()->getPath()), $sharedWith],
  261. $share->getSharedBy(),
  262. $share->getNode()->getId(),
  263. (string) $userFolder->getRelativePath($share->getNode()->getPath())
  264. );
  265. }
  266. }
  267. /**
  268. * publish activity if a file/folder was shared by mail
  269. *
  270. * @param string $subject
  271. * @param array $parameters
  272. * @param string $affectedUser
  273. * @param int $fileId
  274. * @param string $filePath
  275. */
  276. protected function publishActivity(string $subject, array $parameters, string $affectedUser, int $fileId, string $filePath) {
  277. $event = $this->activityManager->generateEvent();
  278. $event->setApp('sharebymail')
  279. ->setType('shared')
  280. ->setSubject($subject, $parameters)
  281. ->setAffectedUser($affectedUser)
  282. ->setObject('files', $fileId, $filePath);
  283. $this->activityManager->publish($event);
  284. }
  285. /**
  286. * @param IShare $share
  287. * @return int
  288. * @throws \Exception
  289. */
  290. protected function createMailShare(IShare $share) {
  291. $share->setToken($this->generateToken());
  292. $shareId = $this->addShareToDB(
  293. $share->getNodeId(),
  294. $share->getNodeType(),
  295. $share->getSharedWith(),
  296. $share->getSharedBy(),
  297. $share->getShareOwner(),
  298. $share->getPermissions(),
  299. $share->getToken(),
  300. $share->getPassword(),
  301. $share->getPasswordExpirationTime(),
  302. $share->getSendPasswordByTalk(),
  303. $share->getHideDownload(),
  304. $share->getLabel(),
  305. $share->getExpirationDate(),
  306. $share->getNote()
  307. );
  308. if (!$this->mailer->validateMailAddress($share->getSharedWith())) {
  309. $this->removeShareFromTable($shareId);
  310. $e = new HintException('Failed to send share by mail. Got an invalid email address: ' . $share->getSharedWith(),
  311. $this->l->t('Failed to send share by email. Got an invalid email address'));
  312. $this->logger->error('Failed to send share by mail. Got an invalid email address ' . $share->getSharedWith(), [
  313. 'app' => 'sharebymail',
  314. 'exception' => $e,
  315. ]);
  316. }
  317. try {
  318. $link = $this->urlGenerator->linkToRouteAbsolute('files_sharing.sharecontroller.showShare',
  319. ['token' => $share->getToken()]);
  320. $this->sendMailNotification(
  321. $share->getNode()->getName(),
  322. $link,
  323. $share->getSharedBy(),
  324. $share->getSharedWith(),
  325. $share->getExpirationDate(),
  326. $share->getNote()
  327. );
  328. } catch (HintException $hintException) {
  329. $this->logger->logException($hintException, [
  330. 'message' => 'Failed to send share by mail.',
  331. 'level' => ILogger::ERROR,
  332. 'app' => 'sharebymail',
  333. ]);
  334. $this->removeShareFromTable($shareId);
  335. throw $hintException;
  336. } catch (\Exception $e) {
  337. $this->logger->logException($e, [
  338. 'message' => 'Failed to send share by mail.',
  339. 'level' => ILogger::ERROR,
  340. 'app' => 'sharebymail',
  341. ]);
  342. $this->removeShareFromTable($shareId);
  343. throw new HintException('Failed to send share by mail',
  344. $this->l->t('Failed to send share by email'));
  345. }
  346. return $shareId;
  347. }
  348. /**
  349. * @param string $filename
  350. * @param string $link
  351. * @param string $initiator
  352. * @param string $shareWith
  353. * @param \DateTime|null $expiration
  354. * @throws \Exception If mail couldn't be sent
  355. */
  356. protected function sendMailNotification($filename,
  357. $link,
  358. $initiator,
  359. $shareWith,
  360. \DateTime $expiration = null,
  361. $note = ''
  362. ) {
  363. $initiatorUser = $this->userManager->get($initiator);
  364. $initiatorDisplayName = ($initiatorUser instanceof IUser) ? $initiatorUser->getDisplayName() : $initiator;
  365. $message = $this->mailer->createMessage();
  366. $emailTemplate = $this->mailer->createEMailTemplate('sharebymail.RecipientNotification', [
  367. 'filename' => $filename,
  368. 'link' => $link,
  369. 'initiator' => $initiatorDisplayName,
  370. 'expiration' => $expiration,
  371. 'shareWith' => $shareWith,
  372. 'note' => $note
  373. ]);
  374. $emailTemplate->setSubject($this->l->t('%1$s shared »%2$s« with you', [$initiatorDisplayName, $filename]));
  375. $emailTemplate->addHeader();
  376. $emailTemplate->addHeading($this->l->t('%1$s shared »%2$s« with you', [$initiatorDisplayName, $filename]), false);
  377. $text = $this->l->t('%1$s shared »%2$s« with you.', [$initiatorDisplayName, $filename]);
  378. if ($note !== '') {
  379. $emailTemplate->addBodyText(htmlspecialchars($note), $note);
  380. }
  381. $emailTemplate->addBodyText(
  382. htmlspecialchars($text . ' ' . $this->l->t('Click the button below to open it.')),
  383. $text
  384. );
  385. $emailTemplate->addBodyButton(
  386. $this->l->t('Open »%s«', [$filename]),
  387. $link
  388. );
  389. $message->setTo([$shareWith]);
  390. // The "From" contains the sharers name
  391. $instanceName = $this->defaults->getName();
  392. $senderName = $instanceName;
  393. if ($this->settingsManager->replyToInitiator()) {
  394. $senderName = $this->l->t(
  395. '%1$s via %2$s',
  396. [
  397. $initiatorDisplayName,
  398. $instanceName
  399. ]
  400. );
  401. }
  402. $message->setFrom([\OCP\Util::getDefaultEmailAddress($instanceName) => $senderName]);
  403. // The "Reply-To" is set to the sharer if an mail address is configured
  404. // also the default footer contains a "Do not reply" which needs to be adjusted.
  405. $initiatorEmail = $initiatorUser->getEMailAddress();
  406. if ($this->settingsManager->replyToInitiator() && $initiatorEmail !== null) {
  407. $message->setReplyTo([$initiatorEmail => $initiatorDisplayName]);
  408. $emailTemplate->addFooter($instanceName . ($this->defaults->getSlogan() !== '' ? ' - ' . $this->defaults->getSlogan() : ''));
  409. } else {
  410. $emailTemplate->addFooter();
  411. }
  412. $message->useTemplate($emailTemplate);
  413. $this->mailer->send($message);
  414. }
  415. /**
  416. * send password to recipient of a mail share
  417. *
  418. * @param IShare $share
  419. * @param string $password
  420. * @return bool
  421. */
  422. protected function sendPassword(IShare $share, $password) {
  423. $filename = $share->getNode()->getName();
  424. $initiator = $share->getSharedBy();
  425. $shareWith = $share->getSharedWith();
  426. if ($password === '' || $this->settingsManager->sendPasswordByMail() === false || $share->getSendPasswordByTalk()) {
  427. return false;
  428. }
  429. $initiatorUser = $this->userManager->get($initiator);
  430. $initiatorDisplayName = ($initiatorUser instanceof IUser) ? $initiatorUser->getDisplayName() : $initiator;
  431. $initiatorEmailAddress = ($initiatorUser instanceof IUser) ? $initiatorUser->getEMailAddress() : null;
  432. $plainBodyPart = $this->l->t("%1\$s shared »%2\$s« with you.\nYou should have already received a separate mail with a link to access it.\n", [$initiatorDisplayName, $filename]);
  433. $htmlBodyPart = $this->l->t('%1$s shared »%2$s« with you. You should have already received a separate mail with a link to access it.', [$initiatorDisplayName, $filename]);
  434. $message = $this->mailer->createMessage();
  435. $emailTemplate = $this->mailer->createEMailTemplate('sharebymail.RecipientPasswordNotification', [
  436. 'filename' => $filename,
  437. 'password' => $password,
  438. 'initiator' => $initiatorDisplayName,
  439. 'initiatorEmail' => $initiatorEmailAddress,
  440. 'shareWith' => $shareWith,
  441. ]);
  442. $emailTemplate->setSubject($this->l->t('Password to access »%1$s« shared to you by %2$s', [$filename, $initiatorDisplayName]));
  443. $emailTemplate->addHeader();
  444. $emailTemplate->addHeading($this->l->t('Password to access »%s«', [$filename]), false);
  445. $emailTemplate->addBodyText(htmlspecialchars($htmlBodyPart), $plainBodyPart);
  446. $emailTemplate->addBodyText($this->l->t('It is protected with the following password:'));
  447. $emailTemplate->addBodyText($password);
  448. if ($this->config->getSystemValue('sharing.enable_mail_link_password_expiration', false) === true) {
  449. $expirationTime = new \DateTime();
  450. $expirationInterval = $this->config->getSystemValue('sharing.mail_link_password_expiration_interval', 3600);
  451. $expirationTime = $expirationTime->add(new \DateInterval('PT' . $expirationInterval . 'S'));
  452. $emailTemplate->addBodyText($this->l->t('This password will expire at %s', [$expirationTime->format('r')]));
  453. }
  454. // The "From" contains the sharers name
  455. $instanceName = $this->defaults->getName();
  456. $senderName = $instanceName;
  457. if ($this->settingsManager->replyToInitiator()) {
  458. $senderName = $this->l->t(
  459. '%1$s via %2$s',
  460. [
  461. $initiatorDisplayName,
  462. $instanceName
  463. ]
  464. );
  465. }
  466. $message->setFrom([\OCP\Util::getDefaultEmailAddress($instanceName) => $senderName]);
  467. if ($this->settingsManager->replyToInitiator() && $initiatorEmailAddress !== null) {
  468. $message->setReplyTo([$initiatorEmailAddress => $initiatorDisplayName]);
  469. $emailTemplate->addFooter($instanceName . ' - ' . $this->defaults->getSlogan());
  470. } else {
  471. $emailTemplate->addFooter();
  472. }
  473. $message->setTo([$shareWith]);
  474. $message->useTemplate($emailTemplate);
  475. $this->mailer->send($message);
  476. $this->createPasswordSendActivity($share, $shareWith, false);
  477. return true;
  478. }
  479. protected function sendNote(IShare $share) {
  480. $recipient = $share->getSharedWith();
  481. $filename = $share->getNode()->getName();
  482. $initiator = $share->getSharedBy();
  483. $note = $share->getNote();
  484. $initiatorUser = $this->userManager->get($initiator);
  485. $initiatorDisplayName = ($initiatorUser instanceof IUser) ? $initiatorUser->getDisplayName() : $initiator;
  486. $initiatorEmailAddress = ($initiatorUser instanceof IUser) ? $initiatorUser->getEMailAddress() : null;
  487. $plainHeading = $this->l->t('%1$s shared »%2$s« with you and wants to add:', [$initiatorDisplayName, $filename]);
  488. $htmlHeading = $this->l->t('%1$s shared »%2$s« with you and wants to add', [$initiatorDisplayName, $filename]);
  489. $message = $this->mailer->createMessage();
  490. $emailTemplate = $this->mailer->createEMailTemplate('shareByMail.sendNote');
  491. $emailTemplate->setSubject($this->l->t('»%s« added a note to a file shared with you', [$initiatorDisplayName]));
  492. $emailTemplate->addHeader();
  493. $emailTemplate->addHeading(htmlspecialchars($htmlHeading), $plainHeading);
  494. $emailTemplate->addBodyText(htmlspecialchars($note), $note);
  495. $link = $this->urlGenerator->linkToRouteAbsolute('files_sharing.sharecontroller.showShare',
  496. ['token' => $share->getToken()]);
  497. $emailTemplate->addBodyButton(
  498. $this->l->t('Open »%s«', [$filename]),
  499. $link
  500. );
  501. // The "From" contains the sharers name
  502. $instanceName = $this->defaults->getName();
  503. $senderName = $instanceName;
  504. if ($this->settingsManager->replyToInitiator()) {
  505. $senderName = $this->l->t(
  506. '%1$s via %2$s',
  507. [
  508. $initiatorDisplayName,
  509. $instanceName
  510. ]
  511. );
  512. }
  513. $message->setFrom([\OCP\Util::getDefaultEmailAddress($instanceName) => $senderName]);
  514. if ($this->settingsManager->replyToInitiator() && $initiatorEmailAddress !== null) {
  515. $message->setReplyTo([$initiatorEmailAddress => $initiatorDisplayName]);
  516. $emailTemplate->addFooter($instanceName . ' - ' . $this->defaults->getSlogan());
  517. } else {
  518. $emailTemplate->addFooter();
  519. }
  520. $message->setTo([$recipient]);
  521. $message->useTemplate($emailTemplate);
  522. $this->mailer->send($message);
  523. }
  524. /**
  525. * send auto generated password to the owner. This happens if the admin enforces
  526. * a password for mail shares and forbid to send the password by mail to the recipient
  527. *
  528. * @param IShare $share
  529. * @param string $password
  530. * @return bool
  531. * @throws \Exception
  532. */
  533. protected function sendPasswordToOwner(IShare $share, $password) {
  534. $filename = $share->getNode()->getName();
  535. $initiator = $this->userManager->get($share->getSharedBy());
  536. $initiatorEMailAddress = ($initiator instanceof IUser) ? $initiator->getEMailAddress() : null;
  537. $initiatorDisplayName = ($initiator instanceof IUser) ? $initiator->getDisplayName() : $share->getSharedBy();
  538. $shareWith = $share->getSharedWith();
  539. if ($initiatorEMailAddress === null) {
  540. throw new \Exception(
  541. $this->l->t("We cannot send you the auto-generated password. Please set a valid email address in your personal settings and try again.")
  542. );
  543. }
  544. $bodyPart = $this->l->t('You just shared »%1$s« with %2$s. The share was already sent to the recipient. Due to the security policies defined by the administrator of %3$s each share needs to be protected by password and it is not allowed to send the password directly to the recipient. Therefore you need to forward the password manually to the recipient.', [$filename, $shareWith, $this->defaults->getName()]);
  545. $message = $this->mailer->createMessage();
  546. $emailTemplate = $this->mailer->createEMailTemplate('sharebymail.OwnerPasswordNotification', [
  547. 'filename' => $filename,
  548. 'password' => $password,
  549. 'initiator' => $initiatorDisplayName,
  550. 'initiatorEmail' => $initiatorEMailAddress,
  551. 'shareWith' => $shareWith,
  552. ]);
  553. $emailTemplate->setSubject($this->l->t('Password to access »%1$s« shared by you with %2$s', [$filename, $shareWith]));
  554. $emailTemplate->addHeader();
  555. $emailTemplate->addHeading($this->l->t('Password to access »%s«', [$filename]), false);
  556. $emailTemplate->addBodyText($bodyPart);
  557. $emailTemplate->addBodyText($this->l->t('This is the password:'));
  558. $emailTemplate->addBodyText($password);
  559. if ($this->config->getSystemValue('sharing.enable_mail_link_password_expiration', false) === true) {
  560. $expirationTime = new \DateTime();
  561. $expirationInterval = $this->config->getSystemValue('sharing.mail_link_password_expiration_interval', 3600);
  562. $expirationTime = $expirationTime->add(new \DateInterval('PT' . $expirationInterval . 'S'));
  563. $emailTemplate->addBodyText($this->l->t('This password will expire at %s', [$expirationTime->format('r')]));
  564. }
  565. $emailTemplate->addBodyText($this->l->t('You can choose a different password at any time in the share dialog.'));
  566. $emailTemplate->addFooter();
  567. $instanceName = $this->defaults->getName();
  568. $senderName = $this->l->t(
  569. '%1$s via %2$s',
  570. [
  571. $initiatorDisplayName,
  572. $instanceName
  573. ]
  574. );
  575. $message->setFrom([\OCP\Util::getDefaultEmailAddress($instanceName) => $senderName]);
  576. $message->setTo([$initiatorEMailAddress => $initiatorDisplayName]);
  577. $message->useTemplate($emailTemplate);
  578. $this->mailer->send($message);
  579. $this->createPasswordSendActivity($share, $shareWith, true);
  580. return true;
  581. }
  582. /**
  583. * generate share token
  584. *
  585. * @return string
  586. */
  587. protected function generateToken($size = 15) {
  588. $token = $this->secureRandom->generate($size, ISecureRandom::CHAR_HUMAN_READABLE);
  589. return $token;
  590. }
  591. /**
  592. * Get all children of this share
  593. *
  594. * @param IShare $parent
  595. * @return IShare[]
  596. */
  597. public function getChildren(IShare $parent) {
  598. $children = [];
  599. $qb = $this->dbConnection->getQueryBuilder();
  600. $qb->select('*')
  601. ->from('share')
  602. ->where($qb->expr()->eq('parent', $qb->createNamedParameter($parent->getId())))
  603. ->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter(IShare::TYPE_EMAIL)))
  604. ->orderBy('id');
  605. $cursor = $qb->executeQuery();
  606. while ($data = $cursor->fetch()) {
  607. $children[] = $this->createShareObject($data);
  608. }
  609. $cursor->closeCursor();
  610. return $children;
  611. }
  612. /**
  613. * Add share to the database and return the ID
  614. */
  615. protected function addShareToDB(
  616. ?int $itemSource,
  617. ?string $itemType,
  618. ?string $shareWith,
  619. ?string $sharedBy,
  620. ?string $uidOwner,
  621. ?int $permissions,
  622. ?string $token,
  623. ?string $password,
  624. ?\DateTimeInterface $passwordExpirationTime,
  625. ?bool $sendPasswordByTalk,
  626. ?bool $hideDownload,
  627. ?string $label,
  628. ?\DateTimeInterface $expirationTime,
  629. ?string $note = ''
  630. ): int {
  631. $qb = $this->dbConnection->getQueryBuilder();
  632. $qb->insert('share')
  633. ->setValue('share_type', $qb->createNamedParameter(IShare::TYPE_EMAIL))
  634. ->setValue('item_type', $qb->createNamedParameter($itemType))
  635. ->setValue('item_source', $qb->createNamedParameter($itemSource))
  636. ->setValue('file_source', $qb->createNamedParameter($itemSource))
  637. ->setValue('share_with', $qb->createNamedParameter($shareWith))
  638. ->setValue('uid_owner', $qb->createNamedParameter($uidOwner))
  639. ->setValue('uid_initiator', $qb->createNamedParameter($sharedBy))
  640. ->setValue('permissions', $qb->createNamedParameter($permissions))
  641. ->setValue('token', $qb->createNamedParameter($token))
  642. ->setValue('password', $qb->createNamedParameter($password))
  643. ->setValue('password_expiration_time', $qb->createNamedParameter($passwordExpirationTime, IQueryBuilder::PARAM_DATE))
  644. ->setValue('password_by_talk', $qb->createNamedParameter($sendPasswordByTalk, IQueryBuilder::PARAM_BOOL))
  645. ->setValue('stime', $qb->createNamedParameter(time()))
  646. ->setValue('hide_download', $qb->createNamedParameter((int)$hideDownload, IQueryBuilder::PARAM_INT))
  647. ->setValue('label', $qb->createNamedParameter($label))
  648. ->setValue('note', $qb->createNamedParameter($note));
  649. if ($expirationTime !== null) {
  650. $qb->setValue('expiration', $qb->createNamedParameter($expirationTime, IQueryBuilder::PARAM_DATE));
  651. }
  652. /*
  653. * Added to fix https://github.com/owncloud/core/issues/22215
  654. * Can be removed once we get rid of ajax/share.php
  655. */
  656. $qb->setValue('file_target', $qb->createNamedParameter(''));
  657. $qb->executeStatement();
  658. return $qb->getLastInsertId();
  659. }
  660. /**
  661. * Update a share
  662. *
  663. * @param IShare $share
  664. * @param string|null $plainTextPassword
  665. * @return IShare The share object
  666. */
  667. public function update(IShare $share, $plainTextPassword = null) {
  668. $originalShare = $this->getShareById($share->getId());
  669. // a real password was given
  670. $validPassword = $plainTextPassword !== null && $plainTextPassword !== '';
  671. if ($validPassword && ($originalShare->getPassword() !== $share->getPassword() ||
  672. ($originalShare->getSendPasswordByTalk() && !$share->getSendPasswordByTalk()))) {
  673. $this->sendPassword($share, $plainTextPassword);
  674. }
  675. /*
  676. * We allow updating the permissions and password of mail shares
  677. */
  678. $qb = $this->dbConnection->getQueryBuilder();
  679. $qb->update('share')
  680. ->where($qb->expr()->eq('id', $qb->createNamedParameter($share->getId())))
  681. ->set('permissions', $qb->createNamedParameter($share->getPermissions()))
  682. ->set('uid_owner', $qb->createNamedParameter($share->getShareOwner()))
  683. ->set('uid_initiator', $qb->createNamedParameter($share->getSharedBy()))
  684. ->set('password', $qb->createNamedParameter($share->getPassword()))
  685. ->set('password_expiration_time', $qb->createNamedParameter($share->getPasswordExpirationTime(), IQueryBuilder::PARAM_DATE))
  686. ->set('label', $qb->createNamedParameter($share->getLabel()))
  687. ->set('password_by_talk', $qb->createNamedParameter($share->getSendPasswordByTalk(), IQueryBuilder::PARAM_BOOL))
  688. ->set('expiration', $qb->createNamedParameter($share->getExpirationDate(), IQueryBuilder::PARAM_DATE))
  689. ->set('note', $qb->createNamedParameter($share->getNote()))
  690. ->set('hide_download', $qb->createNamedParameter((int)$share->getHideDownload(), IQueryBuilder::PARAM_INT))
  691. ->executeStatement();
  692. if ($originalShare->getNote() !== $share->getNote() && $share->getNote() !== '') {
  693. $this->sendNote($share);
  694. }
  695. return $share;
  696. }
  697. /**
  698. * @inheritdoc
  699. */
  700. public function move(IShare $share, $recipient) {
  701. /**
  702. * nothing to do here, mail shares are only outgoing shares
  703. */
  704. return $share;
  705. }
  706. /**
  707. * Delete a share (owner unShares the file)
  708. *
  709. * @param IShare $share
  710. */
  711. public function delete(IShare $share) {
  712. try {
  713. $this->createShareActivity($share, 'unshare');
  714. } catch (\Exception $e) {
  715. }
  716. $this->removeShareFromTable((int)$share->getId());
  717. }
  718. /**
  719. * @inheritdoc
  720. */
  721. public function deleteFromSelf(IShare $share, $recipient) {
  722. // nothing to do here, mail shares are only outgoing shares
  723. }
  724. public function restore(IShare $share, string $recipient): IShare {
  725. throw new GenericShareException('not implemented');
  726. }
  727. /**
  728. * @inheritdoc
  729. */
  730. public function getSharesBy($userId, $shareType, $node, $reshares, $limit, $offset) {
  731. $qb = $this->dbConnection->getQueryBuilder();
  732. $qb->select('*')
  733. ->from('share');
  734. $qb->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter(IShare::TYPE_EMAIL)));
  735. /**
  736. * Reshares for this user are shares where they are the owner.
  737. */
  738. if ($reshares === false) {
  739. //Special case for old shares created via the web UI
  740. $or1 = $qb->expr()->andX(
  741. $qb->expr()->eq('uid_owner', $qb->createNamedParameter($userId)),
  742. $qb->expr()->isNull('uid_initiator')
  743. );
  744. $qb->andWhere(
  745. $qb->expr()->orX(
  746. $qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId)),
  747. $or1
  748. )
  749. );
  750. } elseif ($node === null) {
  751. $qb->andWhere(
  752. $qb->expr()->orX(
  753. $qb->expr()->eq('uid_owner', $qb->createNamedParameter($userId)),
  754. $qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId))
  755. )
  756. );
  757. }
  758. if ($node !== null) {
  759. $qb->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($node->getId())));
  760. }
  761. if ($limit !== -1) {
  762. $qb->setMaxResults($limit);
  763. }
  764. $qb->setFirstResult($offset);
  765. $qb->orderBy('id');
  766. $cursor = $qb->executeQuery();
  767. $shares = [];
  768. while ($data = $cursor->fetch()) {
  769. $shares[] = $this->createShareObject($data);
  770. }
  771. $cursor->closeCursor();
  772. return $shares;
  773. }
  774. /**
  775. * @inheritdoc
  776. */
  777. public function getShareById($id, $recipientId = null) {
  778. $qb = $this->dbConnection->getQueryBuilder();
  779. $qb->select('*')
  780. ->from('share')
  781. ->where($qb->expr()->eq('id', $qb->createNamedParameter($id)))
  782. ->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter(IShare::TYPE_EMAIL)));
  783. $cursor = $qb->executeQuery();
  784. $data = $cursor->fetch();
  785. $cursor->closeCursor();
  786. if ($data === false) {
  787. throw new ShareNotFound();
  788. }
  789. try {
  790. $share = $this->createShareObject($data);
  791. } catch (InvalidShare $e) {
  792. throw new ShareNotFound();
  793. }
  794. return $share;
  795. }
  796. /**
  797. * Get shares for a given path
  798. *
  799. * @param \OCP\Files\Node $path
  800. * @return IShare[]
  801. */
  802. public function getSharesByPath(Node $path) {
  803. $qb = $this->dbConnection->getQueryBuilder();
  804. $cursor = $qb->select('*')
  805. ->from('share')
  806. ->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($path->getId())))
  807. ->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter(IShare::TYPE_EMAIL)))
  808. ->executeQuery();
  809. $shares = [];
  810. while ($data = $cursor->fetch()) {
  811. $shares[] = $this->createShareObject($data);
  812. }
  813. $cursor->closeCursor();
  814. return $shares;
  815. }
  816. /**
  817. * @inheritdoc
  818. */
  819. public function getSharedWith($userId, $shareType, $node, $limit, $offset) {
  820. /** @var IShare[] $shares */
  821. $shares = [];
  822. //Get shares directly with this user
  823. $qb = $this->dbConnection->getQueryBuilder();
  824. $qb->select('*')
  825. ->from('share');
  826. // Order by id
  827. $qb->orderBy('id');
  828. // Set limit and offset
  829. if ($limit !== -1) {
  830. $qb->setMaxResults($limit);
  831. }
  832. $qb->setFirstResult($offset);
  833. $qb->where($qb->expr()->eq('share_type', $qb->createNamedParameter(IShare::TYPE_EMAIL)));
  834. $qb->andWhere($qb->expr()->eq('share_with', $qb->createNamedParameter($userId)));
  835. // Filter by node if provided
  836. if ($node !== null) {
  837. $qb->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($node->getId())));
  838. }
  839. $cursor = $qb->executeQuery();
  840. while ($data = $cursor->fetch()) {
  841. $shares[] = $this->createShareObject($data);
  842. }
  843. $cursor->closeCursor();
  844. return $shares;
  845. }
  846. /**
  847. * Get a share by token
  848. *
  849. * @param string $token
  850. * @return IShare
  851. * @throws ShareNotFound
  852. */
  853. public function getShareByToken($token) {
  854. $qb = $this->dbConnection->getQueryBuilder();
  855. $cursor = $qb->select('*')
  856. ->from('share')
  857. ->where($qb->expr()->eq('share_type', $qb->createNamedParameter(IShare::TYPE_EMAIL)))
  858. ->andWhere($qb->expr()->eq('token', $qb->createNamedParameter($token)))
  859. ->executeQuery();
  860. $data = $cursor->fetch();
  861. if ($data === false) {
  862. throw new ShareNotFound('Share not found', $this->l->t('Could not find share'));
  863. }
  864. try {
  865. $share = $this->createShareObject($data);
  866. } catch (InvalidShare $e) {
  867. throw new ShareNotFound('Share not found', $this->l->t('Could not find share'));
  868. }
  869. return $share;
  870. }
  871. /**
  872. * remove share from table
  873. *
  874. * @param int $shareId
  875. */
  876. protected function removeShareFromTable(int $shareId): void {
  877. $qb = $this->dbConnection->getQueryBuilder();
  878. $qb->delete('share')
  879. ->where($qb->expr()->eq('id', $qb->createNamedParameter($shareId)));
  880. $qb->executeStatement();
  881. }
  882. /**
  883. * Create a share object from an database row
  884. *
  885. * @param array $data
  886. * @return IShare
  887. * @throws InvalidShare
  888. * @throws ShareNotFound
  889. */
  890. protected function createShareObject($data) {
  891. $share = new Share($this->rootFolder, $this->userManager);
  892. $share->setId((int)$data['id'])
  893. ->setShareType((int)$data['share_type'])
  894. ->setPermissions((int)$data['permissions'])
  895. ->setTarget($data['file_target'])
  896. ->setMailSend((bool)$data['mail_send'])
  897. ->setNote($data['note'])
  898. ->setToken($data['token']);
  899. $shareTime = new \DateTime();
  900. $shareTime->setTimestamp((int)$data['stime']);
  901. $share->setShareTime($shareTime);
  902. $share->setSharedWith($data['share_with']);
  903. $share->setPassword($data['password']);
  904. $passwordExpirationTime = \DateTime::createFromFormat('Y-m-d H:i:s', $data['password_expiration_time'] ?? '');
  905. $share->setPasswordExpirationTime($passwordExpirationTime !== false ? $passwordExpirationTime : null);
  906. $share->setLabel($data['label']);
  907. $share->setSendPasswordByTalk((bool)$data['password_by_talk']);
  908. $share->setHideDownload((bool)$data['hide_download']);
  909. if ($data['uid_initiator'] !== null) {
  910. $share->setShareOwner($data['uid_owner']);
  911. $share->setSharedBy($data['uid_initiator']);
  912. } else {
  913. //OLD SHARE
  914. $share->setSharedBy($data['uid_owner']);
  915. $path = $this->getNode($share->getSharedBy(), (int)$data['file_source']);
  916. $owner = $path->getOwner();
  917. $share->setShareOwner($owner->getUID());
  918. }
  919. if ($data['expiration'] !== null) {
  920. $expiration = \DateTime::createFromFormat('Y-m-d H:i:s', $data['expiration']);
  921. if ($expiration !== false) {
  922. $share->setExpirationDate($expiration);
  923. }
  924. }
  925. $share->setNodeId((int)$data['file_source']);
  926. $share->setNodeType($data['item_type']);
  927. $share->setProviderId($this->identifier());
  928. return $share;
  929. }
  930. /**
  931. * Get the node with file $id for $user
  932. *
  933. * @param string $userId
  934. * @param int $id
  935. * @return \OCP\Files\File|\OCP\Files\Folder
  936. * @throws InvalidShare
  937. */
  938. private function getNode($userId, $id) {
  939. try {
  940. $userFolder = $this->rootFolder->getUserFolder($userId);
  941. } catch (NoUserException $e) {
  942. throw new InvalidShare();
  943. }
  944. $nodes = $userFolder->getById($id);
  945. if (empty($nodes)) {
  946. throw new InvalidShare();
  947. }
  948. return $nodes[0];
  949. }
  950. /**
  951. * A user is deleted from the system
  952. * So clean up the relevant shares.
  953. *
  954. * @param string $uid
  955. * @param int $shareType
  956. */
  957. public function userDeleted($uid, $shareType) {
  958. $qb = $this->dbConnection->getQueryBuilder();
  959. $qb->delete('share')
  960. ->where($qb->expr()->eq('share_type', $qb->createNamedParameter(IShare::TYPE_EMAIL)))
  961. ->andWhere($qb->expr()->eq('uid_owner', $qb->createNamedParameter($uid)))
  962. ->executeStatement();
  963. }
  964. /**
  965. * This provider does not support group shares
  966. *
  967. * @param string $gid
  968. */
  969. public function groupDeleted($gid) {
  970. }
  971. /**
  972. * This provider does not support group shares
  973. *
  974. * @param string $uid
  975. * @param string $gid
  976. */
  977. public function userDeletedFromGroup($uid, $gid) {
  978. }
  979. /**
  980. * get database row of a give share
  981. *
  982. * @param $id
  983. * @return array
  984. * @throws ShareNotFound
  985. */
  986. protected function getRawShare($id) {
  987. // Now fetch the inserted share and create a complete share object
  988. $qb = $this->dbConnection->getQueryBuilder();
  989. $qb->select('*')
  990. ->from('share')
  991. ->where($qb->expr()->eq('id', $qb->createNamedParameter($id)));
  992. $cursor = $qb->executeQuery();
  993. $data = $cursor->fetch();
  994. $cursor->closeCursor();
  995. if ($data === false) {
  996. throw new ShareNotFound;
  997. }
  998. return $data;
  999. }
  1000. public function getSharesInFolder($userId, Folder $node, $reshares, $shallow = true) {
  1001. $qb = $this->dbConnection->getQueryBuilder();
  1002. $qb->select('*')
  1003. ->from('share', 's')
  1004. ->andWhere($qb->expr()->orX(
  1005. $qb->expr()->eq('item_type', $qb->createNamedParameter('file')),
  1006. $qb->expr()->eq('item_type', $qb->createNamedParameter('folder'))
  1007. ))
  1008. ->andWhere(
  1009. $qb->expr()->eq('share_type', $qb->createNamedParameter(IShare::TYPE_EMAIL))
  1010. );
  1011. /**
  1012. * Reshares for this user are shares where they are the owner.
  1013. */
  1014. if ($reshares === false) {
  1015. $qb->andWhere($qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId)));
  1016. } else {
  1017. $qb->andWhere(
  1018. $qb->expr()->orX(
  1019. $qb->expr()->eq('uid_owner', $qb->createNamedParameter($userId)),
  1020. $qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId))
  1021. )
  1022. );
  1023. }
  1024. $qb->innerJoin('s', 'filecache', 'f', $qb->expr()->eq('s.file_source', 'f.fileid'));
  1025. if ($shallow) {
  1026. $qb->andWhere($qb->expr()->eq('f.parent', $qb->createNamedParameter($node->getId())));
  1027. } else {
  1028. $qb->andWhere($qb->expr()->like('f.path', $qb->createNamedParameter($this->dbConnection->escapeLikeParameter($node->getInternalPath()) . '/%')));
  1029. }
  1030. $qb->orderBy('id');
  1031. $cursor = $qb->executeQuery();
  1032. $shares = [];
  1033. while ($data = $cursor->fetch()) {
  1034. $shares[$data['fileid']][] = $this->createShareObject($data);
  1035. }
  1036. $cursor->closeCursor();
  1037. return $shares;
  1038. }
  1039. /**
  1040. * @inheritdoc
  1041. */
  1042. public function getAccessList($nodes, $currentAccess) {
  1043. $ids = [];
  1044. foreach ($nodes as $node) {
  1045. $ids[] = $node->getId();
  1046. }
  1047. $qb = $this->dbConnection->getQueryBuilder();
  1048. $qb->select('share_with')
  1049. ->from('share')
  1050. ->where($qb->expr()->eq('share_type', $qb->createNamedParameter(IShare::TYPE_EMAIL)))
  1051. ->andWhere($qb->expr()->in('file_source', $qb->createNamedParameter($ids, IQueryBuilder::PARAM_INT_ARRAY)))
  1052. ->andWhere($qb->expr()->orX(
  1053. $qb->expr()->eq('item_type', $qb->createNamedParameter('file')),
  1054. $qb->expr()->eq('item_type', $qb->createNamedParameter('folder'))
  1055. ))
  1056. ->setMaxResults(1);
  1057. $cursor = $qb->executeQuery();
  1058. $mail = $cursor->fetch() !== false;
  1059. $cursor->closeCursor();
  1060. return ['public' => $mail];
  1061. }
  1062. public function getAllShares(): iterable {
  1063. $qb = $this->dbConnection->getQueryBuilder();
  1064. $qb->select('*')
  1065. ->from('share')
  1066. ->where(
  1067. $qb->expr()->orX(
  1068. $qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share\IShare::TYPE_EMAIL))
  1069. )
  1070. );
  1071. $cursor = $qb->executeQuery();
  1072. while ($data = $cursor->fetch()) {
  1073. try {
  1074. $share = $this->createShareObject($data);
  1075. } catch (InvalidShare $e) {
  1076. continue;
  1077. } catch (ShareNotFound $e) {
  1078. continue;
  1079. }
  1080. yield $share;
  1081. }
  1082. $cursor->closeCursor();
  1083. }
  1084. }