Browse Source

Confirm mails only per POST

- this is to avoid automatic confirmation by certain softwares that open
  links

Signed-off-by: Arthur Schiwon <blizzz@arthur-schiwon.de>
Arthur Schiwon 2 years ago
parent
commit
0dee717c94

+ 2 - 1
apps/provisioning_api/appinfo/routes.php

@@ -76,6 +76,7 @@ return [
 	],
 	'routes' => [
 		// Verification
-		['name' => 'Verification#verifyMail', 'url' => '/mailVerification/{key}/{token}/{userId}', 'verb' => 'GET'],
+		['name' => 'Verification#showVerifyMail', 'url' => '/mailVerification/{key}/{token}/{userId}', 'verb' => 'GET'],
+		['name' => 'Verification#verifyMail', 'url' => '/mailVerification/{key}/{token}/{userId}', 'verb' => 'POST'],
 	]
 ];

+ 24 - 2
apps/provisioning_api/lib/Controller/VerificationController.php

@@ -74,6 +74,27 @@ class VerificationController extends Controller {
 
 	/**
 	 * @NoCSRFRequired
+	 * @NoAdminRequired
+	 * @NoSubAdminRequired
+	 */
+	public function showVerifyMail(string $token, string $userId, string $key) {
+		if ($this->userSession->getUser()->getUID() !== $userId) {
+			// not a public page, hence getUser() must return an IUser
+			throw new InvalidArgumentException('Logged in user is not mail address owner');
+		}
+		$email = $this->crypto->decrypt($key);
+
+		return new TemplateResponse(
+			'core', 'confirmation', [
+				'title' => $this->l10n->t('Email confirmation'),
+				'message' => $this->l10n->t('To enable the email address %s please click the button below.', [$email]),
+				'action' => $this->l10n->t('Confirm'),
+			], TemplateResponse::RENDER_AS_GUEST);
+	}
+
+	/**
+	 * @NoAdminRequired
+	 * @NoSubAdminRequired
 	 */
 	public function verifyMail(string $token, string $userId, string $key) {
 		try {
@@ -95,6 +116,7 @@ class VerificationController extends Controller {
 			}
 			$emailProperty->setLocallyVerified(IAccountManager::VERIFIED);
 			$this->accountManager->updateAccount($userAccount);
+			$this->verificationToken->delete($token, $user, 'verifyMail' . $ref);
 		} catch (InvalidTokenException $e) {
 			$error = $e->getCode() === InvalidTokenException::TOKEN_EXPIRED
 				? $this->l10n->t('Could not verify mail because the token is expired.')
@@ -109,13 +131,13 @@ class VerificationController extends Controller {
 			return new TemplateResponse(
 				'core', 'error', [
 					'errors' => [['error' => $error]]
-				], 'guest');
+				], TemplateResponse::RENDER_AS_GUEST);
 		}
 
 		return new TemplateResponse(
 			'core', 'success', [
 				'title' => $this->l10n->t('Email confirmation successful'),
 				'message' => $this->l10n->t('Email confirmation successful'),
-			], 'guest');
+			], TemplateResponse::RENDER_AS_GUEST);
 	}
 }

+ 20 - 0
core/templates/confirmation.php

@@ -0,0 +1,20 @@
+<?php
+/** @var array $_ */
+/** @var \OCP\IL10N $l */
+/** @var \OCP\Defaults $theme */
+
+?>
+
+<div class="update">
+	<form method="POST" action="<?php print_unescaped($_['targetUrl']);?>">
+		<h2><?php p($_['title']) ?></h2>
+		<p><?php p($_['message']) ?></p>
+		<div class="buttons">
+			<input type="submit" class="primary" value="<?php p($_['action']); ?>">
+		</div>
+		<?php foreach ($_['parameters'] as $name => $value) {?>
+			<input type="hidden" name="<?php p($name); ?>" value="<?php p($value); ?>">
+		<?php } ?>
+		<input type="hidden" name="requesttoken" value="<?php p($_['requesttoken']) ?>">
+	</form>
+</div>

+ 4 - 0
lib/private/Security/VerificationToken/VerificationToken.php

@@ -122,4 +122,8 @@ class VerificationToken implements IVerificationToken {
 
 		return $token;
 	}
+
+	public function delete(string $token, IUser $user, string $subject): void {
+		$this->config->deleteUserValue($user->getUID(), 'core', $subject);
+	}
 }

+ 7 - 0
lib/public/Security/VerificationToken/IVerificationToken.php

@@ -52,4 +52,11 @@ interface IVerificationToken {
 	 * @since 23.0.0
 	 */
 	public function create(IUser $user, string $subject, string $passwordPrefix = ''): string;
+
+	/**
+	 * Deletes the token identified by the provided parameters
+	 *
+	 * @since 23.0.0
+	 */
+	public function delete(string $token, IUser $user, string $subject): void;
 }