Skip to content

Commit edb4db5

Browse files
committed
feat(core/otp): Add test cases for share creation/deletion/retrieval/persistence with OTPs
Signed-off-by: Tobias Knöppler <tobias@knoeppler.org>
1 parent 2374cd9 commit edb4db5

3 files changed

Lines changed: 68 additions & 7 deletions

File tree

lib/private/Share20/DefaultShareProvider.php

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1137,8 +1137,6 @@ private function createShare($data): IShare {
11371137
} elseif ($share->getShareType() === IShare::TYPE_LINK) {
11381138
$share->setPassword($data['password']);
11391139
$share->setSendPasswordByTalk((bool)$data['password_by_talk']);
1140-
$passwordExpirationTime = \DateTime::createFromFormat('Y-m-d H:i:s', $data['password_expiration_time'] ?? '');
1141-
$share->setPasswordExpirationTime($passwordExpirationTime !== false ? $passwordExpirationTime : null);
11421140
$share->setToken($data['token']);
11431141
}
11441142

tests/lib/Share20/DefaultShareProviderTest.php

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
namespace Test\Share20;
1010

1111
use OC\Files\Node\Node;
12+
use OC\OneTimePassword\OneTimePassword;
1213
use OC\Share20\DefaultShareProvider;
1314
use OC\Share20\Exception\ProviderException;
1415
use OC\Share20\Share;
@@ -881,6 +882,15 @@ public function testCreateLinkShare(): void {
881882
$share->setExpirationDate($expireDate);
882883
$share->setTarget('/target');
883884

885+
$qb = $this->dbConn->getQueryBuilder();
886+
$qb->insert('one_time_password')
887+
->setValue('provider', $qb->createNamedParameter('mock'))
888+
->setValue('recipient', $qb->createNamedParameter('recipient'));
889+
$qb->executeStatement();
890+
$otpId = $qb->getLastInsertId();
891+
892+
$share->setOneTimePassword((new OneTimePassword('mock', 'recipient'))->setId($otpId));
893+
884894
$share2 = $this->provider->create($share);
885895

886896
$this->assertNotNull($share2->getId());
@@ -896,16 +906,28 @@ public function testCreateLinkShare(): void {
896906
$this->assertSame(true, $share2->getSendPasswordByTalk());
897907
$this->assertSame('token', $share2->getToken());
898908
$this->assertEquals($expireDate->getTimestamp(), $share2->getExpirationDate()->getTimestamp());
909+
$this->assertEquals('mock', $share2->getOneTimePassword()->getProviderId());
910+
$this->assertEquals('recipient', $share2->getOneTimePassword()->getRecipient());
899911
}
900912

901913
public function testGetShareByToken(): void {
902914
$qb = $this->dbConn->getQueryBuilder();
903915

916+
$qb->insert('one_time_password')
917+
->values([
918+
'provider' => $qb->expr()->literal('mock'),
919+
'recipient' => $qb->expr()->literal('recipient')
920+
]);
921+
$qb->executeStatement();
922+
$otpId = $qb->getLastInsertId();
923+
924+
$qb = $this->dbConn->getQueryBuilder();
904925
$qb->insert('share')
905926
->values([
906927
'share_type' => $qb->expr()->literal(IShare::TYPE_LINK),
907928
'password' => $qb->expr()->literal('password'),
908929
'password_by_talk' => $qb->expr()->literal(true),
930+
'one_time_password' => $qb->expr()->literal($otpId),
909931
'uid_owner' => $qb->expr()->literal('shareOwner'),
910932
'uid_initiator' => $qb->expr()->literal('sharedBy'),
911933
'item_type' => $qb->expr()->literal('file'),
@@ -922,6 +944,12 @@ public function testGetShareByToken(): void {
922944

923945
$this->rootFolder->method('getUserFolder')->with('shareOwner')->willReturnSelf();
924946
$this->rootFolder->method('getFirstNodeById')->with(42)->willReturn($file);
947+
$this->otpManager->method('getOTP')->willReturnCallback(function (int $id) use ($otpId) {
948+
if ($id === $otpId) {
949+
return (new OneTimePassword('mock', 'recipient'))->setId($id);
950+
}
951+
throw new \Exception("Unexpected otp id: " . $id);
952+
});
925953

926954
$share = $this->provider->getShareByToken('secrettoken');
927955
$this->assertEquals($id, $share->getId());
@@ -932,6 +960,8 @@ public function testGetShareByToken(): void {
932960
$this->assertSame('the label', $share->getLabel());
933961
$this->assertSame(true, $share->getSendPasswordByTalk());
934962
$this->assertSame(null, $share->getSharedWith());
963+
$this->assertSame('mock', $share->getOneTimePassword()->getProviderId());
964+
$this->assertSame('recipient', $share->getOneTimePassword()->getRecipient());
935965
}
936966

937967
/**

tests/lib/Share20/ManagerTest.php

Lines changed: 38 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
use DateTimeZone;
1212
use OC\Files\Utils\PathHelper;
1313
use OC\KnownUser\KnownUserService;
14+
use OC\OneTimePassword\OneTimePassword;
1415
use OC\Share20\DefaultShareProvider;
1516
use OC\Share20\Exception\ProviderException;
1617
use OC\Share20\Manager;
@@ -222,15 +223,15 @@ public function testDeleteNoShareId(): void {
222223

223224
public static function dataTestDelete(): array {
224225
return [
225-
[IShare::TYPE_USER, 'sharedWithUser'],
226-
[IShare::TYPE_GROUP, 'sharedWithGroup'],
227-
[IShare::TYPE_LINK, ''],
228-
[IShare::TYPE_REMOTE, 'foo@bar.com'],
226+
[IShare::TYPE_USER, 'sharedWithUser', 1],
227+
[IShare::TYPE_GROUP, 'sharedWithGroup', 5],
228+
[IShare::TYPE_LINK, '', 2],
229+
[IShare::TYPE_REMOTE, 'foo@bar.com', 1],
229230
];
230231
}
231232

232233
#[DataProvider('dataTestDelete')]
233-
public function testDelete($shareType, $sharedWith): void {
234+
public function testDelete($shareType, $sharedWith, $otpId): void {
234235
$manager = $this->createManagerMock()
235236
->onlyMethods(['getShareById', 'deleteChildren', 'promoteReshares'])
236237
->getMock();
@@ -240,17 +241,20 @@ public function testDelete($shareType, $sharedWith): void {
240241
$path = $this->createMock(File::class);
241242
$path->method('getId')->willReturn(1);
242243

244+
$otp = (new OneTimePassword('mock', 'rec'))->setId($otpId);
243245
$share = $this->manager->newShare();
244246
$share->setId(42)
245247
->setProviderId('prov')
246248
->setShareType($shareType)
247249
->setSharedWith($sharedWith)
248250
->setSharedBy('sharedBy')
251+
->setOneTimePassword($otp)
249252
->setNode($path)
250253
->setTarget('myTarget');
251254

252255
$manager->expects($this->once())->method('deleteChildren')->with($share);
253256
$manager->expects($this->once())->method('promoteReshares')->with($share);
257+
$this->otpManager->expects($this->once())->method('deleteOTP')->with($otpId);
254258

255259
$this->defaultProvider
256260
->expects($this->once())
@@ -3602,6 +3606,35 @@ public function testCheckPasswordUpdateShare(): void {
36023606
$this->assertTrue($this->manager->checkPassword($share, 'password'));
36033607
}
36043608

3609+
public static function dataTestCheckPasswordOTP() {
3610+
return [
3611+
[null, (new OneTimePassword('mock', 'rec'))->setPassword(null), 'password', false],
3612+
[null, (new OneTimePassword('mock', 'rec'))->setPassword('hashed(password)'), 'password', true],
3613+
['hashed(password)', (new OneTimePassword('mock', 'rec'))->setPassword(null), 'password', false], // OTP should take precedence
3614+
];
3615+
}
3616+
3617+
#[DataProvider('dataTestCheckPasswordOTP')]
3618+
public function testCheckPasswordOTP(?string $pwHash, ?OneTimePassword $otp, string $password, bool $expected): void {
3619+
$share = $this->manager->newShare()
3620+
->setShareType(IShare::TYPE_LINK)
3621+
->setPassword($pwHash)
3622+
->setOneTimePassword($otp);
3623+
3624+
$this->hasher->method('verify')->willReturnCallback(function (string $pwHash, string $pw, &$newHash): bool {
3625+
return "hashed($pw)" === $pwHash;
3626+
});
3627+
$this->otpManager->method('validateOTP')->willReturnCallback(function(OneTimePassword $otp, ?string $password): bool {
3628+
if ($otp->getPassword() === null) {
3629+
return false;
3630+
}
3631+
return $this->hasher->verify($otp->getPassword(), $password, $newHash);
3632+
});
3633+
3634+
$actual = $this->manager->checkPassword($share, $password);
3635+
$this->assertEquals($expected, $actual, "Password check " . ($actual ? "succeeded" : "failed") . " unexpectedly");
3636+
}
3637+
36053638
public function testUpdateShareCantChangeShareType(): void {
36063639
$this->expectException(\Exception::class);
36073640
$this->expectExceptionMessage('Cannot change share type');

0 commit comments

Comments
 (0)