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: class Manager extends \Aurora\System\Managers\AbstractManager
18: {
19: protected $recaptchaToken = null;
20: protected $allowRecaptchaCheckOnLogin = true;
21:
22: /**
23: * @param \Aurora\System\Module\AbstractModule $oModule
24: */
25: public function __construct(\Aurora\System\Module\AbstractModule $oModule = null)
26: {
27: parent::__construct($oModule);
28: }
29:
30: public function isRecaptchaEnabledForIP()
31: {
32: return !in_array(\Aurora\System\Utils::getClientIp(), $this->oModule->getConfig('WhitelistIPs', []));
33: }
34:
35: public function memorizeRecaptchaWebclientPluginToken($aArgs)
36: {
37: if (isset($aArgs['RecaptchaWebclientPluginToken']) && !empty($aArgs['RecaptchaWebclientPluginToken'])) {
38: $this->recaptchaToken = $aArgs['RecaptchaWebclientPluginToken'];
39: }
40: }
41:
42: public function disableRecaptchaCheckOnLogin()
43: {
44: $this->allowRecaptchaCheckOnLogin = false;
45: }
46:
47: public function needToCheckRecaptchaOnLogin()
48: {
49: if (!$this->allowRecaptchaCheckOnLogin) {
50: return false;
51: }
52:
53: if (!$this->isRecaptchaEnabledForIP()) {
54: return false;
55: }
56:
57: $authErrorCount = isset($_COOKIE['auth-error']) ? (int) $_COOKIE['auth-error'] : 0;
58: // If the user has exceeded the number of authentication attempts
59: if ($authErrorCount >= $this->oModule->getConfig('LimitCount', 0)) {
60: return true;
61: }
62:
63: return false;
64: }
65:
66: public function checkIfRecaptchaError()
67: {
68: if ($this->recaptchaToken === null) {
69: \Aurora\System\Api::Log('RECAPTCHA error: no token');
70: return [
71: 'Error' => [
72: 'Code' => Enums\ErrorCodes::RecaptchaVerificationError,
73: 'ModuleName' => $this->oModule->GetName(),
74: 'Override' => true
75: ]
76: ];
77: }
78:
79: $privateKey = $this->oModule->getConfig('PrivateKey', '');
80: $recaptcha = new \ReCaptcha\ReCaptcha($privateKey, $this->getRequestMethod());
81: $response = $recaptcha->verify($this->recaptchaToken);
82: if (!$response->isSuccess()) {
83: \Aurora\System\Api::Log('RECAPTCHA error: ' . implode(', ', $response->getErrorCodes()));
84: return [
85: 'Error' => [
86: 'Code' => Enums\ErrorCodes::RecaptchaUnknownError,
87: 'ModuleName' => $this->oModule->GetName(),
88: 'Override' => true
89: ]
90: ];
91: }
92:
93: return false;
94: }
95:
96: public function clearAuthErrorCount()
97: {
98: //If the user is authenticated, reset the counter for unsuccessful attempts.
99: if (isset($_COOKIE['auth-error'])) {
100: @\setcookie('auth-error', 0, \strtotime('+1 hour'), \Aurora\System\Api::getCookiePath(), null, \Aurora\System\Api::getCookieSecure());
101: }
102: }
103:
104: public function incrementAuthErrorCount()
105: {
106: $iAuthErrorCount = isset($_COOKIE['auth-error']) ? ((int) $_COOKIE['auth-error'] + 1) : 1;
107: @\setcookie(
108: 'auth-error',
109: $iAuthErrorCount,
110: \strtotime('+1 hour'),
111: \Aurora\System\Api::getCookiePath(),
112: null,
113: \Aurora\System\Api::getCookieSecure()
114: );
115: }
116:
117: private function getRequestMethod()
118: {
119: $sRequestMethod = $this->oModule->getConfig('RequestMethod', Enums\RequestMethods::SocketPost);
120: switch ($sRequestMethod) {
121: case Enums\RequestMethods::CurlPost:
122: return new \ReCaptcha\RequestMethod\CurlPost();
123: case Enums\RequestMethods::Post:
124: return new \ReCaptcha\RequestMethod\Post();
125: case Enums\RequestMethods::SocketPost:
126: default:
127: return new \ReCaptcha\RequestMethod\SocketPost();
128: }
129: }
130: }
131: