diff --git a/app/Libraries/Aauth.php b/app/Libraries/Aauth.php index 93e7845..1ed0084 100644 --- a/app/Libraries/Aauth.php +++ b/app/Libraries/Aauth.php @@ -133,6 +133,16 @@ class Aauth $this->session = $session; $this->modules = $this->config->modules; + if ($this->config->captchaEnabled) + { + $this->modules = array_merge($this->config->modules, ['CAPTCHA']); + } + + if ($this->config->totpEnabled) + { + $this->modules = array_merge($this->config->modules, ['TOTP']); + } + $this->cachePermIds = []; $this->cacheGroupIds = []; diff --git a/app/Libraries/Aauth/CAPTCHA.php b/app/Libraries/Aauth/CAPTCHA.php new file mode 100644 index 0000000..831e796 --- /dev/null +++ b/app/Libraries/Aauth/CAPTCHA.php @@ -0,0 +1,166 @@ + false, + 'errorCodes' => 'missing-input', + ]; + } + + $request = \Config\Services::request(); + $remoteIp = $request->getIPAddress(); + + if ($this->config->captchaType === 'recaptcha') + { + $siteUrl = 'https://www.google.com/recaptcha/api/siteverify'; + $request = $this->_submitGet( + $siteUrl, + [ + 'secret' => $this->config->captchaSecret, + 'remoteip' => $remoteIp, + 'response' => $response, + 'version' => 'php_1.0.0', + ]); + } + else if ($this->config->captchaType === 'hcaptcha') + { + $siteUrl = 'https://hcaptcha.com/siteverify'; + $request = $this->_submitPost( + $siteUrl, + [ + 'secret' => $this->config->captchaSecret, + 'response' => $response, + 'remoteip' => $remoteIp, + ]); + } + + $answer = json_decode($request, true); + + if (trim($answer['success']) === true) + { + return ['success' => true]; + } + else + { + return [ + 'success' => false, + 'errorCodes' => $answer['error-codes'], + ]; + } + } + + /** + * Generate CAPTCHA HTML + * + * @return string + */ + public function generateCaptchaHtml() + { + $content = ''; + + if ($this->config->loginProtection && $this->config->captchaEnabled) + { + $loginAttemptModel = new LoginAttemptModel(); + + if ($loginAttemptModel->find() >= $this->config->captchaLoginAttempts) + { + $siteKey = $this->config->captchaSiteKey; + + if ($this->config->captchaType === 'recaptcha') + { + $content .= "
"; + $content = ''; + } + else if ($this->config->captchaType === 'hcaptcha') + { + $content = ""; + $content .= ''; + } + } + } + + return $content; + } + + /** + * Submit GET + * + * Submits an HTTP GET to a CAPTCHA server. + * + * @param string $url URL path to CAPTCHA server. + * @param array $data Array of parameters to be sent. + * + * @return array response + */ + private function _submitGet($url, $data) + { + $client = \Config\Services::curlrequest(); + $response = $client->request('GET', $url, [ + 'query' => $data, + ]); + + return $response->getBody(); + } + + /** + * Submit POST + * + * Submits an HTTP POST to a CAPTCHA server. + * + * @param string $url URL path to CAPTCHA server. + * @param array $data Array of parameters to be sent. + * + * @return array response + */ + private function _submitPost($url, $data) + { + $client = \Config\Services::curlrequest(); + $response = $client->request('POST', $url, [ + 'query' => $data, + ]); + + return $response->getBody(); + } +} diff --git a/app/Libraries/Aauth/TOTP.php b/app/Libraries/Aauth/TOTP.php new file mode 100644 index 0000000..ffee837 --- /dev/null +++ b/app/Libraries/Aauth/TOTP.php @@ -0,0 +1,153 @@ +session->user['id']; + } + + $userVariableModel = new UserVariableModel(); + + return $userVariableModel->save($userId, 'totp_secret', $secret, true); + } + + /** + * Generate Unique TOTP Secret + * + * @return string + */ + public function generateUniqueTotpSecret() + { + $stop = false; + + while (! $stop) + { + $secret = OTPHP_TOTP::create(); + + if ($userVariable !== $userVariableModel->where(['data_key' => 'totp_secret', 'data_value' => $secret, 'system' => 1])->getFirstRow('array')) + { + $stop = true; + + return $secret; + } + } + } + + /** + * Generate TOTP QR Code + * + * Generate TOTP QR Code URI by Secret + * + * @param string $secret Secret Key + * + * @return string + */ + public function generateTotpQrCode(string $secret) + { + $totp = OTPHP_TOTP::create($secret); + + return $totp->getQrCodeUri(); + } + + /** + * Verify user TOTP Code + * + * @param integer $totpCode TOTP Code + * @param string $userId User Id + * + * @return boolean + */ + public function verifyUserTotpCode(int $totpCode, string $userId = null) + { + if (! $this->isTotpRequired()) + { + return true; + } + + if (! $userId) + { + $userId = (int) @$this->session->user['id']; + } + + if (empty($totpCode)) + { + $this->error(lang('Aauth.requiredTOTPCode')); + + return false; + } + + $userVariableModel = new UserVariableModel(); + + $totpSecret = $userVariableModel->find($userId, 'totp_secret', true); + $totp = OTPHP_TOTP::create($totpSecret); + + if (! $totp->verify($totpCode)) + { + $this->error(lang('Aauth.invalidTOTPCode')); + + return false; + } + else + { + unset($_SESSION['user']['totp_required']); + + return true; + } + } + + /** + * IS TOTP Required + * + * Checks if User need TOTP verification. + * + * @return boolean + */ + public function isTotpRequired() + { + if (@$this->session->user['totp_required']) + { + return true; + } + + return false; + } +}