doc/apiconf.txt'; $blocklogin = TRUE; } if (!isset($apiproto) or !preg_match('/^http(s)?$/', $apiproto)) { $errormsg = "The value for \$apiproto is incorrect in your config. Did you configure it?"; $blocklogin = TRUE; } if (!isset($apisslverify)) { $errormsg = "The value for \$apisslverify is incorrect in your config. Did you configure it?"; $blocklogin = TRUE; } else { $apisslverify = ( bool ) $apisslverify; } if (!isset($authdb)) { $errormsg = "You did not configure a value for the setting \$authdb in your config"; $blocklogin = TRUE; } if (isset($defaults['primaryns'])) { $errormsg = "You should reconfigure your \$defaults['primaryns'] settings to use \$defaults['ns'][0]. We converted if for you now."; $defaults['ns'][] = $defaults['primaryns']; if (isset($defaults['secondaryns'])) { $defaults['ns'][] = $defaults['secondaryns']; } } if (!isset($logo) or empty($logo)) { $logo = 'https://www.tuxis.nl/uploads/images/nsedit.png'; } /* No need to change stuf below */ if (function_exists('curl_init') === FALSE) { $errormsg = "You need PHP Curl to run nsedit"; $blocklogin = TRUE; } if (class_exists('SQLite3') === FALSE) { $errormsg = "You need PHP SQLite3 to run nsedit"; $blocklogin = TRUE; } if (function_exists('openssl_random_pseudo_bytes') === FALSE) { $errormsg = "You need PHP compiled with openssl to run nsedit"; $blocklogin = TRUE; } $defaults['defaulttype'] = ucfirst(strtolower($defaults['defaulttype'])); try { if (isset($authdb) && !file_exists($authdb) && class_exists('SQLite3')) { is_dir(dirname($authdb)) || mkdir(dirname($authdb)); $db = new SQLite3($authdb, SQLITE3_OPEN_CREATE|SQLITE3_OPEN_READWRITE); $createsql = file_get_contents('includes/scheme.sql'); $db->exec($createsql); $salt = bin2hex(openssl_random_pseudo_bytes(16)); $db->exec("INSERT INTO users (emailaddress, password, isadmin) VALUES ('admin', '".crypt("admin", '$6$'.$salt)."', 1)"); } } catch (Exception $e) { print("We have issues getting the authdb working: $e"); $blocklogin = TRUE; } function string_starts_with($string, $prefix) { $length = strlen($prefix); return (substr($string, 0, $length) === $prefix); } function string_ends_with($string, $suffix) { $length = strlen($suffix); if ($length == 0) { return true; } return (substr($string, -$length) === $suffix); } function get_db() { global $authdb, $db; if (!isset($db)) { $db = new SQLite3($authdb, SQLITE3_OPEN_READWRITE); $db->exec('PRAGMA foreign_keys = 1'); } return $db; } function get_all_users() { $db = get_db(); $r = $db->query('SELECT id, emailaddress, isadmin FROM users ORDER BY emailaddress'); $ret = array(); while ($row = $r->fetchArray(SQLITE3_ASSOC)) { array_push($ret, $row); } return $ret; } function get_user_info($u) { $db = get_db(); $q = $db->prepare('SELECT * FROM users WHERE emailaddress = ?'); $q->bindValue(1, $u); $result = $q->execute(); $userinfo = $result->fetchArray(SQLITE3_ASSOC); return $userinfo; } function user_exists($u) { return (bool) get_user_info($u); } function do_db_auth($u, $p) { $db = get_db(); $q = $db->prepare('SELECT * FROM users WHERE emailaddress = ?'); $q->bindValue(1, $u); $result = $q->execute(); $userinfo = $result->fetchArray(SQLITE3_ASSOC); if ($userinfo and $userinfo['password'] and (crypt($p, $userinfo['password']) === $userinfo['password'])) { return TRUE; } return FALSE; } function add_user($username, $isadmin = FALSE, $password = '') { if (!$password) { $password = bin2hex(openssl_random_pseudo_bytes(32)); } if (!string_starts_with($password, '$6$')) { $salt = bin2hex(openssl_random_pseudo_bytes(16)); $password = crypt($password, '$6$'.$salt); } $db = get_db(); $q = $db->prepare('INSERT INTO users (emailaddress, password, isadmin) VALUES (?, ?, ?)'); $q->bindValue(1, $username, SQLITE3_TEXT); $q->bindValue(2, $password, SQLITE3_TEXT); $q->bindValue(3, (int)(bool) $isadmin, SQLITE3_INTEGER); $ret = $q->execute(); if ($isadmin) { writelog("Added user $username as admin."); } else { writelog("Added user $username."); } return $ret; } function update_user($id, $isadmin, $password) { if ($password && !preg_match('/\$6\$/', $password)) { $salt = bin2hex(openssl_random_pseudo_bytes(16)); $password = crypt($password, '$6$'.$salt); } $db = get_db(); $q = $db->prepare('SELECT * FROM users WHERE id = ?'); $q->bindValue(1, $id, SQLITE3_INTEGER); $result = $q->execute(); $userinfo = $result->fetchArray(SQLITE3_ASSOC); $q->close(); $username = $userinfo['emailaddress']; if ($password) { $q = $db->prepare('UPDATE users SET isadmin = ?, password = ? WHERE id = ?'); $q->bindValue(1, (int)(bool)$isadmin, SQLITE3_INTEGER); $q->bindValue(2, $password, SQLITE3_TEXT); $q->bindValue(3, $id, SQLITE3_INTEGER); writelog("Updating password and/or settings for $username. Admin: ".(int)(bool)$isadmin); } else { $q = $db->prepare('UPDATE users SET isadmin = ? WHERE id = ?'); $q->bindValue(1, (int)(bool)$isadmin, SQLITE3_INTEGER); $q->bindValue(2, $id, SQLITE3_INTEGER); writelog("Updating settings for $username. Admin: ".(int)(bool)$isadmin); } $ret = $q->execute(); return $ret; } function delete_user($id) { $db = get_db(); $q = $db->prepare('SELECT * FROM users WHERE id = ?'); $q->bindValue(1, $id, SQLITE3_INTEGER); $result = $q->execute(); $userinfo = $result->fetchArray(SQLITE3_ASSOC); $q->close(); if($userinfo) { $q = $db->prepare('DELETE FROM users WHERE id = ?'); $q->bindValue(1, $id, SQLITE3_INTEGER); $ret = $q->execute(); writelog("Deleted user " . $userinfo['emailaddress'] . "."); return $ret; } else { return false; } } function valid_user($name) { return ( bool ) preg_match( "/^[a-z0-9@_.-]+$/i" , $name ); } function jtable_respond($records, $method = 'multiple', $msg = 'Undefined errormessage') { $jTableResult = array(); if ($method == 'error') { $jTableResult['Result'] = "ERROR"; $jTableResult['Message'] = $msg; } elseif ($method == 'single') { $jTableResult['Result'] = "OK"; $jTableResult['Record'] = $records; } elseif ($method == 'delete') { $jTableResult['Result'] = "OK"; } elseif ($method == 'options') { $jTableResult['Result'] = "OK"; $jTableResult['Options'] = $records; } else { if (isset($_GET['jtPageSize'])) { $jTableResult['TotalRecordCount'] = count($records); $records = array_slice($records, $_GET['jtStartIndex'], $_GET['jtPageSize']); } $jTableResult['Result'] = "OK"; $jTableResult['Records'] = $records; $jTableResult['RecordCount'] = count($records); } $db = get_db(); $db->close(); header('Content-Type: application/json'); print json_encode($jTableResult); exit(0); } function user_template_list() { global $templates; $templatelist = array(); foreach ($templates as $template) { if (is_adminuser() or (isset($template['owner']) and ($template['owner'] == get_sess_user() or $template['owner'] == 'public'))) { array_push($templatelist, $template); } } return $templatelist; } function user_template_names() { $templatenames = array('None' => 'None'); foreach (user_template_list() as $template) { $templatenames[$template['name']] = $template['name']; } return $templatenames; } function getlogs() { global $logging; if ($logging !== TRUE) return; $db = get_db(); $r = $db->query('SELECT * FROM logs ORDER BY timestamp DESC'); $ret = array(); while ($row = $r->fetchArray(SQLITE3_ASSOC)) { array_push($ret, $row); } return $ret; } function clearlogs() { global $logging; if ($logging !== TRUE) return; $db = get_db(); $q = $db->query('DELETE FROM logs;'); writelog("Logtable truncated."); } function rotatelogs() { global $logging, $logsdirectory; if ($logging !== TRUE) return FALSE; if(!is_dir($logsdirectory) || !is_writable($logsdirectory)) { writelog("Logs directory cannot be written to."); return FALSE; } date_default_timezone_set('UTC'); $filename = date("Y-m-d-His") . ".json"; $file = fopen($logsdirectory . "/" . $filename, "x"); if($file === FALSE) { writelog("Can't create file for log rotation."); return FALSE; } if(fwrite($file,json_encode(getlogs())) === FALSE) { writelog("Can't write to file for log rotation."); fclose($file); return FALSE; } else { fclose($file); clearlogs(); return $filename; } } function listrotatedlogs() { global $logging, $logsdirectory; if ($logging !== TRUE) return FALSE; $list = scandir($logsdirectory,SCANDIR_SORT_DESCENDING); if($list === FALSE) { writelog("Logs directory cannot read."); return FALSE; } $list=array_filter($list, function ($val) { return(preg_match('/^[0-9]{4}-[0-9]{2}-[0-9]{2}-[0-9]{6}\.json/',$val) == 1); } ); return $list; } function writelog($line, $user=False) { global $logging; if ($logging !== TRUE) return; if ($user === False) { $user = get_sess_user(); } try { $db = get_db(); $q = $db->prepare('CREATE TABLE IF NOT EXISTS logs ( id INTEGER PRIMARY KEY, user TEXT NOT NULL, log TEXT NOT NULL, timestamp DATETIME DEFAULT CURRENT_TIMESTAMP);'); $ret = $q->execute(); $q = $db->prepare('INSERT INTO logs (user, log) VALUES (:user, :log)'); $q->bindValue(':user', $user, SQLITE3_TEXT); $q->bindValue(':log', $line, SQLITE3_TEXT); $q->execute(); } catch (Exception $e) { return jtable_respond(null, 'error', $e->getMessage()); } } /* This function was taken from https://gist.github.com/rsky/5104756 to make it available on older php versions. Thanks! */ if (!function_exists('hash_pbkdf2')) { function hash_pbkdf2($algo, $password, $salt, $iterations, $length = 0, $rawOutput = false) { // check for hashing algorithm if (!in_array(strtolower($algo), hash_algos())) { trigger_error(sprintf( '%s(): Unknown hashing algorithm: %s', __FUNCTION__, $algo ), E_USER_WARNING); return false; } // check for type of iterations and length foreach (array(4 => $iterations, 5 => $length) as $index => $value) { if (!is_numeric($value)) { trigger_error(sprintf( '%s() expects parameter %d to be long, %s given', __FUNCTION__, $index, gettype($value) ), E_USER_WARNING); return null; } } // check iterations $iterations = (int)$iterations; if ($iterations <= 0) { trigger_error(sprintf( '%s(): Iterations must be a positive integer: %d', __FUNCTION__, $iterations ), E_USER_WARNING); return false; } // check length $length = (int)$length; if ($length < 0) { trigger_error(sprintf( '%s(): Iterations must be greater than or equal to 0: %d', __FUNCTION__, $length ), E_USER_WARNING); return false; } // check salt if (strlen($salt) > PHP_INT_MAX - 4) { trigger_error(sprintf( '%s(): Supplied salt is too long, max of INT_MAX - 4 bytes: %d supplied', __FUNCTION__, strlen($salt) ), E_USER_WARNING); return false; } // initialize $derivedKey = ''; $loops = 1; if ($length > 0) { $loops = (int)ceil($length / strlen(hash($algo, '', $rawOutput))); } // hash for each blocks for ($i = 1; $i <= $loops; $i++) { $digest = hash_hmac($algo, $salt . pack('N', $i), $password, true); $block = $digest; for ($j = 1; $j < $iterations; $j++) { $digest = hash_hmac($algo, $digest, $password, true); $block ^= $digest; } $derivedKey .= $block; } if (!$rawOutput) { $derivedKey = bin2hex($derivedKey); } if ($length > 0) { return substr($derivedKey, 0, $length); } return $derivedKey; } } ?>