From f6ceaa03052e6878afd53a4bbb7f4429849fe25a Mon Sep 17 00:00:00 2001 From: Simon Rettberg Date: Mon, 19 May 2014 15:30:59 +0200 Subject: OO style modules --- inc/user.inc.php | 5 +- index.php | 85 +++++++++---- modules/adduser.inc.php | 8 +- modules/baseconfig.inc.php | 167 ++++++++++++------------- modules/ipxe.inc.php | 55 +++++---- modules/main.inc.php | 47 +++++--- modules/minilinux.inc.php | 153 ++++++++++++----------- modules/session.inc.php | 61 +++++----- modules/sysconfig.inc.php | 168 ++++++++++++-------------- modules/sysconfig/addmodule.inc.php | 188 +++++++++-------------------- modules/sysconfig/addmodule_ad.inc.php | 57 +++++++++ modules/sysconfig/addmodule_custom.inc.php | 142 ++++++++++++++++++++++ modules/syslog.inc.php | 113 ++++++++--------- style/default.css | 10 ++ templates/dialog-generic.html | 2 +- templates/main-menu.html | 12 +- templates/menu-login.html | 2 +- templates/menu-logout.html | 2 +- templates/page-adduser.html | 2 +- templates/page-baseconfig.html | 2 +- templates/page-login.html | 4 +- templates/page-main-guest.html | 2 +- templates/page-main.html | 6 +- templates/page-remote-tgz-list.html | 4 +- templates/page-sysconfig-main.html | 10 +- templates/page-syslog.html | 3 +- templates/sysconfig/ad-start.html | 51 ++++++++ templates/sysconfig/custom-fileselect.html | 2 +- templates/sysconfig/custom-upload.html | 2 +- templates/sysconfig/start.html | 12 ++ 30 files changed, 815 insertions(+), 562 deletions(-) create mode 100644 modules/sysconfig/addmodule_ad.inc.php create mode 100644 modules/sysconfig/addmodule_custom.inc.php create mode 100644 templates/sysconfig/ad-start.html create mode 100644 templates/sysconfig/start.html diff --git a/inc/user.inc.php b/inc/user.inc.php index b333c7e4..19d17753 100644 --- a/inc/user.inc.php +++ b/inc/user.inc.php @@ -25,6 +25,9 @@ class User public static function load() { + if (self::isLoggedIn()) { + return true; + } if (Session::load()) { $uid = Session::get('uid'); if ($uid === false || $uid < 1) self::logout(); @@ -50,7 +53,7 @@ class User public static function logout() { Session::delete(); - Header('Location: ?do=main&fromlogout'); + Header('Location: ?do=Main&fromlogout'); exit(0); } diff --git a/index.php b/index.php index d50d1d71..ae03e86c 100644 --- a/index.php +++ b/index.php @@ -1,51 +1,89 @@ doPreprocess(); } + public static function render() { self::$instance->doRender(); } + public static function ajax() { self::$instance->doAjax(); } + /** + * + * @var \Page + */ + private static $instance = false; + public static function set($name) + { + $name = preg_replace('/[^A-Za-z]/', '', $name); + $modulePath = 'modules/' . strtolower($name) . '.inc.php'; + if (!file_exists($modulePath)) { + Util::traceError('Invalid module file: ' . $modulePath); + } + require_once $modulePath; + $className = 'Page_' . $name; + if (!class_exists($className) || get_parent_class($className) !== 'Page') { + Util::traceError('Module not found: ' . $name); + } + self::$instance = new $className(); + } +} + +// Error reporting (hopefully goind to stderr, not being printed on pages) error_reporting(E_ALL); +// Set variable if this is an ajax request +$isAsync = (isset($_REQUEST['async'])) + || (!empty($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) === 'xmlhttprequest'); + // Autoload classes from ./inc which adhere to naming scheme .inc.php function slxAutoloader($class) { $file = 'inc/' . preg_replace('/[^a-z0-9]/', '', mb_strtolower($class)) . '.inc.php'; if (!file_exists($file)) return; require_once $file; } - spl_autoload_register('slxAutoloader'); -if (empty($_REQUEST['do'])) { - // No specific module - set default - $moduleName = 'main'; -} else { - $moduleName = preg_replace('/[^a-z]/', '', $_REQUEST['do']); -} +// Now determine which module to run +Page::set(empty($_REQUEST['do']) ? 'Main' : $_REQUEST['do']); -$modulePath = 'modules/' . $moduleName . '.inc.php'; - -if (!file_exists($modulePath)) { - Util::traceError('Invalid module: ' . $moduleName); +// Deserialize any messages to display +if (!$isAsync && isset($_REQUEST['message'])) { + Message::fromRequest(); } -// Deserialize any messages -if (isset($_REQUEST['message'])) { - Message::fromRequest(); +// CSRF/XSS check +if ($_SERVER['REQUEST_METHOD'] === 'POST') { + User::load(); + if (!Util::verifyToken()) { + if ($isAsync) { + die('CSRF/XSS? Missing token in POST request!'); + } else { + Util::redirect('?do=Main'); + } + } } -// CSRF/XSS -if ($_SERVER['REQUEST_METHOD'] === 'POST' && !Util::verifyToken()) { - Util::redirect('?do=' . $moduleName); +// AJAX Stuff? Just do so. Otherwise, run preprocessing +if ($isAsync) { + Page::ajax(); + exit(0); } -// Load module - it will execute pre-processing, or act upon request parameters -require_once($modulePath); -unset($modulePath); +// Normal mode - preprocess first.... +Page::preprocess(); -// Main menu +// Generate Main menu $menu = new Menu; Render::addTemplate('main-menu', $menu); Message::renderList(); -// Render module. If the module wants to output anything, it will be done here -render_module(); +// Render page. If the module wants to output anything, it will be done here... +Page::render(); if (defined('CONFIG_DEBUG') && CONFIG_DEBUG) { Message::addWarning('debug-mode'); @@ -53,4 +91,3 @@ if (defined('CONFIG_DEBUG') && CONFIG_DEBUG) { // Send page to client. Render::output(); - diff --git a/modules/adduser.inc.php b/modules/adduser.inc.php index f152643b..6a5faf3a 100644 --- a/modules/adduser.inc.php +++ b/modules/adduser.inc.php @@ -6,13 +6,13 @@ if (isset($_POST['action']) && $_POST['action'] === 'adduser') { // Check required fields if (empty($_POST['user']) || empty($_POST['pass1']) || empty($_POST['pass2']) || empty($_POST['fullname']) || empty($_POST['phone']) || empty($_POST['email'])) { Message::addError('empty-field'); - Util::redirect('?do=adduser'); + Util::redirect('?do=AddUser'); } elseif ($_POST['pass1'] !== $_POST['pass2']) { Message::addError('password-mismatch'); - Util::redirect('?do=adduser'); + Util::redirect('?do=AddUser'); } elseif (Database::queryFirst('SELECT userid FROM user LIMIT 1') !== false) { Message::addError('adduser-disabled'); - Util::redirect('?do=session&action=login'); + Util::redirect('?do=Session&action=login'); } else { $data = array( 'user' => $_POST['user'], @@ -31,7 +31,7 @@ if (isset($_POST['action']) && $_POST['action'] === 'adduser') { Database::exec('UPDATE user SET permissions = 1'); } Message::addInfo('adduser-success'); - Util::redirect('?do=session&action=login'); + Util::redirect('?do=Session&action=login'); } } diff --git a/modules/baseconfig.inc.php b/modules/baseconfig.inc.php index 80dc6cd5..99e7f1bb 100644 --- a/modules/baseconfig.inc.php +++ b/modules/baseconfig.inc.php @@ -1,94 +1,97 @@ 'distroid', - 'value' => (int)$_REQUEST['distroid'], - 'table' => 'setting_distro', - ); - if (isset($_REQUEST['poolid'])) { - $qry_extra[] = array( - 'name' => 'poolid', - 'value' => (int)$_REQUEST['poolid'], - 'table' => 'setting_pool', - ); - } -} +class Page_BaseConfig extends Page +{ + private $qry_extra = array(); + protected function doPreprocess() + { + User::load(); -if (isset($_POST['setting']) && is_array($_POST['setting'])) { - if (User::hasPermission('superadmin')) { - if (Util::verifyToken()) { - // Build variables for specific sub-settings - $qry_insert = ''; - $qry_values = ''; - foreach ($qry_extra as $item) { - $qry_insert = ', ' . $item['name']; - $qry_values = ', :' . $item['name']; + // Determine if we're setting global, distro or pool + if (isset($_REQUEST['distroid'])) { + // TODO: Everything + $this->qry_extra[] = array( + 'name' => 'distroid', + 'value' => (int)$_REQUEST['distroid'], + 'table' => 'setting_distro', + ); + if (isset($_REQUEST['poolid'])) { + $this->qry_extra[] = array( + 'name' => 'poolid', + 'value' => (int)$_REQUEST['poolid'], + 'table' => 'setting_pool', + ); } - // Load all existing config options to validate input - $res = Database::simpleQuery('SELECT setting, validator FROM setting'); - while ($row = $res->fetch(PDO::FETCH_ASSOC)) { - $key = $row['setting']; - $validator = $row['validator']; - $input = (isset($_POST['setting'][$key]) ? $_POST['setting'][$key] : ''); - // Validate data first! - $value = Validator::validate($validator, $input); - if ($value === false) { - Message::addWarning('value-invalid', $key, $input); - continue; + } + + if (isset($_POST['setting']) && is_array($_POST['setting'])) { + if (User::hasPermission('superadmin')) { + // Build variables for specific sub-settings + $qry_insert = ''; + $qry_values = ''; + foreach ($this->qry_extra as $item) { + $qry_insert = ', ' . $item['name']; + $qry_values = ', :' . $item['name']; } - // Now put into DB - Database::exec("INSERT INTO setting_global (setting, value $qry_insert) - VALUES (:key, :value $qry_values) - ON DUPLICATE KEY UPDATE value = :value", - $qry_extra + array( - 'key' => $key, - 'value' => $value, - ) - ); + // Load all existing config options to validate input + $res = Database::simpleQuery('SELECT setting, validator FROM setting'); + while ($row = $res->fetch(PDO::FETCH_ASSOC)) { + $key = $row['setting']; + $validator = $row['validator']; + $input = (isset($_POST['setting'][$key]) ? $_POST['setting'][$key] : ''); + // Validate data first! + $value = Validator::validate($validator, $input); + if ($value === false) { + Message::addWarning('value-invalid', $key, $input); + continue; + } + // Now put into DB + Database::exec("INSERT INTO setting_global (setting, value $qry_insert) + VALUES (:key, :value $qry_values) + ON DUPLICATE KEY UPDATE value = :value", + $this->qry_extra + array( + 'key' => $key, + 'value' => $value, + ) + ); + } + Message::addSuccess('settings-updated'); + Util::redirect('?do=BaseConfig'); } - Message::addSuccess('settings-updated'); - Util::redirect('?do=baseconfig'); } } -} -function render_module() -{ - if (!User::hasPermission('superadmin')) { - Message::addError('no-permission'); - return; - } - // Build left joins for specific settings - global $qry_extra; - $joins = ''; - foreach ($qry_extra as $item) { - $joins .= " LEFT JOIN ${item['table']} "; - } - // List global config option - $settings = array(); - $res = Database::simpleQuery('SELECT cat_setting.name AS category_name, setting.setting, setting.defaultvalue, setting.permissions, setting.description, tbl.value - FROM setting - INNER JOIN cat_setting USING (catid) - LEFT JOIN setting_global AS tbl USING (setting) - ORDER BY cat_setting.sortval ASC, setting.setting ASC'); // TODO: Add setting groups and sort order - while ($row = $res->fetch(PDO::FETCH_ASSOC)) { - $row['description'] = Util::markup($row['description']); - if (is_null($row['value'])) $row['value'] = $row['defaultvalue']; - $row['big'] = false; - $settings[$row['category_name']]['settings'][] = $row; - $settings[$row['category_name']]['category_name'] = $row['category_name']; + protected function doRender() + { + if (!User::hasPermission('superadmin')) { + Message::addError('no-permission'); + return; + } + // Build left joins for specific settings + $joins = ''; + foreach ($this->qry_extra as $item) { + $joins .= " LEFT JOIN {$item['table']} "; + } + // List global config option + $settings = array(); + $res = Database::simpleQuery('SELECT cat_setting.name AS category_name, setting.setting, setting.defaultvalue, setting.permissions, setting.description, tbl.value + FROM setting + INNER JOIN cat_setting USING (catid) + LEFT JOIN setting_global AS tbl USING (setting) + ORDER BY cat_setting.sortval ASC, setting.setting ASC'); // TODO: Add setting groups and sort order + while ($row = $res->fetch(PDO::FETCH_ASSOC)) { + $row['description'] = Util::markup($row['description']); + if (is_null($row['value'])) $row['value'] = $row['defaultvalue']; + $row['big'] = false; + $settings[$row['category_name']]['settings'][] = $row; + $settings[$row['category_name']]['category_name'] = $row['category_name']; + } + $settings = array_values($settings); + Render::addTemplate('page-baseconfig', array( + 'categories' => $settings, + 'token' => Session::get('token'), + )); } - $settings = array_values($settings); - Render::addTemplate('page-baseconfig', array( - 'categories' => $settings, - 'token' => Session::get('token'), - )); -} +} diff --git a/modules/ipxe.inc.php b/modules/ipxe.inc.php index 869f4c72..d479bd15 100644 --- a/modules/ipxe.inc.php +++ b/modules/ipxe.inc.php @@ -1,35 +1,40 @@ $out[1], - 'current' => ($out[1] == $current) - ); + protected function doRender() + { + $ips = array(); + $current = CONFIG_IPXE_DIR . '/last-ip'; + if (file_exists($current)) $current = file_get_contents($current); + exec('/bin/ip a', $retval); + foreach ($retval as $ip) { + if (preg_match('#inet (\d+\.\d+\.\d+\.\d+)/\d+.*scope#', $ip, $out) && $out[1] !== '127.0.0.1') { + $ips[] = array( + 'ip' => $out[1], + 'current' => ($out[1] == $current) + ); + } } + Render::addTemplate('page-ipxe', array('ips' => $ips, 'token' => Session::get('token'))); } - Render::addTemplate('page-ipxe', array('ips' => $ips, 'token' => Session::get('token'))); } - - diff --git a/modules/main.inc.php b/modules/main.inc.php index 24f519c6..3b35ad53 100644 --- a/modules/main.inc.php +++ b/modules/main.inc.php @@ -1,27 +1,34 @@ User::getName(), 'ipxe' => $ipxe, 'sysconfig' => $sysconfig, 'minilinux' => $minilinux)); } - $sysconfig = !file_exists(CONFIG_HTTP_DIR . '/default/config.tgz'); - $minilinux = !file_exists(CONFIG_HTTP_DIR . '/default/kernel') || !file_exists(CONFIG_HTTP_DIR . '/default/initramfs-stage31') || !file_exists(CONFIG_HTTP_DIR . '/default/stage32.sqfs'); - Render::addTemplate('page-main', array('user' => User::getName(), 'ipxe' => $ipxe, 'sysconfig' => $sysconfig, 'minilinux' => $minilinux)); -} +} diff --git a/modules/minilinux.inc.php b/modules/minilinux.inc.php index 72af0eb4..6e68a34e 100644 --- a/modules/minilinux.inc.php +++ b/modules/minilinux.inc.php @@ -1,88 +1,97 @@ $files, 'token' => Session::get('token'))); -} + if (!User::hasPermission('superadmin')) { + Message::addError('no-permission'); + Util::redirect('?do=Main'); + } + } -function checkFile(&$files, $name) -{ - static $someId = 0; - $remote = CONFIG_REMOTE_ML . "/${name}.md5"; - $localTarget = CONFIG_HTTP_DIR . "/default/${name}"; - $local = "${localTarget}.md5"; - $localLock = "${localTarget}.lck"; + protected function doRender() + { + $files = array(); + mkdir(CONFIG_HTTP_DIR . "/default", 0755, true); + $this->checkFile($files, 'kernel'); + $this->checkFile($files, 'initramfs-stage31'); + $this->checkFile($files, 'stage32.sqfs'); + $this->checkFile($files, 'vmware.sqfs'); + $this->checkFile($files, 'nvidia_libs.sqfs'); + Render::addTemplate('page-minilinux', array( + 'files' => $files, + 'token' => Session::get('token') + )); + } - // Maybe already in progress? - if (file_exists($localLock)) { - $data = explode(' ', file_get_contents($localLock)); - if (count($data) == 2) { - $pid = (int)$data[0]; - if (posix_kill($pid, 0)) { - $files[] = array( - 'file' => $name, - 'id' => 'id' . $someId++, - 'pid' => $pid, - 'progress' => $data[1] - ); - return true; - } else { + private function checkFile(&$files, $name) + { + static $someId = 0; + $remote = CONFIG_REMOTE_ML . "/${name}.md5"; + $localTarget = CONFIG_HTTP_DIR . "/default/${name}"; + $local = "${localTarget}.md5"; + $localLock = "${localTarget}.lck"; + + // Maybe already in progress? + if (file_exists($localLock)) { + $data = explode(' ', file_get_contents($localLock)); + if (count($data) == 2) { + $pid = (int)$data[0]; + if (posix_kill($pid, 0)) { + $files[] = array( + 'file' => $name, + 'id' => 'id' . $someId++, + 'pid' => $pid, + 'progress' => $data[1] + ); + return true; + } else { + unlink($localLock); + } + } else { unlink($localLock); - } - } else { - unlink($localLock); - } - } + } + } - // Not in progress, normal display - if (!file_exists($local) || filemtime($local) + 300 < time()) { - if (file_exists($localTarget)) { - $existingMd5 = md5_file($localTarget); + // Not in progress, normal display + if (!file_exists($local) || filemtime($local) + 300 < time()) { + if (file_exists($localTarget)) { + $existingMd5 = md5_file($localTarget); + } else { + $existingMd5 = ''; + } + if (file_put_contents($local, $existingMd5) === false) { + @unlink($local); + Message::addWarning('error-write', $local); + } } else { - $existingMd5 = ''; + $existingMd5 = file_get_contents($local); } - if (file_put_contents($local, $existingMd5) === false) { - @unlink($local); - Message::addWarning('error-write', $local); + $existingMd5 = strtolower(preg_replace('/[^0-9a-f]/is', '', $existingMd5)); + $remoteMd5 = Util::download($remote, 3, $code); + $remoteMd5 = strtolower(preg_replace('/[^0-9a-f]/is', '', $remoteMd5)); + if ($code != 200) { + Message::addError('remote-timeout', $remote, $code); + return false; } - } else { - $existingMd5 = file_get_contents($local); - } - $existingMd5 = strtolower(preg_replace('/[^0-9a-f]/is', '', $existingMd5)); - $remoteMd5 = Util::download($remote, 3, $code); - $remoteMd5 = strtolower(preg_replace('/[^0-9a-f]/is', '', $remoteMd5)); - if ($code != 200) { - Message::addError('remote-timeout', $remote, $code); - return false; - } - if ($existingMd5 === $remoteMd5) { - // Up to date + if ($existingMd5 === $remoteMd5) { + // Up to date + $files[] = array( + 'file' => $name, + 'id' => 'id' . $someId++, + ); + return true; + } + // New version on server $files[] = array( - 'file' => $name, - 'id' => 'id' . $someId++, + 'file' => $name, + 'id' => 'id' . $someId++, + 'update' => true ); return true; } - // New version on server - $files[] = array( - 'file' => $name, - 'id' => 'id' . $someId++, - 'update' => true - ); - return true; } - diff --git a/modules/session.inc.php b/modules/session.inc.php index 456ff6b8..aa7719ab 100644 --- a/modules/session.inc.php +++ b/modules/session.inc.php @@ -1,36 +1,43 @@ preprocess(); -} + // Action: "addmodule" (upload new module) + if ($action === 'addmodule') { + if ($step === 0) $step = 'AddModule_Start'; + require_once 'modules/sysconfig/addmodule.inc.php'; + foreach (glob('modules/sysconfig/addmodule_*.inc.php') as $file) { + require_once $file; + } + AddModule_Base::setStep($step); + AddModule_Base::preprocess(); + } -// Action "activate" (set sysconfig as active) -if ($action === 'activate') { - if (!User::hasPermission('superadmin')) { - Message::addError('no-permission'); - Util::redirect('?do=sysconfig'); - } - if (!isset($_REQUEST['file'])) { - Message::addError('missing-file'); - Util::redirect('?do=sysconfig'); + // Action "activate" (set sysconfig as active) + if ($action === 'activate') { + if (!User::hasPermission('superadmin')) { + Message::addError('no-permission'); + Util::redirect('?do=SysConfig'); + } + if (!isset($_REQUEST['file'])) { + Message::addError('missing-file'); + Util::redirect('?do=SysConfig'); + } + $file = preg_replace('/[^a-z0-9\-_\.]/', '', $_REQUEST['file']); + $path = CONFIG_TGZ_LIST_DIR . '/' . $file; + if (!file_exists($path)) { + Message::addError('invalid-file', $file); + Util::redirect('?do=SysConfig'); + } + mkdir(CONFIG_HTTP_DIR . '/default', 0755, true); + $linkname = CONFIG_HTTP_DIR . '/default/config.tgz'; + @unlink($linkname); + if (file_exists($linkname)) Util::traceError('Could not delete old config.tgz link!'); + if (!symlink($path, $linkname)) Util::traceError("Could not symlink to $path at $linkname!"); + Message::addSuccess('config-activated'); + Util::redirect('?do=SysConfig'); + } } - $file = preg_replace('/[^a-z0-9\-_\.]/', '', $_REQUEST['file']); - $path = CONFIG_TGZ_LIST_DIR . '/' . $file; - if (!file_exists($path)) { - Message::addError('invalid-file', $file); - Util::redirect('?do=sysconfig'); - } - mkdir(CONFIG_HTTP_DIR . '/default', 0755, true); - $linkname = CONFIG_HTTP_DIR . '/default/config.tgz'; - @unlink($linkname); - if (file_exists($linkname)) Util::traceError('Could not delete old config.tgz link!'); - if (!symlink($path, $linkname)) Util::traceError("Could not symlink to $path at $linkname!"); - Message::addSuccess('config-activated'); - Util::redirect('?do=sysconfig'); -} -/** - * Render module; called by main script when this module page should render - * its content. - */ -function render_module() -{ - global $action, $handler; - switch ($action) { - case 'addmodule': - $handler->render(); - break; - case 'list': - rr_list_configs(); - break; - default: - Message::addError('invalid-action', $_REQUEST['action']); - break; + /** + * Render module; called by main script when this module page should render + * its content. + */ + protected function doRender() + { + $action = Request::any('action', 'list'); + switch ($action) { + case 'addmodule': + AddModule_Base::render(); + break; + case 'list': + $this->rr_list_configs(); + break; + default: + Message::addError('invalid-action', $action); + break; + } } -} -function rr_list_configs() -{ - if (!User::hasPermission('superadmin')) { - Message::addError('no-permission'); - return; - } - $res = Database::simpleQuery("SELECT title FROM configtgz_module ORDER BY title ASC"); - $modules = array(); - while ($row = $res->fetch(PDO::FETCH_ASSOC)) { - $modules[] = array( - 'module' => $row['title'] - ); + private function rr_list_configs() + { + if (!User::hasPermission('superadmin')) { + Message::addError('no-permission'); + return; + } + $res = Database::simpleQuery("SELECT title FROM configtgz_module ORDER BY title ASC"); + $modules = array(); + while ($row = $res->fetch(PDO::FETCH_ASSOC)) { + $modules[] = array( + 'module' => $row['title'] + ); + } + Render::addTemplate('page-sysconfig-main', array('modules' => $modules, 'token' => Session::get('token'))); } - Render::addTemplate('page-sysconfig-main', array('modules' => $modules, 'token' => Session::get('token'))); -} -function rr_list_remote_configs() -{ - if (!User::hasPermission('superadmin')) { - Message::addError('no-permission'); - return; - } - $data = Util::download(CONFIG_REMOTE_TGZ . '/list.php', 4, $code); - if ($code !== 200) { - Message::addError('remote-timeout', CONFIG_REMOTE_TGZ . '/list.php', $code); - return; - } - $list = json_decode($data, true); - if (!is_array($list)) { - Message::addError('remote-parse-failed', $data); - return; - } - $id = 0; - foreach ($list as &$item) { - $item['id'] = 'download' . (++$id); - } - Render::addTemplate('page-remote-tgz-list', array('files' => $list)); } diff --git a/modules/sysconfig/addmodule.inc.php b/modules/sysconfig/addmodule.inc.php index aca2f762..924f18fa 100644 --- a/modules/sysconfig/addmodule.inc.php +++ b/modules/sysconfig/addmodule.inc.php @@ -7,31 +7,48 @@ abstract class AddModule_Base { + /** + * Holds all the known configuration modules, with title, description, start class for their wizard, etc. + * @var array + */ + protected static $moduleTypes = array(); + + /** + * Holds the instance for the currently executing step + * @var \AddModule_Base + */ + private static $instance = false; + + public static function addModule($id, $startClass, $title, $description, $sortOrder = 0) + { + self::$moduleTypes[] = array( + 'startClass' => $startClass, + 'title' => $title, + 'description' => $description, + 'sortOrder' => $sortOrder + ); + } + /** * * @param type $step * @return \AddModule_Base */ - public static function get($step) + public static function setStep($step) { - switch ($step) { - case 0: // Upload form - return new AddModule_UploadForm(); - case 1: // Handle config module uploading - return new AddModule_ProcessUpload(); - case 2: // ? - return new AddModule_CompressModule(); + if (empty($step) || !class_exists($step) || get_parent_class($step) !== 'AddModule_Base') { + Message::addError('invalid-action', $step); + Util::redirect('?do=SysConfig'); } - Message::addError('invalid-action', $step); - Util::redirect('?do=sysconfig'); + self::$instance = new $step(); } - + protected function tmError() { Message::addError('taskmanager-error'); - Util::redirect('?do=sysconfig'); + Util::redirect('?do=SysConfig'); } - + protected function taskError($status) { if (isset($status['data']['error'])) { @@ -42,7 +59,7 @@ abstract class AddModule_Base $error = 'Unbekannter Taskmanager-Fehler'; // TODO: No text } Message::addError('task-error', $error); - Util::redirect('?do=sysconfig'); + Util::redirect('?do=SysConfig'); } /** @@ -51,146 +68,53 @@ abstract class AddModule_Base * early if something is wrong, or you received post * data etc. */ - public function preprocess() + protected function preprocessInternal() { // void } /** - * Do page rendering + * Do page rendering. */ - public function render() + protected function renderInternal() { // void } - -} - -class AddModule_UploadForm extends AddModule_Base -{ - - public function render() - { - global $nextStep; - Session::set('mod_temp', false); - Render::addDialog('Eigenes Modul hinzufügen', false, 'sysconfig/custom-upload', array('step' => $nextStep)); - } - -} - -/** - * Some file has just been uploaded. Try to store it, then try to unpack/analyze it. - * If this succeeds, we proceed to the next step where we present the user our findings - * and ask what to do with this. - */ -class AddModule_ProcessUpload extends AddModule_Base -{ - private $taskId = false; - - public function preprocess() + public static function preprocess() { - if (!isset($_FILES['modulefile'])) { - Message::addError('missing-file'); - return; + if (self::$instance === false) { + Util::traceError('No step instance yet'); } - if ($_FILES['modulefile']['error'] != UPLOAD_ERR_OK) { - Message::addError('upload-failed', $_FILE['modulefile']['name']); - return; - } - $tempfile = $_FILES['modulefile']['tmp_name'] . '.tmp'; - if (!move_uploaded_file($_FILES['modulefile']['tmp_name'], $tempfile)) { - Message:addError('error-write', $tempfile); - return; - } - $this->taskId = 'tgzmod' . mt_rand() . '-' . microtime(true); - Taskmanager::submit('ListArchive', array( - 'id' => $this->taskId, - 'file' => $tempfile - ), true); - Session::set('mod_temp', $tempfile); + self::$instance->preprocessInternal(); } - public function render() + public static function render() { - $status = Taskmanager::waitComplete($this->taskId); - Taskmanager::release($this->taskId); - $tempfile = Session::get('mod_temp'); - if (!isset($status['statusCode'])) { - unlink($tempfile); - $this->tmError(); - } - if ($status['statusCode'] != TASK_FINISHED) { - unlink($tempfile); - $this->taskError($status); - } - // Sort files for better display - $dirs = array(); - foreach ($status['data']['entries'] as $file) { - if ($file['isdir']) continue; - $dirs[dirname($file['name'])][] = $file; - } - ksort($dirs); - $list = array(); - foreach ($dirs as $dir => $files) { - $list[] = array( - 'name' => $dir, - 'isdir' => true - ); - sort($files); - foreach ($files as $file) { - $file['size'] = Util::readableFileSize($file['size']); - $list[] = $file; - } + if (self::$instance === false) { + Util::traceError('No step instance yet'); } - global $nextStep; - Render::addDialog('Eigenes Modul hinzufügen', false, 'sysconfig/custom-fileselect', array( - 'step' => $nextStep, - 'files' => $list, - )); - Session::save(); + self::$instance->renderInternal(); } } -class AddModule_CompressModule extends AddModule_Base +/** + * Start dialog for adding module. Here the user + * selects which kind of module they want to add. + */ +class AddModule_Start extends AddModule_Base { - - private $taskId = false; - - public function preprocess() + + protected function renderInternal() { - $title = Request::post('title'); - $tempfile = Session::get('mod_temp'); - if (empty($title) || empty($tempfile) || !file_exists($tempfile)) { - Message::addError('empty-field'); - return; + $title = $order = array(); + foreach (AddModule_Base::$moduleTypes as $module) { + $title[] = $module['title']; + $order[] = $module['sortOrder']; } - // Recompress using task manager - $this->taskId = 'tgzmod' . mt_rand() . '-' . microtime(true); - $destFile = CONFIG_TGZ_LIST_DIR . '/modules/mod-' . preg_replace('/[^a-z0-9_\-]+/is', '_', $title) . '-' . microtime(true) . '.tgz'; - Taskmanager::submit('RecompressArchive', array( - 'id' => $this->taskId, - 'inputFiles' => array($tempfile), - 'outputFile' => $destFile - ), true); - $status = Taskmanager::waitComplete($this->taskId); - unlink($tempfile); - if (!isset($status['statusCode'])) { - $this->tmError(); - } - if ($status['statusCode'] != TASK_FINISHED) { - $this->taskError($status); - } - // Seems ok, create entry in DB - $ret = Database::exec("INSERT INTO configtgz_module (title, moduletype, filename, contents) VALUES (:title, 'custom', :file, '')", - array('title' => $title, 'file' => $destFile)); - if ($ret === false) { - unlink($destFile); - Util::traceError("Could not insert module into Database"); - } - Message::addSuccess('module-added'); - Util::redirect('?do=sysconfig'); + array_multisort($order, SORT_ASC, $title, SORT_ASC, self::$moduleTypes); + Render::addDialog('Modul hinzufügen', false, 'sysconfig/start', array('modules' => self::$moduleTypes)); } - + } diff --git a/modules/sysconfig/addmodule_ad.inc.php b/modules/sysconfig/addmodule_ad.inc.php new file mode 100644 index 00000000..abc55df5 --- /dev/null +++ b/modules/sysconfig/addmodule_ad.inc.php @@ -0,0 +1,57 @@ + 'AdModule_CheckConnection', + 'server' => Request::post('server'), + 'searchbase' => Request::post('searchbase'), + 'binddn' => Request::post('binddn'), + 'bindpw' => Request::post('bindpw'), + )); + } + +} + +class AdModule_CheckConnection extends AddModule_Base +{ + + private $taskId = false; + + protected function preprocessInternal() + { + $server = Request::post('server'); + $searchbase = Request::post('searchbase'); + $binddn = Request::post('binddn'); + $bindpw = Request::post('bindpw'); + if (empty($server) || empty($searchbase) || empty($binddn)) { + Message::addError('empty-field'); + AddModule_Base::setStep('AdModule_Start'); + return; + } + $this->taskId = 'ad_' . mt_rand() . '-' . microtime(true); + Taskmanager::submit('LdapSearch', array( + 'id' => $this->taskId, + 'uri' => '' + ), true); + } + + protected function renderInternal() + { + Message::addInfo('missing-file'); + } + +} \ No newline at end of file diff --git a/modules/sysconfig/addmodule_custom.inc.php b/modules/sysconfig/addmodule_custom.inc.php new file mode 100644 index 00000000..ec2c8af7 --- /dev/null +++ b/modules/sysconfig/addmodule_custom.inc.php @@ -0,0 +1,142 @@ + 'CustomModule_ProcessUpload')); + } + +} + +/** + * Some file has just been uploaded. Try to store it, then try to unpack/analyze it. + * If this succeeds, we proceed to the next step where we present the user our findings + * and ask what to do with this. + */ +class CustomModule_ProcessUpload extends AddModule_Base +{ + + private $taskId = false; + + protected function preprocessInternal() + { + if (!isset($_FILES['modulefile'])) { + Message::addError('missing-file'); + Util::redirect('?do=SysConfig'); + } + if ($_FILES['modulefile']['error'] != UPLOAD_ERR_OK) { + Message::addError('upload-failed', $_FILES['modulefile']['name']); + Util::redirect('?do=SysConfig'); + } + $tempfile = $_FILES['modulefile']['tmp_name'] . '.tmp'; + if (!move_uploaded_file($_FILES['modulefile']['tmp_name'], $tempfile)) { + Message:addError('error-write', $tempfile); + Util::redirect('?do=SysConfig'); + } + $this->taskId = 'tgzmod' . mt_rand() . '-' . microtime(true); + Taskmanager::submit('ListArchive', array( + 'id' => $this->taskId, + 'file' => $tempfile + ), true); + Session::set('mod_temp', $tempfile); + } + + protected function renderInternal() + { + $status = Taskmanager::waitComplete($this->taskId); + Taskmanager::release($this->taskId); + $tempfile = Session::get('mod_temp'); + if (!isset($status['statusCode'])) { + unlink($tempfile); + $this->tmError(); + } + if ($status['statusCode'] != TASK_FINISHED) { + unlink($tempfile); + $this->taskError($status); + } + // Sort files for better display + $dirs = array(); + foreach ($status['data']['entries'] as $file) { + if ($file['isdir']) continue; + $dirs[dirname($file['name'])][] = $file; + } + ksort($dirs); + $list = array(); + foreach ($dirs as $dir => $files) { + $list[] = array( + 'name' => $dir, + 'isdir' => true + ); + sort($files); + foreach ($files as $file) { + $file['size'] = Util::readableFileSize($file['size']); + $list[] = $file; + } + } + Render::addDialog('Eigenes Modul hinzufügen', false, 'sysconfig/custom-fileselect', array( + 'step' => 'CustomModule_CompressModule', + 'files' => $list, + )); + Session::save(); + } + +} + +class CustomModule_CompressModule extends AddModule_Base +{ + + private $taskId = false; + + protected function preprocessInternal() + { + $title = Request::post('title'); + $tempfile = Session::get('mod_temp'); + if (empty($title) || empty($tempfile) || !file_exists($tempfile)) { + Message::addError('empty-field'); + return; + } + // Recompress using task manager + $this->taskId = 'tgzmod' . mt_rand() . '-' . microtime(true); + $destFile = CONFIG_TGZ_LIST_DIR . '/modules/mod-' . preg_replace('/[^a-z0-9_\-]+/is', '_', $title) . '-' . microtime(true) . '.tgz'; + Taskmanager::submit('RecompressArchive', array( + 'id' => $this->taskId, + 'inputFiles' => array($tempfile), + 'outputFile' => $destFile + ), true); + $status = Taskmanager::waitComplete($this->taskId); + unlink($tempfile); + if (!isset($status['statusCode'])) { + $this->tmError(); + } + if ($status['statusCode'] != TASK_FINISHED) { + $this->taskError($status); + } + // Seems ok, create entry in DB + $ret = Database::exec("INSERT INTO configtgz_module (title, moduletype, filename, contents) VALUES (:title, 'custom', :file, '')", + array('title' => $title, 'file' => $destFile)); + if ($ret === false) { + unlink($destFile); + Util::traceError("Could not insert module into Database"); + } + Message::addSuccess('module-added'); + Util::redirect('?do=SysConfig'); + } + +} diff --git a/modules/syslog.inc.php b/modules/syslog.inc.php index 62c94edf..2c54b8f4 100644 --- a/modules/syslog.inc.php +++ b/modules/syslog.inc.php @@ -1,64 +1,69 @@ exec(); - while ($row = $res->fetch(PDO::FETCH_ASSOC)) { - $day = date('d.m.Y', $row['dateline']); - // TODO: No output strings in source files! - if ($day === $today) { - $day = 'Heute'; - } elseif ($day === $yesterday) { - $day = 'Gestern'; + protected function doRender() + { + Render::setTitle('Client Log'); + + if (isset($_GET['filter'])) { + $filter = $_GET['filter']; + $not = isset($_GET['not']) ? 'NOT' : ''; + } elseif (isset($_POST['filter'])) { + $filter = $_POST['filter']; + $not = isset($_POST['not']) ? 'NOT' : ''; + Session::set('log_filter', $filter); + Session::set('log_not', $not); + Session::save(); + } else { + $filter = Session::get('log_filter'); + $not = Session::get('log_not') ? 'NOT' : ''; } - $row['date'] = $day . date(' H:i', $row['dateline']); - $lines[] = $row; + if (!empty($filter)) { + $filterList = explode(',', $filter); + $whereClause = array(); + foreach ($filterList as $filterItem) { + $filterItem = preg_replace('/[^a-z0-9_\-]/', '', trim($filterItem)); + if (empty($filterItem) || in_array($filterItem, $whereClause)) continue; + $whereClause[] = "'$filterItem'"; + } + if (!empty($whereClause)) $whereClause = ' WHERE logtypeid ' . $not . ' IN (' . implode(', ', $whereClause) . ')'; + } + if (!isset($whereClause) || empty($whereClause)) $whereClause = ''; + + $today = date('d.m.Y'); + $yesterday = date('d.m.Y', time() - 86400); + $lines = array(); + $paginate = new Paginate("SELECT logid, dateline, logtypeid, clientip, description, extra FROM clientlog $whereClause ORDER BY logid DESC", 50); + $res = $paginate->exec(); + while ($row = $res->fetch(PDO::FETCH_ASSOC)) { + $day = date('d.m.Y', $row['dateline']); + // TODO: No output strings in source files! + if ($day === $today) { + $day = 'Heute'; + } elseif ($day === $yesterday) { + $day = 'Gestern'; + } + $row['date'] = $day . date(' H:i', $row['dateline']); + $lines[] = $row; + } + + $paginate->render('page-syslog', array( + 'token' => Session::get('token'), + 'filter' => $filter, + 'not' => $not, + 'list' => $lines + )); } - - $paginate->render('page-syslog', array( - 'token' => Session::get('token'), - 'filter' => $filter, - 'not' => $not, - 'list' => $lines - )); -} +} diff --git a/style/default.css b/style/default.css index 98ecadd6..c1e5684a 100644 --- a/style/default.css +++ b/style/default.css @@ -50,6 +50,16 @@ body { font-style: italic; } +.slx-ga { + min-width: 7em; +} + +.slx-dialog { + width: 100%; + min-width: 600px; + max-width: 820px; +} + .bootstrap-tagsinput { width: 100%; margin: 0px; diff --git a/templates/dialog-generic.html b/templates/dialog-generic.html index 5e875e8b..929400a5 100644 --- a/templates/dialog-generic.html +++ b/templates/dialog-generic.html @@ -1,5 +1,5 @@
-