LoginController.php 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403
  1. <?php
  2. namespace App\Http\Controllers;
  3. use Illuminate\Http\Request;
  4. use Illuminate\Support\Facades\Validator;
  5. use Illuminate\Support\Facades\DB;
  6. use Illuminate\Support\Facades\Hash;
  7. use Illuminate\Support\Carbon;
  8. use Firebase\JWT\JWT;
  9. use Firebase\JWT\Key;
  10. use Exception;
  11. use PDOException;
  12. use Jenssegers\Agent\Agent;
  13. use ElephantIO\Client;
  14. class LoginController extends Controller{
  15. private $responseController;
  16. private $encryptionController;
  17. private $functionsController;
  18. private $secretKey = "ydl27x22cNsNY0z6o3Fr6XZoUvsX0QMZx6MaiwN+KCnM6APS4Xbb7GDfudOYD5uD/r8TzQElh4d4HIal5Os0XA==";
  19. private $publicKey = "zOgD0uF22+xg37nTmA+bg/6/E80BJYeHeByGpeTrNFw=";
  20. public function __construct(){
  21. $this->responseController = new ResponseController();
  22. $this->encryptionController = new EncryptionController();
  23. $this->functionsController = new FunctionsController;
  24. }
  25. private function getSocketClient(){
  26. $url = 'http://localhost:3200';
  27. $socketClient = new Client(Client::engine(Client::CLIENT_4X, $url));
  28. $socketClient->initialize();
  29. $socketClient->of('/');
  30. return $socketClient;
  31. }
  32. public function login(Request $request){
  33. DB::enableQueryLog();
  34. $validator = Validator::make($request->all(), [
  35. 'email' => 'required|string|email',
  36. 'password' => 'required|string',
  37. 'linea' => 'required|integer|max: 2',
  38. 'latitude' => 'required|numeric|between:-90,90',
  39. 'longitude' => 'required|numeric|between:-180,180',
  40. 'accuracy' => 'required|numeric|between:0,1000000',
  41. 'city' => 'string|max:100',
  42. 'state' => 'string|max:100',
  43. 'country' => 'required|string|max:50',
  44. ]);
  45. if($validator->fails()){
  46. return $this->responseController->makeResponse(
  47. true,
  48. "Se encontraron uno o más errores.",
  49. $this->responseController->makeErrors(
  50. $validator->errors()->messages()
  51. ),
  52. 401
  53. );
  54. }
  55. $login = $request->all();
  56. //Se obtiene la dirección IP de la solicitud
  57. $ipv = $request->ip();
  58. $v4 = filter_var($ipv, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) ? true : false;
  59. //Se obtiene el dispositivo utilizado
  60. $agent = new Agent();
  61. $device = 'Desconocido';
  62. if($agent->isDesktop()) $device = 'PC';
  63. else if($agent->device()) $device = $agent->device();
  64. //Se obtiene el SO utilizado y la versión del mismo
  65. $platform = $agent->platform() ? $agent->platform() : 'Desconocido';
  66. $version = 'N/A';
  67. if($platform != 'Desconocido') $version = $agent->version($platform);
  68. //Se obtiene el navegador web utilizado
  69. $browser = $agent->browser() ? $agent->browser() : 'Desconocido';
  70. //Se consulta el correo electrónico enviado
  71. $usr = DB::table('S002V01TUSUA')->where([
  72. ['USUA_COEL', '=', $login['email']],
  73. ['USUA_NULI', '=', $login['linea']]
  74. ])->first();
  75. if(is_null($usr)){
  76. return $this->responseController->makeResponse(true, "El correo electrónico no está registrado.", [], 404);
  77. }else if($usr->USUA_ESTA != 'Activo'){
  78. $statusStr = strtolower($usr->USUA_ESTA);
  79. return $this->responseController->makeResponse(true, "El usuario se encuentra $statusStr, por favor contacte al administrador para solucionarlo.", [], 401);
  80. }
  81. $now = $this->functionsController->now();
  82. $nowStr = $now->toDateTimeString();
  83. $contra = $login['password'];
  84. $contra = $this->encryptionController->decrypt($contra);
  85. if(!$contra){
  86. return $this->responseController->makeResponse(true, 'La contraseña no fue encriptada correctamente.', [], 400);
  87. }
  88. $usrContra = $usr->USUA_CONT;
  89. if(!Hash::check($contra, $usrContra)){
  90. $attempts = $usr->USUA_ININ + 1;
  91. $status = $attempts >= 10 ? 'Inactivo' : 'Activo';
  92. DB::table('S002V01TUSUA')->where('USUA_IDUS', '=', $usr->USUA_IDUS)->update([
  93. "USUA_ININ" => $attempts,
  94. "USUA_ESTA" => $status
  95. ]);
  96. return $this->responseController->makeResponse(true, "La contraseña es incorrecta, intento $attempts de 10.", [], 401);
  97. }
  98. $controlPanel = DB::table('S002V01TPACO')->where([
  99. ['PACO_NULI', '=', $login['linea']],
  100. ['PACO_IDPC', '=', $usr->USUA_PCRE]
  101. ])->first();
  102. DB::table('S002V01TUSUA')->where('USUA_IDUS', '=', $usr->USUA_IDUS)->update([
  103. "USUA_ININ" => 0,
  104. "USUA_ESTA" => 'Activo'
  105. ]);
  106. $politicsInfoRoute = str_replace("app\Http\Controllers", "", __DIR__);
  107. $politicsInfoRoute .= "storage\\app\\files\\security-politics.json";
  108. $politicsExists = file_exists($politicsInfoRoute);
  109. if(!$politicsExists){
  110. return $this->responseController->makeResponse(true, 'El archivo de políticas de seguridad no fue encontrado.', [], 404);
  111. }
  112. $politicsStr = file_get_contents($politicsInfoRoute);
  113. $politicsArr = json_decode($politicsStr, true);
  114. if(!array_key_exists('sessions_duration', $politicsArr)){
  115. return $this->responseController->makeResponse(true, 'La configuración de duración de sesiones no existe.', [], 404);
  116. }
  117. $sessionDurationConfig = $politicsArr['sessions_duration'];
  118. $cadDate = new Carbon($nowStr);
  119. $cadDate->addDays($sessionDurationConfig['days']);
  120. $cadDate->addHours($sessionDurationConfig['hours']);
  121. $cadDate->addMinutes($sessionDurationConfig['minutes']);
  122. $cadDate->addSeconds($sessionDurationConfig['seconds']);
  123. $iat = $now->timestamp;
  124. $cad = $cadDate->timestamp;
  125. $state = isset($login['state']) ? $login['state'] : '-';
  126. $ulco = DB::table('S002V01TBIAC')->insertGetId([
  127. 'BIAC_NULI' => $login['linea'],
  128. 'BIAC_IDUS' => $usr->USUA_IDUS,
  129. 'BIAC_FECO' => $nowStr,
  130. 'BIAC_IPV4' => $v4 ? $ipv : null,
  131. 'BIAC_IPV6' => !$v4 ? $ipv : null,
  132. 'BIAC_LATI' => $login['latitude'],
  133. 'BIAC_LONG' => $login['longitude'],
  134. 'BIAC_PREC' => $login['accuracy'],
  135. 'BIAC_CIUD' => $login['city'],
  136. 'BIAC_ESTA' => $state,
  137. 'BIAC_PAIS' => $login['country'],
  138. 'BIAC_DISP' => $device,
  139. 'BIAC_SIOP' => $platform,
  140. 'BIAC_VSOP' => $version,
  141. 'BIAC_NAVE' => $browser,
  142. ]);
  143. DB::table('S002V01TUSUA')->where([
  144. ['USUA_COEL', '=', $login['email']],
  145. ['USUA_NULI', '=', $login['linea']]
  146. ])->update(['USUA_ULCO' => $ulco]);
  147. //Antes de crear el token revisamos los permisos de su perfil
  148. $profile = DB::table('S002V01TPERF')->where([
  149. ['PERF_IDPE', '=', $usr->USUA_PERF],
  150. ['PERF_NULI', '=', $login['linea']]
  151. ])->get()->first();
  152. $permissions = $this->encryptionController->encrypt($profile->PERF_PERM);
  153. $payload = [
  154. "iss" => $login['email'],
  155. "aud" => "dominio.syp.mx",
  156. "iat" => $iat,
  157. "cad" => $cad
  158. ];
  159. $token = JWT::encode($payload, $this->secretKey, 'EdDSA');
  160. if(!array_key_exists('active_sessions_number', $politicsArr)){
  161. return $this->responseController->makeResponse(true, 'La configuración de sesiones máximas no existe.', [], 404);
  162. }
  163. $idUserInt = intval($usr->USUA_IDUS);
  164. if($idUserInt > 0){
  165. $this->getSocketClient()->emit('get_sessions', []);
  166. if($packet = $this->getSocketClient()->wait('new_session_saved')){
  167. $maxSessions = $politicsArr['active_sessions_number'];
  168. $dataStr = $packet->data;
  169. $dataArr = json_decode($dataStr, true);
  170. $sessionsCount = 0;
  171. foreach($dataArr as $session){
  172. $sessionUser = $this->encryptionController->decrypt($session['user']);
  173. if($sessionUser == $usr->USUA_IDUS){
  174. $sessionsCount++;
  175. }
  176. }
  177. if($sessionsCount >= $maxSessions){
  178. return $this->responseController->makeResponse(true, 'Número máximo de sesiones alcanzado.', [], 401);
  179. }
  180. }
  181. }
  182. //Antes de realizar el return obtenemos todos los querys ejecutados en esta consulta
  183. $querys = DB::getQueryLog();
  184. $name = $this->functionsController->joinName($usr->USUA_NOMB, $usr->USUA_APPA, $usr->USUA_APMA);
  185. //Se registra la acción realizada
  186. $idac = $this->functionsController->registerActivity(
  187. $login['linea'],
  188. 'LOGIN',
  189. '-',
  190. '-',
  191. 'Registro',
  192. "El usuario $name (" . $usr->USUA_IDUS . ") inició sesión.",
  193. $usr->USUA_IDUS,
  194. $nowStr
  195. );
  196. $this->functionsController->registerLog($querys, $usr->USUA_IDUS, $nowStr, $idac, $login['linea']);
  197. return $this->responseController->makeResponse(false, "EXITO.", [
  198. "IDUSUARIO" => $this->encryptionController->encrypt($usr->USUA_IDUS),
  199. "NOMBREUSUARIO" => $this->encryptionController->encrypt($usr->USUA_NOMB),
  200. "CORREO" => $this->encryptionController->encrypt($usr->USUA_COEL),
  201. "PERFIL" => $this->encryptionController->encrypt($usr->USUA_PERF),
  202. "PANEL" => isset($controlPanel) ? $this->encryptionController->encrypt($usr->USUA_PCRE) : null,
  203. "PERMISOS" => $permissions,
  204. "TOKEN" => $token,
  205. ]);
  206. }
  207. public function verifyToken(Request $request){
  208. DB::enableQueryLog();
  209. $validator = Validator::make($request->all(), [
  210. 'token' => 'required|string',
  211. 'linea' => 'required|integer',
  212. 'is_scada' => 'string',
  213. ]);
  214. if($validator->fails()){
  215. return $this->responseController->makeResponse(
  216. true,
  217. "Se encontraron uno o más errores.",
  218. $this->responseController->makeErrors(
  219. $validator->errors()->messages()
  220. ),
  221. 401
  222. );
  223. }
  224. $tokenInfo = $request->all();
  225. $isSCADA = array_key_exists('is_scada', $tokenInfo) ? true : false;
  226. try{
  227. $decoded = JWT::decode($tokenInfo['token'], new Key($this->publicKey, 'EdDSA'));
  228. }catch(Exception $e){
  229. return $this->responseController->makeResponse(false, "Token inválido", [
  230. "validToken" => false
  231. ]);
  232. }
  233. $name = "";
  234. $id = "";
  235. if($isSCADA){
  236. $scada = DB::table('S002V01TLISC')->where([
  237. ['LISC_NULI', '=', $tokenInfo['linea']],
  238. ['LISC_IDSC', '=', $decoded->iss],
  239. ])->first();
  240. if(is_null($scada)){
  241. return $this->responseController->makeResponse(false, "El SCADA que generó el token no está registrado en la base.", [
  242. "validToken" => false
  243. ]);
  244. }else if($scada->LISC_ESTA == 'Eliminado'){
  245. return $this->responseController->makeResponse(false, "El SCADA que generó el token está eliminado.", [
  246. "validToken" => false
  247. ]);
  248. }
  249. $name = $scada->LISC_NOSC;
  250. $id = $scada->LISC_IDSC;
  251. }else{
  252. $usr = DB::table('S002V01TUSUA')->where([
  253. ['USUA_NULI', '=', $tokenInfo['linea']],
  254. ['USUA_COEL', '=', $decoded->iss],
  255. ])->first();
  256. if(is_null($usr)){
  257. return $this->responseController->makeResponse(false, "El usuario que generó el token no está registrado en la base.", [
  258. "validToken" => false
  259. ]);
  260. }else if($usr->USUA_ESTA == 'Inactivo'){
  261. return $this->responseController->makeResponse(false, "El usuario que generó el token está desactivado.", [
  262. "validToken" => false
  263. ]);
  264. }else if($usr->USUA_ESTA == 'Eliminado'){
  265. return $this->responseController->makeResponse(false, "El usuario que generó el token está eliminado.", [
  266. "validToken" => false
  267. ]);
  268. }
  269. $name = $this->functionsController->joinName($usr->USUA_NOMB, $usr->USUA_APPA, $usr->USUA_APMA);
  270. $id = $usr->USUA_IDUS;
  271. }
  272. if($decoded->aud != "dominio.syp.mx"){
  273. return $this->responseController->makeResponse(false, "El token enviado fue generado en un sitio diferente.", [
  274. "validToken" => false
  275. ]);
  276. }
  277. $now = $this->functionsController->now();
  278. $nowTimestamp = $now->timestamp;
  279. if($nowTimestamp > $decoded->cad && !$isSCADA){
  280. return $this->responseController->makeResponse(false, "Token expirado.", [
  281. "validToken" => false
  282. ]);
  283. }
  284. //Se registra la acción realizada
  285. $nowStr = $now->toDateTimeString();
  286. $idac = $this->functionsController->registerActivity(
  287. $tokenInfo['linea'],
  288. 'LOGIN',
  289. '-',
  290. '-',
  291. 'Registro',
  292. "El usuario $name (" . $id . ") verificó su token de acceso.",
  293. $id,
  294. $nowStr
  295. );
  296. $actions = DB::getQueryLog();
  297. $this->functionsController->registerLog($actions, $id, $nowStr, $idac, $tokenInfo['linea']);
  298. return $this->responseController->makeResponse(false, "Token válido.", [
  299. "validToken" => true
  300. ]);
  301. }
  302. public function privateValidateSocketSessions() {
  303. $this->getSocketClient()->emit('get_sessions', []);
  304. if($packet = $this->getSocketClient()->wait('new_session_saved')){
  305. $dataStr = $packet->data;
  306. $dataArr = json_decode($dataStr, true);
  307. foreach($dataArr as $session){
  308. try{
  309. $decoded = JWT::decode($session['token'], new Key($this->publicKey, 'EdDSA'));
  310. }catch(Exception $e){
  311. $this->getSocketClient()->emit('etl_delete_session', $session);
  312. }
  313. $now = $this->functionsController->now();
  314. $nowTimestamp = $now->timestamp;
  315. if($nowTimestamp > $decoded->cad){
  316. $this->getSocketClient()->emit('etl_delete_session', $session);
  317. }
  318. }
  319. }
  320. }
  321. public function createPasword(Request $request){
  322. $st = base64_decode("k+SBamn2OKLNuha8s8oXkDggZG1TrHfK1m4prRT1GInKPer4qwT1DHnmaTbtVyiIoHf0cfg9hX9g6PnZ/p4Qj8I+CaQ=");
  323. $no = base64_decode("rOOHqbrNxRamYCqqkwyxeYUcb7M+32NY");
  324. $k1 = base64_decode("7tPoKAbUleTq2C/eiQ03oQ5zynj5eWQAR5h+BM0NDeY=");
  325. $k2 = base64_decode("xGGg6eMXd/ugXqFJfB5wQ9k5Yq/VQRaQeFh4zXmMHSo=");
  326. $encryption_key_dec = sodium_crypto_box_keypair_from_secretkey_and_publickey(
  327. $k1,
  328. $k2
  329. );
  330. $decrypted = sodium_crypto_box_open($st, $no, $encryption_key_dec);
  331. $text = base64_decode($decrypted);
  332. var_dump($decrypted);
  333. $timestamp = Carbon::now('America/Mexico_city')->timestamp;
  334. $id = $this->functionsController->generateID('José Luis Brito Nava', $timestamp);
  335. var_dump(Hash::make('SAMMX-2023'));
  336. $uuid = $this->functionsController->uuidv5('1546058f-5a25-4334-85ae-e68f2a44bbaf', 'jose.b@ittec.mx');
  337. return $this->responseController->makeResponse(false, $id, []);
  338. }
  339. }