diff --git a/lib/AppInfo/Application.php b/lib/AppInfo/Application.php index b1635540ceff074d7f59ffe30d3c1240dd6ec40d..24c5f79574a967db784ba770185bf2fb6e0d5357 100644 --- a/lib/AppInfo/Application.php +++ b/lib/AppInfo/Application.php @@ -31,6 +31,7 @@ use OCA\EcloudAccounts\Listeners\BeforeUserDeletedListener; use OCA\EcloudAccounts\Listeners\PasswordUpdatedListener; use OCA\EcloudAccounts\Listeners\TwoFactorStateChangedListener; use OCA\EcloudAccounts\Listeners\UserChangedListener; +use OCA\EcloudAccounts\Middleware\AccountMiddleware; use OCA\EcloudAccounts\Service\LDAPConnectionService; use OCA\TwoFactorTOTP\Event\StateChanged; use OCP\AppFramework\App; @@ -56,6 +57,8 @@ class Application extends App implements IBootstrap { $context->registerEventListener(UserChangedEvent::class, UserChangedListener::class); $context->registerEventListener(StateChanged::class, TwoFactorStateChangedListener::class); $context->registerEventListener(PasswordUpdatedEvent::class, PasswordUpdatedListener::class); + + $context->registerMiddleware(AccountMiddleware::class); } public function boot(IBootContext $context): void { diff --git a/lib/Controller/AccountController.php b/lib/Controller/AccountController.php index 95c4bb47f04251006e21778128ec8035c092115f..7081ba9a1dc0d0a99f6806cfb2257d515db69837 100644 --- a/lib/Controller/AccountController.php +++ b/lib/Controller/AccountController.php @@ -225,7 +225,7 @@ class AccountController extends Controller { * * @return string|null If validation fails, a string describing the error; otherwise, null. */ - public function validateInput(string $inputName, string $value, ?int $maxLength = null) : ?string { + private function validateInput(string $inputName, string $value, ?int $maxLength = null) : ?string { if ($value === '') { return "$inputName is required."; } diff --git a/lib/Exception/SecurityException.php b/lib/Exception/SecurityException.php new file mode 100644 index 0000000000000000000000000000000000000000..56e22b67b47c8d9b52363078b3981cd9b4406b75 --- /dev/null +++ b/lib/Exception/SecurityException.php @@ -0,0 +1,9 @@ +request = $request; + $this->session = $session; + } + + + public function beforeController($controller, $methodName) { + if (!$controller instanceof AccountController) { + return; + } + + // Add the required params to session for index + if ($methodName === 'index') { + $ipAddr = $this->request->getRemoteAddress(); + $userAgent = $this->request->getHeader(self::HEADER_USER_AGENT); + $this->session->set(self::SESSION_IP_ADDRESS, $ipAddr); + $this->session->set(self::SESSION_USER_AGENT, $userAgent); + return; + } + + if (!in_array($methodName, self::SESSION_METHODS)) { + return; + } + + $ipAddr = $this->request->getRemoteAddress(); + $userAgent = $this->request->getHeader(self::HEADER_USER_AGENT); + if (!$this->isValidSessionParam(self::SESSION_IP_ADDRESS, $ipAddr) + || !$this->isValidSessionParam(self::SESSION_USER_AGENT, $userAgent)) { + throw new SecurityException; + } + } + + public function afterException($controller, $methodName, \Exception $exception) { + if (!$controller instanceof AccountController || !$exception instanceof SecurityException) { + throw $exception; + } + + $response = new DataResponse(); + $response->setStatus(401); + return $response; + } + + private function isValidSessionParam(string $sessionParam, string $value) : bool { + if (!$this->session->exists($sessionParam)) { + return false; + } + if ($this->session->get($sessionParam) !== $value) { + return false; + } + return true; + } +} diff --git a/src/Signup.vue b/src/Signup.vue index ccdd0b5309cd5a8b663efe5092e198ba32364fd4..0bc4009568d217b25a57d12b6c3112b76834a0a4 100644 --- a/src/Signup.vue +++ b/src/Signup.vue @@ -110,8 +110,13 @@ export default { this.showRecoveryEmailForm = false this.showSuccessSection = true } catch (error) { + const genericErrorMessage = 'An error occurred while creating your account!' // Handle network errors and unexpected response structures here - const errorMessage = error.response ? t(this.appName, error.response.data.message) : t(this.appName, error.message) + let errorMessage = error.response ? t(this.appName, error.response.data.message) : t(this.appName, error.message) + if (errorMessage === '') { + // Fallback to generic error message + errorMessage = t(this.appName, genericErrorMessage) + } this.showMessage(errorMessage, 'error') } },