From ad4351f13b5771f1af4853b32b537d6e85c1f2e4 Mon Sep 17 00:00:00 2001 From: M Hamza Siddiqui Date: Tue, 24 Apr 2018 16:55:17 +0500 Subject: [PATCH 1/3] Frontend User Authentication Fixed Frontend User authentication controller and view added. --- application/controllers/Auth.php | 834 ++++++ application/models/Ion_auth_model.php | 2257 +++++++++++++++++ application/views/auth/change_password.php | 25 + application/views/auth/create_group.php | 20 + application/views/auth/create_user.php | 57 + application/views/auth/deactivate_user.php | 18 + application/views/auth/edit_group.php | 20 + application/views/auth/edit_user.php | 66 + application/views/auth/email/activate.tpl.php | 6 + .../views/auth/email/forgot_password.tpl.php | 6 + .../views/auth/email/new_password.tpl.php | 7 + application/views/auth/forgot_password.php | 17 + application/views/auth/index.php | 31 + application/views/auth/login.php | 16 + application/views/auth/reset_password.php | 22 + 15 files changed, 3402 insertions(+) create mode 100644 application/controllers/Auth.php create mode 100644 application/models/Ion_auth_model.php create mode 100644 application/views/auth/change_password.php create mode 100644 application/views/auth/create_group.php create mode 100644 application/views/auth/create_user.php create mode 100644 application/views/auth/deactivate_user.php create mode 100644 application/views/auth/edit_group.php create mode 100644 application/views/auth/edit_user.php create mode 100644 application/views/auth/email/activate.tpl.php create mode 100644 application/views/auth/email/forgot_password.tpl.php create mode 100644 application/views/auth/email/new_password.tpl.php create mode 100644 application/views/auth/forgot_password.php create mode 100644 application/views/auth/index.php create mode 100644 application/views/auth/login.php create mode 100644 application/views/auth/reset_password.php diff --git a/application/controllers/Auth.php b/application/controllers/Auth.php new file mode 100644 index 00000000..fa2e76cb --- /dev/null +++ b/application/controllers/Auth.php @@ -0,0 +1,834 @@ +load->database(); + $this->load->library(array('ion_auth','form_validation')); + $this->load->helper(array('url','language')); + + //$this->form_validation->set_error_delimiters($this->config->item('error_start_delimiter', 'ion_auth'), $this->config->item('error_end_delimiter', 'ion_auth')); + if ($this->ion_auth->logged_in()){ + $this->mViewData['user'] = $this->ion_auth->user()->row(); + } + + $this->lang->load('auth'); + } + + // redirect if needed, otherwise display the user list + function index() + { + + if (!$this->ion_auth->logged_in()) + { + // redirect them to the login page + redirect('auth/login', 'refresh'); + } + /*elseif (!$this->ion_auth->is_admin()) // remove this elseif if you want to enable this for non-admins + { + // redirect them to the home page because they must be an administrator to view this + return show_error('You must be an administrator to view this page.'); + }*/ + else + { + // set the flash data error message if there is one + $this->mViewData['message'] = (validation_errors()) ? validation_errors() : $this->session->flashdata('message'); + + //list the users + $this->mViewData['users'] = $this->ion_auth->users()->result(); + foreach ($this->mViewData['users'] as $k => $user) + { + $this->mViewData['users'][$k]->groups = $this->ion_auth->get_users_groups($user->id)->result(); + } + + $this->render('auth/index'); + } + } + + // log the user in + function login() + { + + if ($this->ion_auth->logged_in()) + { + // redirect them to the login page + redirect('/', 'refresh'); + } + + $this->mViewData['title'] = "Login"; + + $this->load->library('form_builder'); + $form = $this->form_builder->create_form(); + + // the user is not logging in so display the login page + // set the flash data error message if there is one + $this->mViewData['form'] = $form; + $this->render('auth/login'); + } + + function login_process() + { + + + if ($this->ion_auth->logged_in()) + { + // redirect them to the login page + redirect('/', 'refresh'); + } + + // check to see if the user is logging in + // check for "remember me" + // passed validation + $identity = $this->input->post('username'); + $password = $this->input->post('password'); + $remember = ($this->input->post('remember')=='on'); + + if ($this->ion_auth->login($identity, $password, $remember)) + { + //if the login is successful + //redirect them back to the home page + //$this->session->set_flashdata('message', $this->ion_auth->messages()); + //$messages = $this->ion_auth->messages(); + //$this->system_message->set_success($messages); + //echo "Success"; + redirect('/'); + } + else + { + // if the login was un-successful + // redirect them back to the login page + $this->session->set_flashdata('message', $this->ion_auth->errors()); + $errors = $this->ion_auth->errors(); + //print_r($errors); + $this->system_message->set_error($errors); + //echo "Failed"; + redirect('/auth/login'); // use redirects instead of loading views for compatibility with MY_Controller libraries + } + } + + // log the user out + function logout() + { + $this->mViewData['title'] = "Logout"; + + // log the user out + $logout = $this->ion_auth->logout(); + + // redirect them to the login page + //$this->session->set_flashdata('message', $this->ion_auth->messages()); + redirect('auth/login', 'refresh'); + } + + // change password + function change_password() + { + $this->form_validation->set_rules('old', $this->lang->line('change_password_validation_old_password_label'), 'required'); + $this->form_validation->set_rules('new', $this->lang->line('change_password_validation_new_password_label'), 'required|min_length[' . $this->config->item('min_password_length', 'ion_auth') . ']|max_length[' . $this->config->item('max_password_length', 'ion_auth') . ']|matches[new_confirm]'); + $this->form_validation->set_rules('new_confirm', $this->lang->line('change_password_validation_new_password_confirm_label'), 'required'); + + if (!$this->ion_auth->logged_in()) + { + redirect('auth/login', 'refresh'); + } + + $user = $this->ion_auth->user()->row(); + + if ($this->form_validation->run() == false) + { + // display the form + // set the flash data error message if there is one + $this->mViewData['message'] = (validation_errors()) ? validation_errors() : $this->session->flashdata('message'); + + $this->mViewData['min_password_length'] = $this->config->item('min_password_length', 'ion_auth'); + $this->mViewData['old_password'] = array( + 'name' => 'old', + 'id' => 'old', + 'type' => 'password', + ); + $this->mViewData['new_password'] = array( + 'name' => 'new', + 'id' => 'new', + 'type' => 'password', + 'pattern' => '^.{'.$this->mViewData['min_password_length'].'}.*$', + ); + $this->mViewData['new_password_confirm'] = array( + 'name' => 'new_confirm', + 'id' => 'new_confirm', + 'type' => 'password', + 'pattern' => '^.{'.$this->mViewData['min_password_length'].'}.*$', + ); + $this->mViewData['user_id'] = array( + 'name' => 'user_id', + 'id' => 'user_id', + 'type' => 'hidden', + 'value' => $user->id, + ); + + // render + $this->_render_page('auth/change_password', $this->data); + } + else + { + $identity = $this->session->userdata('identity'); + + $change = $this->ion_auth->change_password($identity, $this->input->post('old'), $this->input->post('new')); + + if ($change) + { + //if the password was successfully changed + $this->session->set_flashdata('message', $this->ion_auth->messages()); + $this->logout(); + } + else + { + $this->session->set_flashdata('message', $this->ion_auth->errors()); + redirect('auth/change_password', 'refresh'); + } + } + } + + // forgot password + function forgot_password() + { + // setting validation rules by checking wheather identity is username or email + if($this->config->item('identity', 'ion_auth') != 'email' ) + { + $this->form_validation->set_rules('identity', $this->lang->line('forgot_password_identity_label'), 'required'); + } + else + { + $this->form_validation->set_rules('identity', $this->lang->line('forgot_password_validation_email_label'), 'required|valid_email'); + } + + + if ($this->form_validation->run() == false) + { + $this->mViewData['type'] = $this->config->item('identity','ion_auth'); + // setup the input + $this->mViewData['identity'] = array('name' => 'identity', + 'id' => 'identity', + 'class' => 'form-control' + ); + + if ( $this->config->item('identity', 'ion_auth') != 'email' ){ + $this->mViewData['identity_label'] = $this->lang->line('forgot_password_identity_label'); + } + else + { + $this->mViewData['identity_label'] = $this->lang->line('forgot_password_email_identity_label'); + } + + // set any errors and display the form + $this->mViewData['message'] = (validation_errors()) ? validation_errors() : $this->session->flashdata('message'); + $this->render('auth/forgot_password'); + } + else + { + $identity_column = $this->config->item('identity','ion_auth'); + $identity = $this->ion_auth->where($identity_column, $this->input->get('identity'))->users()->row(); + + if(empty($identity)) { + + if($this->config->item('identity', 'ion_auth') != 'email') + { + $this->ion_auth->set_error('forgot_password_identity_not_found'); + } + else + { + $this->ion_auth->set_error('forgot_password_email_not_found'); + } + + $this->session->set_flashdata('message', $this->ion_auth->errors()); + redirect("auth/forgot_password", 'refresh'); + } + + // run the forgotten password method to email an activation code to the user + $forgotten = $this->ion_auth->forgotten_password($identity->{$this->config->item('identity', 'ion_auth')}); + + if ($forgotten) + { + // if there were no errors + $this->session->set_flashdata('message', $this->ion_auth->messages()); + redirect("auth/login", 'refresh'); //we should display a confirmation page here instead of the login page + } + else + { + $this->session->set_flashdata('message', $this->ion_auth->errors()); + redirect("auth/forgot_password", 'refresh'); + } + } + } + + // reset password - final step for forgotten password + public function reset_password($code = NULL) + { + if (!$code) + { + show_404(); + } + + $user = $this->ion_auth->forgotten_password_check($code); + + if ($user) + { + // if the code is valid then display the password reset form + + $this->form_validation->set_rules('new', $this->lang->line('reset_password_validation_new_password_label'), 'required|min_length[' . $this->config->item('min_password_length', 'ion_auth') . ']|max_length[' . $this->config->item('max_password_length', 'ion_auth') . ']|matches[new_confirm]'); + $this->form_validation->set_rules('new_confirm', $this->lang->line('reset_password_validation_new_password_confirm_label'), 'required'); + + if ($this->form_validation->run() == false) + { + // display the form + + // set the flash data error message if there is one + $this->mViewData['message'] = (validation_errors()) ? validation_errors() : $this->session->flashdata('message'); + + $this->mViewData['min_password_length'] = $this->config->item('min_password_length', 'ion_auth'); + $this->mViewData['new_password'] = array( + 'name' => 'new', + 'id' => 'new', + 'type' => 'password', + 'pattern' => '^.{'.$this->mViewData['min_password_length'].'}.*$', + ); + $this->mViewData['new_password_confirm'] = array( + 'name' => 'new_confirm', + 'id' => 'new_confirm', + 'type' => 'password', + 'pattern' => '^.{'.$this->mViewData['min_password_length'].'}.*$', + ); + $this->mViewData['user_id'] = array( + 'name' => 'user_id', + 'id' => 'user_id', + 'type' => 'hidden', + 'value' => $user->id, + ); + $this->mViewData['csrf'] = $this->_get_csrf_nonce(); + $this->mViewData['code'] = $code; + + // render + $this->_render_page('auth/reset_password', $this->data); + } + else + { + // do we have a valid request? + if ($this->_valid_csrf_nonce() === FALSE || $user->id != $this->input->post('user_id')) + { + + // something fishy might be up + $this->ion_auth->clear_forgotten_password_code($code); + + show_error($this->lang->line('error_csrf')); + + } + else + { + // finally change the password + $identity = $user->{$this->config->item('identity', 'ion_auth')}; + + $change = $this->ion_auth->reset_password($identity, $this->input->post('new')); + + if ($change) + { + // if the password was successfully changed + $this->session->set_flashdata('message', $this->ion_auth->messages()); + redirect("auth/login", 'refresh'); + } + else + { + $this->session->set_flashdata('message', $this->ion_auth->errors()); + redirect('auth/reset_password/' . $code, 'refresh'); + } + } + } + } + else + { + // if the code is invalid then send them back to the forgot password page + $this->session->set_flashdata('message', $this->ion_auth->errors()); + redirect("auth/forgot_password", 'refresh'); + } + } + + + // activate the user + function activate($id, $code=false) + { + if ($code !== false) + { + $activation = $this->ion_auth->activate($id, $code); + } + else if ($this->ion_auth->is_admin()) + { + $activation = $this->ion_auth->activate($id); + } + + if ($activation) + { + // redirect them to the auth page + $this->session->set_flashdata('message', $this->ion_auth->messages()); + redirect("auth", 'refresh'); + } + else + { + // redirect them to the forgot password page + $this->session->set_flashdata('message', $this->ion_auth->errors()); + redirect("auth/forgot_password", 'refresh'); + } + } + + // deactivate the user + function deactivate($id = NULL) + { + if (!$this->ion_auth->logged_in() || !$this->ion_auth->is_admin()) + { + // redirect them to the home page because they must be an administrator to view this + return show_error('You must be an administrator to view this page.'); + } + + $id = (int) $id; + + $this->load->library('form_validation'); + $this->form_validation->set_rules('confirm', $this->lang->line('deactivate_validation_confirm_label'), 'required'); + $this->form_validation->set_rules('id', $this->lang->line('deactivate_validation_user_id_label'), 'required|alpha_numeric'); + + if ($this->form_validation->run() == FALSE) + { + // insert csrf check + $this->mViewData['csrf'] = $this->_get_csrf_nonce(); + $this->mViewData['user'] = $this->ion_auth->user($id)->row(); + + $this->_render_page('auth/deactivate_user', $this->data); + } + else + { + // do we really want to deactivate? + if ($this->input->post('confirm') == 'yes') + { + // do we have a valid request? + if ($this->_valid_csrf_nonce() === FALSE || $id != $this->input->post('id')) + { + show_error($this->lang->line('error_csrf')); + } + + // do we have the right userlevel? + if ($this->ion_auth->logged_in() && $this->ion_auth->is_admin()) + { + $this->ion_auth->deactivate($id); + } + } + + // redirect them back to the auth page + redirect('auth', 'refresh'); + } + } + + // create a new user + function create_user() + { + $this->mViewData['title'] = "Create User"; + + if (!$this->ion_auth->logged_in() || !$this->ion_auth->is_admin()) + { + redirect('auth', 'refresh'); + } + + $tables = $this->config->item('tables','ion_auth'); + $identity_column = $this->config->item('identity','ion_auth'); + $this->mViewData['identity_column'] = $identity_column; + + // validate form input + $this->form_validation->set_rules('first_name', $this->lang->line('create_user_validation_fname_label'), 'required'); + $this->form_validation->set_rules('last_name', $this->lang->line('create_user_validation_lname_label'), 'required'); + if($identity_column!=='email') + { + $this->form_validation->set_rules('identity',$this->lang->line('create_user_validation_identity_label'),'required|is_unique['.$tables['users'].'.'.$identity_column.']'); + $this->form_validation->set_rules('email', $this->lang->line('create_user_validation_email_label'), 'required|valid_email'); + } + else + { + $this->form_validation->set_rules('email', $this->lang->line('create_user_validation_email_label'), 'required|valid_email|is_unique[' . $tables['users'] . '.email]'); + } + $this->form_validation->set_rules('phone', $this->lang->line('create_user_validation_phone_label'), 'trim'); + $this->form_validation->set_rules('company', $this->lang->line('create_user_validation_company_label'), 'trim'); + $this->form_validation->set_rules('password', $this->lang->line('create_user_validation_password_label'), 'required|min_length[' . $this->config->item('min_password_length', 'ion_auth') . ']|max_length[' . $this->config->item('max_password_length', 'ion_auth') . ']|matches[password_confirm]'); + $this->form_validation->set_rules('password_confirm', $this->lang->line('create_user_validation_password_confirm_label'), 'required'); + + if ($this->form_validation->run() == true) + { + $email = strtolower($this->input->post('email')); + $identity = ($identity_column==='email') ? $email : $this->input->post('identity'); + $password = $this->input->post('password'); + + $additional_data = array( + 'first_name' => $this->input->post('first_name'), + 'last_name' => $this->input->post('last_name'), + 'company' => $this->input->post('company'), + 'phone' => $this->input->post('phone'), + ); + } + if ($this->form_validation->run() == true && $this->ion_auth->register($identity, $password, $email, $additional_data)) + { + // check to see if we are creating the user + // redirect them back to the admin page + $this->session->set_flashdata('message', $this->ion_auth->messages()); + redirect("auth", 'refresh'); + } + else + { + // display the create user form + // set the flash data error message if there is one + $this->mViewData['message'] = (validation_errors() ? validation_errors() : ($this->ion_auth->errors() ? $this->ion_auth->errors() : $this->session->flashdata('message'))); + + $this->mViewData['first_name'] = array( + 'name' => 'first_name', + 'id' => 'first_name', + 'type' => 'text', + 'value' => $this->form_validation->set_value('first_name'), + ); + $this->mViewData['last_name'] = array( + 'name' => 'last_name', + 'id' => 'last_name', + 'type' => 'text', + 'value' => $this->form_validation->set_value('last_name'), + ); + $this->mViewData['identity'] = array( + 'name' => 'identity', + 'id' => 'identity', + 'type' => 'text', + 'value' => $this->form_validation->set_value('identity'), + ); + $this->mViewData['email'] = array( + 'name' => 'email', + 'id' => 'email', + 'type' => 'text', + 'value' => $this->form_validation->set_value('email'), + ); + $this->mViewData['company'] = array( + 'name' => 'company', + 'id' => 'company', + 'type' => 'text', + 'value' => $this->form_validation->set_value('company'), + ); + $this->mViewData['phone'] = array( + 'name' => 'phone', + 'id' => 'phone', + 'type' => 'text', + 'value' => $this->form_validation->set_value('phone'), + ); + $this->mViewData['password'] = array( + 'name' => 'password', + 'id' => 'password', + 'type' => 'password', + 'value' => $this->form_validation->set_value('password'), + ); + $this->mViewData['password_confirm'] = array( + 'name' => 'password_confirm', + 'id' => 'password_confirm', + 'type' => 'password', + 'value' => $this->form_validation->set_value('password_confirm'), + ); + + $this->_render_page('auth/create_user', $this->data); + } + } + + // edit a user + function edit_user($id) + { + $this->mViewData['title'] = "Edit User"; + + if (!$this->ion_auth->logged_in() || (!$this->ion_auth->is_admin() && !($this->ion_auth->user()->row()->id == $id))) + { + redirect('auth', 'refresh'); + } + + $user = $this->ion_auth->user($id)->row(); + $groups=$this->ion_auth->groups()->result_array(); + $currentGroups = $this->ion_auth->get_users_groups($id)->result(); + + // validate form input + $this->form_validation->set_rules('first_name', $this->lang->line('edit_user_validation_fname_label'), 'required'); + $this->form_validation->set_rules('last_name', $this->lang->line('edit_user_validation_lname_label'), 'required'); + $this->form_validation->set_rules('phone', $this->lang->line('edit_user_validation_phone_label'), 'required'); + $this->form_validation->set_rules('company', $this->lang->line('edit_user_validation_company_label'), 'required'); + + if (isset($_POST) && !empty($_POST)) + { + // do we have a valid request? + if ($this->_valid_csrf_nonce() === FALSE || $id != $this->input->post('id')) + { + show_error($this->lang->line('error_csrf')); + } + + // update the password if it was posted + if ($this->input->post('password')) + { + $this->form_validation->set_rules('password', $this->lang->line('edit_user_validation_password_label'), 'required|min_length[' . $this->config->item('min_password_length', 'ion_auth') . ']|max_length[' . $this->config->item('max_password_length', 'ion_auth') . ']|matches[password_confirm]'); + $this->form_validation->set_rules('password_confirm', $this->lang->line('edit_user_validation_password_confirm_label'), 'required'); + } + + if ($this->form_validation->run() === TRUE) + { + $data = array( + 'first_name' => $this->input->post('first_name'), + 'last_name' => $this->input->post('last_name'), + 'company' => $this->input->post('company'), + 'phone' => $this->input->post('phone'), + ); + + // update the password if it was posted + if ($this->input->post('password')) + { + $data['password'] = $this->input->post('password'); + } + + + + // Only allow updating groups if user is admin + if ($this->ion_auth->is_admin()) + { + //Update the groups user belongs to + $groupData = $this->input->post('groups'); + + if (isset($groupData) && !empty($groupData)) { + + $this->ion_auth->remove_from_group('', $id); + + foreach ($groupData as $grp) { + $this->ion_auth->add_to_group($grp, $id); + } + + } + } + + // check to see if we are updating the user + if($this->ion_auth->update($user->id, $data)) + { + // redirect them back to the admin page if admin, or to the base url if non admin + $this->session->set_flashdata('message', $this->ion_auth->messages() ); + if ($this->ion_auth->is_admin()) + { + redirect('auth', 'refresh'); + } + else + { + redirect('/', 'refresh'); + } + + } + else + { + // redirect them back to the admin page if admin, or to the base url if non admin + $this->session->set_flashdata('message', $this->ion_auth->errors() ); + if ($this->ion_auth->is_admin()) + { + redirect('auth', 'refresh'); + } + else + { + redirect('/', 'refresh'); + } + + } + + } + } + + // display the edit user form + $this->mViewData['csrf'] = $this->_get_csrf_nonce(); + + // set the flash data error message if there is one + $this->mViewData['message'] = (validation_errors() ? validation_errors() : ($this->ion_auth->errors() ? $this->ion_auth->errors() : $this->session->flashdata('message'))); + + // pass the user to the view + $this->mViewData['user'] = $user; + $this->mViewData['groups'] = $groups; + $this->mViewData['currentGroups'] = $currentGroups; + + $this->mViewData['first_name'] = array( + 'name' => 'first_name', + 'id' => 'first_name', + 'type' => 'text', + 'value' => $this->form_validation->set_value('first_name', $user->first_name), + ); + $this->mViewData['last_name'] = array( + 'name' => 'last_name', + 'id' => 'last_name', + 'type' => 'text', + 'value' => $this->form_validation->set_value('last_name', $user->last_name), + ); + $this->mViewData['company'] = array( + 'name' => 'company', + 'id' => 'company', + 'type' => 'text', + 'value' => $this->form_validation->set_value('company', $user->company), + ); + $this->mViewData['phone'] = array( + 'name' => 'phone', + 'id' => 'phone', + 'type' => 'text', + 'value' => $this->form_validation->set_value('phone', $user->phone), + ); + $this->mViewData['password'] = array( + 'name' => 'password', + 'id' => 'password', + 'type' => 'password' + ); + $this->mViewData['password_confirm'] = array( + 'name' => 'password_confirm', + 'id' => 'password_confirm', + 'type' => 'password' + ); + + $this->_render_page('auth/edit_user', $this->data); + } + + // create a new group + function create_group() + { + $this->mViewData['title'] = $this->lang->line('create_group_title'); + + if (!$this->ion_auth->logged_in() || !$this->ion_auth->is_admin()) + { + redirect('auth', 'refresh'); + } + + // validate form input + $this->form_validation->set_rules('group_name', $this->lang->line('create_group_validation_name_label'), 'required|alpha_dash'); + + if ($this->form_validation->run() == TRUE) + { + $new_group_id = $this->ion_auth->create_group($this->input->post('group_name'), $this->input->post('description')); + if($new_group_id) + { + // check to see if we are creating the group + // redirect them back to the admin page + $this->session->set_flashdata('message', $this->ion_auth->messages()); + redirect("auth", 'refresh'); + } + } + else + { + // display the create group form + // set the flash data error message if there is one + $this->mViewData['message'] = (validation_errors() ? validation_errors() : ($this->ion_auth->errors() ? $this->ion_auth->errors() : $this->session->flashdata('message'))); + + $this->mViewData['group_name'] = array( + 'name' => 'group_name', + 'id' => 'group_name', + 'type' => 'text', + 'value' => $this->form_validation->set_value('group_name'), + ); + $this->mViewData['description'] = array( + 'name' => 'description', + 'id' => 'description', + 'type' => 'text', + 'value' => $this->form_validation->set_value('description'), + ); + + $this->_render_page('auth/create_group', $this->data); + } + } + + // edit a group + function edit_group($id) + { + // bail if no group id given + if(!$id || empty($id)) + { + redirect('auth', 'refresh'); + } + + $this->mViewData['title'] = $this->lang->line('edit_group_title'); + + if (!$this->ion_auth->logged_in() || !$this->ion_auth->is_admin()) + { + redirect('auth', 'refresh'); + } + + $group = $this->ion_auth->group($id)->row(); + + // validate form input + $this->form_validation->set_rules('group_name', $this->lang->line('edit_group_validation_name_label'), 'required|alpha_dash'); + + if (isset($_POST) && !empty($_POST)) + { + if ($this->form_validation->run() === TRUE) + { + $group_update = $this->ion_auth->update_group($id, $_POST['group_name'], $_POST['group_description']); + + if($group_update) + { + $this->session->set_flashdata('message', $this->lang->line('edit_group_saved')); + } + else + { + $this->session->set_flashdata('message', $this->ion_auth->errors()); + } + redirect("auth", 'refresh'); + } + } + + // set the flash data error message if there is one + $this->mViewData['message'] = (validation_errors() ? validation_errors() : ($this->ion_auth->errors() ? $this->ion_auth->errors() : $this->session->flashdata('message'))); + + // pass the user to the view + $this->mViewData['group'] = $group; + + $readonly = $this->config->item('admin_group', 'ion_auth') === $group->name ? 'readonly' : ''; + + $this->mViewData['group_name'] = array( + 'name' => 'group_name', + 'id' => 'group_name', + 'type' => 'text', + 'value' => $this->form_validation->set_value('group_name', $group->name), + $readonly => $readonly, + ); + $this->mViewData['group_description'] = array( + 'name' => 'group_description', + 'id' => 'group_description', + 'type' => 'text', + 'value' => $this->form_validation->set_value('group_description', $group->description), + ); + + $this->_render_page('auth/edit_group', $this->data); + } + + + function _get_csrf_nonce() + { + $this->load->helper('string'); + $key = random_string('alnum', 8); + $value = random_string('alnum', 20); + $this->session->set_flashdata('csrfkey', $key); + $this->session->set_flashdata('csrfvalue', $value); + + return array($key => $value); + } + + function _valid_csrf_nonce() + { + if ($this->input->post($this->session->flashdata('csrfkey')) !== FALSE && + $this->input->post($this->session->flashdata('csrfkey')) == $this->session->flashdata('csrfvalue')) + { + return TRUE; + } + else + { + return FALSE; + } + } + + function _render_page($view, $data=null, $returnhtml=false)//I think this makes more sense + { + + $this->viewdata = (empty($data)) ? $this->data: $data; + + $view_html = $this->load->view($view, $this->viewdata, $returnhtml); + + if ($returnhtml) return $view_html;//This will return html on 3rd argument being true + } + +} diff --git a/application/models/Ion_auth_model.php b/application/models/Ion_auth_model.php new file mode 100644 index 00000000..7f6181e5 --- /dev/null +++ b/application/models/Ion_auth_model.php @@ -0,0 +1,2257 @@ +load->database(); + $this->load->config('ion_auth', TRUE); + $this->load->helper('cookie'); + $this->load->helper('date'); + $this->lang->load('ion_auth'); + + // initialize db tables data + $this->tables = $this->config->item('tables', 'ion_auth'); + + //initialize data + $this->identity_column = $this->config->item('identity', 'ion_auth'); + $this->store_salt = $this->config->item('store_salt', 'ion_auth'); + $this->salt_length = $this->config->item('salt_length', 'ion_auth'); + $this->join = $this->config->item('join', 'ion_auth'); + + + // initialize hash method options (Bcrypt) + $this->hash_method = $this->config->item('hash_method', 'ion_auth'); + $this->default_rounds = $this->config->item('default_rounds', 'ion_auth'); + $this->random_rounds = $this->config->item('random_rounds', 'ion_auth'); + $this->min_rounds = $this->config->item('min_rounds', 'ion_auth'); + $this->max_rounds = $this->config->item('max_rounds', 'ion_auth'); + + + // initialize messages and error + $this->messages = array(); + $this->errors = array(); + $delimiters_source = $this->config->item('delimiters_source', 'ion_auth'); + + // load the error delimeters either from the config file or use what's been supplied to form validation + if ($delimiters_source === 'form_validation') + { + // load in delimiters from form_validation + // to keep this simple we'll load the value using reflection since these properties are protected + $this->load->library('form_validation'); + $form_validation_class = new ReflectionClass("CI_Form_validation"); + + $error_prefix = $form_validation_class->getProperty("_error_prefix"); + $error_prefix->setAccessible(TRUE); + $this->error_start_delimiter = $error_prefix->getValue($this->form_validation); + $this->message_start_delimiter = $this->error_start_delimiter; + + $error_suffix = $form_validation_class->getProperty("_error_suffix"); + $error_suffix->setAccessible(TRUE); + $this->error_end_delimiter = $error_suffix->getValue($this->form_validation); + $this->message_end_delimiter = $this->error_end_delimiter; + } + else + { + // use delimiters from config + $this->message_start_delimiter = $this->config->item('message_start_delimiter', 'ion_auth'); + $this->message_end_delimiter = $this->config->item('message_end_delimiter', 'ion_auth'); + $this->error_start_delimiter = $this->config->item('error_start_delimiter', 'ion_auth'); + $this->error_end_delimiter = $this->config->item('error_end_delimiter', 'ion_auth'); + } + + + // initialize our hooks object + $this->_ion_hooks = new stdClass; + + // load the bcrypt class if needed + if ($this->hash_method == 'bcrypt') { + if ($this->random_rounds) + { + $rand = rand($this->min_rounds,$this->max_rounds); + $params = array('rounds' => $rand); + } + else + { + $params = array('rounds' => $this->default_rounds); + } + + $params['salt_prefix'] = $this->config->item('salt_prefix', 'ion_auth'); + $this->load->library('bcrypt',$params); + } + + $this->trigger_events('model_constructor'); + } + + /** + * Misc functions + * + * Hash password : Hashes the password to be stored in the database. + * Hash password db : This function takes a password and validates it + * against an entry in the users table. + * Salt : Generates a random salt value. + * + * @author Mathew + */ + + /** + * Hashes the password to be stored in the database. + * + * @return void + * @author Mathew + **/ + public function hash_password($password, $salt=false, $use_sha1_override=FALSE) + { + if (empty($password)) + { + return FALSE; + } + + // bcrypt + if ($use_sha1_override === FALSE && $this->hash_method == 'bcrypt') + { + return $this->bcrypt->hash($password); + } + + + if ($this->store_salt && $salt) + { + return sha1($password . $salt); + } + else + { + $salt = $this->salt(); + return $salt . substr(sha1($salt . $password), 0, -$this->salt_length); + } + } + + /** + * This function takes a password and validates it + * against an entry in the users table. + * + * @return void + * @author Mathew + **/ + public function hash_password_db($id, $password, $use_sha1_override=FALSE) + { + if (empty($id) || empty($password)) + { + return FALSE; + } + + $this->trigger_events('extra_where'); + + $query = $this->db->select('password, salt') + ->where('id', $id) + ->limit(1) + ->order_by('id', 'desc') + ->get($this->tables['users']); + + $hash_password_db = $query->row(); + + if ($query->num_rows() !== 1) + { + return FALSE; + } + + // bcrypt + if ($use_sha1_override === FALSE && $this->hash_method == 'bcrypt') + { + if ($this->bcrypt->verify($password,$hash_password_db->password)) + { + return TRUE; + } + + return FALSE; + } + + // sha1 + if ($this->store_salt) + { + $db_password = sha1($password . $hash_password_db->salt); + } + else + { + $salt = substr($hash_password_db->password, 0, $this->salt_length); + + $db_password = $salt . substr(sha1($salt . $password), 0, -$this->salt_length); + } + + if($db_password == $hash_password_db->password) + { + return TRUE; + } + else + { + return FALSE; + } + } + + /** + * Generates a random salt value for forgotten passwords or any other keys. Uses SHA1. + * + * @return void + * @author Mathew + **/ + public function hash_code($password) + { + return $this->hash_password($password, FALSE, TRUE); + } + + /** + * Generates a random salt value. + * + * Salt generation code taken from https://github.com/ircmaxell/password_compat/blob/master/lib/password.php + * + * @return void + * @author Anthony Ferrera + **/ + public function salt() + { + + $raw_salt_len = 16; + + $buffer = ''; + $buffer_valid = false; + + if (function_exists('mcrypt_create_iv') && !defined('PHALANGER')) { + $buffer = mcrypt_create_iv($raw_salt_len, MCRYPT_DEV_URANDOM); + if ($buffer) { + $buffer_valid = true; + } + } + + if (!$buffer_valid && function_exists('openssl_random_pseudo_bytes')) { + $buffer = openssl_random_pseudo_bytes($raw_salt_len); + if ($buffer) { + $buffer_valid = true; + } + } + + if (!$buffer_valid && @is_readable('/dev/urandom')) { + $f = fopen('/dev/urandom', 'r'); + $read = strlen($buffer); + while ($read < $raw_salt_len) { + $buffer .= fread($f, $raw_salt_len - $read); + $read = strlen($buffer); + } + fclose($f); + if ($read >= $raw_salt_len) { + $buffer_valid = true; + } + } + + if (!$buffer_valid || strlen($buffer) < $raw_salt_len) { + $bl = strlen($buffer); + for ($i = 0; $i < $raw_salt_len; $i++) { + if ($i < $bl) { + $buffer[$i] = $buffer[$i] ^ chr(mt_rand(0, 255)); + } else { + $buffer .= chr(mt_rand(0, 255)); + } + } + } + + $salt = $buffer; + + // encode string with the Base64 variant used by crypt + $base64_digits = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; + $bcrypt64_digits = './ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; + $base64_string = base64_encode($salt); + $salt = strtr(rtrim($base64_string, '='), $base64_digits, $bcrypt64_digits); + + $salt = substr($salt, 0, $this->salt_length); + + + return $salt; + + } + + /** + * Activation functions + * + * Activate : Validates and removes activation code. + * Deactivae : Updates a users row with an activation code. + * + * @author Mathew + */ + + /** + * activate + * + * @return void + * @author Mathew + **/ + public function activate($id, $code = false) + { + $this->trigger_events('pre_activate'); + + if ($code !== FALSE) + { + $query = $this->db->select($this->identity_column) + ->where('activation_code', $code) + ->where('id', $id) + ->limit(1) + ->order_by('id', 'desc') + ->get($this->tables['users']); + + $result = $query->row(); + + if ($query->num_rows() !== 1) + { + $this->trigger_events(array('post_activate', 'post_activate_unsuccessful')); + $this->set_error('activate_unsuccessful'); + return FALSE; + } + + $data = array( + 'activation_code' => NULL, + 'active' => 1 + ); + + $this->trigger_events('extra_where'); + $this->db->update($this->tables['users'], $data, array('id' => $id)); + } + else + { + $data = array( + 'activation_code' => NULL, + 'active' => 1 + ); + + + $this->trigger_events('extra_where'); + $this->db->update($this->tables['users'], $data, array('id' => $id)); + } + + + $return = $this->db->affected_rows() == 1; + if ($return) + { + $this->trigger_events(array('post_activate', 'post_activate_successful')); + $this->set_message('activate_successful'); + } + else + { + $this->trigger_events(array('post_activate', 'post_activate_unsuccessful')); + $this->set_error('activate_unsuccessful'); + } + + + return $return; + } + + + /** + * Deactivate + * + * @return void + * @author Mathew + **/ + public function deactivate($id = NULL) + { + $this->trigger_events('deactivate'); + + if (!isset($id)) + { + $this->set_error('deactivate_unsuccessful'); + return FALSE; + } + + $activation_code = sha1(md5(microtime())); + $this->activation_code = $activation_code; + + $data = array( + 'activation_code' => $activation_code, + 'active' => 0 + ); + + $this->trigger_events('extra_where'); + $this->db->update($this->tables['users'], $data, array('id' => $id)); + + $return = $this->db->affected_rows() == 1; + if ($return) + $this->set_message('deactivate_successful'); + else + $this->set_error('deactivate_unsuccessful'); + + return $return; + } + + public function clear_forgotten_password_code($code) { + + if (empty($code)) + { + return FALSE; + } + + $this->db->where('forgotten_password_code', $code); + + if ($this->db->count_all_results($this->tables['users']) > 0) + { + $data = array( + 'forgotten_password_code' => NULL, + 'forgotten_password_time' => NULL + ); + + $this->db->update($this->tables['users'], $data, array('forgotten_password_code' => $code)); + + return TRUE; + } + + return FALSE; + } + + /** + * reset password + * + * @return bool + * @author Mathew + **/ + public function reset_password($identity, $new) { + $this->trigger_events('pre_change_password'); + + if (!$this->identity_check($identity)) { + $this->trigger_events(array('post_change_password', 'post_change_password_unsuccessful')); + return FALSE; + } + + $this->trigger_events('extra_where'); + + $query = $this->db->select('id, password, salt') + ->where($this->identity_column, $identity) + ->limit(1) + ->order_by('id', 'desc') + ->get($this->tables['users']); + + if ($query->num_rows() !== 1) + { + $this->trigger_events(array('post_change_password', 'post_change_password_unsuccessful')); + $this->set_error('password_change_unsuccessful'); + return FALSE; + } + + $result = $query->row(); + + $new = $this->hash_password($new, $result->salt); + + // store the new password and reset the remember code so all remembered instances have to re-login + // also clear the forgotten password code + $data = array( + 'password' => $new, + 'remember_code' => NULL, + 'forgotten_password_code' => NULL, + 'forgotten_password_time' => NULL, + ); + + $this->trigger_events('extra_where'); + $this->db->update($this->tables['users'], $data, array($this->identity_column => $identity)); + + $return = $this->db->affected_rows() == 1; + if ($return) + { + $this->trigger_events(array('post_change_password', 'post_change_password_successful')); + $this->set_message('password_change_successful'); + } + else + { + $this->trigger_events(array('post_change_password', 'post_change_password_unsuccessful')); + $this->set_error('password_change_unsuccessful'); + } + + return $return; + } + + /** + * change password + * + * @return bool + * @author Mathew + **/ + public function change_password($identity, $old, $new) + { + $this->trigger_events('pre_change_password'); + + $this->trigger_events('extra_where'); + + $query = $this->db->select('id, password, salt') + ->where($this->identity_column, $identity) + ->limit(1) + ->order_by('id', 'desc') + ->get($this->tables['users']); + + if ($query->num_rows() !== 1) + { + $this->trigger_events(array('post_change_password', 'post_change_password_unsuccessful')); + $this->set_error('password_change_unsuccessful'); + return FALSE; + } + + $user = $query->row(); + + $old_password_matches = $this->hash_password_db($user->id, $old); + + if ($old_password_matches === TRUE) + { + // store the new password and reset the remember code so all remembered instances have to re-login + $hashed_new_password = $this->hash_password($new, $user->salt); + $data = array( + 'password' => $hashed_new_password, + 'remember_code' => NULL, + ); + + $this->trigger_events('extra_where'); + + $successfully_changed_password_in_db = $this->db->update($this->tables['users'], $data, array($this->identity_column => $identity)); + if ($successfully_changed_password_in_db) + { + $this->trigger_events(array('post_change_password', 'post_change_password_successful')); + $this->set_message('password_change_successful'); + } + else + { + $this->trigger_events(array('post_change_password', 'post_change_password_unsuccessful')); + $this->set_error('password_change_unsuccessful'); + } + + return $successfully_changed_password_in_db; + } + + $this->set_error('password_change_unsuccessful'); + return FALSE; + } + + /** + * Checks username + * + * @return bool + * @author Mathew + **/ + public function username_check($username = '') + { + $this->trigger_events('username_check'); + + if (empty($username)) + { + return FALSE; + } + + $this->trigger_events('extra_where'); + + return $this->db->where('username', $username) + ->group_by("id") + ->order_by("id", "ASC") + ->limit(1) + ->count_all_results($this->tables['users']) > 0; + } + + /** + * Checks email + * + * @return bool + * @author Mathew + **/ + public function email_check($email = '') + { + $this->trigger_events('email_check'); + + if (empty($email)) + { + return FALSE; + } + + $this->trigger_events('extra_where'); + + return $this->db->where('email', $email) + ->group_by("id") + ->order_by("id", "ASC") + ->limit(1) + ->count_all_results($this->tables['users']) > 0; + } + + /** + * Identity check + * + * @return bool + * @author Mathew + **/ + public function identity_check($identity = '') + { + $this->trigger_events('identity_check'); + + if (empty($identity)) + { + return FALSE; + } + + return $this->db->where($this->identity_column, $identity) + ->count_all_results($this->tables['users']) > 0; + } + + /** + * Insert a forgotten password key. + * + * @return bool + * @author Mathew + * @updated Ryan + * @updated 52aa456eef8b60ad6754b31fbdcc77bb + **/ + public function forgotten_password($identity) + { + if (empty($identity)) + { + $this->trigger_events(array('post_forgotten_password', 'post_forgotten_password_unsuccessful')); + return FALSE; + } + + // All some more randomness + $activation_code_part = ""; + if(function_exists("openssl_random_pseudo_bytes")) { + $activation_code_part = openssl_random_pseudo_bytes(128); + } + + for($i=0;$i<1024;$i++) { + $activation_code_part = sha1($activation_code_part . mt_rand() . microtime()); + } + + $key = $this->hash_code($activation_code_part.$identity); + + // If enable query strings is set, then we need to replace any unsafe characters so that the code can still work + if ($key != '' && $this->config->item('permitted_uri_chars') != '' && $this->config->item('enable_query_strings') == FALSE) + { + // preg_quote() in PHP 5.3 escapes -, so the str_replace() and addition of - to preg_quote() is to maintain backwards + // compatibility as many are unaware of how characters in the permitted_uri_chars will be parsed as a regex pattern + if ( ! preg_match("|^[".str_replace(array('\\-', '\-'), '-', preg_quote($this->config->item('permitted_uri_chars'), '-'))."]+$|i", $key)) + { + $key = preg_replace("/[^".$this->config->item('permitted_uri_chars')."]+/i", "-", $key); + } + } + + $this->forgotten_password_code = $key; + + $this->trigger_events('extra_where'); + + $update = array( + 'forgotten_password_code' => $key, + 'forgotten_password_time' => time() + ); + + $this->db->update($this->tables['users'], $update, array($this->identity_column => $identity)); + + $return = $this->db->affected_rows() == 1; + + if ($return) + $this->trigger_events(array('post_forgotten_password', 'post_forgotten_password_successful')); + else + $this->trigger_events(array('post_forgotten_password', 'post_forgotten_password_unsuccessful')); + + return $return; + } + + /** + * Forgotten Password Complete + * + * @return string + * @author Mathew + **/ + public function forgotten_password_complete($code, $salt=FALSE) + { + $this->trigger_events('pre_forgotten_password_complete'); + + if (empty($code)) + { + $this->trigger_events(array('post_forgotten_password_complete', 'post_forgotten_password_complete_unsuccessful')); + return FALSE; + } + + $profile = $this->where('forgotten_password_code', $code)->users()->row(); //pass the code to profile + + if ($profile) { + + if ($this->config->item('forgot_password_expiration', 'ion_auth') > 0) { + //Make sure it isn't expired + $expiration = $this->config->item('forgot_password_expiration', 'ion_auth'); + if (time() - $profile->forgotten_password_time > $expiration) { + //it has expired + $this->set_error('forgot_password_expired'); + $this->trigger_events(array('post_forgotten_password_complete', 'post_forgotten_password_complete_unsuccessful')); + return FALSE; + } + } + + $password = $this->salt(); + + $data = array( + 'password' => $this->hash_password($password, $salt), + 'forgotten_password_code' => NULL, + 'active' => 1, + ); + + $this->db->update($this->tables['users'], $data, array('forgotten_password_code' => $code)); + + $this->trigger_events(array('post_forgotten_password_complete', 'post_forgotten_password_complete_successful')); + return $password; + } + + $this->trigger_events(array('post_forgotten_password_complete', 'post_forgotten_password_complete_unsuccessful')); + return FALSE; + } + + /** + * register + * + * @return bool + * @author Mathew + **/ + public function register($identity, $password, $email, $additional_data = array(), $groups = array()) + { + $this->trigger_events('pre_register'); + + $manual_activation = $this->config->item('manual_activation', 'ion_auth'); + + if ($this->identity_check($identity)) + { + $this->set_error('account_creation_duplicate_identity'); + return FALSE; + } + elseif ( !$this->config->item('default_group', 'ion_auth') && empty($groups) ) + { + $this->set_error('account_creation_missing_default_group'); + return FALSE; + } + + // check if the default set in config exists in database + $query = $this->db->get_where($this->tables['groups'],array('name' => $this->config->item('default_group', 'ion_auth')),1)->row(); + if( !isset($query->id) && empty($groups) ) + { + $this->set_error('account_creation_invalid_default_group'); + return FALSE; + } + + // capture default group details + $default_group = $query; + + // IP Address + $ip_address = $this->_prepare_ip($this->input->ip_address()); + $salt = $this->store_salt ? $this->salt() : FALSE; + $password = $this->hash_password($password, $salt); + + // Users table. + $data = array( + $this->identity_column => $identity, + 'password' => $password, + 'email' => $email, + 'ip_address' => $ip_address, + 'created_on' => time(), + 'active' => ($manual_activation === false ? 1 : 0) + ); + + if ($this->store_salt) + { + $data['salt'] = $salt; + } + + // filter out any data passed that doesnt have a matching column in the users table + // and merge the set user data and the additional data + $user_data = array_merge($this->_filter_data($this->tables['users'], $additional_data), $data); + + $this->trigger_events('extra_set'); + + $this->db->insert($this->tables['users'], $user_data); + + $id = $this->db->insert_id(); + + // add in groups array if it doesn't exits and stop adding into default group if default group ids are set + if( isset($default_group->id) && empty($groups) ) + { + $groups[] = $default_group->id; + } + + if (!empty($groups)) + { + // add to groups + foreach ($groups as $group) + { + $this->add_to_group($group, $id); + } + } + + $this->trigger_events('post_register'); + + return (isset($id)) ? $id : FALSE; + } + + /** + * login + * + * @return bool + * @author Mathew + **/ + public function login($identity, $password, $remember=FALSE) + { + + $this->trigger_events('pre_login'); + + if (empty($identity) || empty($password)) + { + $this->set_error('login_unsuccessful'); + return FALSE; + } + + $this->trigger_events('extra_where'); + + $query = $this->db->select($this->identity_column . ', email, id, password, active, last_login') + ->where($this->identity_column, $identity) + ->limit(1) + ->order_by('id', 'desc') + ->get($this->tables['users']); + + exit; + if($this->is_time_locked_out($identity)) + { + // Hash something anyway, just to take up time + $this->hash_password($password); + + $this->trigger_events('post_login_unsuccessful'); + $this->set_error('login_timeout'); + + return FALSE; + } + + if ($query->num_rows() === 1) + { + $user = $query->row(); + + $password = $this->hash_password_db($user->id, $password); + + if ($password === TRUE) + { + if ($user->active == 0) + { + $this->trigger_events('post_login_unsuccessful'); + $this->set_error('login_unsuccessful_not_active'); + + return FALSE; + } + + $this->set_session($user); + + $this->update_last_login($user->id); + + $this->clear_login_attempts($identity); + + if ($remember && $this->config->item('remember_users', 'ion_auth')) + { + $this->remember_user($user->id); + } + + $this->trigger_events(array('post_login', 'post_login_successful')); + $this->set_message('login_successful'); + + return TRUE; + } + } + + // Hash something anyway, just to take up time + $this->hash_password($password); + + $this->increase_login_attempts($identity); + + $this->trigger_events('post_login_unsuccessful'); + $this->set_error('login_unsuccessful'); + + return FALSE; + } + + /** + * is_max_login_attempts_exceeded + * Based on code from Tank Auth, by Ilya Konyukhov (https://github.com/ilkon/Tank-Auth) + * + * @param string $identity + * @return boolean + **/ + public function is_max_login_attempts_exceeded($identity) { + if ($this->config->item('track_login_attempts', 'ion_auth')) { + $max_attempts = $this->config->item('maximum_login_attempts', 'ion_auth'); + if ($max_attempts > 0) { + $attempts = $this->get_attempts_num($identity); + return $attempts >= $max_attempts; + } + } + return FALSE; + } + + /** + * Get number of attempts to login occured from given IP-address or identity + * Based on code from Tank Auth, by Ilya Konyukhov (https://github.com/ilkon/Tank-Auth) + * + * @param string $identity + * @return int + */ + function get_attempts_num($identity) + { + if ($this->config->item('track_login_attempts', 'ion_auth')) { + $ip_address = $this->_prepare_ip($this->input->ip_address()); + $this->db->select('1', FALSE); + if ($this->config->item('track_login_ip_address', 'ion_auth')) { + $this->db->where('ip_address', $ip_address); + $this->db->where('login', $identity); + } else if (strlen($identity) > 0) $this->db->or_where('login', $identity); + $qres = $this->db->get($this->tables['login_attempts']); + return $qres->num_rows(); + } + return 0; + } + + /** + * Get a boolean to determine if an account should be locked out due to + * exceeded login attempts within a given period + * + * @return boolean + */ + public function is_time_locked_out($identity) { + + return $this->is_max_login_attempts_exceeded($identity) && $this->get_last_attempt_time($identity) > time() - $this->config->item('lockout_time', 'ion_auth'); + } + + /** + * Get the time of the last time a login attempt occured from given IP-address or identity + * + * @param string $identity + * @return int + */ + public function get_last_attempt_time($identity) { + if ($this->config->item('track_login_attempts', 'ion_auth')) { + $ip_address = $this->_prepare_ip($this->input->ip_address()); + + $this->db->select_max('time'); + if ($this->config->item('track_login_ip_address', 'ion_auth')) $this->db->where('ip_address', $ip_address); + else if (strlen($identity) > 0) $this->db->or_where('login', $identity); + $qres = $this->db->get($this->tables['login_attempts'], 1); + + if($qres->num_rows() > 0) { + return $qres->row()->time; + } + } + + return 0; + } + + /** + * increase_login_attempts + * Based on code from Tank Auth, by Ilya Konyukhov (https://github.com/ilkon/Tank-Auth) + * + * @param string $identity + **/ + public function increase_login_attempts($identity) { + if ($this->config->item('track_login_attempts', 'ion_auth')) { + $ip_address = $this->_prepare_ip($this->input->ip_address()); + return $this->db->insert($this->tables['login_attempts'], array('ip_address' => $ip_address, 'login' => $identity, 'time' => time())); + } + return FALSE; + } + + /** + * clear_login_attempts + * Based on code from Tank Auth, by Ilya Konyukhov (https://github.com/ilkon/Tank-Auth) + * + * @param string $identity + **/ + public function clear_login_attempts($identity, $expire_period = 86400) { + if ($this->config->item('track_login_attempts', 'ion_auth')) { + $ip_address = $this->_prepare_ip($this->input->ip_address()); + + $this->db->where(array('ip_address' => $ip_address, 'login' => $identity)); + // Purge obsolete login attempts + $this->db->or_where('time <', time() - $expire_period, FALSE); + + return $this->db->delete($this->tables['login_attempts']); + } + return FALSE; + } + + public function limit($limit) + { + $this->trigger_events('limit'); + $this->_ion_limit = $limit; + + return $this; + } + + public function offset($offset) + { + $this->trigger_events('offset'); + $this->_ion_offset = $offset; + + return $this; + } + + public function where($where, $value = NULL) + { + $this->trigger_events('where'); + + if (!is_array($where)) + { + $where = array($where => $value); + } + + array_push($this->_ion_where, $where); + + return $this; + } + + public function like($like, $value = NULL, $position = 'both') + { + $this->trigger_events('like'); + + if (!is_array($like)) + { + $like = array($like => array( + 'value' => $value, + 'position' => $position, + )); + } + + array_push($this->_ion_like, $like); + + return $this; + } + + public function select($select) + { + $this->trigger_events('select'); + + $this->_ion_select[] = $select; + + return $this; + } + + public function order_by($by, $order='desc') + { + $this->trigger_events('order_by'); + + $this->_ion_order_by = $by; + $this->_ion_order = $order; + + return $this; + } + + public function row() + { + $this->trigger_events('row'); + + $row = $this->response->row(); + + return $row; + } + + public function row_array() + { + $this->trigger_events(array('row', 'row_array')); + + $row = $this->response->row_array(); + + return $row; + } + + public function result() + { + $this->trigger_events('result'); + + $result = $this->response->result(); + + return $result; + } + + public function result_array() + { + $this->trigger_events(array('result', 'result_array')); + + $result = $this->response->result_array(); + + return $result; + } + + public function num_rows() + { + $this->trigger_events(array('num_rows')); + + $result = $this->response->num_rows(); + + return $result; + } + + /** + * users + * + * @return object Users + * @author Ben Edmunds + **/ + public function users($groups = NULL) + { + $this->trigger_events('users'); + + if (isset($this->_ion_select) && !empty($this->_ion_select)) + { + foreach ($this->_ion_select as $select) + { + $this->db->select($select); + } + + $this->_ion_select = array(); + } + else + { + //default selects + $this->db->select(array( + $this->tables['users'].'.*', + $this->tables['users'].'.id as id', + $this->tables['users'].'.id as user_id' + )); + } + + // filter by group id(s) if passed + if (isset($groups)) + { + // build an array if only one group was passed + if (!is_array($groups)) + { + $groups = Array($groups); + } + + // join and then run a where_in against the group ids + if (isset($groups) && !empty($groups)) + { + $this->db->distinct(); + $this->db->join( + $this->tables['users_groups'], + $this->tables['users_groups'].'.'.$this->join['users'].'='.$this->tables['users'].'.id', + 'inner' + ); + } + + // verify if group name or group id was used and create and put elements in different arrays + $group_ids = array(); + $group_names = array(); + foreach($groups as $group) + { + if(is_numeric($group)) $group_ids[] = $group; + else $group_names[] = $group; + } + $or_where_in = (!empty($group_ids) && !empty($group_names)) ? 'or_where_in' : 'where_in'; + // if group name was used we do one more join with groups + if(!empty($group_names)) + { + $this->db->join($this->tables['groups'], $this->tables['users_groups'] . '.' . $this->join['groups'] . ' = ' . $this->tables['groups'] . '.id', 'inner'); + $this->db->where_in($this->tables['groups'] . '.name', $group_names); + } + if(!empty($group_ids)) + { + $this->db->{$or_where_in}($this->tables['users_groups'].'.'.$this->join['groups'], $group_ids); + } + } + + $this->trigger_events('extra_where'); + + // run each where that was passed + if (isset($this->_ion_where) && !empty($this->_ion_where)) + { + foreach ($this->_ion_where as $where) + { + $this->db->where($where); + } + + $this->_ion_where = array(); + } + + if (isset($this->_ion_like) && !empty($this->_ion_like)) + { + foreach ($this->_ion_like as $like) + { + $this->db->or_like($like); + } + + $this->_ion_like = array(); + } + + if (isset($this->_ion_limit) && isset($this->_ion_offset)) + { + $this->db->limit($this->_ion_limit, $this->_ion_offset); + + $this->_ion_limit = NULL; + $this->_ion_offset = NULL; + } + else if (isset($this->_ion_limit)) + { + $this->db->limit($this->_ion_limit); + + $this->_ion_limit = NULL; + } + + // set the order + if (isset($this->_ion_order_by) && isset($this->_ion_order)) + { + $this->db->order_by($this->_ion_order_by, $this->_ion_order); + + $this->_ion_order = NULL; + $this->_ion_order_by = NULL; + } + + $this->response = $this->db->get($this->tables['users']); + + return $this; + } + + /** + * user + * + * @return object + * @author Ben Edmunds + **/ + public function user($id = NULL) + { + $this->trigger_events('user'); + + // if no id was passed use the current users id + $id = isset($id) ? $id : $this->session->userdata('user_id'); + + $this->limit(1); + $this->order_by($this->tables['users'].'.id', 'desc'); + $this->where($this->tables['users'].'.id', $id); + + $this->users(); + + return $this; + } + + /** + * get_users_groups + * + * @return array + * @author Ben Edmunds + **/ + public function get_users_groups($id=FALSE) + { + $this->trigger_events('get_users_group'); + + // if no id was passed use the current users id + $id || $id = $this->session->userdata('user_id'); + + return $this->db->select($this->tables['users_groups'].'.'.$this->join['groups'].' as id, '.$this->tables['groups'].'.name, '.$this->tables['groups'].'.description') + ->where($this->tables['users_groups'].'.'.$this->join['users'], $id) + ->join($this->tables['groups'], $this->tables['users_groups'].'.'.$this->join['groups'].'='.$this->tables['groups'].'.id') + ->get($this->tables['users_groups']); + } + + /** + * add_to_group + * + * @return bool + * @author Ben Edmunds + **/ + public function add_to_group($group_ids, $user_id=false) + { + $this->trigger_events('add_to_group'); + + // if no id was passed use the current users id + $user_id || $user_id = $this->session->userdata('user_id'); + + if(!is_array($group_ids)) + { + $group_ids = array($group_ids); + } + + $return = 0; + + // Then insert each into the database + foreach ($group_ids as $group_id) + { + if ($this->db->insert($this->tables['users_groups'], array( $this->join['groups'] => (float)$group_id, $this->join['users'] => (float)$user_id))) + { + if (isset($this->_cache_groups[$group_id])) { + $group_name = $this->_cache_groups[$group_id]; + } + else { + $group = $this->group($group_id)->result(); + $group_name = $group[0]->name; + $this->_cache_groups[$group_id] = $group_name; + } + $this->_cache_user_in_group[$user_id][$group_id] = $group_name; + + // Return the number of groups added + $return += 1; + } + } + + return $return; + } + + /** + * remove_from_group + * + * @return bool + * @author Ben Edmunds + **/ + public function remove_from_group($group_ids=false, $user_id=false) + { + $this->trigger_events('remove_from_group'); + + // user id is required + if(empty($user_id)) + { + return FALSE; + } + + // if group id(s) are passed remove user from the group(s) + if( ! empty($group_ids)) + { + if(!is_array($group_ids)) + { + $group_ids = array($group_ids); + } + + foreach($group_ids as $group_id) + { + $this->db->delete($this->tables['users_groups'], array($this->join['groups'] => (float)$group_id, $this->join['users'] => (float)$user_id)); + if (isset($this->_cache_user_in_group[$user_id]) && isset($this->_cache_user_in_group[$user_id][$group_id])) + { + unset($this->_cache_user_in_group[$user_id][$group_id]); + } + } + + $return = TRUE; + } + // otherwise remove user from all groups + else + { + if ($return = $this->db->delete($this->tables['users_groups'], array($this->join['users'] => (float)$user_id))) { + $this->_cache_user_in_group[$user_id] = array(); + } + } + return $return; + } + + /** + * groups + * + * @return object + * @author Ben Edmunds + **/ + public function groups() + { + $this->trigger_events('groups'); + + // run each where that was passed + if (isset($this->_ion_where) && !empty($this->_ion_where)) + { + foreach ($this->_ion_where as $where) + { + $this->db->where($where); + } + $this->_ion_where = array(); + } + + if (isset($this->_ion_limit) && isset($this->_ion_offset)) + { + $this->db->limit($this->_ion_limit, $this->_ion_offset); + + $this->_ion_limit = NULL; + $this->_ion_offset = NULL; + } + else if (isset($this->_ion_limit)) + { + $this->db->limit($this->_ion_limit); + + $this->_ion_limit = NULL; + } + + // set the order + if (isset($this->_ion_order_by) && isset($this->_ion_order)) + { + $this->db->order_by($this->_ion_order_by, $this->_ion_order); + } + + $this->response = $this->db->get($this->tables['groups']); + + return $this; + } + + /** + * group + * + * @return object + * @author Ben Edmunds + **/ + public function group($id = NULL) + { + $this->trigger_events('group'); + + if (isset($id)) + { + $this->where($this->tables['groups'].'.id', $id); + } + + $this->limit(1); + $this->order_by('id', 'desc'); + + return $this->groups(); + } + + /** + * update + * + * @return bool + * @author Phil Sturgeon + **/ + public function update($id, array $data) + { + $this->trigger_events('pre_update_user'); + + $user = $this->user($id)->row(); + + $this->db->trans_begin(); + + if (array_key_exists($this->identity_column, $data) && $this->identity_check($data[$this->identity_column]) && $user->{$this->identity_column} !== $data[$this->identity_column]) + { + $this->db->trans_rollback(); + $this->set_error('account_creation_duplicate_identity'); + + $this->trigger_events(array('post_update_user', 'post_update_user_unsuccessful')); + $this->set_error('update_unsuccessful'); + + return FALSE; + } + + // Filter the data passed + $data = $this->_filter_data($this->tables['users'], $data); + + if (array_key_exists($this->identity_column, $data) || array_key_exists('password', $data) || array_key_exists('email', $data)) + { + if (array_key_exists('password', $data)) + { + if( ! empty($data['password'])) + { + $data['password'] = $this->hash_password($data['password'], $user->salt); + } + else + { + // unset password so it doesn't effect database entry if no password passed + unset($data['password']); + } + } + } + + $this->trigger_events('extra_where'); + $this->db->update($this->tables['users'], $data, array('id' => $user->id)); + + if ($this->db->trans_status() === FALSE) + { + $this->db->trans_rollback(); + + $this->trigger_events(array('post_update_user', 'post_update_user_unsuccessful')); + $this->set_error('update_unsuccessful'); + return FALSE; + } + + $this->db->trans_commit(); + + $this->trigger_events(array('post_update_user', 'post_update_user_successful')); + $this->set_message('update_successful'); + return TRUE; + } + + /** + * delete_user + * + * @return bool + * @author Phil Sturgeon + **/ + public function delete_user($id) + { + $this->trigger_events('pre_delete_user'); + + $this->db->trans_begin(); + + // remove user from groups + $this->remove_from_group(NULL, $id); + + // delete user from users table should be placed after remove from group + $this->db->delete($this->tables['users'], array('id' => $id)); + + // if user does not exist in database then it returns FALSE else removes the user from groups + if ($this->db->affected_rows() == 0) + { + return FALSE; + } + + if ($this->db->trans_status() === FALSE) + { + $this->db->trans_rollback(); + $this->trigger_events(array('post_delete_user', 'post_delete_user_unsuccessful')); + $this->set_error('delete_unsuccessful'); + return FALSE; + } + + $this->db->trans_commit(); + + $this->trigger_events(array('post_delete_user', 'post_delete_user_successful')); + $this->set_message('delete_successful'); + return TRUE; + } + + /** + * update_last_login + * + * @return bool + * @author Ben Edmunds + **/ + public function update_last_login($id) + { + $this->trigger_events('update_last_login'); + + $this->load->helper('date'); + + $this->trigger_events('extra_where'); + + $this->db->update($this->tables['users'], array('last_login' => time()), array('id' => $id)); + + return $this->db->affected_rows() == 1; + } + + /** + * set_lang + * + * @return bool + * @author Ben Edmunds + **/ + public function set_lang($lang = 'en') + { + $this->trigger_events('set_lang'); + + // if the user_expire is set to zero we'll set the expiration two years from now. + if($this->config->item('user_expire', 'ion_auth') === 0) + { + $expire = (60*60*24*365*2); + } + // otherwise use what is set + else + { + $expire = $this->config->item('user_expire', 'ion_auth'); + } + + set_cookie(array( + 'name' => 'lang_code', + 'value' => $lang, + 'expire' => $expire + )); + + return TRUE; + } + + /** + * set_session + * + * @return bool + * @author jrmadsen67 + **/ + public function set_session($user) + { + + $this->trigger_events('pre_set_session'); + + $session_data = array( + 'identity' => $user->{$this->identity_column}, + $this->identity_column => $user->{$this->identity_column}, + 'email' => $user->email, + 'user_id' => $user->id, //everyone likes to overwrite id so we'll use user_id + 'old_last_login' => $user->last_login + ); + + $this->session->set_userdata($session_data); + + $this->trigger_events('post_set_session'); + + return TRUE; + } + + /** + * remember_user + * + * @return bool + * @author Ben Edmunds + **/ + public function remember_user($id) + { + $this->trigger_events('pre_remember_user'); + + if (!$id) + { + return FALSE; + } + + $user = $this->user($id)->row(); + + $salt = $this->salt(); + + $this->db->update($this->tables['users'], array('remember_code' => $salt), array('id' => $id)); + + if ($this->db->affected_rows() > -1) + { + // if the user_expire is set to zero we'll set the expiration two years from now. + if($this->config->item('user_expire', 'ion_auth') === 0) + { + $expire = (60*60*24*365*2); + } + // otherwise use what is set + else + { + $expire = $this->config->item('user_expire', 'ion_auth'); + } + + set_cookie(array( + 'name' => $this->config->item('identity_cookie_name', 'ion_auth'), + 'value' => $user->{$this->identity_column}, + 'expire' => $expire + )); + + set_cookie(array( + 'name' => $this->config->item('remember_cookie_name', 'ion_auth'), + 'value' => $salt, + 'expire' => $expire + )); + + $this->trigger_events(array('post_remember_user', 'remember_user_successful')); + return TRUE; + } + + $this->trigger_events(array('post_remember_user', 'remember_user_unsuccessful')); + return FALSE; + } + + /** + * login_remembed_user + * + * @return bool + * @author Ben Edmunds + **/ + public function login_remembered_user() + { + $this->trigger_events('pre_login_remembered_user'); + + // check for valid data + if (!get_cookie($this->config->item('identity_cookie_name', 'ion_auth')) + || !get_cookie($this->config->item('remember_cookie_name', 'ion_auth')) + || !$this->identity_check(get_cookie($this->config->item('identity_cookie_name', 'ion_auth')))) + { + $this->trigger_events(array('post_login_remembered_user', 'post_login_remembered_user_unsuccessful')); + return FALSE; + } + + // get the user + $this->trigger_events('extra_where'); + $query = $this->db->select($this->identity_column.', id, email, last_login') + ->where($this->identity_column, get_cookie($this->config->item('identity_cookie_name', 'ion_auth'))) + ->where('remember_code', get_cookie($this->config->item('remember_cookie_name', 'ion_auth'))) + ->limit(1) + ->order_by('id', 'desc') + ->get($this->tables['users']); + + // if the user was found, sign them in + if ($query->num_rows() == 1) + { + $user = $query->row(); + + $this->update_last_login($user->id); + + $this->set_session($user); + + // extend the users cookies if the option is enabled + if ($this->config->item('user_extend_on_login', 'ion_auth')) + { + $this->remember_user($user->id); + } + + $this->trigger_events(array('post_login_remembered_user', 'post_login_remembered_user_successful')); + return TRUE; + } + + $this->trigger_events(array('post_login_remembered_user', 'post_login_remembered_user_unsuccessful')); + return FALSE; + } + + + /** + * create_group + * + * @author aditya menon + */ + public function create_group($group_name = FALSE, $group_description = '', $additional_data = array()) + { + // bail if the group name was not passed + if(!$group_name) + { + $this->set_error('group_name_required'); + return FALSE; + } + + // bail if the group name already exists + $existing_group = $this->db->get_where($this->tables['groups'], array('name' => $group_name))->num_rows(); + if($existing_group !== 0) + { + $this->set_error('group_already_exists'); + return FALSE; + } + + $data = array('name'=>$group_name,'description'=>$group_description); + + // filter out any data passed that doesnt have a matching column in the groups table + // and merge the set group data and the additional data + if (!empty($additional_data)) $data = array_merge($this->_filter_data($this->tables['groups'], $additional_data), $data); + + $this->trigger_events('extra_group_set'); + + // insert the new group + $this->db->insert($this->tables['groups'], $data); + $group_id = $this->db->insert_id(); + + // report success + $this->set_message('group_creation_successful'); + // return the brand new group id + return $group_id; + } + + /** + * update_group + * + * @return bool + * @author aditya menon + **/ + public function update_group($group_id = FALSE, $group_name = FALSE, $additional_data = array()) + { + if (empty($group_id)) return FALSE; + + $data = array(); + + if (!empty($group_name)) + { + // we are changing the name, so do some checks + + // bail if the group name already exists + $existing_group = $this->db->get_where($this->tables['groups'], array('name' => $group_name))->row(); + if(isset($existing_group->id) && $existing_group->id != $group_id) + { + $this->set_error('group_already_exists'); + return FALSE; + } + + $data['name'] = $group_name; + } + + // restrict change of name of the admin group + $group = $this->db->get_where($this->tables['groups'], array('id' => $group_id))->row(); + if($this->config->item('admin_group', 'ion_auth') === $group->name && $group_name !== $group->name) + { + $this->set_error('group_name_admin_not_alter'); + return FALSE; + } + + + // IMPORTANT!! Third parameter was string type $description; this following code is to maintain backward compatibility + // New projects should work with 3rd param as array + if (is_string($additional_data)) $additional_data = array('description' => $additional_data); + + + // filter out any data passed that doesnt have a matching column in the groups table + // and merge the set group data and the additional data + if (!empty($additional_data)) $data = array_merge($this->_filter_data($this->tables['groups'], $additional_data), $data); + + + $this->db->update($this->tables['groups'], $data, array('id' => $group_id)); + + $this->set_message('group_update_successful'); + + return TRUE; + } + + /** + * delete_group + * + * @return bool + * @author aditya menon + **/ + public function delete_group($group_id = FALSE) + { + // bail if mandatory param not set + if(!$group_id || empty($group_id)) + { + return FALSE; + } + $group = $this->group($group_id)->row(); + if($group->name == $this->config->item('admin_group', 'ion_auth')) + { + $this->trigger_events(array('post_delete_group', 'post_delete_group_notallowed')); + $this->set_error('group_delete_notallowed'); + return FALSE; + } + + $this->trigger_events('pre_delete_group'); + + $this->db->trans_begin(); + + // remove all users from this group + $this->db->delete($this->tables['users_groups'], array($this->join['groups'] => $group_id)); + // remove the group itself + $this->db->delete($this->tables['groups'], array('id' => $group_id)); + + if ($this->db->trans_status() === FALSE) + { + $this->db->trans_rollback(); + $this->trigger_events(array('post_delete_group', 'post_delete_group_unsuccessful')); + $this->set_error('group_delete_unsuccessful'); + return FALSE; + } + + $this->db->trans_commit(); + + $this->trigger_events(array('post_delete_group', 'post_delete_group_successful')); + $this->set_message('group_delete_successful'); + return TRUE; + } + + public function set_hook($event, $name, $class, $method, $arguments) + { + $this->_ion_hooks->{$event}[$name] = new stdClass; + $this->_ion_hooks->{$event}[$name]->class = $class; + $this->_ion_hooks->{$event}[$name]->method = $method; + $this->_ion_hooks->{$event}[$name]->arguments = $arguments; + } + + public function remove_hook($event, $name) + { + if (isset($this->_ion_hooks->{$event}[$name])) + { + unset($this->_ion_hooks->{$event}[$name]); + } + } + + public function remove_hooks($event) + { + if (isset($this->_ion_hooks->$event)) + { + unset($this->_ion_hooks->$event); + } + } + + protected function _call_hook($event, $name) + { + if (isset($this->_ion_hooks->{$event}[$name]) && method_exists($this->_ion_hooks->{$event}[$name]->class, $this->_ion_hooks->{$event}[$name]->method)) + { + $hook = $this->_ion_hooks->{$event}[$name]; + + return call_user_func_array(array($hook->class, $hook->method), $hook->arguments); + } + + return FALSE; + } + + public function trigger_events($events) + { + if (is_array($events) && !empty($events)) + { + foreach ($events as $event) + { + $this->trigger_events($event); + } + } + else + { + if (isset($this->_ion_hooks->$events) && !empty($this->_ion_hooks->$events)) + { + foreach ($this->_ion_hooks->$events as $name => $hook) + { + $this->_call_hook($events, $name); + } + } + } + } + + /** + * set_message_delimiters + * + * Set the message delimiters + * + * @return void + * @author Ben Edmunds + **/ + public function set_message_delimiters($start_delimiter, $end_delimiter) + { + $this->message_start_delimiter = $start_delimiter; + $this->message_end_delimiter = $end_delimiter; + + return TRUE; + } + + /** + * set_error_delimiters + * + * Set the error delimiters + * + * @return void + * @author Ben Edmunds + **/ + public function set_error_delimiters($start_delimiter, $end_delimiter) + { + $this->error_start_delimiter = $start_delimiter; + $this->error_end_delimiter = $end_delimiter; + + return TRUE; + } + + /** + * set_message + * + * Set a message + * + * @return void + * @author Ben Edmunds + **/ + public function set_message($message) + { + $this->messages[] = $message; + + return $message; + } + + + + /** + * messages + * + * Get the messages + * + * @return void + * @author Ben Edmunds + **/ + public function messages() + { + $_output = ''; + foreach ($this->messages as $message) + { + $messageLang = $this->lang->line($message) ? $this->lang->line($message) : '##' . $message . '##'; + $_output .= $this->message_start_delimiter . $messageLang . $this->message_end_delimiter; + } + + return $_output; + } + + /** + * messages as array + * + * Get the messages as an array + * + * @return array + * @author Raul Baldner Junior + **/ + public function messages_array($langify = TRUE) + { + if ($langify) + { + $_output = array(); + foreach ($this->messages as $message) + { + $messageLang = $this->lang->line($message) ? $this->lang->line($message) : '##' . $message . '##'; + $_output[] = $this->message_start_delimiter . $messageLang . $this->message_end_delimiter; + } + return $_output; + } + else + { + return $this->messages; + } + } + + + /** + * clear_messages + * + * Clear messages + * + * @return void + * @author Ben Edmunds + **/ + public function clear_messages() + { + $this->messages = array(); + + return TRUE; + } + + + /** + * set_error + * + * Set an error message + * + * @return void + * @author Ben Edmunds + **/ + public function set_error($error) + { + $this->errors[] = $error; + + return $error; + } + + /** + * errors + * + * Get the error message + * + * @return void + * @author Ben Edmunds + **/ + public function errors() + { + $_output = ''; + foreach ($this->errors as $error) + { + $errorLang = $this->lang->line($error) ? $this->lang->line($error) : '##' . $error . '##'; + $_output .= $this->error_start_delimiter . $errorLang . $this->error_end_delimiter; + } + + return $_output; + } + + /** + * errors as array + * + * Get the error messages as an array + * + * @return array + * @author Raul Baldner Junior + **/ + public function errors_array($langify = TRUE) + { + if ($langify) + { + $_output = array(); + foreach ($this->errors as $error) + { + $errorLang = $this->lang->line($error) ? $this->lang->line($error) : '##' . $error . '##'; + $_output[] = $this->error_start_delimiter . $errorLang . $this->error_end_delimiter; + } + return $_output; + } + else + { + return $this->errors; + } + } + + + /** + * clear_errors + * + * Clear Errors + * + * @return void + * @author Ben Edmunds + **/ + public function clear_errors() + { + $this->errors = array(); + + return TRUE; + } + + + + protected function _filter_data($table, $data) + { + $filtered_data = array(); + $columns = $this->db->list_fields($table); + + if (is_array($data)) + { + foreach ($columns as $column) + { + if (array_key_exists($column, $data)) + $filtered_data[$column] = $data[$column]; + } + } + + return $filtered_data; + } + + protected function _prepare_ip($ip_address) { + // just return the string IP address now for better compatibility + return $ip_address; + } +} diff --git a/application/views/auth/change_password.php b/application/views/auth/change_password.php new file mode 100644 index 00000000..f8ce60b6 --- /dev/null +++ b/application/views/auth/change_password.php @@ -0,0 +1,25 @@ +

+ +
+ + + +

+
+ +

+ +

+
+ +

+ +

+
+ +

+ + +

+ + diff --git a/application/views/auth/create_group.php b/application/views/auth/create_group.php new file mode 100644 index 00000000..86b07e93 --- /dev/null +++ b/application/views/auth/create_group.php @@ -0,0 +1,20 @@ +

+

+ +
+ + + +

+
+ +

+ +

+
+ +

+ +

+ + \ No newline at end of file diff --git a/application/views/auth/create_user.php b/application/views/auth/create_user.php new file mode 100644 index 00000000..b292d7b4 --- /dev/null +++ b/application/views/auth/create_user.php @@ -0,0 +1,57 @@ +

+

+ +
+ + + +

+
+ +

+ +

+
+ +

+ + '; + echo lang('create_user_identity_label', 'identity'); + echo '
'; + echo form_error('identity'); + echo form_input($identity); + echo '

'; + } + ?> + +

+
+ +

+ +

+
+ +

+ +

+
+ +

+ +

+
+ +

+ +

+
+ +

+ + +

+ + diff --git a/application/views/auth/deactivate_user.php b/application/views/auth/deactivate_user.php new file mode 100644 index 00000000..85e9c36d --- /dev/null +++ b/application/views/auth/deactivate_user.php @@ -0,0 +1,18 @@ +

+

username);?>

+ +id);?> + +

+ + + + +

+ + + $user->id)); ?> + +

+ + \ No newline at end of file diff --git a/application/views/auth/edit_group.php b/application/views/auth/edit_group.php new file mode 100644 index 00000000..080dad7a --- /dev/null +++ b/application/views/auth/edit_group.php @@ -0,0 +1,20 @@ +

+

+ +
+ + + +

+
+ +

+ +

+
+ +

+ +

+ + \ No newline at end of file diff --git a/application/views/auth/edit_user.php b/application/views/auth/edit_user.php new file mode 100644 index 00000000..46e4190f --- /dev/null +++ b/application/views/auth/edit_user.php @@ -0,0 +1,66 @@ +

+

+ +
+ + + +

+
+ +

+ +

+
+ +

+ +

+
+ +

+ +

+
+ +

+ +

+
+ +

+ +

+
+ +

+ + ion_auth->is_admin()): ?> + +

+ + + + + + + id);?> + + +

+ + diff --git a/application/views/auth/email/activate.tpl.php b/application/views/auth/email/activate.tpl.php new file mode 100644 index 00000000..e2436cf7 --- /dev/null +++ b/application/views/auth/email/activate.tpl.php @@ -0,0 +1,6 @@ + + +

+

+ + \ No newline at end of file diff --git a/application/views/auth/email/forgot_password.tpl.php b/application/views/auth/email/forgot_password.tpl.php new file mode 100644 index 00000000..2cc5b02f --- /dev/null +++ b/application/views/auth/email/forgot_password.tpl.php @@ -0,0 +1,6 @@ + + +

