diff --git a/src/application/config/constants.php b/src/application/config/constants.php
index 994944c4..deefe73e 100644
--- a/src/application/config/constants.php
+++ b/src/application/config/constants.php
@@ -70,5 +70,7 @@ define('PAGE_SERVICES', 'services');
define('PAGE_USERS', 'users');
define('PAGE_SYSTEM_SETTINGS', 'system_settings');
define('PAGE_USER_SETTINGS', 'user_settings');
+
+define('MIN_PASSWORD_LENGTH', 7);
/* End of file constants.php */
/* Location: ./application/config/constants.php */
\ No newline at end of file
diff --git a/src/application/controllers/backend.php b/src/application/controllers/backend.php
index e12587af..20a38410 100644
--- a/src/application/controllers/backend.php
+++ b/src/application/controllers/backend.php
@@ -143,17 +143,12 @@ class Backend extends CI_Controller {
$this->load->model('settings_model');
$this->load->model('user_model');
- $this->load->library('session');
-
- // @task Apply data for testing this page (this must be done during the login process).
- $this->session->set_userdata('user_id', 18);
- $this->session->set_userdata('user_slug', DB_SLUG_ADMIN);
-
+ $this->load->library('session');
$user_id = $this->session->userdata('user_id');
$view['base_url'] = $this->config->item('base_url');
$view['company_name'] = $this->settings_model->get_setting('company_name');
- $view['user_slug'] = $this->session->userdata('user_slug');
+ $view['role_slug'] = $this->session->userdata('role_slug');
$view['system_settings'] = $this->settings_model->get_settings();
$view['user_settings'] = $this->user_model->get_settings($user_id);
diff --git a/src/application/controllers/backend_api.php b/src/application/controllers/backend_api.php
index b864c18d..9c7a555f 100644
--- a/src/application/controllers/backend_api.php
+++ b/src/application/controllers/backend_api.php
@@ -703,6 +703,13 @@ class Backend_api extends CI_Controller {
try {
$this->load->model('providers_model');
$provider = json_decode($_POST['provider'], true);
+
+ if (!isset($provider['working_plan'])) {
+ $this->load->model('settings_model');
+ $provider['settings']['working_plan'] = $this->settings_model
+ ->get_setting('company_working_plan');
+ }
+
$this->providers_model->add($provider);
echo json_encode(AJAX_SUCCESS);
} catch(Exception $exc) {
@@ -822,6 +829,26 @@ class Backend_api extends CI_Controller {
));
}
}
+
+ /**
+ * [AJAX] This method checks whether the username already exists in the database.
+ *
+ * @param string $_POST['username'] Record's username to validate.
+ * @param bool $_POST['record_exists'] Whether the record already exists in database.
+ */
+ public function ajax_validate_username() {
+ try {
+ // We will use the function in the admins_model because it is sufficient for
+ // the rest user types for now (providers, secretaries).
+ $this->load->model('admins_model');
+ $is_valid = $this->admins_model->validate_username($_POST['username'], $_POST['record_exists']);
+ echo json_encode($is_valid);
+ } catch(Exception $exc) {
+ echo json_encode(array(
+ 'exceptions' => array(exceptionToJavaScript($exc))
+ ));
+ }
+ }
}
/* End of file backend_api.php */
diff --git a/src/application/controllers/user.php b/src/application/controllers/user.php
index c3bb6a05..4966930f 100644
--- a/src/application/controllers/user.php
+++ b/src/application/controllers/user.php
@@ -13,11 +13,24 @@ class User extends CI_Controller {
public function login() {
$view['base_url'] = $this->config->item('base_url');
$view['dest_url'] = $this->session->userdata('dest_url');
+
+ if (!$view['dest_url']) {
+ $view['dest_url'] = $view['base_url'] . 'backend';
+ }
+
$this->load->view('user/login', $view);
}
public function logout() {
+ $this->session->unset_userdata('user_id');
+ $this->session->unset_userdata('user_email');
+ $this->session->unset_userdata('role_slug');
+ $this->session->unset_userdata('username');
+ $this->session->unset_userdata('dest_url');
+ $view['base_url'] = $this->config->item('base_url');
+
+ $this->load->view('user/logout', $view);
}
public function forgot_password() {
@@ -37,17 +50,14 @@ class User extends CI_Controller {
throw new Exception('Invalid credentials given!');
}
- $this->load->helper('general');
$this->load->model('user_model');
-
- $hash_password = $this->hash_password($_POST['password']);
- $user_data = $this->user_model->check_login($_POST['username'], $hash_password);
+ $user_data = $this->user_model->check_login($_POST['username'], $_POST['password']);
if ($user_data) {
$this->session->set_userdata($user_data); // Save data on user's session.
echo json_encode(AJAX_SUCCESS);
} else {
- echo json_encode(AJAX_SUCCESS);
+ echo json_encode(AJAX_FAILURE);
}
} catch(Exception $exc) {
diff --git a/src/application/helpers/general_helper.php b/src/application/helpers/general_helper.php
index 8f31c5a0..871c0cf6 100644
--- a/src/application/helpers/general_helper.php
+++ b/src/application/helpers/general_helper.php
@@ -29,13 +29,38 @@ function date3339($timestamp=0) {
* Generate a hash of password string.
*
* For user security, all system passwords are stored in hash string into the database. Use
- * this method to produce the hash.
+ * this method to produce the hashed password.
*
+ * @param string $salt Salt value for current user. This value is stored on the database and
+ * is used when generating the password hash.
* @param string $password Given string password.
* @return string Returns the hash string of the given password.
*/
-function hash_password($password) {
- return md5($password); // @task include salt and hash more times.
+function hash_password($salt, $password) {
+ $salt = strtoupper($salt);
+ $password = strtoupper($password);
+ $half = (int)(strlen($salt) / 2);
+ $hash = hash('sha256', substr($salt, 0, $half ) . $password . substr($salt, $half));
+
+ for ($i = 0; $i < 100000; $i++) {
+ $hash = hash('sha256', $hash);
+ }
+
+ return $hash; // @task include salt and hash more times.
+}
+
+/**
+ * Generate a new password salt.
+ *
+ * This method will not check if the salt is unique in database. This must be done
+ * from the calling procedure.
+ *
+ * @return string Returns a salt string.
+ */
+function generate_salt() {
+ $max_length = 100;
+ $salt = hash('sha256', (uniqid(rand(), true)));
+ return substr($salt, 0, $max_length);
}
/* End of file general_helper.php */
diff --git a/src/application/models/admins_model.php b/src/application/models/admins_model.php
index 07f3f22c..38149563 100644
--- a/src/application/models/admins_model.php
+++ b/src/application/models/admins_model.php
@@ -85,6 +85,8 @@ class Admins_Model extends CI_Model {
* @throws Exception When the insert operation fails.
*/
public function insert($admin) {
+ $this->load->helper('general');
+
$admin['id_roles'] = $this->get_admin_role_id();
$settings = $admin['settings'];
unset($admin['settings']);
@@ -97,6 +99,8 @@ class Admins_Model extends CI_Model {
$admin['id'] = intval($this->db->insert_id());
$settings['id_users'] = $admin['id'];
+ $settings['salt'] = generate_salt();
+ $settings['password'] = hash_password($settings['salt'], $settings['password']);
// Insert admin settings.
if (!$this->db->insert('ea_user_settings', $settings)) {
@@ -117,10 +121,17 @@ class Admins_Model extends CI_Model {
* @throws Exception When the update operation fails.
*/
public function update($admin) {
+ $this->load->helper('general');
+
$settings = $admin['settings'];
unset($admin['settings']);
$settings['id_users'] = $admin['id'];
+ if (isset($settings['password'])) {
+ $salt = $this->db->get_where('ea_user_settings', array('id_users' => $admin['id']))->row()->salt;
+ $settings['password'] = hash_password($salt, $settings['password']);
+ }
+
$this->db->where('id', $admin['id']);
if (!$this->db->update('ea_users', $admin)) {
throw new Exception('Could not update admin record.');
@@ -193,6 +204,24 @@ class Admins_Model extends CI_Model {
throw new Exception('Invalid email address provided : ' . $admin['email']);
}
+ // Validate admin username
+ if (isset($admin['settings']['username'])) {
+ $num_rows = $this->db->get_where('ea_user_settings',
+ array('username' => $admin['settings']['username']))->num_rows();
+ if ($num_rows > 0) {
+ throw new Exception('Username already exists, please select another '
+ . 'and try again (username: ' . $admin['settings']['username'] . ')');
+ }
+ }
+
+ // Validate admin password
+ if (isset($admin['settings']['password'])) {
+ if (strlen($admin['settings']['password']) < MIN_PASSWORD_LENGTH) {
+ throw new Exception('The user password must be at least '
+ . MIN_PASSWORD_LENGTH . ' characters long.');
+ }
+ }
+
return TRUE;
} catch (Exception $exc) {
return FALSE;
@@ -328,6 +357,22 @@ class Admins_Model extends CI_Model {
public function get_admin_role_id() {
return intval($this->db->get_where('ea_roles', array('slug' => DB_SLUG_ADMIN))->row()->id);
}
+
+ /**
+ * Validate Records Username
+ *
+ * @param string $username The provider records username.
+ * @param bool $record_exists Whether the record exists or not.
+ * @return bool Returns the validation result.
+ */
+ public function validate_username($username, $record_exists) {
+ $num_rows = $this->db->get_where('ea_user_settings', array('username' => $username))->num_rows();
+ if ($num_rows == 0 && $record_exists == FALSE || $num_rows == 1 && $record_exists == TRUE) {
+ return true;
+ } else {
+ return false;
+ }
+ }
}
/* End of file admins_model.php */
diff --git a/src/application/models/providers_model.php b/src/application/models/providers_model.php
index 6ef9d0af..d84513a9 100644
--- a/src/application/models/providers_model.php
+++ b/src/application/models/providers_model.php
@@ -98,6 +98,8 @@ class Providers_Model extends CI_Model {
* @throws Exception When the insert operation fails.
*/
public function insert($provider) {
+ $this->load->helper('general');
+
// Get provider role id.
$provider['id_roles'] = $this->get_providers_role_id();
@@ -112,6 +114,9 @@ class Providers_Model extends CI_Model {
throw new Exception('Could not insert provider into the database');
}
+ $settings['salt'] = generate_salt();
+ $settings['password'] = hash_password($settings['salt'], $settings['password']);
+
$provider['id'] = $this->db->insert_id();
$this->save_settings($settings, $provider['id']);
$this->save_services($services, $provider['id']);
@@ -128,12 +133,19 @@ class Providers_Model extends CI_Model {
* @throws Exception When the update operation fails.
*/
public function update($provider) {
+ $this->load->helper('general');
+
// Store service and settings (must not be present on the $provider array).
$services = $provider['services'];
unset($provider['services']);
$settings = $provider['settings'];
unset($provider['settings']);
+ if (isset($settings['password'])) {
+ $salt = $this->db->get_where('ea_user_settings', array('id_users' => $provider['id']))->row()->salt;
+ $settings['password'] = hash_password($salt, $settings['password']);
+ }
+
// Update provider record.
$this->db->where('id', $provider['id']);
if (!$this->db->update('ea_users', $provider)) {
@@ -224,6 +236,24 @@ class Providers_Model extends CI_Model {
throw new Exception('Invalid provider settings given: ' . print_r($provider, TRUE));
}
+ // Validate admin username
+ if (isset($provider['settings']['username'])) {
+ $num_rows = $this->db->get_where('ea_user_settings',
+ array('username' => $provider['settings']['username']))->num_rows();
+ if ($num_rows > 0) {
+ throw new Exception('Username already exists, please select another '
+ . 'and try again (username: ' . $provider['settings']['username'] . ')');
+ }
+ }
+
+ // Validate admin password
+ if (isset($provider['settings']['password'])) {
+ if (strlen($provider['settings']['password']) < MIN_PASSWORD_LENGTH) {
+ throw new Exception('The user password must be at least '
+ . MIN_PASSWORD_LENGTH . ' characters long.');
+ }
+ }
+
return TRUE;
} catch (Exception $exc) {
return FALSE;
diff --git a/src/application/models/secretaries_model.php b/src/application/models/secretaries_model.php
index 492db372..97a7a808 100644
--- a/src/application/models/secretaries_model.php
+++ b/src/application/models/secretaries_model.php
@@ -86,6 +86,8 @@ class Secretaries_Model extends CI_Model {
* @throws Exception When the insert operation fails.
*/
public function insert($secretary) {
+ $this->load->helper('general');
+
$providers = $secretary['providers'];
unset($secretary['providers']);
$settings = $secretary['settings'];
@@ -98,6 +100,8 @@ class Secretaries_Model extends CI_Model {
}
$secretary['id'] = intval($this->db->insert_id());
+ $settings['salt'] = generate_salt();
+ $settings['password'] = hash_password($settings['salt'], $settings['password']);
$this->save_providers($providers, $secretary['id']);
$this->save_settings($settings, $secretary['id']);
@@ -113,11 +117,18 @@ class Secretaries_Model extends CI_Model {
* @throws Exception When the update operation fails.
*/
public function update($secretary) {
+ $this->load->helper('general');
+
$providers = $secretary['providers'];
unset($secretary['providers']);
$settings = $secretary['settings'];
unset($secretary['settings']);
+ if (isset($settings['password'])) {
+ $salt = $this->db->get_where('ea_user_settings', array('id_users' => $secretary['id']))->row()->salt;
+ $settings['password'] = hash_password($salt, $settings['password']);
+ }
+
$this->db->where('id', $secretary['id']);
if (!$this->db->update('ea_users', $secretary)){
throw new Exception('Could not update secretary record.');
@@ -193,6 +204,24 @@ class Secretaries_Model extends CI_Model {
throw new Exception('Invalid email address provided : ' . $secretary['email']);
}
+ // Validate admin username
+ if (isset($secretary['settings']['username'])) {
+ $num_rows = $this->db->get_where('ea_user_settings',
+ array('username' => $secretary['settings']['username']))->num_rows();
+ if ($num_rows > 0) {
+ throw new Exception('Username already exists, please select another '
+ . 'and try again (username: ' . $secretary['settings']['username'] . ')');
+ }
+ }
+
+ // Validate admin password
+ if (isset($secretary['settings']['password'])) {
+ if (strlen($secretary['settings']['password']) < MIN_PASSWORD_LENGTH) {
+ throw new Exception('The user password must be at least '
+ . MIN_PASSWORD_LENGTH . ' characters long.');
+ }
+ }
+
return TRUE;
} catch (Exception $exc) {
return FALSE;
diff --git a/src/application/models/user_model.php b/src/application/models/user_model.php
index 0fb003e8..53a2173e 100644
--- a/src/application/models/user_model.php
+++ b/src/application/models/user_model.php
@@ -35,6 +35,13 @@ class User_Model extends CI_Model {
$user_settings['id_users'] = $user['id'];
unset($user['settings']);
+ // Prepare user password (hash).
+ if (isset($user_settings['password'])) {
+ $this->load->helper('general');
+ $salt = $this->db->get_where('ea_user_settings', array('id_users' => $user['id']))->row()->salt;
+ $user_settings['password'] = hash_password($salt, $user_settings['password']);
+ }
+
if (!$this->db->update('ea_users', $user, array('id' => $user['id']))) {
return FALSE;
}
@@ -45,6 +52,43 @@ class User_Model extends CI_Model {
return TRUE;
}
+
+ /**
+ * Retrieve user's salt from database.
+ *
+ * @param string $username This will be used to find the user record.
+ * @return string Returns the salt db value.
+ */
+ public function get_salt($username) {
+ $user = $this->db->get_where('ea_user_settings', array('username' => $username))->row_array();
+ return ($user) ? $user['salt'] : '';
+ }
+
+ /**
+ * Performs the check of the given user credentials.
+ *
+ * @param string $username Given user's name.
+ * @param type $password Given user's password (not hashed yet).
+ * @return array|null Returns the session data of the logged in user or null on
+ * failure.
+ */
+ public function check_login($username, $password) {
+ $this->load->helper('general');
+ $salt = $this->user_model->get_salt($username);
+ $password = hash_password($salt, $password);
+
+ $user_data = $this->db
+ ->select('ea_users.id AS user_id, ea_users.email AS user_email, '
+ . 'ea_roles.slug AS role_slug, ea_user_settings.username')
+ ->from('ea_users')
+ ->join('ea_roles', 'ea_roles.id = ea_users.id_roles', 'innder')
+ ->join('ea_user_settings', 'ea_user_settings.id_users = ea_users.id')
+ ->where('ea_user_settings.username', $username)
+ ->where('ea_user_settings.password', $password)
+ ->get()->row_array();
+
+ return ($user_data) ? $user_data : NULL;
+ }
}
/* End of file user_model.php */
diff --git a/src/application/views/appointments/book_success.php b/src/application/views/appointments/book_success.php
index 5320ea81..3ce128bb 100644
--- a/src/application/views/appointments/book_success.php
+++ b/src/application/views/appointments/book_success.php
@@ -149,7 +149,7 @@
'Your appointment has successfully been added to ' +
'your Google Calendar account.
' +
'' +
- 'Click here to view your appoinmtent on Google ' +
+ 'Click here to view your appointment on Google ' +
'Calendar.' +
'' +
'
Welcome! You will need to login in order to view this page.
+Welcome! You will need to login in order to view backend pages.
+ You have been successfully logged out! Click on one of the following buttons to + navigate to a different page. +
+ +