cloudlog/application/models/User_model.php
Peter Goodhall 4fe8ca4093 Handle AMSAT override for OscarWatch
Add a persisted `force_amsat` OscarWatch user option, expose it on the user edit form, and keep the AMSAT upload setting in sync when OscarWatch status uploads are enabled. The controller now defaults unchecked values correctly and shows a notice when OscarWatch disables direct AMSAT uploads or when the override keeps both enabled.
2026-08-04 13:15:01 +01:00

740 lines
28 KiB
PHP

<?php
/* user_model.php
*
* This model implements user authentication and authorization
*
*/
// Uses 'phpass' from http://www.openwall.com/phpass/ to implement password hashing
// TODO migration away from this?
//require_once('application/third_party/PasswordHash.php');
class User_Model extends CI_Model {
// FUNCTION: object get($username)
// Retrieve a user
function get($username) {
// Clean ID
$clean_username = $this->security->xss_clean($username);
$this->db->where('user_name', $clean_username);
$r = $this->db->get($this->config->item('auth_table'));
return $r;
}
// FUNCTION: object get_by_id($id)
// Retrieve a user by user ID
function get_by_id($id) {
// Clean ID
$clean_id = $this->security->xss_clean($id);
$this->db->where('user_id', $clean_id);
$r = $this->db->get($this->config->item('auth_table'));
return $r;
}
// FUNCTION: object get_all_lotw_users
// Returns all users with lotw details
function get_all_lotw_users() {
$this->db->where('user_lotw_name !=', null);
$this->db->where('user_lotw_name !=', "");
$r = $this->db->get($this->config->item('auth_table'));
return $r;
}
// FUNCTION: object get_by_email($email)
// Retrieve a user by email address
function get_by_email($email) {
$clean_email = $this->security->xss_clean($email);
$this->db->where('user_email', $clean_email);
$r = $this->db->get($this->config->item('auth_table'));
return $r;
}
// FUNCTION: object get_by_callsign($callsign)
// Retrieve a user by callsign (case-insensitive)
function get_by_callsign($callsign) {
$clean_callsign = $this->security->xss_clean($callsign);
$this->db->where('UPPER(user_callsign)', strtoupper($clean_callsign));
$r = $this->db->get($this->config->item('auth_table'));
return $r;
}
/*
* Function: check_email_address
*
* Checks if an email address is already in use
*
* @param string $email
*/
function check_email_address($email) {
$clean_email = $this->security->xss_clean($email);
$this->db->where('user_email', $clean_email);
$query = $this->db->get($this->config->item('auth_table'));
if ($query->num_rows() > 0) {
return true;
} else {
return false;
}
}
function get_user_email_by_id($id) {
$clean_id = $this->security->xss_clean($id);
$this->db->where('user_id', $clean_id);
$query = $this->db->get($this->config->item('auth_table'));
$r = $query->row();
return $r->user_email;
}
function hasQrzKey($user_id) {
$user_id = (int) $user_id;
$this->db->where('station_profile.qrzapikey is not null');
$this->db->where('station_profile.qrzapikey != ""');
$this->db->join('station_profile', 'station_profile.user_id = '.$this->config->item('auth_table').'.user_id');
$this->db->where('station_profile.user_id', $user_id);
$query = $this->db->get($this->config->item('auth_table'));
$ret = $query->row();
if ($ret->user_email ?? '' != '') {
return $ret->user_email;
} else {
return '';
}
}
function get_email_address($station_id) {
$this->db->where('station_id', (int) $station_id);
$this->db->join('station_profile', 'station_profile.user_id = '.$this->config->item('auth_table').'.user_id');
$query = $this->db->get($this->config->item('auth_table'));
$ret = $query->row();
return $ret->user_email;
}
// FUNCTION: bool exists($username)
// Check if a user exists (by username)
function exists($username) {
$clean_username = $this->security->xss_clean($username);
if($this->get($clean_username)->num_rows() == 0) {
return 0;
} else {
return 1;
}
}
// FUNCTION: bool exists_by_id($id)
// Check if a user exists (by user ID)
function exists_by_id($id) {
$clean_id = $this->security->xss_clean($id);
if($this->get_by_id($clean_id)->num_rows() == 0) {
return 0;
} else {
return 1;
}
}
// FUNCTION: bool exists_by_email($email)
// Check if a user exists (by email address)
function exists_by_email($email) {
if($this->get_by_email($email)->num_rows() == 0) {
return 0;
} else {
return 1;
}
}
// FUNCTION: bool exists_by_callsign($callsign, $exclude_user_id = NULL)
// Check if a user exists (by callsign), optionally excluding one user ID
function exists_by_callsign($callsign, $exclude_user_id = NULL) {
$clean_callsign = $this->security->xss_clean($callsign);
$this->db->where('UPPER(user_callsign)', strtoupper($clean_callsign));
if ($exclude_user_id !== NULL && $exclude_user_id !== '') {
$this->db->where('user_id !=', $this->security->xss_clean($exclude_user_id));
}
$query = $this->db->get($this->config->item('auth_table'));
if($query->num_rows() == 0) {
return 0;
} else {
return 1;
}
}
function count_admin_users() {
$this->db->where('user_type', 99);
return $this->db->count_all_results($this->config->item('auth_table'));
}
function would_remove_last_admin($user_id, $new_user_type) {
if ((string) $new_user_type === '99') {
return false;
}
$user = $this->get_by_id($user_id);
if ($user->num_rows() === 0) {
return false;
}
if ((int) $user->row()->user_type !== 99) {
return false;
}
return $this->count_admin_users() <= 1;
}
// FUNCTION: bool add($username, $password, $email, $type)
// Add a user
function add($username, $password, $email, $type, $firstname, $lastname, $callsign, $locator, $timezone,
$measurement, $user_date_format, $user_stylesheet, $user_qth_lookup, $user_sota_lookup, $user_wwff_lookup,
$user_pota_lookup, $user_show_notes, $user_column1, $user_column2, $user_column3, $user_column4, $user_column5,
$user_show_profile_image, $user_previous_qsl_type, $user_amsat_status_upload, $user_mastodon_url,
$user_default_band, $user_default_confirmation, $user_qso_end_times, $user_quicklog, $user_quicklog_enter,
$language, $user_hamsat_key, $user_hamsat_workable_only, $callbook_type, $callbook_username, $callbook_password,
$user_winkey, $user_winkey_websocket, $user_remote_operation) {
// Check that the user isn't already used
if(!$this->exists($username)) {
$data = array(
'user_name' => xss_clean($username),
'user_password' => $this->_hash($password),
'user_email' => xss_clean($email),
'user_type' => xss_clean($type),
'user_firstname' => xss_clean($firstname),
'user_lastname' => xss_clean($lastname),
'user_callsign' => strtoupper(xss_clean($callsign)),
'user_locator' => xss_clean($locator),
'user_timezone' => (int)$timezone,
'user_measurement_base' => xss_clean($measurement),
'user_date_format' => xss_clean($user_date_format),
'user_stylesheet' => xss_clean($user_stylesheet),
'user_qth_lookup' => (int)$user_qth_lookup,
'user_sota_lookup' => (int)$user_sota_lookup,
'user_wwff_lookup' => (int)$user_wwff_lookup,
'user_pota_lookup' => (int)$user_pota_lookup,
'user_show_notes' => (int)$user_show_notes,
'user_column1' => xss_clean($user_column1),
'user_column2' => xss_clean($user_column2),
'user_column3' => xss_clean($user_column3),
'user_column4' => xss_clean($user_column4),
'user_column5' => xss_clean($user_column5),
'user_show_profile_image' => (int)$user_show_profile_image,
'user_previous_qsl_type' => (int)$user_previous_qsl_type,
'user_amsat_status_upload' => (int)$user_amsat_status_upload,
'user_mastodon_url' => xss_clean($user_mastodon_url),
'user_default_band' => xss_clean($user_default_band),
'user_default_confirmation' => xss_clean($user_default_confirmation),
'user_qso_end_times' => (int)$user_qso_end_times,
'user_quicklog' => (int)$user_quicklog,
'user_quicklog_enter' => xss_clean($user_quicklog_enter),
'language' => xss_clean($language),
'winkey' => (int)$user_winkey,
'winkey_websocket' => (int)$user_winkey_websocket,
'remote_operation' => (int)$user_remote_operation,
'user_eqsl_qth_nickname' => "",
);
// Check the password is valid
if($data['user_password'] == EPASSWORDINVALID) {
return EPASSWORDINVALID;
}
// Check the email address isn't in use
if($this->exists_by_email($email)) {
return EEMAILEXISTS;
}
// Check the callsign isn't in use
if($this->exists_by_callsign($callsign)) {
return ECALLSIGNEXISTS;
}
// Add user and insert bandsettings for user
$this->db->insert($this->config->item('auth_table'), $data);
$insert_id = $this->db->insert_id();
$this->db->query("insert into bandxuser (bandid, userid, active, cq, dok, dxcc, iota, pota, sig, sota, uscounties, was, wwff, vucc) select bands.id, " . $insert_id . ", 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 from bands;");
$this->db->query("insert into awardxuser (userid, cq, dok, dxcc, ffma, iota, gridmaster_dl, gridmaster_lx, gridmaster_ja, gridmaster_us, gridmaster_uk, gmdxsummer, pota, sig, sota, uscounties, vucc, wab, waja, was, wwff) values (" . $insert_id . ", 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1);");
$this->db->query("insert into paper_types (user_id,paper_name,metric,width,orientation,height) SELECT ".$insert_id.", paper_name, metric, width, orientation,height FROM paper_types where user_id = -1;");
$this->db->query("insert into user_options (user_id, option_type, option_name, option_key, option_value) values (" . $insert_id . ", 'hamsat','hamsat_key','api','".xss_clean($user_hamsat_key)."');");
$this->db->query("insert into user_options (user_id, option_type, option_name, option_key, option_value) values (" . $insert_id . ", 'hamsat','hamsat_key','workable','".xss_clean($user_hamsat_workable_only)."');");
$this->db->query("insert into user_options (user_id, option_type, option_name, option_key, option_value) values (" . $insert_id . ", 'oscarwatch','api_token','value','');");
$this->db->query("insert into user_options (user_id, option_type, option_name, option_key, option_value) values (" . $insert_id . ", 'oscarwatch','status_upload','enabled','0');");
$this->db->query("insert into user_options (user_id, option_type, option_name, option_key, option_value) values (" . $insert_id . ", 'oscarwatch','force_amsat','enabled','0');");
$this->db->query("insert into user_options (user_id, option_type, option_name, option_key, option_value) values (" . $insert_id . ", 'callbook','callbook_type','value','".xss_clean($callbook_type)."');");
$this->db->query("insert into user_options (user_id, option_type, option_name, option_key, option_value) values (" . $insert_id . ", 'callbook','callbook_username','value','".xss_clean($callbook_username)."');");
// Load the encryption library
$this->load->library('encryption');
// Encrypt the password
$encrypted_password = $this->encryption->encrypt($callbook_password);
// Insert the encrypted password into the database
$this->db->query("INSERT INTO user_options (user_id, option_type, option_name, option_key, option_value) VALUES (" . $insert_id . ", 'callbook', 'callbook_password', 'value', '" . xss_clean($encrypted_password) . "');");
return OK;
} else {
return EUSERNAMEEXISTS;
}
}
// FUNCTION: bool edit()
// Edit a user
function edit($fields) {
// Check user privileges
if(($this->session->userdata('user_type') == 99) || ($this->session->userdata('user_id') == $fields['id'])) {
if($this->exists_by_id($fields['id'])) {
$data = array(
'user_name' => xss_clean($fields['user_name']),
'user_email' => xss_clean($fields['user_email']),
'user_callsign' => strtoupper(xss_clean($fields['user_callsign'])),
'user_locator' => xss_clean($fields['user_locator']),
'user_firstname' => xss_clean($fields['user_firstname']),
'user_lastname' => xss_clean($fields['user_lastname']),
'user_timezone' => xss_clean($fields['user_timezone']),
'user_lotw_name' => xss_clean($fields['user_lotw_name']),
'user_eqsl_name' => xss_clean($fields['user_eqsl_name']),
'user_clublog_name' => xss_clean($fields['user_clublog_name']), // Must be a valid email address - Clublog no longer accepts callsigns
'user_measurement_base' => xss_clean($fields['user_measurement_base']),
'user_date_format' => xss_clean($fields['user_date_format']),
'user_stylesheet' => xss_clean($fields['user_stylesheet']),
'user_qth_lookup' => xss_clean($fields['user_qth_lookup']),
'user_sota_lookup' => xss_clean($fields['user_sota_lookup']),
'user_wwff_lookup' => xss_clean($fields['user_wwff_lookup']),
'user_pota_lookup' => xss_clean($fields['user_pota_lookup']),
'user_show_notes' => xss_clean($fields['user_show_notes']),
'user_column1' => xss_clean($fields['user_column1']),
'user_column2' => xss_clean($fields['user_column2']),
'user_column3' => xss_clean($fields['user_column3']),
'user_column4' => xss_clean($fields['user_column4']),
'user_column5' => xss_clean($fields['user_column5']),
'user_show_profile_image' => xss_clean($fields['user_show_profile_image']),
'user_previous_qsl_type' => (int)$fields['user_previous_qsl_type'],
'user_amsat_status_upload' => (int)$fields['user_amsat_status_upload'],
'user_mastodon_url' => xss_clean($fields['user_mastodon_url']),
'user_default_band' => xss_clean($fields['user_default_band']),
'user_default_confirmation' => (isset($fields['user_default_confirmation_qsl']) ? 'Q' : '').(isset($fields['user_default_confirmation_lotw']) ? 'L' : '').(isset($fields['user_default_confirmation_eqsl']) ? 'E' : '').(isset($fields['user_default_confirmation_qrz']) ? 'Z' : ''),
'user_qso_end_times' => xss_clean($fields['user_qso_end_times']),
'user_quicklog' => xss_clean($fields['user_quicklog']),
'user_quicklog_enter' => xss_clean($fields['user_quicklog_enter']),
'language' => xss_clean($fields['language']),
'winkey' => (isset($fields['user_winkey']) && is_numeric($clean = xss_clean($fields['user_winkey'])) && $clean !== '') ? intval($clean) : 0,
'winkey_websocket' => isset($fields['user_winkey_websocket']) ? xss_clean($fields['user_winkey_websocket']) : 0,
'remote_operation' => isset($fields['user_remote_operation']) ? xss_clean($fields['user_remote_operation']) : 0,
);
$this->db->query("replace into user_options (user_id, option_type, option_name, option_key, option_value) values (" . $fields['id'] . ", 'hamsat','hamsat_key','api','".xss_clean($fields['user_hamsat_key'])."');");
$this->db->query("replace into user_options (user_id, option_type, option_name, option_key, option_value) values (" . $fields['id'] . ", 'hamsat','hamsat_key','workable','".xss_clean($fields['user_hamsat_workable_only'])."');");
$this->db->query("replace into user_options (user_id, option_type, option_name, option_key, option_value) values (" . $fields['id'] . ", 'oscarwatch','api_token','value','".xss_clean($fields['user_oscarwatch_token'] ?? '')."');");
$this->db->query("replace into user_options (user_id, option_type, option_name, option_key, option_value) values (" . $fields['id'] . ", 'oscarwatch','status_upload','enabled','".(int)($fields['user_oscarwatch_status_upload'] ?? 0)."');");
$this->db->query("replace into user_options (user_id, option_type, option_name, option_key, option_value) values (" . $fields['id'] . ", 'oscarwatch','force_amsat','enabled','".(int)($fields['user_force_amsat_status_upload'] ?? 0)."');");
// Check to see if the user is allowed to change user levels
if($this->session->userdata('user_type') == 99) {
if ($this->would_remove_last_admin($fields['id'], $fields['user_type'])) {
return ELASTADMIN;
}
$data['user_type'] = $fields['user_type'];
}
// Check to see if username is used already
if($this->exists($fields['user_name']) && $this->get($fields['user_name'])->row()->user_id != $fields['id']) {
return EUSERNAMEEXISTS;
}
// Check to see if email address is used already
if($this->exists_by_email($fields['user_email']) && $this->get_by_email($fields['user_email'])->row()->user_id != $fields['id']) {
return EEMAILEXISTS;
}
// Check to see if callsign is used already
if($this->exists_by_callsign($fields['user_callsign'], $fields['id'])) {
return ECALLSIGNEXISTS;
}
// Hash password
if($fields['user_password'] != NULL)
{
$data['user_password'] = $this->_hash($fields['user_password']);
if($data['user_password'] == EPASSWORDINVALID) {
return EPASSWORDINVALID;
}
}
if($fields['user_lotw_password'] != NULL)
{
$data['user_lotw_password'] = $fields['user_lotw_password'];
}
if($fields['user_clublog_password'] != NULL)
{
$data['user_clublog_password'] = $fields['user_clublog_password'];
}
if($fields['user_eqsl_password'] != NULL)
{
$this->load->library('encryption');
$encrypted_password = $this->encryption->encrypt($fields['user_eqsl_password']);
if ($encrypted_password !== false && $encrypted_password !== null) {
$data['user_eqsl_password'] = 'enc:' . $encrypted_password;
}
}
// Update the user
$this->db->where('user_id', $fields['id']);
$this->db->update($this->config->item('auth_table'), $data);
return OK;
} else {
return ENOSUCHUSER;
}
} else {
return EFORBIDDEN;
}
}
// FUNCTION: bool delete()
// Deletes a user
function delete($user_id) {
if($this->exists_by_id($user_id)) {
$this->db->query("DELETE FROM ".$this->config->item('auth_table')." WHERE user_id = '".$user_id."'");
$this->db->query("delete from user_options where user_id=?",$user_id);
return 1;
} else {
return 0;
}
}
// FUNCTION: bool login()
// Validates a username/password combination
// This is really just a wrapper around User_Model::authenticate
function login() {
$username = $this->input->post('user_name', true);
$password = $this->input->post('user_password', true);
return $this->authenticate($username, $password);
}
// FUNCTION: void clear_session()
// Clears a user's login session
// Nothing is returned - it can be assumed that if this is called, the user's
// login session *will* be cleared, no matter what state it is in
function clear_session() {
$this->session->sess_destroy();
}
// FUNCTION: void update_session()
// Updates a user's login session after they've logged in
// TODO: This should return bool TRUE/FALSE or 0/1
function update_session($id) {
$CI =& get_instance();
$CI->load->model('user_options_model');
$callbook_type_object = $CI->user_options_model->get_options('callbook')->result();
$remote_operation_option = $CI->user_options_model->get_options(
'remote_operation',
array('option_name' => 'enabled', 'option_key' => 'value'),
$id
)->row();
$show_qsl_cards_option = $CI->user_options_model->get_options(
'menu',
array('option_name' => 'show_qsl_cards', 'option_key' => 'enabled'),
$id
)->row();
$show_sstv_images_option = $CI->user_options_model->get_options(
'menu',
array('option_name' => 'show_sstv_images', 'option_key' => 'enabled'),
$id
)->row();
$oscarwatch_status_option = $CI->user_options_model->get_options(
'oscarwatch',
array('option_name' => 'status_upload', 'option_key' => 'enabled'),
$id
)->row();
// Get the callbook type
if (isset($callbook_type_object[1]->option_value)) {
$callbook_type = $callbook_type_object[1]->option_value;
} else {
$callbook_type = "None";
}
// Get the callbook type
if (isset($callbook_type_object[2]->option_value)) {
$callbook_username = $callbook_type_object[2]->option_value;
} else {
$callbook_username = "";
}
// Get the callbook type
if (isset($callbook_type_object[0]->option_value)) {
$callbook_password = $callbook_type_object[0]->option_value;
} else {
$callbook_password = "";
}
$u = $this->get_by_id($id);
$has_eqsl_credentials = ($u->row()->user_eqsl_name != '' && $u->row()->user_eqsl_password != '');
if (!$has_eqsl_credentials) {
$this->load->model('eqsl_mappings_model');
$has_eqsl_credentials = $this->eqsl_mappings_model->has_mappings_for_user($id);
}
$show_qsl_cards = true;
if (isset($show_qsl_cards_option->option_value)) {
$show_qsl_cards = ($show_qsl_cards_option->option_value == 'true');
}
$show_sstv_images = false;
if (isset($show_sstv_images_option->option_value)) {
$show_sstv_images = ($show_sstv_images_option->option_value == 'true');
}
$oscarwatch_status_upload = 0;
if (isset($oscarwatch_status_option->option_value)) {
$oscarwatch_status_upload = (int) $oscarwatch_status_option->option_value;
}
$userdata = array(
'user_id' => $u->row()->user_id,
'user_name' => $u->row()->user_name,
'user_type' => $u->row()->user_type,
'user_callsign' => $u->row()->user_callsign,
'operator_callsign' => ((($this->session->userdata('operator_callsign') ?? '') == '') ? $u->row()->user_callsign : $this->session->userdata('operator_callsign')),
'user_locator' => $u->row()->user_locator,
'user_lotw_name' => $u->row()->user_lotw_name,
'user_eqsl_name' => $u->row()->user_eqsl_name,
'user_eqsl_qth_nickname' => $u->row()->user_eqsl_qth_nickname,
'has_eqsl_credentials' => $has_eqsl_credentials,
'user_show_qsl_cards' => $show_qsl_cards,
'user_show_sstv_images' => $show_sstv_images,
'user_hash' => $this->_hash($u->row()->user_id."-".$u->row()->user_type),
'radio' => isset($_COOKIE["radio"])?$_COOKIE["radio"]:"",
'station_profile_id' => isset($_COOKIE["station_profile_id"])?$_COOKIE["station_profile_id"]:"",
'user_measurement_base' => $u->row()->user_measurement_base,
'user_date_format' => $u->row()->user_date_format,
'user_stylesheet' => $u->row()->user_stylesheet,
'user_qth_lookup' => isset($u->row()->user_qth_lookup) ? $u->row()->user_qth_lookup : 0,
'user_sota_lookup' => isset($u->row()->user_sota_lookup) ? $u->row()->user_sota_lookup : 0,
'user_wwff_lookup' => isset($u->row()->user_wwff_lookup) ? $u->row()->user_wwff_lookup : 0,
'user_pota_lookup' => isset($u->row()->user_pota_lookup) ? $u->row()->user_pota_lookup : 0,
'user_show_notes' => isset($u->row()->user_show_notes) ? $u->row()->user_show_notes : 1,
'user_show_profile_image' => isset($u->row()->user_show_profile_image) ? $u->row()->user_show_profile_image : 0,
'user_column1' => isset($u->row()->user_column1) ? $u->row()->user_column1: 'Mode',
'user_column2' => isset($u->row()->user_column2) ? $u->row()->user_column2: 'RSTS',
'user_column3' => isset($u->row()->user_column3) ? $u->row()->user_column3: 'RSTR',
'user_column4' => isset($u->row()->user_column4) ? $u->row()->user_column4: 'Band',
'user_column5' => isset($u->row()->user_column5) ? $u->row()->user_column5: 'Country',
'user_previous_qsl_type' => isset($u->row()->user_previous_qsl_type) ? $u->row()->user_previous_qsl_type: 0,
'user_amsat_status_upload' => isset($u->row()->user_amsat_status_upload) ? $u->row()->user_amsat_status_upload: 0,
'user_oscarwatch_status_upload' => $oscarwatch_status_upload,
'user_mastodon_url' => $u->row()->user_mastodon_url,
'user_default_band' => $u->row()->user_default_band,
'user_default_confirmation' => $u->row()->user_default_confirmation,
'user_qso_end_times' => isset($u->row()->user_qso_end_times) ? $u->row()->user_qso_end_times : 1,
'user_quicklog' => isset($u->row()->user_quicklog) ? $u->row()->user_quicklog : 1,
'user_quicklog_enter' => isset($u->row()->user_quicklog_enter) ? $u->row()->user_quicklog_enter : 1,
'active_station_logbook' => $u->row()->active_station_logbook,
'language' => isset($u->row()->language) ? $u->row()->language: 'english',
'isWinkeyEnabled' => $u->row()->winkey,
'isWinkeyWebsocketEnabled' => isset($u->row()->winkey_websocket) ? (bool)$u->row()->winkey_websocket : false,
'isRemoteOperationEnabled' => (isset($remote_operation_option->option_value) ? ((string)$remote_operation_option->option_value === 'true' || (string)$remote_operation_option->option_value === '1') : (isset($u->row()->remote_operation) ? (bool)$u->row()->remote_operation : false)),
'hasQrzKey' => $this->hasQrzKey($u->row()->user_id),
'callbook_type' => $callbook_type,
'callbook_username' => $callbook_username,
'callbook_password' => $callbook_password,
);
$this->session->set_userdata($userdata);
}
// FUNCTION: bool validate_session()
// Validate a user's login session
// If the user's session is corrupted in any way, it will clear the session
function validate_session() {
if (!$this->session->userdata('user_id')) {
return 0;
}
$user_id = $this->session->userdata('user_id');
$user_hash = $this->session->userdata('user_hash');
if (empty($user_hash)) {
$this->clear_session();
return 0;
}
// Re-read the user from the database and validate against persisted state.
$u = $this->get_by_id($user_id);
if ($u->num_rows() !== 1) {
$this->clear_session();
return 0;
}
$db_user_type = $u->row()->user_type;
if ($this->_auth($user_id."-".$db_user_type, $user_hash)) {
// Freshen the session
$this->update_session($user_id);
return 1;
}
$this->clear_session();
return 0;
}
// FUNCTION: bool authenticate($username, $password)
// Authenticate a user against the users table
function authenticate($username, $password) {
$u = $this->get($username);
if($u->num_rows() != 0)
{
if($this->_auth($password, $u->row()->user_password)) {
return 1;
}
}
return 0;
}
// FUNCTION: set's the last-login timestamp in user table
function set_last_login($user_id) {
$data = array(
'last_login_date' => date('Y-m-d H:i:s')
);
$this->db->where('user_id', $user_id);
$this->db->update('users', $data);
}
// FUNCTION: bool authorize($level)
// Checks a user's level of access against the given $level
function authorize($level) {
$u = $this->get_by_id($this->session->userdata('user_id'));
$l = $this->config->item('auth_mode');
// Check to see if the minimum level of access is higher than
// the user's own level. If it is, use that.
if($this->config->item('auth_mode') > $level) {
$level = $this->config->item('auth_mode');
}
if(($this->validate_session()) && ($u->row()->user_type >= $level) || $this->config->item('use_auth') == FALSE || $level == 0) {
return 1;
} else {
return 0;
}
}
// FUNCTION: bool set($username, $data)
// Updates a user's record in the database
// TODO: This returns TRUE/1 no matter what at the moment - should
// TODO: return TRUE/FALSE or 0/1 depending on success/failure
function set($username, $data) {
$this->db->where('user_name', $username);
$this->db->update($this->config->item('auth_table', $data));
return 1;
}
// FUNCTION: object users()
// Returns a list of users
function users() {
$r = $this->db->get($this->config->item('auth_table'));
return $r;
}
// FUNCTION: array timezones()
// Returns a list of timezones
function timezones() {
$r = $this->db->query('SELECT id, name FROM timezones ORDER BY `offset`');
$ts = array();
foreach ($r->result_array() as $t) {
$ts[$t['id']] = $t['name'];
}
return $ts;
}
// FUNCTION: array getThemes()
// Returns a list of themes
function getThemes() {
$result = $this->db->query('SELECT * FROM themes order by name');
return $result->result();
}
/*
* FUNCTION: set_password_reset_code
*
* Stores generated password reset code in the database and sets the date to exactly
* when the sql query runs.
*
* @param string $user_email
* @return string $reset_code
*/
function set_password_reset_code($user_email, $reset_code) {
$data = array(
'reset_password_code' => $reset_code,
'reset_password_date' => date('Y-m-d H:i:s')
);
$this->db->where('user_email', $user_email);
$this->db->update('users', $data);
}
/*
* FUNCTION: reset_password
*
* Sets new password for users account where the reset code matches then clears the password reset code and password reset date.
*
* @param string $password
* @return string $reset_code
*/
function reset_password($password, $reset_code) {
$data = array(
'user_password' => $this->_hash($password),
'reset_password_code' => NULL,
'reset_password_date' => NULL
);
$this->db->where('reset_password_code', $reset_code);
$this->db->update('users', $data);
}
// FUNCTION: bool _auth($password, $hash)
// Checks a password against the stored hash
private function _auth($password, $hash) {
if(password_verify($password, $hash)) {
return 1;
} else {
return 0;
}
}
// FUNCTION: string _hash($password)
// Returns a hashed version of the supplied $password
// Will return '0' in the event of problems with the
// hashing function
private function _hash($password) {
$hash = password_hash($password, PASSWORD_DEFAULT);
if(strlen($hash) < 20) {
return EPASSWORDINVALID;
} else {
return $hash;
}
}
}
?>