diff --git a/plugin/whispeakauth/Controller/AuthenticationRequestController.php b/plugin/whispeakauth/Controller/AuthenticationRequestController.php new file mode 100644 index 0000000000..adb2874274 --- /dev/null +++ b/plugin/whispeakauth/Controller/AuthenticationRequestController.php @@ -0,0 +1,295 @@ +user2fa)) { + $this->user = api_get_user_entity($this->user2fa); + } elseif (isset($_POST['username'])) { + $this->user = \UserManager::getRepository()->findOneBy(['username' => $_POST['username']]); + } else { + $this->user = api_get_user_entity(api_get_user_id()); + } + } + + /** + * @return bool + */ + protected function userIsAllowed() + { + $userId = api_get_user_id(); + $this->user2fa = \ChamiloSession::read(\WhispeakAuthPlugin::SESSION_2FA_USER, 0); + + if (!empty($this->user2fa) || !empty($userId)) { + return !empty($_FILES['audio']); + } + + return !empty($_POST['username']) && !empty($_FILES['audio']); + } + + /** + * @throws \Exception + * + * @return string + */ + protected function doApiRequest() + { + $failedLogins = \ChamiloSession::read(\WhispeakAuthPlugin::SESSION_FAILED_LOGINS, 0); + $maxAttempts = $this->plugin->getMaxAttempts(); + + if ($maxAttempts && $failedLogins >= $maxAttempts) { + return \Display::return_message($this->plugin->get_lang('MaxAttemptsReached'), 'warning'); + } + + $wsId = \WhispeakAuthPlugin::getAuthUidValue($this->user->getId()); + + if (empty($wsId)) { + return \Display::return_message($this->plugin->get_lang('SpeechAuthNotEnrolled'), 'warning'); + } + + $token = $this->createSessionToken(); + $success = $this->performAuthentication($token, $wsId->getValue()); + + /** @var array $lpItemInfo */ + $lpItemInfo = \ChamiloSession::read(\WhispeakAuthPlugin::SESSION_LP_ITEM, []); + /** @var array $quizQuestionInfo */ + $quizQuestionInfo = \ChamiloSession::read(\WhispeakAuthPlugin::SESSION_QUIZ_QUESTION, []); + + $return = ''; + + $message = $this->plugin->get_lang('AuthentifySuccess'); + + if (!$success) { + if (!empty($lpItemInfo)) { + $this->plugin->addAttemptInLearningPath( + LogEvent::STATUS_FAILED, + $this->user->getId(), + $lpItemInfo['lp_item'], + $lpItemInfo['lp'] + ); + } + + if (!empty($quizQuestionInfo)) { + $this->plugin->addAttemptInQuiz( + LogEvent::STATUS_FAILED, + $this->user->getId(), + $quizQuestionInfo['question'], + $quizQuestionInfo['quiz'] + ); + } + + $message = $this->plugin->get_lang('AuthentifyFailed'); + + \ChamiloSession::write(\WhispeakAuthPlugin::SESSION_FAILED_LOGINS, ++$failedLogins); + + if ($maxAttempts && $failedLogins >= $maxAttempts) { + $message .= PHP_EOL + .''.$this->plugin->get_lang('MaxAttemptsReached').'' + .PHP_EOL + .'
' + .$this->plugin->get_lang('LoginWithUsernameAndPassword') + .''; + + if (!empty($user2fa)) { + \Display::addFlash(\Display::return_message($message, 'warning', false)); + } + } else { + $message .= PHP_EOL.$this->plugin->get_lang('TryAgain'); + + if ('true' === api_get_setting('allow_lostpassword')) { + $message .= '
' + .\Display::url( + get_lang('LostPassword'), + api_get_path(WEB_CODE_PATH).'auth/lostPassword.php', + ['target' => $lpItemInfo ? '_top' : '_self'] + ); + } + } + } + + $return .= \Display::return_message( + $message, + $success ? 'success' : 'warning', + false + ); + + if (!$success && $maxAttempts && $failedLogins >= $maxAttempts) { + \ChamiloSession::erase(\WhispeakAuthPlugin::SESSION_FAILED_LOGINS); + + if (!empty($lpItemInfo)) { + $return .= ''; + + return $return; + } + + if (!empty($quizQuestionInfo)) { + $url = api_get_path(WEB_CODE_PATH).'exercise/exercise_submit.php?'.$quizQuestionInfo['url_params']; + + \ChamiloSession::write(\WhispeakAuthPlugin::SESSION_AUTH_PASSWORD, true); + + $return .= ""; + + exit; + } + + $return .= ''; + + return $return; + } + + if ($success) { + \ChamiloSession::erase(\WhispeakAuthPlugin::SESSION_SENTENCE_TEXT); + \ChamiloSession::erase(\WhispeakAuthPlugin::SESSION_FAILED_LOGINS); + + if (!empty($lpItemInfo)) { + \ChamiloSession::erase(\WhispeakAuthPlugin::SESSION_LP_ITEM); + \ChamiloSession::erase(\WhispeakAuthPlugin::SESSION_2FA_USER); + + $this->plugin->addAttemptInLearningPath( + LogEvent::STATUS_SUCCESS, + $this->user->getId(), + $lpItemInfo['lp_item'], + $lpItemInfo['lp'] + ); + + $return .= ''; + + return $return; + } + + if (!empty($quizQuestionInfo)) { + $quizQuestionInfo['passed'] = true; + $url = api_get_path(WEB_CODE_PATH).'exercise/exercise_submit.php?'.$quizQuestionInfo['url_params']; + + \ChamiloSession::write(\WhispeakAuthPlugin::SESSION_QUIZ_QUESTION, $quizQuestionInfo); + + $this->plugin->addAttemptInQuiz( + LogEvent::STATUS_SUCCESS, + $this->user->getId(), + $quizQuestionInfo['question'], + $quizQuestionInfo['quiz'] + ); + + $return .= ''; + + return $return; + } + + $loggedUser = [ + 'user_id' => $this->user->getId(), + 'status' => $this->user->getStatus(), + 'uidReset' => true, + ]; + + if (empty($user2fa)) { + \ChamiloSession::write(\WhispeakAuthPlugin::SESSION_2FA_USER, $this->user->getId()); + } + + \ChamiloSession::erase(\WhispeakAuthPlugin::SESSION_FAILED_LOGINS); + \ChamiloSession::write('_user', $loggedUser); + \Login::init_user($this->user->getId(), true); + + $return .= ''; + } + + return $return; + } + + /** + * @throws \Exception + * + * @return string + */ + private function createSessionToken() + { + $client = new Client(); + $response = $client->get( + "{$this->apiEndpoint}/auth", + [ + 'headers' => [ + 'Authorization' => "Bearer {$this->apiKey}", + ], + 'json' => [], + 'query' => [ + 'lang' => \WhispeakAuthPlugin::getLanguageIsoCode($this->user->getLanguage()), + ], + ] + ); + + $bodyContents = $response->getBody()->getContents(); + $json = json_decode($bodyContents, true); + + switch ($response->getStatusCode()) { + case 200: + return $json['token']; + case 400: + case 401: + case 403: + throw new \Exception($json['message']); + } + } + + /** + * @param string $token + * @param string $wsId + * + * @throws \Exception + * + * @return bool + */ + private function performAuthentication($token, $wsId) + { + $client = new Client(); + $response = $client->post( + "{$this->apiEndpoint}/auth", + [ + 'headers' => [ + 'Authorization' => "Bearer $token", + ], + 'multipart' => [ + [ + 'name' => 'speaker', + 'contents' => $wsId, + ], + [ + 'name' => 'file', + 'contents' => fopen($this->audioFilePath, 'r'), + 'filename' => basename($this->audioFilePath), + ], + ], + ] + ); + + $bodyContents = $response->getBody()->getContents(); + $json = json_decode($bodyContents, true); + + switch ($response->getStatusCode()) { + case 200: + return true; + case 419: + throw new \Exception($this->plugin->get_lang('TryAgain')); + default: + throw new \Exception($json['message']); + } + } +} diff --git a/plugin/whispeakauth/Controller/BaseRequestController.php b/plugin/whispeakauth/Controller/BaseRequestController.php index bda5c93c68..3be3d8104e 100644 --- a/plugin/whispeakauth/Controller/BaseRequestController.php +++ b/plugin/whispeakauth/Controller/BaseRequestController.php @@ -5,6 +5,7 @@ namespace Chamilo\PluginBundle\WhispeakAuth\Controller; use FFMpeg\FFMpeg; use FFMpeg\Format\Audio\Wav; +use GuzzleHttp\Exception\ClientException; /** * Class BaseRequestController. @@ -61,10 +62,6 @@ abstract class BaseRequestController } $this->plugin->protectTool(false); - - if (empty($this->user)) { - throw new \Exception(get_lang('NoUser')); - } } /** @@ -99,8 +96,12 @@ abstract class BaseRequestController public function process() { try { - $this->setUser(); $this->protect(); + $this->setUser(); + + if (empty($this->user)) { + throw new \Exception(get_lang('NoUser')); + } $this->uploadAudioFile(); diff --git a/plugin/whispeakauth/WhispeakAuthRequest.php b/plugin/whispeakauth/WhispeakAuthRequest.php index 199a27016a..89125fb999 100644 --- a/plugin/whispeakauth/WhispeakAuthRequest.php +++ b/plugin/whispeakauth/WhispeakAuthRequest.php @@ -10,85 +10,6 @@ class WhispeakAuthRequest { const API_URL = 'http://api.whispeak.io:8080/v1.1/'; - /** - * @param WhispeakAuthPlugin $plugin - * - * @throws Exception - * - * @return string - */ - public static function activityId(WhispeakAuthPlugin $plugin) - { - $headers = [ - "Authorization: Bearer {$plugin->getAccessToken()}", - ]; - - $result = self::doGet('activityid', $headers); - - if (empty($result['activity_id'])) { - throw new Exception(get_lang('BadFormData')); - } - - return $result['activity_id']; - } - - /** - * @param WhispeakAuthPlugin $plugin - * - * @throws Exception - * - * @return string - */ - public static function authenticateSentence(WhispeakAuthPlugin $plugin) - { - $headers = [ - "Authorization: Bearer ".$plugin->getAccessToken(), - ]; - - $result = self::doGet('authenticatesentence', $headers); - - if (empty($result['text'])) { - throw new Exception(get_lang('BadFormData')); - } - - return $result['text']; - } - - /** - * @param WhispeakAuthPlugin $plugin - * @param string $wsId - * @param string $text Sentence text used to create the voice file. - * @param string $filePath - * - * @throws Exception - * - * @return array - */ - public static function authentify(WhispeakAuthPlugin $plugin, $wsId, $text, $filePath) - { - $headers = [ - "Authorization: Bearer ".$plugin->getAccessToken(), - ]; - if (empty($text)) { - $text = ''; - } - $body = [ - 'wsid' => $wsId, - 'activityId' => self::activityId($plugin), - 'audioType' => 'pcm', - 'text' => $text, - 'voice' => new CURLFile($filePath), - ]; - - $result = self::doPost('authentify', $headers, $body); - - if (empty($result)) { - throw new Exception(get_lang('BadFormData')); - } - - return $result; - } - /** * @param WhispeakAuthPlugin $plugin * @param array $wsIds @@ -169,40 +90,4 @@ class WhispeakAuthRequest return $result; } - - /** - * @param string $uri - * @param array $headers - * - * @throws Exception - * - * @return array - */ - private static function doGet($uri, array $headers = []) - { - $ch = curl_init(self::API_URL.$uri); - - if ($headers) { - curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); - } - - curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); - - $result = curl_exec($ch); - $error = curl_error($ch); - - curl_close($ch); - - if (!empty($error)) { - throw new Exception($error); - } - - $result = json_decode($result, true); - - if (!empty($result['error'])) { - throw new Exception($result['error']); - } - - return $result; - } } diff --git a/plugin/whispeakauth/ajax/record_audio.php b/plugin/whispeakauth/ajax/record_audio.php index 6391fc2ef8..07e152f2e6 100644 --- a/plugin/whispeakauth/ajax/record_audio.php +++ b/plugin/whispeakauth/ajax/record_audio.php @@ -1,11 +1,8 @@ process(); die; - - $isAllowed = !empty($_FILES['audio']); -} elseif ($isAuthentify) { - $userId = api_get_user_id(); - $user2fa = ChamiloSession::read(WhispeakAuthPlugin::SESSION_2FA_USER, 0); - - if (!empty($user2fa) || !empty($userId)) { - $isAllowed = !empty($_FILES['audio']); - } else { - $isAllowed = !empty($_POST['username']) && !empty($_FILES['audio']); - } -} - -if (!$isAllowed) { - WhispeakAuthPlugin::displayNotAllowedMessage(); -} - -$plugin = WhispeakAuthPlugin::create(); - -$plugin->protectTool(false); - -$failedLogins = 0; -$maxAttempts = 0; - -if ($isAuthentify) { - $failedLogins = ChamiloSession::read(WhispeakAuthPlugin::SESSION_FAILED_LOGINS, 0); - $maxAttempts = $plugin->getMaxAttempts(); - - $em = Database::getManager(); - - if (!empty($user2fa)) { - $user = api_get_user_entity($user2fa); - } elseif (!empty($userId)) { - $user = api_get_user_entity($userId); - } else { - /** @var User|null $user */ - $user = UserManager::getRepository()->findOneBy(['username' => $_POST['username']]); - } -} else { - /** @var User $user */ - $user = api_get_user_entity(api_get_user_id()); -} - -if (empty($user)) { - echo Display::return_message(get_lang('NoUser'), 'error'); - - exit; -} - -$path = api_upload_file('whispeakauth', $_FILES['audio'], $user->getId()); - -if (false === $path) { - echo Display::return_message(get_lang('UploadError'), 'error'); - - exit; -} - -$newFullPath = $originFullPath = api_get_path(SYS_UPLOAD_PATH).'whispeakauth'.$path['path_to_save']; -$fileType = mime_content_type($originFullPath); - -if ('wav' !== substr($fileType, -3)) { - $directory = dirname($originFullPath); - $newFullPath = $directory.'/audio.wav'; - - try { - $ffmpeg = FFMpeg::create(); - - $audio = $ffmpeg->open($originFullPath); - $audio->save(new Wav(), $newFullPath); - } catch (Exception $exception) { - echo Display::return_message($exception->getMessage(), 'error'); - - exit; - } } if ($isAuthentify) { - if ($maxAttempts && $failedLogins >= $maxAttempts) { - echo Display::return_message($plugin->get_lang('MaxAttemptsReached'), 'warning'); - - exit; - } - - $wsid = WhispeakAuthPlugin::getAuthUidValue($user->getId()); - - if (empty($wsid)) { - echo Display::return_message($plugin->get_lang('SpeechAuthNotEnrolled'), 'warning'); - - exit; - } - - try { - $text = ChamiloSession::read(WhispeakAuthPlugin::SESSION_SENTENCE_TEXT); - - $authentifyResult = WhispeakAuthRequest::authentify($plugin, $wsid->getValue(), $text, $newFullPath); - } catch (Exception $exception) { - echo Display::return_message($plugin->get_lang('TryAgain'), 'error'); - - exit; - } - - $success = (bool) $authentifyResult['result']; - $qualityNote = !empty($authentifyResult['quality']) ? explode('|', $authentifyResult['quality']) : []; - $qualityNote = array_map('ucfirst', $qualityNote); - - /** @var array $lpItemInfo */ - $lpItemInfo = ChamiloSession::read(WhispeakAuthPlugin::SESSION_LP_ITEM, []); - /** @var array $quizQuestionInfo */ - $quizQuestionInfo = ChamiloSession::read(WhispeakAuthPlugin::SESSION_QUIZ_QUESTION, []); - - $message = $plugin->get_lang('AuthentifySuccess'); - - if (!$success) { - if (!empty($lpItemInfo)) { - $plugin->addAttemptInLearningPath( - LogEvent::STATUS_FAILED, - $user->getId(), - $lpItemInfo['lp_item'], - $lpItemInfo['lp'] - ); - } - - if (!empty($quizQuestionInfo)) { - $plugin->addAttemptInQuiz( - LogEvent::STATUS_FAILED, - $user->getId(), - $quizQuestionInfo['question'], - $quizQuestionInfo['quiz'] - ); - } - - $message = $plugin->get_lang('AuthentifyFailed'); - - ChamiloSession::write(WhispeakAuthPlugin::SESSION_FAILED_LOGINS, ++$failedLogins); - - if ($maxAttempts && $failedLogins >= $maxAttempts) { - $message .= PHP_EOL - .''.$plugin->get_lang('MaxAttemptsReached').'' - .PHP_EOL - .'
' - .$plugin->get_lang('LoginWithUsernameAndPassword') - .''; - - if (!empty($user2fa)) { - Display::addFlash( - Display::return_message($message, 'warning', false) - ); - } - } else { - $message .= PHP_EOL.$plugin->get_lang('TryAgain'); - - if ('true' === api_get_setting('allow_lostpassword')) { - $message .= '
' - .Display::url( - get_lang('LostPassword'), - api_get_path(WEB_CODE_PATH).'auth/lostPassword.php', - ['target' => $lpItemInfo ? '_top' : '_self'] - ); - } - } - } - - foreach ($qualityNote as $note) { - $message .= '
'.PHP_EOL.$plugin->get_lang("AudioQuality$note"); - } - - echo Display::return_message( - $message, - $success ? 'success' : 'warning', - false - ); - - if (!$success && $maxAttempts && $failedLogins >= $maxAttempts) { - ChamiloSession::erase(WhispeakAuthPlugin::SESSION_FAILED_LOGINS); - - if (!empty($lpItemInfo)) { - echo ''; - - exit; - } - - if (!empty($quizQuestionInfo)) { - $url = api_get_path(WEB_CODE_PATH).'exercise/exercise_submit.php?'.$quizQuestionInfo['url_params']; - - ChamiloSession::write(WhispeakAuthPlugin::SESSION_AUTH_PASSWORD, true); - - echo ""; - - exit; - } - - echo ''; - - exit; - } - - if ($success) { - ChamiloSession::erase(WhispeakAuthPlugin::SESSION_SENTENCE_TEXT); - ChamiloSession::erase(WhispeakAuthPlugin::SESSION_FAILED_LOGINS); - - if (!empty($lpItemInfo)) { - ChamiloSession::erase(WhispeakAuthPlugin::SESSION_LP_ITEM); - ChamiloSession::erase(WhispeakAuthPlugin::SESSION_2FA_USER); - - $plugin->addAttemptInLearningPath( - LogEvent::STATUS_SUCCESS, - $user->getId(), - $lpItemInfo['lp_item'], - $lpItemInfo['lp'] - ); - - echo ''; - - exit; - } - - if (!empty($quizQuestionInfo)) { - $quizQuestionInfo['passed'] = true; - $url = api_get_path(WEB_CODE_PATH).'exercise/exercise_submit.php?'.$quizQuestionInfo['url_params']; - - ChamiloSession::write(WhispeakAuthPlugin::SESSION_QUIZ_QUESTION, $quizQuestionInfo); - - $plugin->addAttemptInQuiz( - LogEvent::STATUS_SUCCESS, - $user->getId(), - $quizQuestionInfo['question'], - $quizQuestionInfo['quiz'] - ); - - echo ''; - - exit; - } - - $loggedUser = [ - 'user_id' => $user->getId(), - 'status' => $user->getStatus(), - 'uidReset' => true, - ]; - - if (empty($user2fa)) { - ChamiloSession::write(WhispeakAuthPlugin::SESSION_2FA_USER, $user->getId()); - } - - ChamiloSession::erase(WhispeakAuthPlugin::SESSION_FAILED_LOGINS); - ChamiloSession::write('_user', $loggedUser); - Login::init_user($user->getId(), true); - - echo ''; - } + $authenticationRequest = new AuthenticationRequestController(); + $authenticationRequest->process(); + die; } diff --git a/plugin/whispeakauth/authentify.php b/plugin/whispeakauth/authentify.php index 28a839b491..d42ec96a28 100644 --- a/plugin/whispeakauth/authentify.php +++ b/plugin/whispeakauth/authentify.php @@ -70,27 +70,7 @@ if (!empty($lpQuestionInfo) && empty($lpItemInfo)) { $htmlHeadXtra[] = api_get_js_simple(api_get_path(WEB_PLUGIN_PATH).'whispeakauth/assets/js/RecordAudio.js'); } -$sampleText = ''; - -try { - $sampleText = WhispeakAuthRequest::authenticateSentence($plugin); -} catch (Exception $exception) { - if ($showFullPage) { - api_not_allowed( - true, - Display::return_message($exception->getMessage(), 'error') - ); - } - - if (!$showFullPage && $oLp) { - api_not_allowed( - false, - Display::return_message($exception->getMessage(), 'error') - ); - } - - WhispeakAuthPlugin::displayNotAllowedMessage($exception->getMessage()); -} +$sampleText = 'Hola, mundo'; ChamiloSession::write(WhispeakAuthPlugin::SESSION_SENTENCE_TEXT, $sampleText);