Skip to content

Commit e35cbd2

Browse files
StCyrnextcloud-command
authored andcommitted
Various improvements related to the recent implementation of temporary passwords
for mail shares: 1- Changes style of "forgot password?" and "Back" button 2- Adds information about share password's expiration time in the emails sent. 3- Shows password expiration time in the Share menu 4- Fixes an issue when the message "Password expires..." would be shown for non email share types (which don't have temporary passswords) 5- At share's creation, password should only be sent when it's a permanent one See also #31952 Signed-off-by: Cyrille Bollu <cyrpub@bollu.be> Signed-off-by: nextcloud-command <nextcloud-command@users.noreply.github.com>
1 parent 1cf2ed4 commit e35cbd2

10 files changed

+89
-36
lines changed

apps/files_sharing/lib/Controller/ShareAPIController.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -279,7 +279,7 @@ protected function formatShare(IShare $share, Node $recipientNode = null): array
279279
} elseif ($share->getShareType() === IShare::TYPE_EMAIL) {
280280
$result['share_with'] = $share->getSharedWith();
281281
$result['password'] = $share->getPassword();
282-
$result['password_expiration_time'] = $share->getPasswordExpirationTime();
282+
$result['password_expiration_time'] = $share->getPasswordExpirationTime() !== null ? $share->getPasswordExpirationTime()->format(\DateTime::ATOM) : null;
283283
$result['send_password_by_talk'] = $share->getSendPasswordByTalk();
284284
$result['share_with_displayname'] = $this->getDisplayNameFromAddressBook($share->getSharedWith(), 'EMAIL');
285285
$result['token'] = $share->getToken();

apps/files_sharing/src/components/SharingEntryLink.vue

+20
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,12 @@
192192
@submit="onPasswordSubmit">
193193
{{ t('files_sharing', 'Enter a password') }}
194194
</ActionInput>
195+
<ActionText v-if="isEmailShareType && passwordExpirationTime" icon="icon-info">
196+
{{ t('files_sharing', 'Password expires {passwordExpirationTime}', {passwordExpirationTime}) }}
197+
</ActionText>
198+
<ActionText v-else-if="isEmailShareType && passwordExpirationTime !== null" icon="icon-error">
199+
{{ t('files_sharing', 'Password expired') }}
200+
</ActionText>
195201

196202
<!-- password protected by Talk -->
197203
<ActionCheckbox v-if="isPasswordProtectedByTalkAvailable"
@@ -461,6 +467,20 @@ export default {
461467
},
462468
},
463469

