|
1
|
|
|
<?php |
|
2
|
|
|
/** |
|
3
|
|
|
* Circles - Bring cloud-users closer together. |
|
4
|
|
|
* |
|
5
|
|
|
* This file is licensed under the Affero General Public License version 3 or |
|
6
|
|
|
* later. See the COPYING file. |
|
7
|
|
|
* |
|
8
|
|
|
* @author Maxence Lange <[email protected]> |
|
9
|
|
|
* @copyright 2017 |
|
10
|
|
|
* @license GNU AGPL version 3 or any later version |
|
11
|
|
|
* |
|
12
|
|
|
* This program is free software: you can redistribute it and/or modify |
|
13
|
|
|
* it under the terms of the GNU Affero General Public License as |
|
14
|
|
|
* published by the Free Software Foundation, either version 3 of the |
|
15
|
|
|
* License, or (at your option) any later version. |
|
16
|
|
|
* |
|
17
|
|
|
* This program is distributed in the hope that it will be useful, |
|
18
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
19
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
20
|
|
|
* GNU Affero General Public License for more details. |
|
21
|
|
|
* |
|
22
|
|
|
* You should have received a copy of the GNU Affero General Public License |
|
23
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
|
24
|
|
|
* |
|
25
|
|
|
*/ |
|
26
|
|
|
|
|
27
|
|
|
|
|
28
|
|
|
namespace OCA\Circles\Circles; |
|
29
|
|
|
|
|
30
|
|
|
use Exception; |
|
31
|
|
|
use OC; |
|
32
|
|
|
use OC\Share20\Share; |
|
33
|
|
|
use OCA\Circles\AppInfo\Application; |
|
34
|
|
|
use OCA\Circles\Db\SharesRequest; |
|
35
|
|
|
use OCA\Circles\Db\TokensRequest; |
|
36
|
|
|
use OCA\Circles\IBroadcaster; |
|
37
|
|
|
use OCA\Circles\Model\Circle; |
|
38
|
|
|
use OCA\Circles\Model\Member; |
|
39
|
|
|
use OCA\Circles\Model\SharesToken; |
|
40
|
|
|
use OCA\Circles\Model\SharingFrame; |
|
41
|
|
|
use OCA\Circles\Service\ConfigService; |
|
42
|
|
|
use OCA\Circles\Service\MiscService; |
|
43
|
|
|
use OCA\FederatedFileSharing\Notifications; |
|
44
|
|
|
use OCP\AppFramework\QueryException; |
|
45
|
|
|
use OCP\Defaults; |
|
46
|
|
|
use OCP\Federation\ICloudFederationFactory; |
|
47
|
|
|
use OCP\Federation\ICloudFederationProviderManager; |
|
48
|
|
|
use OCP\Federation\ICloudIdManager; |
|
49
|
|
|
use OCP\Files\IRootFolder; |
|
50
|
|
|
use OCP\Files\NotFoundException; |
|
51
|
|
|
use OCP\IL10N; |
|
52
|
|
|
use OCP\ILogger; |
|
53
|
|
|
use OCP\IURLGenerator; |
|
54
|
|
|
use OCP\IUser; |
|
55
|
|
|
use OCP\IUserManager; |
|
56
|
|
|
use OCP\Mail\IEMailTemplate; |
|
57
|
|
|
use OCP\Mail\IMailer; |
|
58
|
|
|
use OCP\Share\Exceptions\IllegalIDChangeException; |
|
59
|
|
|
use OCP\Share\IShare; |
|
60
|
|
|
use OCP\Util; |
|
61
|
|
|
|
|
62
|
|
|
|
|
63
|
|
|
class FileSharingBroadcaster implements IBroadcaster { |
|
64
|
|
|
|
|
65
|
|
|
|
|
66
|
|
|
/** @var bool */ |
|
67
|
|
|
private $initiated = false; |
|
68
|
|
|
|
|
69
|
|
|
/** @var IL10N */ |
|
70
|
|
|
private $l10n = null; |
|
71
|
|
|
|
|
72
|
|
|
/** @var IMailer */ |
|
73
|
|
|
private $mailer; |
|
74
|
|
|
|
|
75
|
|
|
/** @var IRootFolder */ |
|
76
|
|
|
private $rootFolder; |
|
77
|
|
|
|
|
78
|
|
|
/** @var IUserManager */ |
|
79
|
|
|
private $userManager; |
|
80
|
|
|
|
|
81
|
|
|
/** @var ICloudFederationFactory */ |
|
82
|
|
|
private $federationFactory; |
|
83
|
|
|
|
|
84
|
|
|
/** @var ICloudFederationProviderManager */ |
|
85
|
|
|
private $federationProviderManager; |
|
86
|
|
|
|
|
87
|
|
|
/** @var ICloudIdManager */ |
|
88
|
|
|
private $federationCloudIdManager; |
|
89
|
|
|
|
|
90
|
|
|
/** @var Notifications */ |
|
91
|
|
|
private $federationNotifications; |
|
92
|
|
|
|
|
93
|
|
|
/** @var ILogger */ |
|
94
|
|
|
private $logger; |
|
95
|
|
|
|
|
96
|
|
|
/** @var Defaults */ |
|
97
|
|
|
private $defaults; |
|
98
|
|
|
|
|
99
|
|
|
/** @var IURLGenerator */ |
|
100
|
|
|
private $urlGenerator; |
|
101
|
|
|
|
|
102
|
|
|
/** @var SharesRequest */ |
|
103
|
|
|
private $sharesRequest; |
|
104
|
|
|
|
|
105
|
|
|
/** @var TokensRequest */ |
|
106
|
|
|
private $tokensRequest; |
|
107
|
|
|
|
|
108
|
|
|
/** @var ConfigService */ |
|
109
|
|
|
private $configService; |
|
110
|
|
|
|
|
111
|
|
|
/** @var MiscService */ |
|
112
|
|
|
private $miscService; |
|
113
|
|
|
|
|
114
|
|
|
/** @var bool */ |
|
115
|
|
|
private $federatedEnabled = false; |
|
116
|
|
|
|
|
117
|
|
|
/** |
|
118
|
|
|
* {@inheritdoc} |
|
119
|
|
|
*/ |
|
120
|
|
|
public function init() { |
|
121
|
|
|
if ($this->initiated) { |
|
122
|
|
|
return; |
|
123
|
|
|
} |
|
124
|
|
|
|
|
125
|
|
|
$this->initiated = true; |
|
126
|
|
|
$this->l10n = OC::$server->getL10N(Application::APP_NAME); |
|
127
|
|
|
$this->mailer = OC::$server->getMailer(); |
|
128
|
|
|
$this->rootFolder = OC::$server->getLazyRootFolder(); |
|
129
|
|
|
$this->userManager = OC::$server->getUserManager(); |
|
130
|
|
|
$this->federationFactory = OC::$server->getCloudFederationFactory(); |
|
131
|
|
|
$this->federationProviderManager = OC::$server->getCloudFederationProviderManager(); |
|
132
|
|
|
$this->federationCloudIdManager = OC::$server->getCloudIdManager(); |
|
133
|
|
|
$this->logger = OC::$server->getLogger(); |
|
134
|
|
|
$this->urlGenerator = OC::$server->getURLGenerator(); |
|
135
|
|
|
try { |
|
136
|
|
|
$this->defaults = OC::$server->query(Defaults::class); |
|
137
|
|
|
$this->sharesRequest = OC::$server->query(SharesRequest::class); |
|
138
|
|
|
$this->tokensRequest = OC::$server->query(TokensRequest::class); |
|
139
|
|
|
$this->configService = OC::$server->query(ConfigService::class); |
|
140
|
|
|
$this->miscService = OC::$server->query(MiscService::class); |
|
141
|
|
|
} catch (QueryException $e) { |
|
|
|
|
|
|
142
|
|
|
OC::$server->getLogger() |
|
143
|
|
|
->log(1, 'Circles: cannot init FileSharingBroadcaster - ' . $e->getMessage()); |
|
144
|
|
|
} |
|
145
|
|
|
|
|
146
|
|
|
try { |
|
147
|
|
|
$this->federationNotifications = |
|
148
|
|
|
OC::$server->query(Notifications::class); |
|
149
|
|
|
$this->federatedEnabled = true; |
|
150
|
|
|
} catch (QueryException $e) { |
|
|
|
|
|
|
151
|
|
|
} |
|
152
|
|
|
|
|
153
|
|
|
} |
|
154
|
|
|
|
|
155
|
|
|
|
|
156
|
|
|
/** |
|
157
|
|
|
* {@inheritdoc} |
|
158
|
|
|
*/ |
|
159
|
|
|
public function end() { |
|
160
|
|
|
} |
|
161
|
|
|
|
|
162
|
|
|
|
|
163
|
|
|
/** |
|
164
|
|
|
* {@inheritdoc} |
|
165
|
|
|
*/ |
|
166
|
|
|
public function createShareToCircle(SharingFrame $frame, Circle $circle) { |
|
167
|
|
|
if ($frame->is0Circle()) { |
|
|
|
|
|
|
168
|
|
|
return false; |
|
169
|
|
|
} |
|
170
|
|
|
|
|
171
|
|
|
return true; |
|
172
|
|
|
} |
|
173
|
|
|
|
|
174
|
|
|
|
|
175
|
|
|
/** |
|
176
|
|
|
* {@inheritdoc} |
|
177
|
|
|
*/ |
|
178
|
|
|
public function deleteShareToCircle(SharingFrame $frame, Circle $circle) { |
|
179
|
|
|
return true; |
|
180
|
|
|
} |
|
181
|
|
|
|
|
182
|
|
|
|
|
183
|
|
|
/** |
|
184
|
|
|
* {@inheritdoc} |
|
185
|
|
|
*/ |
|
186
|
|
|
public function editShareToCircle(SharingFrame $frame, Circle $circle) { |
|
187
|
|
|
return true; |
|
188
|
|
|
} |
|
189
|
|
|
|
|
190
|
|
|
|
|
191
|
|
|
/** |
|
192
|
|
|
* {@inheritdoc} |
|
193
|
|
|
* @throws IllegalIDChangeException |
|
194
|
|
|
*/ |
|
195
|
|
|
public function createShareToMember(SharingFrame $frame, Member $member) { |
|
196
|
|
|
if (!$frame->is0Circle()) { |
|
197
|
|
|
return false; |
|
198
|
|
|
} |
|
199
|
|
|
|
|
200
|
|
|
$payload = $frame->getPayload(); |
|
201
|
|
|
if (!key_exists('share', $payload)) { |
|
202
|
|
|
return false; |
|
203
|
|
|
} |
|
204
|
|
|
|
|
205
|
|
|
$share = $this->generateShare($payload['share']); |
|
206
|
|
|
if ($member->getType() === Member::TYPE_MAIL || $member->getType() === Member::TYPE_CONTACT) { |
|
207
|
|
|
try { |
|
208
|
|
|
$circle = $frame->getCircle(); |
|
209
|
|
|
|
|
210
|
|
|
// federated shared in contact |
|
211
|
|
|
$clouds = $this->getCloudsFromContact($member->getUserId()); |
|
212
|
|
|
if ($this->federatedEnabled && !empty($clouds)) { |
|
213
|
|
|
$sent = false; |
|
214
|
|
|
foreach ($clouds as $cloudId) { |
|
215
|
|
|
$token = $this->tokensRequest->generateTokenForMember($member, $share->getId()); |
|
216
|
|
|
if ($this->sharedByFederated($circle, $share, $cloudId, $token)) { |
|
217
|
|
|
$sent = true; |
|
218
|
|
|
} |
|
219
|
|
|
} |
|
220
|
|
|
|
|
221
|
|
|
if ($sent) { |
|
222
|
|
|
return true; |
|
223
|
|
|
} |
|
224
|
|
|
} |
|
225
|
|
|
|
|
226
|
|
|
$password = ''; |
|
227
|
|
|
if ($this->configService->enforcePasswordProtection()) { |
|
228
|
|
|
$password = $this->miscService->token(15); |
|
229
|
|
|
} |
|
230
|
|
|
|
|
231
|
|
|
$token = $this->tokensRequest->generateTokenForMember($member, $share->getId(), $password); |
|
232
|
|
|
if ($token !== '') { |
|
233
|
|
|
$mails = [$member->getUserId()]; |
|
234
|
|
|
if ($member->getType() === Member::TYPE_CONTACT) { |
|
235
|
|
|
$mails = $this->getMailsFromContact($member->getUserId()); |
|
236
|
|
|
} |
|
237
|
|
|
|
|
238
|
|
|
foreach ($mails as $mail) { |
|
239
|
|
|
$this->sharedByMail($circle, $share, $mail, $token, $password); |
|
240
|
|
|
} |
|
241
|
|
|
} |
|
242
|
|
|
} catch (Exception $e) { |
|
|
|
|
|
|
243
|
|
|
} |
|
244
|
|
|
} |
|
245
|
|
|
|
|
246
|
|
|
return true; |
|
247
|
|
|
} |
|
248
|
|
|
|
|
249
|
|
|
|
|
250
|
|
|
/** |
|
251
|
|
|
* {@inheritdoc} |
|
252
|
|
|
*/ |
|
253
|
|
|
public function deleteShareToMember(SharingFrame $frame, Member $member) { |
|
254
|
|
|
return true; |
|
255
|
|
|
} |
|
256
|
|
|
|
|
257
|
|
|
|
|
258
|
|
|
/** |
|
259
|
|
|
* {@inheritdoc} |
|
260
|
|
|
*/ |
|
261
|
|
|
public function editShareToMember(SharingFrame $frame, Member $member) { |
|
262
|
|
|
return true; |
|
263
|
|
|
} |
|
264
|
|
|
|
|
265
|
|
|
|
|
266
|
|
|
/** |
|
267
|
|
|
* @param Circle $circle |
|
268
|
|
|
* @param Member $member |
|
269
|
|
|
*/ |
|
270
|
|
|
public function sendMailAboutExistingShares(Circle $circle, Member $member) { |
|
271
|
|
|
$this->init(); |
|
272
|
|
|
if ($member->getType() !== Member::TYPE_MAIL && $member->getType() !== Member::TYPE_CONTACT) { |
|
273
|
|
|
return; |
|
274
|
|
|
} |
|
275
|
|
|
|
|
276
|
|
|
$allShares = $this->sharesRequest->getSharesForCircle($member->getCircleId()); |
|
277
|
|
|
$knownShares = array_map( |
|
278
|
|
|
function(SharesToken $shareToken) { |
|
279
|
|
|
return $shareToken->getShareId(); |
|
280
|
|
|
}, |
|
281
|
|
|
$this->tokensRequest->getTokensFromMember($member) |
|
282
|
|
|
); |
|
283
|
|
|
|
|
284
|
|
|
$unknownShares = []; |
|
285
|
|
|
foreach ($allShares as $share) { |
|
286
|
|
|
if (!in_array($share['id'], $knownShares)) { |
|
287
|
|
|
$unknownShares[] = $share; |
|
288
|
|
|
} |
|
289
|
|
|
} |
|
290
|
|
|
|
|
291
|
|
|
$author = $circle->getViewer() |
|
292
|
|
|
->getUserId(); |
|
293
|
|
|
|
|
294
|
|
|
// TODO: check that contact got cloudIds. if so, broadcast share to federated cloud Id; also use ContactMeta. |
|
295
|
|
|
// $clouds = $this->getCloudsFromContact($member->getUserId()); |
|
296
|
|
|
// if ($this->federatedEnabled && !empty($clouds)) { |
|
297
|
|
|
// foreach ($clouds as $cloudId) { |
|
298
|
|
|
// foreach ($unknownShares as $data) { |
|
299
|
|
|
// $share = $this->generateShare($data); |
|
300
|
|
|
// } |
|
301
|
|
|
// } |
|
302
|
|
|
// } |
|
303
|
|
|
|
|
304
|
|
|
$this->sendMailExitingShares( |
|
305
|
|
|
$unknownShares, MiscService::getDisplay($author, Member::TYPE_USER), $member, $circle->getName() |
|
306
|
|
|
); |
|
307
|
|
|
} |
|
308
|
|
|
|
|
309
|
|
|
|
|
310
|
|
|
/** |
|
311
|
|
|
* recreate the share from the JSON payload. |
|
312
|
|
|
* |
|
313
|
|
|
* @param array $data |
|
314
|
|
|
* |
|
315
|
|
|
* @return IShare |
|
|
|
|
|
|
316
|
|
|
* @throws IllegalIDChangeException |
|
317
|
|
|
*/ |
|
318
|
|
|
private function generateShare($data) { |
|
319
|
|
|
$this->logger->log(0, 'Regenerate shares from payload: ' . json_encode($data)); |
|
320
|
|
|
|
|
321
|
|
|
$share = new Share($this->rootFolder, $this->userManager); |
|
322
|
|
|
$share->setId($data['id']); |
|
323
|
|
|
$share->setSharedBy($data['sharedBy']); |
|
324
|
|
|
$share->setSharedWith($data['sharedWith']); |
|
325
|
|
|
$share->setNodeId($data['nodeId']); |
|
326
|
|
|
$share->setShareOwner($data['shareOwner']); |
|
327
|
|
|
$share->setPermissions($data['permissions']); |
|
328
|
|
|
$share->setToken($data['token']); |
|
329
|
|
|
$share->setPassword($data['password']); |
|
330
|
|
|
|
|
331
|
|
|
return $share; |
|
332
|
|
|
} |
|
333
|
|
|
|
|
334
|
|
|
|
|
335
|
|
|
/** |
|
336
|
|
|
* @param Circle $circle |
|
337
|
|
|
* @param IShare $share |
|
338
|
|
|
* @param string $address |
|
339
|
|
|
* @param string $token |
|
340
|
|
|
* |
|
341
|
|
|
* @return bool |
|
342
|
|
|
*/ |
|
343
|
|
|
private function sharedByFederated(Circle $circle, IShare $share, string $address, string $token): bool { |
|
|
|
|
|
|
344
|
|
|
|
|
345
|
|
|
try { |
|
346
|
|
|
$cloudId = $this->federationCloudIdManager->resolveCloudId($address); |
|
347
|
|
|
|
|
348
|
|
|
$localUrl = $this->urlGenerator->getAbsoluteURL('/'); |
|
349
|
|
|
$sharedByFederatedId = $share->getSharedBy(); |
|
350
|
|
|
if ($this->userManager->userExists($sharedByFederatedId)) { |
|
351
|
|
|
$cloudId = $this->federationCloudIdManager->getCloudId($sharedByFederatedId, $localUrl); |
|
352
|
|
|
$sharedByFederatedId = $cloudId->getId(); |
|
353
|
|
|
} |
|
354
|
|
|
$ownerCloudId = $this->federationCloudIdManager->getCloudId($share->getShareOwner(), $localUrl); |
|
355
|
|
|
|
|
356
|
|
|
$send = $this->federationNotifications->sendRemoteShare( |
|
357
|
|
|
$token, |
|
358
|
|
|
$address, |
|
359
|
|
|
$share->getNode() |
|
360
|
|
|
->getName(), |
|
361
|
|
|
$share->getId(), |
|
362
|
|
|
$share->getShareOwner(), |
|
363
|
|
|
$ownerCloudId->getId(), |
|
364
|
|
|
$share->getSharedBy(), |
|
365
|
|
|
$sharedByFederatedId, |
|
366
|
|
|
Share::TYPE_USER |
|
367
|
|
|
); |
|
368
|
|
|
|
|
369
|
|
|
return $send; |
|
370
|
|
|
} catch (\Exception $e) { |
|
371
|
|
|
$this->logger->logException( |
|
372
|
|
|
$e, [ |
|
373
|
|
|
'message' => 'Failed to notify remote server of circles-federated share', |
|
374
|
|
|
'level' => ILogger::ERROR, |
|
375
|
|
|
'app' => 'circles', |
|
376
|
|
|
] |
|
377
|
|
|
); |
|
378
|
|
|
} |
|
379
|
|
|
|
|
380
|
|
|
return false; |
|
381
|
|
|
} |
|
382
|
|
|
|
|
383
|
|
|
|
|
384
|
|
|
/** |
|
385
|
|
|
* @param Circle $circle |
|
386
|
|
|
* @param IShare $share |
|
387
|
|
|
* @param string $email |
|
388
|
|
|
* @param string $token |
|
389
|
|
|
* @param string $password |
|
390
|
|
|
*/ |
|
391
|
|
|
private function sharedByMail(Circle $circle, IShare $share, $email, $token, $password) { |
|
392
|
|
|
// genelink |
|
393
|
|
|
$link = $this->urlGenerator->linkToRouteAbsolute( |
|
394
|
|
|
'files_sharing.sharecontroller.showShare', |
|
395
|
|
|
['token' => $token] |
|
396
|
|
|
); |
|
397
|
|
|
|
|
398
|
|
|
try { |
|
399
|
|
|
$this->sendMail( |
|
400
|
|
|
$share->getNode() |
|
401
|
|
|
->getName(), $link, |
|
402
|
|
|
MiscService::getDisplay($share->getSharedBy(), Member::TYPE_USER), |
|
403
|
|
|
$circle->getName(), $email |
|
404
|
|
|
); |
|
405
|
|
|
$this->sendPasswordByMail( |
|
406
|
|
|
$share, MiscService::getDisplay($share->getSharedBy(), Member::TYPE_USER), |
|
407
|
|
|
$email, $password |
|
408
|
|
|
); |
|
409
|
|
|
} catch (Exception $e) { |
|
410
|
|
|
OC::$server->getLogger() |
|
411
|
|
|
->log(1, 'Circles::sharedByMail - mail were not sent: ' . $e->getMessage()); |
|
412
|
|
|
} |
|
413
|
|
|
} |
|
414
|
|
|
|
|
415
|
|
|
|
|
416
|
|
|
/** |
|
417
|
|
|
* @param $fileName |
|
418
|
|
|
* @param string $link |
|
419
|
|
|
* @param string $author |
|
420
|
|
|
* @param $circleName |
|
421
|
|
|
* @param string $email |
|
422
|
|
|
* |
|
423
|
|
|
* @throws Exception |
|
424
|
|
|
*/ |
|
425
|
|
|
protected function sendMail($fileName, $link, $author, $circleName, $email) { |
|
426
|
|
|
$message = $this->mailer->createMessage(); |
|
427
|
|
|
|
|
428
|
|
|
$this->logger->log( |
|
429
|
|
|
0, "Sending mail to circle '" . $circleName . "': " . $email . ' file: ' . $fileName |
|
430
|
|
|
. ' - link: ' . $link |
|
431
|
|
|
); |
|
432
|
|
|
|
|
433
|
|
|
$subject = $this->l10n->t('%s shared »%s« with you.', [$author, $fileName]); |
|
434
|
|
|
$text = $this->l10n->t('%s shared »%s« with \'%s\'.', [$author, $fileName, $circleName]); |
|
435
|
|
|
|
|
436
|
|
|
$emailTemplate = |
|
437
|
|
|
$this->generateEmailTemplate($subject, $text, $fileName, $link, $author, $circleName); |
|
438
|
|
|
|
|
439
|
|
|
$instanceName = $this->defaults->getName(); |
|
440
|
|
|
$senderName = $this->l10n->t('%s on %s', [$author, $instanceName]); |
|
441
|
|
|
|
|
442
|
|
|
$message->setFrom([Util::getDefaultEmailAddress($instanceName) => $senderName]); |
|
443
|
|
|
$message->setSubject($subject); |
|
444
|
|
|
$message->setPlainBody($emailTemplate->renderText()); |
|
445
|
|
|
$message->setHtmlBody($emailTemplate->renderHtml()); |
|
446
|
|
|
$message->setTo([$email]); |
|
447
|
|
|
|
|
448
|
|
|
$this->mailer->send($message); |
|
449
|
|
|
} |
|
450
|
|
|
|
|
451
|
|
|
|
|
452
|
|
|
/** |
|
453
|
|
|
* @param IShare $share |
|
454
|
|
|
* @param string $circleName |
|
455
|
|
|
* @param string $email |
|
456
|
|
|
* |
|
457
|
|
|
* @param $password |
|
458
|
|
|
* |
|
459
|
|
|
* @throws NotFoundException |
|
460
|
|
|
* @throws Exception |
|
461
|
|
|
*/ |
|
462
|
|
|
protected function sendPasswordByMail(IShare $share, $circleName, $email, $password) { |
|
463
|
|
|
if (!$this->configService->sendPasswordByMail() || $password === '') { |
|
464
|
|
|
return; |
|
465
|
|
|
} |
|
466
|
|
|
|
|
467
|
|
|
$message = $this->mailer->createMessage(); |
|
468
|
|
|
|
|
469
|
|
|
$this->logger->log(0, "Sending password mail to circle '" . $circleName . "': " . $email); |
|
470
|
|
|
|
|
471
|
|
|
$filename = $share->getNode() |
|
472
|
|
|
->getName(); |
|
473
|
|
|
$initiator = $share->getSharedBy(); |
|
474
|
|
|
$shareWith = $share->getSharedWith(); |
|
475
|
|
|
|
|
476
|
|
|
$initiatorUser = $this->userManager->get($initiator); |
|
477
|
|
|
$initiatorDisplayName = |
|
478
|
|
|
($initiatorUser instanceof IUser) ? $initiatorUser->getDisplayName() : $initiator; |
|
|
|
|
|
|
479
|
|
|
$initiatorEmailAddress = |
|
480
|
|
|
($initiatorUser instanceof IUser) ? $initiatorUser->getEMailAddress() : null; |
|
|
|
|
|
|
481
|
|
|
|
|
482
|
|
|
$plainBodyPart = $this->l10n->t( |
|
483
|
|
|
"%1\$s shared »%2\$s« with you.\nYou should have already received a separate mail with a link to access it.\n", |
|
484
|
|
|
[$initiatorDisplayName, $filename] |
|
485
|
|
|
); |
|
486
|
|
|
$htmlBodyPart = $this->l10n->t( |
|
487
|
|
|
'%1$s shared »%2$s« with you. You should have already received a separate mail with a link to access it.', |
|
488
|
|
|
[$initiatorDisplayName, $filename] |
|
489
|
|
|
); |
|
490
|
|
|
|
|
491
|
|
|
$emailTemplate = $this->mailer->createEMailTemplate( |
|
492
|
|
|
'sharebymail.RecipientPasswordNotification', [ |
|
493
|
|
|
'filename' => $filename, |
|
494
|
|
|
'password' => $password, |
|
495
|
|
|
'initiator' => $initiatorDisplayName, |
|
496
|
|
|
'initiatorEmail' => $initiatorEmailAddress, |
|
497
|
|
|
'shareWith' => $shareWith, |
|
498
|
|
|
] |
|
499
|
|
|
); |
|
500
|
|
|
|
|
501
|
|
|
$emailTemplate->setSubject( |
|
502
|
|
|
$this->l10n->t( |
|
503
|
|
|
'Password to access »%1$s« shared to you by %2$s', [$filename, $initiatorDisplayName] |
|
504
|
|
|
) |
|
505
|
|
|
); |
|
506
|
|
|
$emailTemplate->addHeader(); |
|
507
|
|
|
$emailTemplate->addHeading($this->l10n->t('Password to access »%s«', [$filename]), false); |
|
508
|
|
|
$emailTemplate->addBodyText(htmlspecialchars($htmlBodyPart), $plainBodyPart); |
|
509
|
|
|
$emailTemplate->addBodyText($this->l10n->t('It is protected with the following password:')); |
|
510
|
|
|
$emailTemplate->addBodyText($password); |
|
511
|
|
|
|
|
512
|
|
|
// The "From" contains the sharers name |
|
513
|
|
|
$instanceName = $this->defaults->getName(); |
|
514
|
|
|
$senderName = $this->l10n->t( |
|
515
|
|
|
'%1$s via %2$s', |
|
516
|
|
|
[ |
|
517
|
|
|
$initiatorDisplayName, |
|
518
|
|
|
$instanceName |
|
519
|
|
|
] |
|
520
|
|
|
); |
|
521
|
|
|
$message->setFrom([\OCP\Util::getDefaultEmailAddress($instanceName) => $senderName]); |
|
522
|
|
View Code Duplication |
if ($initiatorEmailAddress !== null) { |
|
|
|
|
|
|
523
|
|
|
$message->setReplyTo([$initiatorEmailAddress => $initiatorDisplayName]); |
|
524
|
|
|
$emailTemplate->addFooter($instanceName . ' - ' . $this->defaults->getSlogan()); |
|
525
|
|
|
} else { |
|
526
|
|
|
$emailTemplate->addFooter(); |
|
527
|
|
|
} |
|
528
|
|
|
|
|
529
|
|
|
$message->setTo([$email]); |
|
530
|
|
|
$message->useTemplate($emailTemplate); |
|
531
|
|
|
$this->mailer->send($message); |
|
532
|
|
|
} |
|
533
|
|
|
|
|
534
|
|
|
|
|
535
|
|
|
/** |
|
536
|
|
|
* @param $subject |
|
537
|
|
|
* @param $text |
|
538
|
|
|
* @param $fileName |
|
539
|
|
|
* @param $link |
|
540
|
|
|
* @param string $author |
|
541
|
|
|
* @param string $circleName |
|
542
|
|
|
* |
|
543
|
|
|
* @return IEMailTemplate |
|
544
|
|
|
*/ |
|
545
|
|
|
private function generateEmailTemplate($subject, $text, $fileName, $link, $author, $circleName |
|
546
|
|
|
) { |
|
547
|
|
|
$emailTemplate = $this->mailer->createEMailTemplate( |
|
548
|
|
|
'circles.ShareNotification', [ |
|
549
|
|
|
'fileName' => $fileName, |
|
550
|
|
|
'fileLink' => $link, |
|
551
|
|
|
'author' => $author, |
|
552
|
|
|
'circleName' => $circleName, |
|
553
|
|
|
] |
|
554
|
|
|
); |
|
555
|
|
|
|
|
556
|
|
|
$emailTemplate->addHeader(); |
|
557
|
|
|
$emailTemplate->addHeading($subject, false); |
|
558
|
|
|
$emailTemplate->addBodyText( |
|
559
|
|
|
htmlspecialchars($text) . '<br>' . htmlspecialchars( |
|
560
|
|
|
$this->l10n->t('Click the button below to open it.') |
|
561
|
|
|
), $text |
|
562
|
|
|
); |
|
563
|
|
|
$emailTemplate->addBodyButton( |
|
564
|
|
|
$this->l10n->t('Open »%s«', [htmlspecialchars($fileName)]), $link |
|
565
|
|
|
); |
|
566
|
|
|
|
|
567
|
|
|
return $emailTemplate; |
|
568
|
|
|
} |
|
569
|
|
|
|
|
570
|
|
|
|
|
571
|
|
|
/** |
|
572
|
|
|
* @param array $unknownShares |
|
573
|
|
|
* @param string $author |
|
574
|
|
|
* @param Member $member |
|
575
|
|
|
* @param string $circleName |
|
576
|
|
|
*/ |
|
577
|
|
|
private function sendMailExitingShares(array $unknownShares, $author, Member $member, $circleName) { |
|
578
|
|
|
$password = ''; |
|
579
|
|
|
if ($this->configService->enforcePasswordProtection()) { |
|
580
|
|
|
try { |
|
581
|
|
|
$password = $this->miscService->token(15); |
|
582
|
|
|
} catch (Exception $e) { |
|
583
|
|
|
return; |
|
584
|
|
|
} |
|
585
|
|
|
} |
|
586
|
|
|
|
|
587
|
|
|
$data = []; |
|
588
|
|
|
foreach ($unknownShares as $share) { |
|
589
|
|
|
$data[] = $this->getMailLinkFromShare($share, $member, $password); |
|
590
|
|
|
} |
|
591
|
|
|
|
|
592
|
|
|
if (sizeof($data) === 0) { |
|
593
|
|
|
return; |
|
594
|
|
|
} |
|
595
|
|
|
|
|
596
|
|
|
try { |
|
597
|
|
|
$template = $this->generateMailExitingShares($author, $circleName); |
|
598
|
|
|
$this->fillMailExistingShares($template, $data); |
|
599
|
|
|
$this->sendMailExistingShares($template, $author, $member->getUserId()); |
|
600
|
|
|
$this->sendPasswordExistingShares($author, $member->getUserId(), $password); |
|
601
|
|
|
} catch (Exception $e) { |
|
602
|
|
|
$this->logger->log(2, 'Failed to send mail about existing share ' . $e->getMessage()); |
|
603
|
|
|
} |
|
604
|
|
|
} |
|
605
|
|
|
|
|
606
|
|
|
|
|
607
|
|
|
/** |
|
608
|
|
|
* @param $author |
|
609
|
|
|
* @param string $email |
|
610
|
|
|
* |
|
611
|
|
|
* @param $password |
|
612
|
|
|
* |
|
613
|
|
|
* @throws Exception |
|
614
|
|
|
*/ |
|
615
|
|
|
protected function sendPasswordExistingShares($author, $email, $password) { |
|
616
|
|
|
if (!$this->configService->sendPasswordByMail() || $password === '') { |
|
617
|
|
|
return; |
|
618
|
|
|
} |
|
619
|
|
|
|
|
620
|
|
|
$message = $this->mailer->createMessage(); |
|
621
|
|
|
|
|
622
|
|
|
$authorUser = $this->userManager->get($author); |
|
623
|
|
|
$authorName = ($authorUser instanceof IUser) ? $authorUser->getDisplayName() : $author; |
|
|
|
|
|
|
624
|
|
|
$authorEmail = ($authorUser instanceof IUser) ? $authorUser->getEMailAddress() : null; |
|
|
|
|
|
|
625
|
|
|
|
|
626
|
|
|
$this->logger->log(0, "Sending password mail about existing files to '" . $email . "'"); |
|
627
|
|
|
|
|
628
|
|
|
$plainBodyPart = $this->l10n->t( |
|
629
|
|
|
"%1\$s shared multiple files with you.\nYou should have already received a separate mail with a link to access them.\n", |
|
630
|
|
|
[$authorName] |
|
631
|
|
|
); |
|
632
|
|
|
$htmlBodyPart = $this->l10n->t( |
|
633
|
|
|
'%1$s shared multiple files with you. You should have already received a separate mail with a link to access them.', |
|
634
|
|
|
[$authorName] |
|
635
|
|
|
); |
|
636
|
|
|
|
|
637
|
|
|
$emailTemplate = $this->mailer->createEMailTemplate( |
|
638
|
|
|
'sharebymail.RecipientPasswordNotification', [ |
|
639
|
|
|
'password' => $password, |
|
640
|
|
|
'author' => $author |
|
641
|
|
|
] |
|
642
|
|
|
); |
|
643
|
|
|
|
|
644
|
|
|
$emailTemplate->setSubject( |
|
645
|
|
|
$this->l10n->t( |
|
646
|
|
|
'Password to access files shared to you by %1$s', [$authorName] |
|
647
|
|
|
) |
|
648
|
|
|
); |
|
649
|
|
|
$emailTemplate->addHeader(); |
|
650
|
|
|
$emailTemplate->addHeading($this->l10n->t('Password to access files'), false); |
|
651
|
|
|
$emailTemplate->addBodyText(htmlspecialchars($htmlBodyPart), $plainBodyPart); |
|
652
|
|
|
$emailTemplate->addBodyText($this->l10n->t('It is protected with the following password:')); |
|
653
|
|
|
$emailTemplate->addBodyText($password); |
|
654
|
|
|
|
|
655
|
|
|
// The "From" contains the sharers name |
|
656
|
|
|
$instanceName = $this->defaults->getName(); |
|
657
|
|
|
$senderName = $this->l10n->t( |
|
658
|
|
|
'%1$s via %2$s', |
|
659
|
|
|
[ |
|
660
|
|
|
$authorName, |
|
661
|
|
|
$instanceName |
|
662
|
|
|
] |
|
663
|
|
|
); |
|
664
|
|
|
|
|
665
|
|
|
$message->setFrom([\OCP\Util::getDefaultEmailAddress($instanceName) => $senderName]); |
|
666
|
|
View Code Duplication |
if ($authorEmail !== null) { |
|
|
|
|
|
|
667
|
|
|
$message->setReplyTo([$authorEmail => $authorName]); |
|
668
|
|
|
$emailTemplate->addFooter($instanceName . ' - ' . $this->defaults->getSlogan()); |
|
669
|
|
|
} else { |
|
670
|
|
|
$emailTemplate->addFooter(); |
|
671
|
|
|
} |
|
672
|
|
|
|
|
673
|
|
|
$message->setTo([$email]); |
|
674
|
|
|
$message->useTemplate($emailTemplate); |
|
675
|
|
|
$this->mailer->send($message); |
|
676
|
|
|
} |
|
677
|
|
|
|
|
678
|
|
|
/** |
|
679
|
|
|
* @param array $share |
|
680
|
|
|
* @param Member $member |
|
681
|
|
|
* @param string $password |
|
682
|
|
|
* |
|
683
|
|
|
* @return array |
|
684
|
|
|
*/ |
|
685
|
|
|
private function getMailLinkFromShare(array $share, Member $member, $password) { |
|
686
|
|
|
$token = $this->tokensRequest->generateTokenForMember($member, $share['id'], $password); |
|
687
|
|
|
$link = $this->urlGenerator->linkToRouteAbsolute( |
|
688
|
|
|
'files_sharing.sharecontroller.showShare', |
|
689
|
|
|
['token' => $token] |
|
690
|
|
|
); |
|
691
|
|
|
$author = $share['uid_initiator']; |
|
692
|
|
|
|
|
693
|
|
|
$filename = basename($share['file_target']); |
|
694
|
|
|
|
|
695
|
|
|
return [ |
|
696
|
|
|
'author' => $author, |
|
697
|
|
|
'link' => $link, |
|
698
|
|
|
'password' => $password, |
|
699
|
|
|
'filename' => $filename |
|
700
|
|
|
]; |
|
701
|
|
|
} |
|
702
|
|
|
|
|
703
|
|
|
|
|
704
|
|
|
/** |
|
705
|
|
|
* @param $author |
|
706
|
|
|
* @param string $circleName |
|
707
|
|
|
* |
|
708
|
|
|
* @return IEMailTemplate |
|
709
|
|
|
* @throws Exception |
|
710
|
|
|
*/ |
|
711
|
|
|
protected function generateMailExitingShares($author, $circleName) { |
|
712
|
|
|
$this->logger->log( |
|
713
|
|
|
0, "Generating mail about existing share mail from '" . $author . "' in " |
|
714
|
|
|
. $circleName |
|
715
|
|
|
); |
|
716
|
|
|
|
|
717
|
|
|
$emailTemplate = $this->mailer->createEMailTemplate('circles.ExistingShareNotification', []); |
|
718
|
|
|
$emailTemplate->addHeader(); |
|
719
|
|
|
|
|
720
|
|
|
$text = $this->l10n->t('%s shared multiple files with \'%s\'.', [$author, $circleName]); |
|
721
|
|
|
$emailTemplate->addBodyText(htmlspecialchars($text), $text); |
|
722
|
|
|
|
|
723
|
|
|
return $emailTemplate; |
|
724
|
|
|
} |
|
725
|
|
|
|
|
726
|
|
|
|
|
727
|
|
|
/** |
|
728
|
|
|
* @param IEMailTemplate $emailTemplate |
|
729
|
|
|
* @param array $data |
|
730
|
|
|
*/ |
|
731
|
|
|
protected function fillMailExistingShares(IEMailTemplate $emailTemplate, array $data) { |
|
732
|
|
|
foreach ($data as $item) { |
|
733
|
|
|
// $text = $this->l10n->t('%s shared »%s« with you.', [$item['author'], $item['filename']]); |
|
734
|
|
|
// $emailTemplate->addBodyText( |
|
735
|
|
|
// htmlspecialchars($text) . '<br>' . htmlspecialchars( |
|
736
|
|
|
// $this->l10n->t('Click the button below to open it.') |
|
737
|
|
|
// ), $text |
|
738
|
|
|
// ); |
|
739
|
|
|
$emailTemplate->addBodyButton( |
|
740
|
|
|
$this->l10n->t('Open »%s«', [htmlspecialchars($item['filename'])]), $item['link'] |
|
741
|
|
|
); |
|
742
|
|
|
} |
|
743
|
|
|
} |
|
744
|
|
|
|
|
745
|
|
|
|
|
746
|
|
|
/** |
|
747
|
|
|
* @param IEMailTemplate $emailTemplate |
|
748
|
|
|
* @param $author |
|
749
|
|
|
* @param $recipient |
|
750
|
|
|
* |
|
751
|
|
|
* @throws Exception |
|
752
|
|
|
*/ |
|
753
|
|
|
protected function sendMailExistingShares(IEMailTemplate $emailTemplate, $author, $recipient) { |
|
754
|
|
|
$subject = $this->l10n->t('%s shared multiple files with you.', [$author]); |
|
755
|
|
|
// $emailTemplate->addHeading($subject, false); |
|
756
|
|
|
|
|
757
|
|
|
$instanceName = $this->defaults->getName(); |
|
758
|
|
|
$senderName = $this->l10n->t('%s on %s', [$author, $instanceName]); |
|
759
|
|
|
|
|
760
|
|
|
$message = $this->mailer->createMessage(); |
|
761
|
|
|
|
|
762
|
|
|
$message->setFrom([Util::getDefaultEmailAddress($instanceName) => $senderName]); |
|
763
|
|
|
$message->setSubject($subject); |
|
764
|
|
|
$message->setPlainBody($emailTemplate->renderText()); |
|
765
|
|
|
$message->setHtmlBody($emailTemplate->renderHtml()); |
|
766
|
|
|
$message->setTo([$recipient]); |
|
767
|
|
|
|
|
768
|
|
|
$this->mailer->send($message); |
|
769
|
|
|
} |
|
770
|
|
|
|
|
771
|
|
|
|
|
772
|
|
|
/** |
|
773
|
|
|
* @param string $contactId |
|
774
|
|
|
* |
|
775
|
|
|
* @return array |
|
776
|
|
|
*/ |
|
777
|
|
View Code Duplication |
private function getCloudsFromContact(string $contactId): array { |
|
|
|
|
|
|
778
|
|
|
$contact = MiscService::getContactData($contactId); |
|
779
|
|
|
if (!key_exists('CLOUD', $contact)) { |
|
780
|
|
|
return []; |
|
781
|
|
|
} |
|
782
|
|
|
|
|
783
|
|
|
return $contact['CLOUD']; |
|
784
|
|
|
} |
|
785
|
|
|
|
|
786
|
|
|
/** |
|
787
|
|
|
* @param string $contactId |
|
788
|
|
|
* |
|
789
|
|
|
* @return array |
|
790
|
|
|
*/ |
|
791
|
|
View Code Duplication |
private function getMailsFromContact(string $contactId): array { |
|
|
|
|
|
|
792
|
|
|
$contact = MiscService::getContactData($contactId); |
|
793
|
|
|
if (!key_exists('EMAIL', $contact)) { |
|
794
|
|
|
return []; |
|
795
|
|
|
} |
|
796
|
|
|
|
|
797
|
|
|
return $contact['EMAIL']; |
|
798
|
|
|
} |
|
799
|
|
|
|
|
800
|
|
|
} |
|
801
|
|
|
|
Scrutinizer analyzes your
composer.json/composer.lockfile if available to determine the classes, and functions that are defined by your dependencies.It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.