1: <?php
2: /**
3: * This code is licensed under AGPLv3 license or Afterlogic Software License
4: * if commercial version of the product was purchased.
5: * For full statements of the licenses see LICENSE-AFTERLOGIC and LICENSE-AGPL3 files.
6: */
7:
8: namespace Aurora\Modules\RecaptchaWebclientPlugin;
9:
10: /**
11: * @license https://www.gnu.org/licenses/agpl-3.0.html AGPL-3.0
12: * @license https://afterlogic.com/products/common-licensing Afterlogic Software License
13: * @copyright Copyright (c) 2023, Afterlogic Corp.
14: *
15: * @ignore
16: *
17: * @property Module $oModule
18: */
19: class Manager extends \Aurora\System\Managers\AbstractManager
20: {
21: protected $recaptchaToken = null;
22: protected $allowRecaptchaCheckOnLogin = true;
23:
24: /**
25: * @param \Aurora\System\Module\AbstractModule $oModule
26: */
27: public function __construct(\Aurora\System\Module\AbstractModule $oModule = null)
28: {
29: parent::__construct($oModule);
30: }
31:
32: public function isRecaptchaEnabledForIP()
33: {
34: return !in_array(\Aurora\System\Utils::getClientIp(), $this->oModule->oModuleSettings->WhitelistIPs);
35: }
36:
37: public function memorizeRecaptchaWebclientPluginToken($aArgs)
38: {
39: if (isset($aArgs['RecaptchaWebclientPluginToken']) && !empty($aArgs['RecaptchaWebclientPluginToken'])) {
40: $this->recaptchaToken = $aArgs['RecaptchaWebclientPluginToken'];
41: }
42: }
43:
44: public function disableRecaptchaCheckOnLogin()
45: {
46: $this->allowRecaptchaCheckOnLogin = false;
47: }
48:
49: public function needToCheckRecaptchaOnLogin()
50: {
51: if (!$this->allowRecaptchaCheckOnLogin) {
52: return false;
53: }
54:
55: if (!$this->isRecaptchaEnabledForIP()) {
56: return false;
57: }
58:
59: $authErrorCount = isset($_COOKIE['auth-error']) ? (int) $_COOKIE['auth-error'] : 0;
60: // If the user has exceeded the number of authentication attempts
61: if ($authErrorCount >= $this->oModule->oModuleSettings->LimitCount) {
62: return true;
63: }
64:
65: return false;
66: }
67:
68: public function checkIfRecaptchaError()
69: {
70: if ($this->recaptchaToken === null) {
71: \Aurora\System\Api::Log('RECAPTCHA error: no token');
72: return [
73: 'Error' => [
74: 'Code' => Enums\ErrorCodes::RecaptchaVerificationError,
75: 'ModuleName' => $this->oModule->GetName(),
76: 'Override' => true
77: ]
78: ];
79: }
80:
81: $privateKey = $this->oModule->oModuleSettings->PrivateKey;
82: $recaptcha = new \ReCaptcha\ReCaptcha($privateKey, $this->getRequestMethod());
83: $response = $recaptcha->verify($this->recaptchaToken);
84: if (!$response->isSuccess()) {
85: \Aurora\System\Api::Log('RECAPTCHA error: ' . implode(', ', $response->getErrorCodes()));
86: return [
87: 'Error' => [
88: 'Code' => Enums\ErrorCodes::RecaptchaUnknownError,
89: 'ModuleName' => $this->oModule->GetName(),
90: 'Override' => true
91: ]
92: ];
93: }
94:
95: return false;
96: }
97:
98: public function clearAuthErrorCount()
99: {
100: //If the user is authenticated, reset the counter for unsuccessful attempts.
101: if (isset($_COOKIE['auth-error'])) {
102: \Aurora\System\Api::setCookie(
103: 'auth-error',
104: 0,
105: \strtotime('+1 hour'),
106: false
107: );
108: }
109: }
110:
111: public function incrementAuthErrorCount()
112: {
113: $iAuthErrorCount = isset($_COOKIE['auth-error']) ? ((int) $_COOKIE['auth-error'] + 1) : 1;
114: \Aurora\System\Api::setCookie(
115: 'auth-error',
116: $iAuthErrorCount,
117: \strtotime('+1 hour'),
118: false
119: );
120: }
121:
122: private function getRequestMethod()
123: {
124: $sRequestMethod = $this->oModule->oModuleSettings->RequestMethod;
125: switch ($sRequestMethod) {
126: case Enums\RequestMethods::CurlPost:
127: return new \ReCaptcha\RequestMethod\CurlPost();
128: case Enums\RequestMethods::Post:
129: return new \ReCaptcha\RequestMethod\Post();
130: case Enums\RequestMethods::SocketPost:
131: default:
132: return new \ReCaptcha\RequestMethod\SocketPost();
133: }
134: }
135: }
136: