From 4ed5e66412bdf95bb3b80ad79b46bc77ef890de6 Mon Sep 17 00:00:00 2001 From: dartcafe Date: Sat, 21 Sep 2024 13:07:59 +0200 Subject: [PATCH 1/3] convert email and contact share on first access Signed-off-by: dartcafe --- lib/Db/Share.php | 8 +++- lib/Service/ShareService.php | 85 ++++++++++++++++++++++++++++-------- 2 files changed, 74 insertions(+), 19 deletions(-) diff --git a/lib/Db/Share.php b/lib/Db/Share.php index f2029cccb..33d8cb9ee 100644 --- a/lib/Db/Share.php +++ b/lib/Db/Share.php @@ -69,12 +69,16 @@ class Share extends EntityWithUser implements JsonSerializable { public const TYPE_CONTACTGROUP = 'contactGroup'; + public const CONVERATABLE_PUBLIC_SHARES = [ + self::TYPE_EMAIL, + self::TYPE_CONTACT, + ]; + // Share types, that are allowed for public access (without login) public const SHARE_PUBLIC_ACCESS_ALLOWED = [ self::TYPE_PUBLIC, - self::TYPE_CONTACT, - self::TYPE_EMAIL, self::TYPE_EXTERNAL, + ...self::CONVERATABLE_PUBLIC_SHARES, ]; // Share types, that are allowed for authenticated access (with login) diff --git a/lib/Service/ShareService.php b/lib/Service/ShareService.php index 24c374ef4..77cba1cf8 100644 --- a/lib/Service/ShareService.php +++ b/lib/Service/ShareService.php @@ -36,9 +36,15 @@ use OCP\DB\Exception; use OCP\EventDispatcher\IEventDispatcher; use OCP\Security\ISecureRandom; +use phpDocumentor\Reflection\Types\This; use Psr\Log\LoggerInterface; class ShareService { + private const SHARES_TO_CONVERT_ON_ACCESS = [ + Share::TYPE_EMAIL, + Share::TYPE_CONTACT, + ]; + /** @var Share[] * */ private array $shares; @@ -107,7 +113,7 @@ public function listNotInvited(int $pollId): array { * If user is not authorized for this poll, create a personal share * for this user and return the created share instead of the public share */ - private function convertPublicToPersonalShare(): void { + private function convertPublicShareToPersonalShare(): void { try { $this->share = $this->createNewShare( $this->share->getPollId(), @@ -128,6 +134,7 @@ private function convertPublicToPersonalShare(): void { * @param string $token Token of share to get */ public function request(string $token): Share { + $this->share = $this->shareMapper->findByToken($token); $this->validateShareType(); @@ -139,8 +146,14 @@ public function request(string $token): Share { // Exception: logged in user, accesses the poll via public share link if ($this->share->getType() === Share::TYPE_PUBLIC && $this->userSession->getIsLoggedIn()) { - $this->convertPublicToPersonalShare(); + $this->convertPublicShareToPersonalShare(); + } + + // Exception for convertable (email and contact) shares + if (in_array($this->share->getType(), Share::CONVERATABLE_PUBLIC_SHARES, true)) { + $this->convertPersonalPublicShareToExternalShare(); } + return $this->share; } @@ -270,9 +283,57 @@ public function deleteEmailAddress(Share $share): Share { } } + /** + * Convert convertable public shares to external share and generates a unique user id + * @param string|null $userId + * @param string|null $displayName + * @param string|null $emailAddress + * @param string|null $timeZone + * @param string|null $language + * @return Share + */ + private function convertPersonalPublicShareToExternalShare( + string|null $userId = null, + string|null $displayName = null, + string|null $emailAddress = null, + string|null $timeZone = null, + string|null $language = null, + ): Share { + + // paranoia double check + if (!in_array($this->share->getType(), Share::CONVERATABLE_PUBLIC_SHARES, true)) { + return $this->share; + } + + $this->share->setUserId($userId ?? $this->generatePublicUserId()); + $this->share->setDisplayName($displayName ?? $this->share->getDisplayName()); + $this->share->setTimeZoneName($timeZone ?? $this->share->getTimeZoneName()); + $this->share->setLanguage($language ?? $this->share->getLanguage()); + + if ($emailAddress && $emailAddress !== $this->share->getEmailAddress()) { + // reset invitation sent, if email address is changed + $this->share->setInvitationSent(0); + } + + $this->share->setEmailAddress($emailAddress ?? $this->share->getEmailAddress()); + + // convert to type external + $this->share->setType(Share::TYPE_EXTERNAL); + + // remove personal information from user id + $this->share->setUserId($this->generatePublicUserId()); + $this->share = $this->shareMapper->update($this->share); + return $this->share; + } + /** * Create a personal share from a public share * or update an email share with the displayName + * @param string $publicShareToken + * @param string $displayName + * @param string $emailAddress + * @param string $timeZone + * @return Share */ public function register( string $publicShareToken, @@ -289,6 +350,7 @@ public function register( $language = $this->systemService->getGenericLanguage(); $userId = $this->generatePublicUserId(); + $resetInvitation = false; if ($this->share->getType() === Share::TYPE_PUBLIC) { // Create new external share for user, who entered the poll via public link, @@ -300,23 +362,12 @@ public function register( $timeZone ); $this->eventDispatcher->dispatchTyped(new ShareRegistrationEvent($this->share)); - } elseif ( - $this->share->getType() === Share::TYPE_EMAIL - || $this->share->getType() === Share::TYPE_CONTACT - ) { + + } elseif (in_array($this->share->getType(), Share::CONVERATABLE_PUBLIC_SHARES, true)) { // Convert email and contact shares to external share, if user registers - $this->share->setType(Share::TYPE_EXTERNAL); - $this->share->setUserId($userId); - $this->share->setDisplayName($displayName); - $this->share->setTimeZoneName($timeZone); - $this->share->setLanguage($language); + // this should be avoided by the actual use cases, but keep code in case of later changes + $this->convertPersonalPublicShareToExternalShare($userId, $displayName, $emailAddress, $timeZone, $language, $resetInvitation); - // prepare for resending invitation to new email address - if ($emailAddress !== $this->share->getEmailAddress()) { - $this->share->setInvitationSent(0); - } - $this->share->setEmailAddress($emailAddress); - $this->shareMapper->update($this->share); } else { throw new ForbiddenException('Share does not allow registering for poll'); } From 53463bf7b7557bf19f0943571db7f944ba26a185 Mon Sep 17 00:00:00 2001 From: dartcafe Date: Sat, 21 Sep 2024 13:19:04 +0200 Subject: [PATCH 2/3] fix Signed-off-by: dartcafe --- lib/Service/ShareService.php | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/Service/ShareService.php b/lib/Service/ShareService.php index 77cba1cf8..f9a0b8988 100644 --- a/lib/Service/ShareService.php +++ b/lib/Service/ShareService.php @@ -290,7 +290,6 @@ public function deleteEmailAddress(Share $share): Share { * @param string|null $emailAddress * @param string|null $timeZone * @param string|null $language - * @return Share */ private function convertPersonalPublicShareToExternalShare( string|null $userId = null, @@ -298,7 +297,7 @@ private function convertPersonalPublicShareToExternalShare( string|null $emailAddress = null, string|null $timeZone = null, string|null $language = null, - ): Share { + ): void { // paranoia double check if (!in_array($this->share->getType(), Share::CONVERATABLE_PUBLIC_SHARES, true)) { @@ -323,7 +322,6 @@ private function convertPersonalPublicShareToExternalShare( // remove personal information from user id $this->share->setUserId($this->generatePublicUserId()); $this->share = $this->shareMapper->update($this->share); - return $this->share; } /** @@ -366,7 +364,7 @@ public function register( } elseif (in_array($this->share->getType(), Share::CONVERATABLE_PUBLIC_SHARES, true)) { // Convert email and contact shares to external share, if user registers // this should be avoided by the actual use cases, but keep code in case of later changes - $this->convertPersonalPublicShareToExternalShare($userId, $displayName, $emailAddress, $timeZone, $language, $resetInvitation); + $this->convertPersonalPublicShareToExternalShare($userId, $displayName, $emailAddress, $timeZone, $language); } else { throw new ForbiddenException('Share does not allow registering for poll'); From d7135d159976898b0a8c8f90caedcc3c1fd43fc4 Mon Sep 17 00:00:00 2001 From: dartcafe Date: Sat, 21 Sep 2024 13:24:54 +0200 Subject: [PATCH 3/3] =?UTF-8?q?@%=C2=A7$?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: dartcafe --- lib/Service/ShareService.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/Service/ShareService.php b/lib/Service/ShareService.php index f9a0b8988..16c4b4784 100644 --- a/lib/Service/ShareService.php +++ b/lib/Service/ShareService.php @@ -301,7 +301,7 @@ private function convertPersonalPublicShareToExternalShare( // paranoia double check if (!in_array($this->share->getType(), Share::CONVERATABLE_PUBLIC_SHARES, true)) { - return $this->share; + return; } $this->share->setUserId($userId ?? $this->generatePublicUserId()); @@ -348,7 +348,6 @@ public function register( $language = $this->systemService->getGenericLanguage(); $userId = $this->generatePublicUserId(); - $resetInvitation = false; if ($this->share->getType() === Share::TYPE_PUBLIC) { // Create new external share for user, who entered the poll via public link,