Skip to content
Prev Previous commit
Next Next commit
Fix disabling send password by Talk without new password in mail shares
When "send password by Talk" was disabled in a mail share it was
possible to keep the same password as before, as it does not pose any
security issue (unlike keeping it when "send password by Talk" is
enabled, as in that case the password was already disclosed by mail).

However, if a mail share is updated but the password is not set again
only the hashed password will be available. In that case it would not
make sense to send the password by mail, so now the password must be
changed when disabling "send password by Talk".

Note that, even if explicitly setting the same password again along with
the "send password by Talk" property would work, this was also prevented
for simplicity.

Signed-off-by: Daniel Calviño Sánchez <[email protected]>
  • Loading branch information
danxuliu authored and backportbot[bot] committed May 29, 2020
commit 6ca312eec9a5658473ace50641a4f366c47336e0
8 changes: 4 additions & 4 deletions lib/private/Share20/Manager.php
Original file line number Diff line number Diff line change
Expand Up @@ -983,18 +983,18 @@ public function updateShare(\OCP\Share\IShare $share) {
}
} elseif ($share->getShareType() === \OCP\Share::SHARE_TYPE_EMAIL) {
// The new password is not set again if it is the same as the old
// one, unless when switching from sending by Talk to sending by
// mail.
// one.
$plainTextPassword = $share->getPassword();
if (!empty($plainTextPassword) && !$this->updateSharePasswordIfNeeded($share, $originalShare) &&
!($originalShare->getSendPasswordByTalk() && !$share->getSendPasswordByTalk())) {
if (!empty($plainTextPassword) && !$this->updateSharePasswordIfNeeded($share, $originalShare)) {
$plainTextPassword = null;
}
if (empty($plainTextPassword) && !$originalShare->getSendPasswordByTalk() && $share->getSendPasswordByTalk()) {
// If the same password was already sent by mail the recipient
// would already have access to the share without having to call
// the sharer to verify her identity
throw new \InvalidArgumentException('Can’t enable sending the password by Talk without setting a new password');
} elseif (empty($plainTextPassword) && $originalShare->getSendPasswordByTalk() && !$share->getSendPasswordByTalk()) {
throw new \InvalidArgumentException('Can’t disable sending the password by Talk without setting a new password');
}
}

Expand Down
84 changes: 79 additions & 5 deletions tests/lib/Share20/ManagerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -3339,6 +3339,9 @@ public function testUpdateShareMailEnableSendPasswordByTalkWithPreviousPassword(
}

public function testUpdateShareMailDisableSendPasswordByTalkWithPreviousPassword() {
$this->expectException(\InvalidArgumentException::class);
$this->expectExceptionMessage('Can’t disable sending the password by Talk without setting a new password');

$manager = $this->createManagerMock()
->setMethods([
'canShare',
Expand Down Expand Up @@ -3380,8 +3383,8 @@ public function testUpdateShareMailDisableSendPasswordByTalkWithPreviousPassword
$manager->expects($this->once())->method('canShare')->willReturn(true);
$manager->expects($this->once())->method('getShareById')->with('foo:42')->willReturn($originalShare);
$manager->expects($this->once())->method('generalCreateChecks')->with($share);
$manager->expects($this->once())->method('pathCreateChecks')->with($file);
$manager->expects($this->never())->method('verifyPassword');
$manager->expects($this->never())->method('pathCreateChecks');
$manager->expects($this->never())->method('linkCreateChecks');
$manager->expects($this->never())->method('validateExpirationDate');

Expand All @@ -3393,10 +3396,8 @@ public function testUpdateShareMailDisableSendPasswordByTalkWithPreviousPassword
$this->hasher->expects($this->never())
->method('hash');

$this->defaultProvider->expects($this->once())
->method('update')
->with($share, 'password')
->willReturn($share);
$this->defaultProvider->expects($this->never())
->method('update');

$hookListner = $this->getMockBuilder('Dummy')->setMethods(['post'])->getMock();
\OCP\Util::connectHook('OCP\Share', 'post_set_expiration_date', $hookListner, 'post');
Expand All @@ -3413,6 +3414,79 @@ public function testUpdateShareMailDisableSendPasswordByTalkWithPreviousPassword
$manager->updateShare($share);
}

public function testUpdateShareMailDisableSendPasswordByTalkWithoutChangingPassword() {
$this->expectException(\InvalidArgumentException::class);
$this->expectExceptionMessage('Can’t disable sending the password by Talk without setting a new password');

$manager = $this->createManagerMock()
->setMethods([
'canShare',
'getShareById',
'generalCreateChecks',
'verifyPassword',
'pathCreateChecks',
'linkCreateChecks',
'validateExpirationDate',
])
->getMock();

$originalShare = $this->manager->newShare();
$originalShare->setShareType(\OCP\Share::SHARE_TYPE_EMAIL)
->setPermissions(\OCP\Constants::PERMISSION_ALL)
->setPassword('passwordHash')
->setSendPasswordByTalk(true);

$tomorrow = new \DateTime();
$tomorrow->setTime(0,0,0);
$tomorrow->add(new \DateInterval('P1D'));

$file = $this->createMock(File::class);
$file->method('getId')->willReturn(100);

$share = $this->manager->newShare();
$share->setProviderId('foo')
->setId('42')
->setShareType(\OCP\Share::SHARE_TYPE_EMAIL)
->setToken('token')
->setSharedBy('owner')
->setShareOwner('owner')
->setPassword('passwordHash')
->setSendPasswordByTalk(false)
->setExpirationDate($tomorrow)
->setNode($file)
->setPermissions(\OCP\Constants::PERMISSION_ALL);

$manager->expects($this->once())->method('canShare')->willReturn(true);
$manager->expects($this->once())->method('getShareById')->with('foo:42')->willReturn($originalShare);
$manager->expects($this->once())->method('generalCreateChecks')->with($share);
$manager->expects($this->never())->method('verifyPassword');
$manager->expects($this->never())->method('pathCreateChecks');
$manager->expects($this->never())->method('linkCreateChecks');
$manager->expects($this->never())->method('validateExpirationDate');

$this->hasher->expects($this->never())
->method('verify');

$this->hasher->expects($this->never())
->method('hash');

$this->defaultProvider->expects($this->never())
->method('update');

$hookListner = $this->getMockBuilder('Dummy')->setMethods(['post'])->getMock();
\OCP\Util::connectHook('OCP\Share', 'post_set_expiration_date', $hookListner, 'post');
$hookListner->expects($this->never())->method('post');

$hookListner2 = $this->getMockBuilder('Dummy')->setMethods(['post'])->getMock();
\OCP\Util::connectHook('OCP\Share', 'post_update_password', $hookListner2, 'post');
$hookListner2->expects($this->never())->method('post');

$hookListner3 = $this->getMockBuilder('Dummy')->setMethods(['post'])->getMock();
\OCP\Util::connectHook('OCP\Share', 'post_update_permissions', $hookListner3, 'post');
$hookListner3->expects($this->never())->method('post');

$manager->updateShare($share);
}

public function testMoveShareLink() {
$this->expectException(\InvalidArgumentException::class);
Expand Down