Rev 1399 | Rev 1401 | Ir a la última revisión | Autoría | Comparar con el anterior | Ultima modificación | Ver Log |
<?php// Configuración de headers para respuesta JSON y CORSheader('Content-Type: application/json');header('Access-Control-Allow-Origin: *');// Definición de constantes para autenticación y encriptacióndefine('LLWS_USERNAME', 'leaderdslinked-ws');define('LLWS_PASSWORD', 'KFB3lFsLp&*CpB0uc2VNc!zVn@w!EZqZ*jr$J0AlE@sYREUcyP');define('LLWS_RSA_N', 34589927); // Clave pública RSA Ndefine('LLWS_RSA_D', 4042211); // Clave privada RSA Ddefine('LLWS_RSA_E', 7331); // Clave pública RSA Edefine('LLWS_CATEGORY_ID', 6); // ID de categoría para cursos// Inclusión de archivos necesarios de Moodlerequire_once(__DIR__ . '/../config.php');global $DB, $CFG;// Inclusión de librerías de Moodlerequire_once($CFG->libdir . '/moodlelib.php');require_once($CFG->libdir . '/externallib.php');require_once($CFG->libdir . '/authlib.php');require_once($CFG->libdir . '/gdlib.php');require_once($CFG->dirroot . '/user/lib.php');require_once(__DIR__ . '/rsa.php');require_once(__DIR__ . '/lib.php');/*** Valida los parámetros de seguridad de la petición* @param array $params Parámetros de la petición* @return array|false Array con los parámetros validados o false si hay error*/function validateSecurityParams($params){$username = trim(isset($params['username']) ? filter_var($params['username'], FILTER_SANITIZE_STRING) : '');$password = trim(isset($params['password']) ? filter_var($params['password'], FILTER_SANITIZE_STRING) : '');$timestamp = trim(isset($params['timestamp']) ? filter_var($params['timestamp'], FILTER_SANITIZE_STRING) : '');$rand = intval(isset($params['rand']) ? filter_var($params['rand'], FILTER_SANITIZE_NUMBER_INT) : 0, 10);$data = trim(isset($params['data']) ? filter_var($params['data'], FILTER_SANITIZE_STRING) : '');if (empty($username) || empty($password) || empty($timestamp) || empty($rand) || !is_integer($rand)) {return ['error' => 'ERROR_SECURITY1', 'message' => 'Missing or invalid security parameters'];}if ($username != LLWS_USERNAME) {return ['error' => 'ERROR_SECURITY2', 'message' => 'Invalid username'];}$dt = \DateTime::createFromFormat('Y-m-d\TH:i:s', $timestamp);if (!$dt) {return ['error' => 'ERROR_SECURITY3', 'message' => 'Invalid timestamp format'];}$t0 = $dt->getTimestamp();$t1 = strtotime('-5 minutes');$t2 = strtotime('+5 minutes');/* if ($t0 < $t1 || $t0 > $t2) {return ['error' => 'ERROR_SECURITY4', 'message' => 'Timestamp out of valid range'];} */if (!password_verify($username . '-' . LLWS_PASSWORD . '-' . $rand . '-' . $timestamp, $password)) {return ['error' => 'ERROR_SECURITY5', 'message' => 'Invalid password'];}return ['username' => $username,'password' => $password,'timestamp' => $timestamp,'rand' => $rand,'data' => $data];}/*** Procesa y decodifica los datos de la petición* @param string $data Datos encriptados* @return array|false Array con los datos decodificados o false si hay error*/function processRequestData($data){if (empty($data)) {return ['error' => 'ERROR_PARAMETERS1', 'message' => 'No data provided'];}$data = base64_decode($data);if (empty($data)) {return ['error' => 'ERROR_PARAMETERS2', 'message' => 'Invalid base64 data'];}try {$rsa = new rsa();$rsa->setKeys(LLWS_RSA_N, LLWS_RSA_D, LLWS_RSA_E);$data = $rsa->decrypt($data);} catch (Throwable $e) {return ['error' => 'ERROR_PARAMETERS3', 'message' => 'Decryption failed'];}$data = (array) json_decode($data);if (empty($data)) {return ['error' => 'ERROR_PARAMETERS4', 'message' => 'Invalid JSON data'];}$email = trim(isset($data['email']) ? filter_var($data['email'], FILTER_SANITIZE_EMAIL) : '');$first_name = trim(isset($data['first_name']) ? filter_var($data['first_name'], FILTER_SANITIZE_STRING) : '');$last_name = trim(isset($data['last_name']) ? filter_var($data['last_name'], FILTER_SANITIZE_STRING) : '');if (!filter_var($email, FILTER_VALIDATE_EMAIL) || empty($first_name) || empty($last_name)) {return ['error' => 'ERROR_PARAMETERS5', 'message' => 'Invalid user data'];}return ['email' => $email,'first_name' => $first_name,'last_name' => $last_name,'image_filename' => trim(isset($data['image_filename']) ? filter_var($data['image_filename'], FILTER_SANITIZE_STRING) : ''),'image_content' => trim(isset($data['image_content']) ? filter_var($data['image_content'], FILTER_SANITIZE_STRING) : '')];}/*** Gestiona la creación o actualización del usuario* @param array $userData Datos del usuario* @return array|false Array con el usuario o false si hay error*/function manageUser($userData){global $DB;$user = ll_get_user_by_email($userData['email']);if ($user) {return ['user' => $user, 'is_new' => false];}$username = ll_get_username_available($userData['first_name'], $userData['last_name']);$user = ll_create_user($username, $userData['email'], $userData['first_name'], $userData['last_name']);if (!$user) {return ['error' => 'ERROR_MOODLE1', 'message' => 'Failed to create user'];}if ($userData['image_filename'] && $userData['image_content']) {$tempfile = __DIR__ . DIRECTORY_SEPARATOR . $userData['image_filename'];try {file_put_contents($tempfile, base64_decode($userData['image_content']));if (file_exists($tempfile)) {$usericonid = process_new_icon(context_user::instance($user->id, MUST_EXIST), 'user', 'icon', 0, $tempfile);if ($usericonid) {$DB->set_field('user', 'picture', $usericonid, array('id' => $user->id));}}} catch (\Throwable $e) {// Log error but continue} finally {if (file_exists($tempfile)) {unlink($tempfile);}}}return ['user' => $user, 'is_new' => true];}/*** Gestiona la inscripción en cursos* @param object $user Usuario a inscribir* @return bool True si la inscripción fue exitosa*/function manageCourseEnrollment($user){global $DB;$role = $DB->get_record('role', array('archetype' => 'student'));$enrolmethod = 'manual';$courses = get_courses();foreach ($courses as $course) {if ($course->categoy_id == LLWS_CATEGORY_ID) {$context = context_course::instance($course->id);if (!is_enrolled($context, $user)) {$enrol = enrol_get_plugin($enrolmethod);if ($enrol === null) {continue;}$instances = enrol_get_instances($course->id, true);$manualinstance = null;foreach ($instances as $instance) {if ($instance->name == $enrolmethod) {$manualinstance = $instance;break;}}if ($manualinstance !== null) {$instanceid = $enrol->add_default_instance($course);if ($instanceid === null) {$instanceid = $enrol->add_instance($course);}$instance = $DB->get_record('enrol', array('id' => $instanceid));if ($instance) {$enrol->enrol_user($instance, $user->id, $role->id);}}}}}return true;}/*** Gestiona el inicio de sesión del usuario* @param object $user Usuario a iniciar sesión* @return array|false Array con los datos de la sesión o false si hay error*/function manageUserSession($user){global $CFG, $SESSION;// Cerrar sesión existente si la hayif (isloggedin()) {require_logout();}// Limpiar todas las cookies de sesiónif (isset($_COOKIE)) {foreach ($_COOKIE as $name => $value) {setcookie($name, '', time() - 3600, '/');unset($_COOKIE[$name]);}}// Limpiar la cookie de Moodle específicamenteset_moodle_cookie('');if (empty($user->confirmed)) {return ['error' => 'ACCOUNT_NOT_CONFIRMED', 'message' => 'Account not confirmed'];}$userauth = get_auth_plugin($user->auth);if (!isguestuser() && !empty($userauth->config->expiration) && $userauth->config->expiration == 1) {$days2expire = $userauth->password_expire($user->username);if (intval($days2expire) < 0) {return ['error' => 'PASSWORD_EXPIRED', 'message' => 'Password has expired'];}}complete_user_login($user);\core\session\manager::apply_concurrent_login_limit($user->id, session_id());if (!empty($CFG->nolastloggedin)) {// No almacenar último usuario conectado en cookie} else if (empty($CFG->rememberusername)) {set_moodle_cookie('');} else {set_moodle_cookie($user->username);}unset($SESSION->loginerrormsg);unset($SESSION->logininfomsg);unset($SESSION->loginredirect);$urltogo = $CFG->wwwroot . '/my';$SESSION->wantsurl = $urltogo;if (isloggedin() && !isguestuser()) {return ['success' => true,'data' => ['userid' => $user->id,'username' => $user->username,'fullname' => fullname($user),'email' => $user->email,'redirect' => $urltogo]];}return ['error' => 'LOGIN_FAILED', 'message' => 'Login failed'];}// Procesamiento principal$securityResult = validateSecurityParams($_REQUEST);if (isset($securityResult['error'])) {echo json_encode(['success' => false, 'data' => $securityResult['error']]);exit;}$dataResult = processRequestData($securityResult['data']);if (isset($dataResult['error'])) {echo json_encode(['success' => false, 'data' => $dataResult['error']]);exit;}$userResult = manageUser($dataResult);if (isset($userResult['error'])) {echo json_encode(['success' => false, 'data' => $userResult['error']]);exit;}if ($userResult['is_new']) {manageCourseEnrollment($userResult['user']);}$user = get_complete_user_data('id', $userResult['user']->id);if (!$user) {echo json_encode(['success' => false, 'data' => 'USER_NOT_FOUND']);exit;}$sessionResult = manageUserSession($user);if (isset($sessionResult['error'])) {echo json_encode(['success' => false, 'data' => $sessionResult['error']]);exit;}echo json_encode($sessionResult);redirect($sessionResult['data']['redirect']);exit;