470+
passwordExpirationTime() {
471+
if (this.share.passwordExpirationTime === null) {
472+
return null
473+
}
474+
475+
const expirationTime = moment(this.share.passwordExpirationTime)
476+
477+
if (expirationTime.diff(moment()) < 0) {
478+
return false
479+
}
480+
481+
return expirationTime.fromNow()
482+
},
483+
464484
/**
465485
* Is Talk enabled?
466486
*

apps/files_sharing/src/mixins/ShareRequests.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -103,8 +103,9 @@ export default {
103103
const request = await axios.put(shareUrl + `/${id}`, properties)
104104
if (!request?.data?.ocs) {
105105
throw request
106+
} else {
107+
return request.data.ocs.data
106108
}
107-
return true
108109
} catch (error) {
109110
console.error('Error while updating share', error)
110111
if (error.response.status !== 400) {

apps/files_sharing/src/mixins/SharesMixin.js

+4-1
Original file line numberDiff line numberDiff line change
@@ -235,11 +235,14 @@ export default {
235235
this.saving = true
236236
this.errors = {}
237237
try {
238-
await this.updateShare(this.share.id, properties)
238+
const updatedShare = await this.updateShare(this.share.id, properties)
239239

240240
if (propertyNames.indexOf('password') >= 0) {
241241
// reset password state after sync
242242
this.$delete(this.share, 'newPassword')
243+
244+
// updates password expiration time after sync
245+
this.share.passwordExpirationTime = updatedShare.password_expiration_time
243246
}
244247

245248
// clear any previous errors

apps/files_sharing/src/models/Share.js

+21
Original file line numberDiff line numberDiff line change
@@ -358,6 +358,27 @@ export default class Share {
358358
this._share.password = password
359359
}
360360

361+
/**
362+
* Password expiration time
363+
*
364+
* @return {string}
365+
* @readonly
366+
* @memberof Share
367+
*/
368+
get passwordExpirationTime() {
369+
return this._share.password_expiration_time
370+
}
371+
372+
/**
373+
* Password expiration time
374+
*
375+
* @param {string} password exipration time
376+
* @memberof Share
377+
*/
378+
set passwordExpirationTime(passwordExpirationTime) {
379+
this._share.password_expiration_time = passwordExpirationTime
380+
}
381+
361382
/**
362383
* Password protection by Talk of the share
363384
*

apps/sharebymail/lib/ShareByMailProvider.php

+17-1
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,7 @@ public function create(IShare $share) {
198198

199199
// Sends share password to receiver when it's a permanent one (otherwise she will have to request it via the showShare UI)
200200
// or to owner when the password shall be given during a Talk session
201-
if ($this->config->getSystemValue('sharing.enable_mail_link_password_expiration', false) === true || $share->getSendPasswordByTalk()) {
201+
if ($this->config->getSystemValue('sharing.enable_mail_link_password_expiration', false) === false || $share->getSendPasswordByTalk()) {
202202
$send = $this->sendPassword($share, $password);
203203
if ($passwordEnforced && $send === false) {
204204
$this->sendPasswordToOwner($share, $password);
@@ -503,6 +503,13 @@ protected function sendPassword(IShare $share, $password) {
503503
$emailTemplate->addBodyText($this->l->t('It is protected with the following password:'));
504504
$emailTemplate->addBodyText($password);
505505

506+
if ($this->config->getSystemValue('sharing.enable_mail_link_password_expiration', false) === true) {
507+
$expirationTime = new \DateTime();
508+
$expirationInterval = $this->config->getSystemValue('sharing.mail_link_password_expiration_interval', 3600);
509+
$expirationTime = $expirationTime->add(new \DateInterval('PT' . $expirationInterval . 'S'));
510+
$emailTemplate->addBodyText($this->l->t('This password will expire at %s', [$expirationTime->format('r')]));
511+
}
512+
506513
// The "From" contains the sharers name
507514
$instanceName = $this->defaults->getName();
508515
$senderName = $instanceName;
@@ -627,7 +634,16 @@ protected function sendPasswordToOwner(IShare $share, $password) {
627634
$emailTemplate->addBodyText($bodyPart);
628635
$emailTemplate->addBodyText($this->l->t('This is the password:'));
629636
$emailTemplate->addBodyText($password);
637+
638+
if ($this->config->getSystemValue('sharing.enable_mail_link_password_expiration', false) === true) {
639+
$expirationTime = new \DateTime();
640+
$expirationInterval = $this->config->getSystemValue('sharing.mail_link_password_expiration_interval', 3600);
641+
$expirationTime = $expirationTime->add(new \DateInterval('PT' . $expirationInterval . 'S'));
642+
$emailTemplate->addBodyText($this->l->t('This password will expire at %s', [$expirationTime->format('r')]));
643+
}
644+
630645
$emailTemplate->addBodyText($this->l->t('You can choose a different password at any time in the share dialog.'));
646+
631647
$emailTemplate->addFooter();
632648

633649
$instanceName = $this->defaults->getName();

apps/sharebymail/tests/ShareByMailProviderTest.php

+15-20
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,7 @@ public function testCreateSendPasswordByMailWithoutEnforcedPasswordProtection()
252252
);
253253
}
254254

255-
public function testCreateSendPasswordByMailWithPasswordAndWithoutEnforcedPasswordProtection() {
255+
public function testCreateSendPasswordByMailWithPasswordAndWithoutEnforcedPasswordProtectionWithPermanentPassword() {
256256
$share = $this->getMockBuilder(IShare::class)->getMock();
257257
$share->expects($this->any())->method('getSharedWith')->willReturn('receiver@example.com');
258258
$share->expects($this->any())->method('getSendPasswordByTalk')->willReturn(false);
@@ -285,7 +285,7 @@ public function testCreateSendPasswordByMailWithPasswordAndWithoutEnforcedPasswo
285285
);
286286
}
287287

288-
public function testCreateSendPasswordByMailWithPasswordAndWithoutEnforcedPasswordProtectionWithPermanentPassword() {
288+
public function testCreateSendPasswordByMailWithPasswordAndWithoutEnforcedPasswordProtectionWithoutPermanentPassword() {
289289
$share = $this->getMockBuilder(IShare::class)->getMock();
290290
$share->expects($this->any())->method('getSharedWith')->willReturn('receiver@example.com');
291291
$share->expects($this->any())->method('getSendPasswordByTalk')->willReturn(false);
@@ -310,21 +310,16 @@ public function testCreateSendPasswordByMailWithPasswordAndWithoutEnforcedPasswo
310310
// The given password (but not the autogenerated password) should be
311311
// mailed to the receiver of the share because permanent passwords are enforced.
312312
$this->shareManager->expects($this->any())->method('shareApiLinkEnforcePassword')->willReturn(false);
313-
$this->config->expects($this->once())->method('getSystemValue')->with('sharing.enable_mail_link_password_expiration')->willReturn(true);
314-
$this->settingsManager->expects($this->any())->method('sendPasswordByMail')->willReturn(true);
315313
$instance->expects($this->never())->method('autoGeneratePassword');
316-
317-
$message = $this->createMock(IMessage::class);
318-
$message->expects($this->once())->method('setTo')->with(['receiver@example.com']);
319-
$this->mailer->expects($this->once())->method('createMessage')->willReturn($message);
320-
$this->mailer->expects($this->once())->method('createEMailTemplate')->with('sharebymail.RecipientPasswordNotification', [
321-
'filename' => 'filename',
322-
'password' => 'password',
323-
'initiator' => 'owner',
324-
'initiatorEmail' => null,
325-
'shareWith' => 'receiver@example.com',
326-
]);
327-
$this->mailer->expects($this->once())->method('send');
314+
$this->config->expects($this->any())->method('getSystemValue')->withConsecutive(
315+
['sharing.enable_mail_link_password_expiration'],
316+
['sharing.enable_mail_link_password_expiration'],
317+
['sharing.mail_link_password_expiration_interval']
318+
)->willReturnOnConsecutiveCalls(
319+
true,
320+
true,
321+
3600
322+
);
328323

329324
$this->assertSame('shareObject',
330325
$instance->create($share)
@@ -363,7 +358,7 @@ public function testCreateSendPasswordByMailWithEnforcedPasswordProtectionWithPe
363358

364359
// The autogenerated password should be mailed to the receiver of the share because permanent passwords are enforced.
365360
$this->shareManager->expects($this->any())->method('shareApiLinkEnforcePassword')->willReturn(true);
366-
$this->config->expects($this->once())->method('getSystemValue')->with('sharing.enable_mail_link_password_expiration')->willReturn(true);
361+
$this->config->expects($this->any())->method('getSystemValue')->with('sharing.enable_mail_link_password_expiration')->willReturn(false);
367362
$this->settingsManager->expects($this->any())->method('sendPasswordByMail')->willReturn(true);
368363

369364
$message = $this->createMock(IMessage::class);
@@ -408,7 +403,7 @@ public function testCreateSendPasswordByMailWithPasswordAndWithEnforcedPasswordP
408403
// The given password (but not the autogenerated password) should be
409404
// mailed to the receiver of the share.
410405
$this->shareManager->expects($this->any())->method('shareApiLinkEnforcePassword')->willReturn(true);
411-
$this->config->expects($this->once())->method('getSystemValue')->with('sharing.enable_mail_link_password_expiration')->willReturn(true);
406+
$this->config->expects($this->any())->method('getSystemValue')->with('sharing.enable_mail_link_password_expiration')->willReturn(false);
412407
$this->settingsManager->expects($this->any())->method('sendPasswordByMail')->willReturn(true);
413408
$instance->expects($this->never())->method('autoGeneratePassword');
414409

@@ -429,7 +424,7 @@ public function testCreateSendPasswordByMailWithPasswordAndWithEnforcedPasswordP
429424
);
430425
}
431426

432-
public function testCreateSendPasswordByTalkWithEnforcedPasswordProtection() {
427+
public function testCreateSendPasswordByTalkWithEnforcedPasswordProtectionWithPermanentPassword() {
433428
$share = $this->getMockBuilder(IShare::class)->getMock();
434429
$share->expects($this->any())->method('getSharedWith')->willReturn('receiver@example.com');
435430
$share->expects($this->any())->method('getSendPasswordByTalk')->willReturn(true);
@@ -453,7 +448,7 @@ public function testCreateSendPasswordByTalkWithEnforcedPasswordProtection() {
453448

454449
// The autogenerated password should be mailed to the owner of the share.
455450
$this->shareManager->expects($this->any())->method('shareApiLinkEnforcePassword')->willReturn(true);
456-
$this->config->expects($this->once())->method('getSystemValue')->with('sharing.enable_mail_link_password_expiration')->willReturn(false);
451+
$this->config->expects($this->any())->method('getSystemValue')->with('sharing.enable_mail_link_password_expiration')->willReturn(false);
457452
$this->settingsManager->expects($this->any())->method('sendPasswordByMail')->willReturn(true);
458453
$instance->expects($this->once())->method('autoGeneratePassword')->with($share)->willReturn('autogeneratedPassword');
459454

core/templates/publicshareauth.php

+6-9
Original file line numberDiff line numberDiff line change
@@ -61,23 +61,20 @@ class="svg icon-confirm input-button-inline" value="" disabled="disabled" />
6161

6262
<!-- request password button -->
6363
<?php if (!isset($_['identityOk']) && $_['share']->getShareType() === $_['share']::TYPE_EMAIL && !$_['share']->getSendPasswordByTalk()): ?>
64-
<input type="button"
65-
id="request-password-button-not-talk"
66-
value="<?php p($l->t('Request password')); ?>"
67-
class="primary" />
64+
<a id="request-password-button-not-talk"><?php p($l->t('Forgot password?')); ?></a>
6865
<?php endif; ?>
6966

7067
<!-- back to showShare button -->
7168
<form method="get">
7269
<fieldset>
73-
<input type="submit"
70+
<a
71+
href=""
7472
id="request-password-back-button"
75-
value="<?php p($l->t('Back')); ?>"
76-
class="primary"
7773
<?php if (isset($_['identityOk'])): ?>
78-
style="display:block;" />
74+
style="display:block;">
7975
<?php else: ?>
80-
style="display:none;" />
76+
style="display:none;">
8177
<?php endif; ?>
78+
<?php p($l->t('Back')); ?></a>
8279
</fieldset>
8380
</form>

dist/files_sharing-files_sharing_tab.js

+2-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/files_sharing-files_sharing_tab.js.map

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)