+

+ + \ No newline at end of file diff --git a/application/views/auth/email/new_password.tpl.php b/application/views/auth/email/new_password.tpl.php new file mode 100644 index 00000000..f2239860 --- /dev/null +++ b/application/views/auth/email/new_password.tpl.php @@ -0,0 +1,7 @@ + + +

+ +

+ + \ No newline at end of file diff --git a/application/views/auth/forgot_password.php b/application/views/auth/forgot_password.php new file mode 100644 index 00000000..5e969e03 --- /dev/null +++ b/application/views/auth/forgot_password.php @@ -0,0 +1,17 @@ +
+

+

+ +
+ + + +

+
+ +

+ +

+ + +
\ No newline at end of file diff --git a/application/views/auth/index.php b/application/views/auth/index.php new file mode 100644 index 00000000..d9576447 --- /dev/null +++ b/application/views/auth/index.php @@ -0,0 +1,31 @@ +

+

+ +
+ + + + + + + + + + + + + + + + + + + + +
first_name,ENT_QUOTES,'UTF-8');?>last_name,ENT_QUOTES,'UTF-8');?>email,ENT_QUOTES,'UTF-8');?> + groups as $group):?> + id, htmlspecialchars($group->name,ENT_QUOTES,'UTF-8')) ;?>
+ +
active) ? anchor("auth/deactivate/".$user->id, lang('index_active_link')) : anchor("auth/activate/". $user->id, lang('index_inactive_link'));?>id, 'Edit') ;?>
+ +

