Files
safekat/ci4/app/Controllers/Login.php

628 lines
28 KiB
PHP
Executable File

<?php
namespace App\Controllers;
use App\Libraries\Authenticator;
use App\Libraries\PasswordHash;
use App\Models\ActivityModel;
use App\Models\ConfirmationTokenModel;
use App\Models\NotificationModel;
use App\Models\PasswordRecoveryModel;
use App\Models\SettingsModel;
use App\Models\TemplateModel;
use App\Models\Usuarios\UserModel;
use App\Models\Usuarios\UserGroupModel;
use App\Models\Usuarios\GroupUserModel;
class login extends BaseController
{
private $user_model;
private $group_model;
private $settings_model;
private $pass_recovery_model;
private $activity_model;
private $notification_model;
private $template_model;
private $confirmation_model;
private $integration;
private $group_user_model;
function __construct()
{
$this->user_model = new UserModel();
$this->group_model = new UserGroupModel();
$this->settings_model = new SettingsModel();
$this->pass_recovery_model = new PasswordRecoveryModel();
$this->activity_model = new ActivityModel();
$this->notification_model = new NotificationModel();
$this->template_model = new TemplateModel();
$this->confirmation_model = new ConfirmationTokenModel();
$this->integration = new Integration();
// Get Settings
$loginAuthFilter = new \App\Filters\LoginAuthFilter();
$loginAuthFilter->getSettings();
$this->group_user_model = new GroupUserModel();
}
public function index()
{
$session = session();
$data['settings'] = $session->get('settings');
$header['title'] = lang("App.login_title");
echo view(getenv('theme.path').'login/header',$header);
echo view(getenv('theme.path').'form/login/index',$data);
echo view(getenv('theme.path').'login/footer');
}
public function forgot_password()
{
$session = session();
if($session->get('settings')['forgot_password']??false){
$data['settings'] = $session->get('settings');
$header['title'] = lang("App.login_title_forgot_password");
echo view(getenv('theme.path').'login/header',$header);
echo view(getenv('theme.path').'form/login/forgot_password',$data);
echo view(getenv('theme.path').'login/footer');
}else{
return redirect()->to('/login');
}
}
public function authenticate()
{
$session = session();
$settings = $session->get('settings');
if(!empty($session->get('oauth'))){
// Data obtained by oAuth
$login = $this->user_model->where('email', $session->get('oauth')->email)->first();
} else {
// Data obtained by Form
$getVar = $this->request->getvar();
$login = $this->user_model->where('email', $getVar['email']??'')->first();
// Captcha Validation
if($settings['captcha_login']??false){
if($settings['captcha_gateway'] == 'recaptcha'){
if(isset($getVar['g-recaptcha-response'])){
$captcha = $getVar['g-recaptcha-response'];
$url = 'https://www.google.com/recaptcha/api/siteverify?secret='.urlencode($settings['captcha_secret_key']??'').'&response='.urlencode($captcha);
$response = file_get_contents($url);
$responseKeys = json_decode($response,true);
if(!$responseKeys["success"]) {
$session->setFlashdata('toast', ['error',lang("App.login_alert"),lang("App.login_alert_captcha_invalid")]);
return redirect()->to('login');
}
}else{
$session->setFlashdata('toast', ['error',lang("App.login_alert"),lang("App.login_alert_captcha_not_found")]);
return redirect()->to('login');
}
}
if($settings['captcha_gateway'] == 'hcaptcha'){
if(isset($getVar['h-captcha-response'])){
$captcha = $getVar['h-captcha-response'];
$url = 'https://hcaptcha.com/siteverify?secret='.urlencode($settings['captcha_secret_key']??'').'&response='.urlencode($captcha).'&remoteip='.$_SERVER['REMOTE_ADDR'];
$response = file_get_contents($url);
$responseKeys = json_decode($response,true);
if(!$responseKeys["success"]) {
$session->setFlashdata('toast', ['error',lang("App.login_alert"),lang("App.login_alert_captcha_invalid")]);
return redirect()->to('login');
}
}else{
$session->setFlashdata('toast', ['error',lang("App.login_alert"),lang("App.login_alert_captcha_not_found")]);
return redirect()->to('login');
}
}
}
// Remember Me Validation
if($settings['remember_me']??false){
if($getVar['remember']??'' == 'on') {
$params = session_get_cookie_params();
setcookie(session_name(), $_COOKIE[session_name()], time() + 60*60*24*30, $params["path"], $params["domain"], $params["secure"], $params["httponly"]);
}
}
}
if(!empty($login))
{
// Blocked Validation
if($login->blocked!=null){
$dateBlocked = date($login->blocked);
$dateNow = date('Y-m-d H:i:s');
if($dateBlocked > $dateNow){
$session->setFlashdata('toast', ['error',lang("App.login_alert"),lang("App.login_alert_user_blocked").$settings['throttle_auth_lockour_time'].' '.lang("App.global_hours")]);
return redirect()->to('login');
}else{
$this->user_model->save([
'id_user' => $login->id_user,
'blocked' => null
]);
}
}
// Get Ip Address
$request = \Config\Services::request();
$last_ip = $request->getIPAddress();
if(empty($session->get('oauth'))){
// Check user password
$phpass = new PasswordHash(8, true);
if(!$phpass->CheckPassword($getVar['password']??'', $login->password)){
// Throttling Validation
if($settings['throttle_auth']??false){
$initialDate = date('Y-m-d H:i:s', strtotime('-12 hour', time()));
$finalDate = date('Y-m-d H:i:s');
$amount = $this->activity_model->where('user',$login->token)->where('level','throttling')->where('created_at between \''.$initialDate.'\' and \''.$finalDate.'\'')->countAllResults();
if($amount >= intval($settings['throttle_auth_max_attempts']??'')){
$session->setFlashdata('toast', ['error',lang("App.login_alert"),lang("App.login_alert_user_blocked").$settings['throttle_auth_lockour_time'].' '.lang("App.global_hours")]);
$blocked = date('Y-m-d H:i:s', strtotime('+'.$settings['throttle_auth_lockour_time'].' hour', time()));
$this->user_model->save([
'id_user' => $login->id_user,
'blocked' => $blocked
]);
return redirect()->to('login');
}else{
// Register Throttling Log
$this->integration->setLog('throttling','login-authenticate',$login->token);
$session->setFlashdata('toast', ['error',lang("App.login_alert"),lang("App.login_alert_pass_invalid_2"). ($amount+1) .lang("App.login_alert_pass_attempt"). $settings['throttle_auth_max_attempts']??0]);
return redirect()->to('login');
}
}
$session->setFlashdata('toast', ['error',lang("App.login_alert"),lang("App.login_alert_pass_invalid")]);
return redirect()->to('login');
}
// Check email confirmed
if($settings['email_confirmation']??false){
if(!$login->email_confirmed){
$session->setFlashdata('toast', ['error',lang("App.login_alert"),lang("App.user_alert_email_confirmed")]);
return redirect()->to('login');
}
}
}
// Check user status
if(!$login->status){
$session->setFlashdata('toast', ['error',lang("App.login_alert"),lang("App.login_alert_disabled_access")]);
return redirect()->to('/login');
}
// Get access rules
#$rules = $this->group_model->where('token', $login->'group'])->first();
$groups = $this->group_user_model
->select('token_group')
->where('token_user',$login->token)->findAll();
if (sizeof($groups)>1){
$rules = $this->group_model->select('rules')->where('token',$groups[0])->first()->rules;
$rules = json_decode(html_entity_decode($rules), true);
if($rules==null){
// group doesn't exists now -> then delete from group-user
$groups = $this->group_user_model
->where('token_group',$groups[0])
->delete();
}
for ($i=1; $i<sizeof($groups); $i++){
$temp_rules = $this->group_model->select('rules')->where('token',$groups[$i])->first();
if($temp_rules==null){
// group doesn't exists now -> then delete from group-user
$groups = $this->group_user_model
->where('token_group',$groups[$i])
->delete();
}
else{
$temp_rules=$temp_rules->rules;
foreach ($rules as $key => $value){
if (array_key_exists($key, json_decode(html_entity_decode($temp_rules), true))){
$value2 = json_decode(html_entity_decode($temp_rules), true)[$key];
$rules[$key] = array_unique(array_merge($value, $value2));
}
else{
$rules[$key]= $value;
}
}
foreach (json_decode(html_entity_decode($temp_rules), true) as $key2 => $value2){
if (!array_key_exists($key2, $rules)){
$rules[$key2] = $value2;
}
}
}
}
}
else{
$rules = json_decode($this->group_model->select('rules')->where('token',$groups[0])->first()->rules);
}
// Save data in session
$session->set('id_user', $login->id_user);
//$session->set('group', $login->'group']);
$session->set('first_name', $login->first_name);
$session->set('last_name', $login->last_name);
$session->set('email', $login->email);
$session->set('token', $login->token);
// JJO
$dashboard = 'user';
foreach ($groups as $group){
if($this->group_model->select('dashboard')->where('token',$group)->first()->dashboard == 'admin')
$dashboard = 'admin';
}
$session->set('dashboard', $dashboard);
$session->set('rules', html_entity_decode(json_encode($rules)));
$session->set('picture', $login->picture);
$session->set('tfa', $login->tfa);
$session->set('tfa_secret', $login->tfa_secret);
$session->set('tfa_code', $login->tfa_code);
$session->set('lang', $login->language ?? 'en');
// Update last access
$last_access = date('Y-m-d H:i:s');
$this->user_model->set('last_access', $last_access)->set('last_ip', $last_ip)->where('id_user', $session->get('id_user'))->update();
// Register Access Log
$integration = new \App\Controllers\Integration;
$integration->setLog('information','login-authenticate');
// Check if it has two factors
if($login->tfa??false){
return redirect()->to('/login/authentication');
}else{
return redirect()->to('home');
}
}
else
{
$session->setFlashdata('toast', ['error',lang("App.login_alert"),lang("App.login_alert_user_not_found")]);
return redirect()->to('login');
}
}
public function logout()
{
// Destroy the session
$session = session();
$lang = $session->get('lang');
$session->destroy();
return redirect()->to('/lang/'.$lang);
}
public function signup()
{
$session = session();
helper('form');
$data['settings'] = $session->get('settings');
$header['title'] = lang("App.login_title_signup");
echo view(getenv('theme.path').'login/header',$header);
echo view(getenv('theme.path').'form/login/signup',$data);
echo view(getenv('theme.path').'login/footer');
}
public function authentication()
{
$session = session();
if($session->get('tfa')??false){
$header['title'] = lang("App.login_title_otp");
echo view(getenv('theme.path').'login/header',$header);
echo view(getenv('theme.path').'form/login/authentication');
echo view(getenv('theme.path').'login/footer');
}else{
return redirect()->to('/login');
}
}
public function otp()
{
$session = session();
$tfa_secret = $session->get('tfa_secret');
$tfa_code = $session->get('tfa_code');
$pin = $this->request->getVar();
$otp = "";
foreach ($pin as $key=>$value){
if(strpos($key, 'pin') !== false){
$otp .= $value;
}
}
$tfa = new Authenticator();
$backup_pass = false;
$checkResult = $tfa->verify($tfa_secret??'', $otp);
if($tfa_code??'') {
$backup_codes = explode(',' , $tfa_code??'');
if (in_array($otp, $backup_codes)) {
$backup_pass = true;
$key = array_search($otp, $backup_codes);
unset($backup_codes[$key]);
}
}
if($checkResult || $backup_pass == true) {
$session->set('tfa',false);
$session->set('tfa_secret','');
$session->set('tfa_code','');
return redirect()->to('/home');
} else {
$session->setFlashdata('toast', ['error',lang("App.login_alert"),lang("App.login_alert_code_invalid")]);
return redirect()->to('/login/authentication');
}
}
public function store()
{
$session = session();
$settings = $session->get('settings');
helper('form');
helper('text');
$rules = [
'first_name' => 'required',
'last_name' => 'required',
'email' => 'required|valid_email|is_unique[auth_user.email]',
'password' => 'required|min_length[8]'
];
$rules_error = [
'first_name' => [
'required' => lang("App.login_rules_first_name_r")
],
'last_name' => [
'required' => lang("App.login_rules_last_name_r")
],
'email' => [
'required' => lang("App.login_rules_email_r"),
'is_unique' => lang("App.login_rules_email_i"),
'valid_email' => lang("App.login_rules_email_v"),
],
'password' => [
'required' => lang("App.login_rules_password_r"),
'min_length' => lang("App.login_rules_password_m")
]
];
if ($this->validate($rules,$rules_error)){
if($listPost = $this->request->getPost()) {
if($settings['captcha_register']??false){
if($settings['captcha_gateway'] == 'recaptcha'){
if(isset($listPost['g-recaptcha-response'])){
$captcha = $listPost['g-recaptcha-response'];
$url = 'https://www.google.com/recaptcha/api/siteverify?secret='.urlencode($settings['captcha_secret_key']??'').'&response='.urlencode($captcha);
$response = file_get_contents($url);
$responseKeys = json_decode($response,true);
if(!$responseKeys["success"]) {
$session->setFlashdata('toast', ['error',lang("App.login_alert"),lang("App.login_alert_captcha_invalid")]);
$this->signup();
die();
}
}else{
$session->setFlashdata('toast', ['error',lang("App.login_alert"),lang("App.login_alert_captcha_not_found")]);
$this->signup();
die();
}
}
if($settings['captcha_gateway'] == 'hcaptcha'){
if(isset($listPost['h-captcha-response'])){
$captcha = $listPost['h-captcha-response'];
$url = 'https://hcaptcha.com/siteverify?secret='.urlencode($settings['captcha_secret_key']??'').'&response='.urlencode($captcha).'&remoteip='.$_SERVER['REMOTE_ADDR'];
$response = file_get_contents($url);
$responseKeys = json_decode($response,true);
if(!$responseKeys["success"]) {
$session->setFlashdata('toast', ['error',lang("App.login_alert"),lang("App.login_alert_captcha_invalid")]);
$this->signup();
die();
}
}else{
$session->setFlashdata('toast', ['error',lang("App.login_alert"),lang("App.login_alert_captcha_not_found")]);
$this->signup();
die();
}
}
}
$phpass = new PasswordHash(8, true);
$userToken = md5(uniqid(rand(), true));
$this->user_model->skipValidation(true)->save([
//'group' => $settings['default_role'],
'first_name' => $listPost['first_name'],
'last_name' => $listPost['last_name'],
'mobile' => '',
'picture' => '/assets/img/default-user.png',
'email' => $listPost['email'],
'password' => $phpass->HashPassword($listPost['password']),
'last_access' => date('Y-m-d h:i:s'),
'last_ip' => '::1',
'language' => $settings['default_language'],
'token' => $userToken,
'status' => 1,
'address' => '',
'city' => '',
'state' => '',
'country' => '',
'zip_code' => '',
]);
//Get Data Template
$templates = $this->template_model->findAll();
//Notification E-mail User Welcome
if($settings['send_email_welcome']??false){
$template = templateSelect($templates,'template_label_welcome','email');
if($template != null){
try {
$this->integration->send_email($listPost['email'],$template['subject'],$template['body'],$phpass->HashPassword(MD5($listPost['email'])));
}catch (\Exception $e){
}
}
}
//E-mail Account Confirmation
if($settings['email_confirmation']??false){
$template = templateSelect($templates,'template_label_confirmation_email','email');
if($template != null){
$token = random_string("alnum", 50);
$url = base_url().'/login/confirmation/'.$token;
$body = str_replace('[link_confirmation]',$url,$template['body']);
try {
$this->integration->send_email($listPost['email'],$template['subject'],$body,$phpass->HashPassword(MD5($listPost['email'])));
$this->confirmation_model->save([
'id_confirmation' => null,
'user' => $userToken,
'token' => $token,
'confirmed' => false,
'type' => 'email'
]);
}catch (\Exception $e){
}
}
}
//Notification New Register
if($settings['send_notification_register']??false){
$template = templateSelect($templates,'template_label_notification','email');
if($template != null){
if(!empty($settings['send_user_register']??null)){
$data = [
'id_notification' => null,
'user_sender' => $settings['send_user_register']??null,
'user_recipient' => $settings['send_user_register']??null,
'title' => $template['subject'],
'body' => $template['body'],
'is_read' => false,
'is_send_email' => false,
'send_email_notification' => $settings['send_email_register']??false,
'token' => md5(uniqid(rand(), true))
];
$this->notification_model->save($data);
}
}
}else{
$userAdm = $this->user_model->where('token',$settings['send_user_register']??null)->first();
if($settings['send_email_register']??false){
$template = templateSelect($templates,'template_label_notification','email');
if($template != null){
try {
$this->integration->send_email($userAdm['email'],$template['subject'],$template['body'],$phpass->HashPassword(MD5($listPost['email'])));
}catch (\Exception $e){
}
}
}
}
$session = session();
$session->setFlashdata('toast', ['success', lang("App.login_alert_success"), lang("App.login_alert_success_register")]);
return redirect()->to('/login');
}else{
$session->setFlashdata('toast', ['error', lang("App.login_alert"),lang("App.login_alert_parameter_invalid")]);
$this->signup();
}
}else{
$session = session();
$session->setFlashdata('error','error');
$this->signup();
}
}
public function recovery($token=null)
{
$session = session();
if(!empty($token) && $session->get('settings')['forgot_password']??false){
$pass_recovery = $this->pass_recovery_model->where('token',$token)->where('changed',false)->first();
if($pass_recovery != null){
$data['token'] = $token;
$data['user'] = $pass_recovery['user'];
$header['title'] = lang("App.login_title_recovery");
echo view(getenv('theme.path').'login/header',$header);
echo view(getenv('theme.path').'form/login/password_recovery',$data);
echo view(getenv('theme.path').'login/footer');
}else{
$session->setFlashdata('toast', ['error', lang("App.login_alert"), lang("App.login_alert_invalid_token")]);
return redirect()->to('/login');
}
}else{
$session->setFlashdata('toast', ['error', lang("App.login_alert"), lang("App.login_alert_empty_token")]);
return redirect()->to('/login');
}
}
public function recovery_store()
{
$session = session();
helper('form');
$rules = [
'password' => 'required|min_length[8]'
];
$rules_error = [
'password' => [
'required' => lang("App.login_rules_password_r"),
'min_length' => lang("App.login_rules_password_m")
]
];
if ($this->validate($rules,$rules_error)){
if($listPost = $this->request->getPost()) {
$pass_recovery = $this->pass_recovery_model->where('user',$listPost['user'])->where('token',$listPost['token'])->where('changed',false)->first();
if($pass_recovery != null){
$user = $this->user_model->select('id_user')->where('token',$listPost['user'])->first();
if($user != null){
$phpass = new PasswordHash(8, true);
$this->user_model->save([
'id_user' => $user->id_user,
'password' => $phpass->HashPassword($listPost['password'])
]);
$this->pass_recovery_model->save([
'id_pass_recovery' => $pass_recovery['id_pass_recovery'],
'changed' => true
]);
$session->setFlashdata('toast', ['success', lang("App.login_alert_success"), lang("App.login_alert_success_recovery")]);
}
}
return redirect()->to('/login');
}else{
$session->setFlashdata('toast', ['error', lang("App.login_alert"), lang("App.login_alert_parameter_invalid")]);
$this->recovery($this->request->getVar('token'));
}
}else{
$session->setFlashdata('error','error');
$this->recovery($this->request->getVar('token'));
}
}
public function confirmation($token=null)
{
$session = session();
if(!empty($token)){
$confirmation = $this->confirmation_model->where('token',$token)->where('confirmed',false)->first();
if($confirmation != null){
$user = $this->user_model->select('id_user')->where('token',$confirmation['user'])->first();
if($confirmation['type'] == 'email'){
$this->user_model->save([
'id_user'=>$user['id_user'],
'email_confirmed'=>true
]);
}
$this->confirmation_model->save([
'id_confirmation'=>$confirmation['id_confirmation'],
'confirmed'=>true
]);
$session->setFlashdata('toast', ['success', lang("App.login_alert_success"), lang("App.login_alert_success_confirmation")]);
return redirect()->to('/login');
}else{
$session->setFlashdata('toast', ['error', lang("App.login_alert"), lang("App.login_alert_invalid_token")]);
return redirect()->to('/login');
}
}else{
$session->setFlashdata('toast', ['error', lang("App.login_alert"), lang("App.login_alert_empty_token")]);
return redirect()->to('/login');
}
}
}