summaryrefslogtreecommitdiffstats
path: root/core/Controller
diff options
context:
space:
mode:
Diffstat (limited to 'core/Controller')
-rw-r--r--core/Controller/LostController.php145
-rw-r--r--core/Controller/SvgController.php5
-rw-r--r--core/Controller/TwoFactorChallengeController.php11
-rw-r--r--core/Controller/UnifiedSearchController.php18
4 files changed, 77 insertions, 102 deletions
diff --git a/core/Controller/LostController.php b/core/Controller/LostController.php
index bed96eeec83..87a629b9ee8 100644
--- a/core/Controller/LostController.php
+++ b/core/Controller/LostController.php
@@ -40,7 +40,6 @@ use OC\Core\Exception\ResetPasswordException;
use OCP\AppFramework\Controller;
use OCP\AppFramework\Http\JSONResponse;
use OCP\AppFramework\Http\TemplateResponse;
-use OCP\AppFramework\Utility\ITimeFactory;
use OCP\Defaults;
use OCP\Encryption\IEncryptionModule;
use OCP\Encryption\IManager;
@@ -54,8 +53,8 @@ use OCP\IURLGenerator;
use OCP\IUser;
use OCP\IUserManager;
use OCP\Mail\IMailer;
-use OCP\Security\ICrypto;
-use OCP\Security\ISecureRandom;
+use OCP\Security\VerificationToken\InvalidTokenException;
+use OCP\Security\VerificationToken\IVerificationToken;
use function array_filter;
use function count;
use function reset;
@@ -82,67 +81,46 @@ class LostController extends Controller {
protected $encryptionManager;
/** @var IConfig */
protected $config;
- /** @var ISecureRandom */
- protected $secureRandom;
/** @var IMailer */
protected $mailer;
- /** @var ITimeFactory */
- protected $timeFactory;
- /** @var ICrypto */
- protected $crypto;
/** @var ILogger */
private $logger;
/** @var Manager */
private $twoFactorManager;
/** @var IInitialStateService */
private $initialStateService;
-
- /**
- * @param string $appName
- * @param IRequest $request
- * @param IURLGenerator $urlGenerator
- * @param IUserManager $userManager
- * @param Defaults $defaults
- * @param IL10N $l10n
- * @param IConfig $config
- * @param ISecureRandom $secureRandom
- * @param string $defaultMailAddress
- * @param IManager $encryptionManager
- * @param IMailer $mailer
- * @param ITimeFactory $timeFactory
- * @param ICrypto $crypto
- */
- public function __construct($appName,
- IRequest $request,
- IURLGenerator $urlGenerator,
- IUserManager $userManager,
- Defaults $defaults,
- IL10N $l10n,
- IConfig $config,
- ISecureRandom $secureRandom,
- $defaultMailAddress,
- IManager $encryptionManager,
- IMailer $mailer,
- ITimeFactory $timeFactory,
- ICrypto $crypto,
- ILogger $logger,
- Manager $twoFactorManager,
- IInitialStateService $initialStateService) {
+ /** @var IVerificationToken */
+ private $verificationToken;
+
+ public function __construct(
+ $appName,
+ IRequest $request,
+ IURLGenerator $urlGenerator,
+ IUserManager $userManager,
+ Defaults $defaults,
+ IL10N $l10n,
+ IConfig $config,
+ $defaultMailAddress,
+ IManager $encryptionManager,
+ IMailer $mailer,
+ ILogger $logger,
+ Manager $twoFactorManager,
+ IInitialStateService $initialStateService,
+ IVerificationToken $verificationToken
+ ) {
parent::__construct($appName, $request);
$this->urlGenerator = $urlGenerator;
$this->userManager = $userManager;
$this->defaults = $defaults;
$this->l10n = $l10n;
- $this->secureRandom = $secureRandom;
$this->from = $defaultMailAddress;
$this->encryptionManager = $encryptionManager;
$this->config = $config;
$this->mailer = $mailer;
- $this->timeFactory = $timeFactory;
- $this->crypto = $crypto;
$this->logger = $logger;
$this->twoFactorManager = $twoFactorManager;
$this->initialStateService = $initialStateService;
+ $this->verificationToken = $verificationToken;
}
/**
@@ -156,22 +134,24 @@ class LostController extends Controller {
* @return TemplateResponse
*/
public function resetform($token, $userId) {
- if ($this->config->getSystemValue('lost_password_link', '') !== '') {
- return new TemplateResponse('core', 'error', [
- 'errors' => [['error' => $this->l10n->t('Password reset is disabled')]]
- ],
- 'guest'
- );
- }
-
try {
$this->checkPasswordResetToken($token, $userId);
} catch (\Exception $e) {
- return new TemplateResponse(
- 'core', 'error', [
- "errors" => [["error" => $e->getMessage()]]
- ],
- 'guest'
+ if ($this->config->getSystemValue('lost_password_link', '') !== 'disabled'
+ || ($e instanceof InvalidTokenException
+ && !in_array($e->getCode(), [InvalidTokenException::TOKEN_NOT_FOUND, InvalidTokenException::USER_UNKNOWN]))
+ ) {
+ return new TemplateResponse(
+ 'core', 'error', [
+ "errors" => [["error" => $e->getMessage()]]
+ ],
+ TemplateResponse::RENDER_AS_GUEST
+ );
+ }
+ return new TemplateResponse('core', 'error', [
+ 'errors' => [['error' => $this->l10n->t('Password reset is disabled')]]
+ ],
+ TemplateResponse::RENDER_AS_GUEST
);
}
$this->initialStateService->provideInitialState('core', 'resetPasswordUser', $userId);
@@ -192,36 +172,15 @@ class LostController extends Controller {
* @param string $userId
* @throws \Exception
*/
- protected function checkPasswordResetToken($token, $userId) {
- $user = $this->userManager->get($userId);
- if ($user === null || !$user->isEnabled()) {
- throw new \Exception($this->l10n->t('Couldn\'t reset password because the token is invalid'));
- }
-
- $encryptedToken = $this->config->getUserValue($userId, 'core', 'lostpassword', null);
- if ($encryptedToken === null) {
- throw new \Exception($this->l10n->t('Couldn\'t reset password because the token is invalid'));
- }
-
+ protected function checkPasswordResetToken(string $token, string $userId): void {
try {
- $mailAddress = !is_null($user->getEMailAddress()) ? $user->getEMailAddress() : '';
- $decryptedToken = $this->crypto->decrypt($encryptedToken, $mailAddress.$this->config->getSystemValue('secret'));
- } catch (\Exception $e) {
- throw new \Exception($this->l10n->t('Couldn\'t reset password because the token is invalid'));
- }
-
- $splittedToken = explode(':', $decryptedToken);
- if (count($splittedToken) !== 2) {
- throw new \Exception($this->l10n->t('Couldn\'t reset password because the token is invalid'));
- }
-
- if ($splittedToken[0] < ($this->timeFactory->getTime() - 60 * 60 * 24 * 7) ||
- $user->getLastLogin() > $splittedToken[0]) {
- throw new \Exception($this->l10n->t('Couldn\'t reset password because the token is expired'));
- }
-
- if (!hash_equals($splittedToken[1], $token)) {
- throw new \Exception($this->l10n->t('Couldn\'t reset password because the token is invalid'));
+ $user = $this->userManager->get($userId);
+ $this->verificationToken->check($token, $user, 'lostpassword', $user ? $user->getEMailAddress() : '', true);
+ } catch (InvalidTokenException $e) {
+ $error = $e->getCode() === InvalidTokenException::TOKEN_EXPIRED
+ ? $this->l10n->t('Could not reset password because the token is expired')
+ : $this->l10n->t('Could not reset password because the token is invalid');
+ throw new \Exception($error, (int)$e->getCode(), $e);
}
}
@@ -285,10 +244,6 @@ class LostController extends Controller {
* @return array
*/
public function setPassword($token, $userId, $password, $proceed) {
- if ($this->config->getSystemValue('lost_password_link', '') !== '') {
- return $this->error($this->l10n->t('Password reset is disabled'));
- }
-
if ($this->encryptionManager->isEnabled() && !$proceed) {
$encryptionModules = $this->encryptionManager->getEncryptionModules();
foreach ($encryptionModules as $module) {
@@ -343,15 +298,7 @@ class LostController extends Controller {
// secret being the users' email address appended with the system secret.
// This makes the token automatically invalidate once the user changes
// their email address.
- $token = $this->secureRandom->generate(
- 21,
- ISecureRandom::CHAR_DIGITS.
- ISecureRandom::CHAR_LOWER.
- ISecureRandom::CHAR_UPPER
- );
- $tokenValue = $this->timeFactory->getTime() .':'. $token;
- $encryptedValue = $this->crypto->encrypt($tokenValue, $email . $this->config->getSystemValue('secret'));
- $this->config->setUserValue($user->getUID(), 'core', 'lostpassword', $encryptedValue);
+ $token = $this->verificationToken->create($user, 'lostpassword', $email);
$link = $this->urlGenerator->linkToRouteAbsolute('core.lost.resetform', ['userId' => $user->getUID(), 'token' => $token]);
diff --git a/core/Controller/SvgController.php b/core/Controller/SvgController.php
index ea73ba118d9..17f16dd48e6 100644
--- a/core/Controller/SvgController.php
+++ b/core/Controller/SvgController.php
@@ -31,6 +31,7 @@ declare(strict_types=1);
*/
namespace OC\Core\Controller;
+use OC\Files\Filesystem;
use OC\Template\IconsCacher;
use OCP\App\AppPathNotFoundException;
use OCP\App\IAppManager;
@@ -117,6 +118,10 @@ class SvgController extends Controller {
* @return DataDisplayResponse|NotFoundResponse
*/
private function getSvg(string $path, string $color, string $fileName) {
+ if (!Filesystem::isValidPath($path)) {
+ return new NotFoundResponse();
+ }
+
if (!file_exists($path)) {
return new NotFoundResponse();
}
diff --git a/core/Controller/TwoFactorChallengeController.php b/core/Controller/TwoFactorChallengeController.php
index f23df5aea28..8f82346c050 100644
--- a/core/Controller/TwoFactorChallengeController.php
+++ b/core/Controller/TwoFactorChallengeController.php
@@ -34,6 +34,7 @@ use OCP\Authentication\TwoFactorAuth\IActivatableAtLogin;
use OCP\Authentication\TwoFactorAuth\IProvider;
use OCP\Authentication\TwoFactorAuth\IProvidesCustomCSP;
use OCP\Authentication\TwoFactorAuth\TwoFactorException;
+use OCP\ILogger;
use OCP\IRequest;
use OCP\ISession;
use OCP\IURLGenerator;
@@ -50,6 +51,9 @@ class TwoFactorChallengeController extends Controller {
/** @var ISession */
private $session;
+ /** @var ILogger */
+ private $logger;
+
/** @var IURLGenerator */
private $urlGenerator;
@@ -60,14 +64,16 @@ class TwoFactorChallengeController extends Controller {
* @param IUserSession $userSession
* @param ISession $session
* @param IURLGenerator $urlGenerator
+ * @param ILogger $logger
*/
public function __construct($appName, IRequest $request, Manager $twoFactorManager, IUserSession $userSession,
- ISession $session, IURLGenerator $urlGenerator) {
+ ISession $session, IURLGenerator $urlGenerator, ILogger $logger) {
parent::__construct($appName, $request);
$this->twoFactorManager = $twoFactorManager;
$this->userSession = $userSession;
$this->session = $session;
$this->urlGenerator = $urlGenerator;
+ $this->logger = $logger;
}
/**
@@ -207,6 +213,9 @@ class TwoFactorChallengeController extends Controller {
$this->session->set('two_factor_auth_error_message', $e->getMessage());
}
+ $ip = $this->request->getRemoteAddress();
+ $uid = $user->getUID();
+ $this->logger->warning("Two-factor challenge failed: $uid (Remote IP: $ip)");
$this->session->set('two_factor_auth_error', true);
return new RedirectResponse($this->urlGenerator->linkToRoute('core.TwoFactorChallenge.showChallenge', [
'challengeProviderId' => $provider->getId(),
diff --git a/core/Controller/UnifiedSearchController.php b/core/Controller/UnifiedSearchController.php
index 93fbb323ee5..bfed6d606ae 100644
--- a/core/Controller/UnifiedSearchController.php
+++ b/core/Controller/UnifiedSearchController.php
@@ -33,6 +33,7 @@ use OCP\AppFramework\OCSController;
use OCP\AppFramework\Http;
use OCP\AppFramework\Http\DataResponse;
use OCP\IRequest;
+use OCP\IURLGenerator;
use OCP\IUserSession;
use OCP\Route\IRouter;
use OCP\Search\ISearchQuery;
@@ -49,15 +50,20 @@ class UnifiedSearchController extends OCSController {
/** @var IRouter */
private $router;
+ /** @var IURLGenerator */
+ private $urlGenerator;
+
public function __construct(IRequest $request,
IUserSession $userSession,
SearchComposer $composer,
- IRouter $router) {
+ IRouter $router,
+ IURLGenerator $urlGenerator) {
parent::__construct('core', $request);
$this->composer = $composer;
$this->userSession = $userSession;
$this->router = $router;
+ $this->urlGenerator = $urlGenerator;
}
/**
@@ -123,9 +129,17 @@ class UnifiedSearchController extends OCSController {
if ($url !== '') {
$urlParts = parse_url($url);
+ $urlPath = $urlParts['path'];
+
+ // Optionally strip webroot from URL. Required for route matching on setups
+ // with Nextcloud in a webserver subfolder (webroot).
+ $webroot = $this->urlGenerator->getWebroot();
+ if ($webroot !== '' && substr($urlPath, 0, strlen($webroot)) === $webroot) {
+ $urlPath = substr($urlPath, strlen($webroot));
+ }
try {
- $parameters = $this->router->findMatchingRoute($urlParts['path']);
+ $parameters = $this->router->findMatchingRoute($urlPath);
// contacts.PageController.index => contacts.Page.index
$route = $parameters['caller'];