|

\ No newline at end of file diff --git a/application/views/auth/login.php b/application/views/auth/login.php new file mode 100644 index 00000000..a43b939a --- /dev/null +++ b/application/views/auth/login.php @@ -0,0 +1,16 @@ +
+ + + messages(); ?> + bs3_text('Email', 'username', ENVIRONMENT==='development' ? 'mhamzasite@gmail.com' : ''); ?> + bs3_password('Password', 'password', ENVIRONMENT==='development' ? '3267559' : ''); ?> +
+
+ bs3_submit('Sign In', 'btn btn-primary btn-block btn-flat'); ?> +
+
+ close(); ?> +

+ + +
\ No newline at end of file diff --git a/application/views/auth/reset_password.php b/application/views/auth/reset_password.php new file mode 100644 index 00000000..71017048 --- /dev/null +++ b/application/views/auth/reset_password.php @@ -0,0 +1,22 @@ +

+ +
+ + + +

+
+ +

+ +

+
+ +

+ + + + +

+ + \ No newline at end of file From ef1da925862210671a236b0fa55b83c3839a150e Mon Sep 17 00:00:00 2001 From: M Hamza Siddiqui Date: Tue, 24 Apr 2018 16:56:16 +0500 Subject: [PATCH 2/3] Update Build Number --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e95261fd..839a669f 100755 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ ## CodeIgniter 3 Bootstrap -**Latest Build: 2016-07-02** +**Latest Build: 2018-04-24** **Note: This project is still in progress, but welcome for any issues encountered** From 2092877e5eb3687321a8427a1cc410d407427e42 Mon Sep 17 00:00:00 2001 From: M Hamza Siddiqui Date: Tue, 24 Apr 2018 19:20:42 +0500 Subject: [PATCH 3/3] Login Form Fix --- application/views/auth/login.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/application/views/auth/login.php b/application/views/auth/login.php index a43b939a..28082d26 100644 --- a/application/views/auth/login.php +++ b/application/views/auth/login.php @@ -2,8 +2,8 @@ messages(); ?> - bs3_text('Email', 'username', ENVIRONMENT==='development' ? 'mhamzasite@gmail.com' : ''); ?> - bs3_password('Password', 'password', ENVIRONMENT==='development' ? '3267559' : ''); ?> + bs3_text('Email', 'username', ''); ?> + bs3_password('Password', 'password', ''); ?>
bs3_submit('Sign In', 'btn btn-primary btn-block btn-flat'); ?>