<?php
/*
* OIDplus 2.0
* Copyright 2019 Daniel Marschall, ViaThinkSoft
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
class OIDplus {
private static
/*OIDplusPagePlugin[][]*/ $pagePlugins = array();
private static
/*OIDplusAuthPlugin[][]*/ $authPlugins = array();
private static
/*OIDplusObjectTypePlugin[]*/ $objectTypePlugins = array();
private static
/*string[]*/ $enabledObjectTypes = array();
private static
/*string[]*/ $disabledObjectTypes = array();
private static
/*OIDplusDatabasePlugin[]*/ $dbPlugins = array();
private function __construct() {
}
# --- Singleton classes
public static function config() {
static $config = null;
$config = new OIDplusConfig();
}
return $config;
}
public static function gui() {
static $gui = null;
$gui = new OIDplusGui();
}
return $gui;
}
public static function authUtils() {
static $authUtils = null;
$authUtils = new OIDplusAuthUtils();
}
return $authUtils;
}
public static function logger() {
static $logger = null;
$logger = new OIDplusLogger();
}
return $logger;
}
public static function sesHandler() {
static $sesHandler = null;
$sesHandler = new OIDplusSessionHandler(OIDPLUS_SESSION_SECRET);
}
return $sesHandler;
}
# --- Database Plugin
private static function registerDatabasePlugin(OIDplusDatabasePlugin $plugin) {
$name = $plugin->name();
if ($name === false) return false;
self::$dbPlugins[$name] = $plugin;
return true;
}
public static function getDatabasePlugins() {
return self::$dbPlugins;
}
public static function db() {
if (!isset(self::$dbPlugins[OIDPLUS_DATABASE_PLUGIN
])) {
throw new Exception
("Database plugin '".htmlentities(OIDPLUS_DATABASE_PLUGIN
)."' not found. Please check config.inc.php or run <a href=\"setup/\">setup</a> again.");
}
$obj = self::$dbPlugins[OIDPLUS_DATABASE_PLUGIN];
if (!$obj->isConnected()) $obj->connect();
return $obj;
}
# --- Page plugin
private static function registerPagePlugin(OIDplusPagePlugin $plugin) {
$type = $plugin->type();
if ($type === false) return false;
$prio = $plugin->priority();
if ($prio === false) return false;
if (!isset(self::$pagePlugins[$type])) self::$pagePlugins[$type] = array();
self::$pagePlugins[$type][$prio] = $plugin;
return true;
}
public static function getPagePlugins($type) {
if ($type == '*') {
foreach (self::$pagePlugins as $data) {
}
} else {
$res = isset(self::$pagePlugins[$type]) ?
self::$pagePlugins[$type] : array();
}
return $res;
}
# --- Auth plugin
private static function registerAuthPlugin(OIDplusAuthPlugin $plugin) {
self::$authPlugins[] = $plugin;
return true;
}
public static function getAuthPlugins() {
return self::$authPlugins;
}
# --- Object type plugin
private static function registerObjectTypePlugin(OIDplusObjectTypePlugin $plugin) {
self::$objectTypePlugins[] = $plugin;
$ot = $plugin::getObjectTypeClassName();
self::registerObjectType($ot);
return true;
}
private static function registerObjectType($ot) {
$ns = $ot::ns();
if (empty($ns)) die("Attention: Empty NS at $ot\n");
$ns_found = false;
foreach (array_merge(OIDplus
::getEnabledObjectTypes(), OIDplus
::getDisabledObjectTypes()) as $test_ot) {
if ($test_ot::ns() == $ns) {
$ns_found = true;
break;
}
}
if ($ns_found) {
throw new Exception("Attention: Two objectType plugins use the same namespace \"$ns\"!");
}
$init = OIDplus::config()->getValue("objecttypes_initialized");
$enabled = OIDplus::config()->getValue("objecttypes_enabled");
$enabled_ary = array_map('trim', $enabled_ary);
$do_enable = false;
$do_enable = true;
} else {
if (!OIDplus::config()->getValue('registration_done')) {
$do_enable = $ns == 'oid';
} else {
}
}
if ($do_enable) {
self::$enabledObjectTypes[] = $ot;
usort(self::$enabledObjectTypes, function($a, $b) {
$enabled = OIDplus::config()->getValue("objecttypes_enabled");
$enabled_ary = explode(';', $enabled);
if ($idx_a == $idx_b) {
return 0;
}
return ($idx_a > $idx_b) ? +1 : -1;
});
} else {
self::$disabledObjectTypes[] = $ot;
}
// Was never initialized before, so we add it to the list of enabled object types once
if ($do_enable) {
$enabled_ary[] = $ns;
OIDplus
::config()->setValue("objecttypes_enabled", implode(';', $enabled_ary));
}
$init_ary[] = $ns;
OIDplus
::config()->setValue("objecttypes_initialized", implode(';', $init_ary));
}
}
public static function getObjectTypePlugins() {
return self::$objectTypePlugins;
}
public static function getObjectTypePluginsEnabled() {
foreach (self::$objectTypePlugins as $plugin) {
$ot = $plugin::getObjectTypeClassName();
if (in_array($ot, self::$enabledObjectTypes)) $res[] = $plugin;
}
return $res;
}
public static function getObjectTypePluginsDisabled() {
foreach (self::$objectTypePlugins as $plugin) {
$ot = $plugin::getObjectTypeClassName();
if (in_array($ot, self::$disabledObjectTypes)) $res[] = $plugin;
}
return $res;
}
public static function getEnabledObjectTypes() {
return self::$enabledObjectTypes;
}
public static function getDisabledObjectTypes() {
return self::$disabledObjectTypes;
}
# --- Initialization of OIDplus
public static function init($html=true) {
define('OIDPLUS_HTML_OUTPUT', $html);
// Include config file
include_once __DIR__ . '/../config.inc.php';
} else {
if ($html) {
echo 'Error: Setup directory missing.';
} else {
}
} else {
echo 'Error: Setup directory missing!';
}
}
// Auto-fill non-existing config values
if (!defined('OIDPLUS_CONFIG_VERSION')) define('OIDPLUS_CONFIG_VERSION', 0.0);
if (!defined('OIDPLUS_ADMIN_PASSWORD')) define('OIDPLUS_ADMIN_PASSWORD', '');
if (!defined('OIDPLUS_DATABASE_PLUGIN')) define('OIDPLUS_DATABASE_PLUGIN', 'MySQL');
if (!defined('OIDPLUS_MYSQL_HOST')) define('OIDPLUS_MYSQL_HOST', 'localhost');
if (!defined('OIDPLUS_MYSQL_USERNAME')) define('OIDPLUS_MYSQL_USERNAME', 'root');
if (!defined('OIDPLUS_MYSQL_PASSWORD')) define('OIDPLUS_MYSQL_PASSWORD', ''); // base64 encoded
if (!defined('OIDPLUS_MYSQL_DATABASE')) define('OIDPLUS_MYSQL_DATABASE', 'oidplus');
if (!defined('OIDPLUS_TABLENAME_PREFIX')) define('OIDPLUS_TABLENAME_PREFIX', '');
if (!defined('OIDPLUS_SESSION_SECRET')) define('OIDPLUS_SESSION_SECRET', '');
if (!defined('RECAPTCHA_ENABLED')) define('RECAPTCHA_ENABLED', false);
if (!defined('RECAPTCHA_PUBLIC')) define('RECAPTCHA_PUBLIC', '');
if (!defined('RECAPTCHA_PRIVATE')) define('RECAPTCHA_PRIVATE', '');
if (!defined('OIDPLUS_ENFORCE_SSL')) define('OIDPLUS_ENFORCE_SSL', 2 /* Auto */);
// Check version of the config file
if (OIDPLUS_CONFIG_VERSION != 2.0) {
if ($html) {
echo '<h1>Error</h1><p>The information located in <b>includes/config.inc.php</b> is outdated.</p><p>Please run <a href="setup/">setup</a> again.</p>';
} else {
echo 'The information located in includes/config.inc.php is outdated. Please run setup again.';
}
}
// Register database types (highest priority)
$ary = glob(__DIR__
. '/../../plugins/database/'.'*'.'/plugin.inc.php');
foreach ($ary as $a) include $a;
self::registerDatabasePlugin(new $c());
}
}
// Do redirect stuff etc.
define('OIDPLUS_SSL_AVAILABLE', self::isSslAvailable());
// System config settings
OIDplus::config()->prepareConfigKey('objecttypes_initialized', 'List of object type plugins that were initialized once', '', 1, 1);
OIDplus::config()->prepareConfigKey('objecttypes_enabled', 'Enabled object types and their order, separated with a semicolon (please reload the page so that the change is applied)', '', 0, 1);
OIDplus::config()->prepareConfigKey('oidplus_private_key', 'Private key for this system', '', 1, 0);
OIDplus::config()->prepareConfigKey('oidplus_public_key', 'Public key for this system. If you "clone" your system, you must delete this key (e.g. using phpMyAdmin), so that a new one is created.', '', 1, 1);
// Initialize public / private keys
OIDplus::getPkiStatus(true);
// Register plugins
$ary = glob(__DIR__
. '/../../plugins/objectTypes/'.'*'.'/plugin.inc.php');
foreach ($ary as $a) include $a;
$ary = glob(__DIR__
. '/../../plugins/publicPages/'.'*'.'/plugin.inc.php');
foreach ($ary as $a) include $a;
$ary = glob(__DIR__
. '/../../plugins/raPages/'.'*'.'/plugin.inc.php');
foreach ($ary as $a) include $a;
$ary = glob(__DIR__
. '/../../plugins/adminPages/'.'*'.'/plugin.inc.php');
foreach ($ary as $a) include $a;
$ary = glob(__DIR__
. '/../../plugins/auth/'.'*'.'/plugin.inc.php');
foreach ($ary as $a) include $a;
self::registerPagePlugin(new $c());
}
self::registerAuthPlugin(new $c());
}
self::registerObjectTypePlugin(new $c());
}
}
// Initialize page plugins
foreach (OIDplus::getPagePlugins('*') as $plugin) {
$plugin->init($html);
}
}
# --- System URL, System ID, PKI, and other functions
public static function getSystemUrl($relative=false) {
if (!isset($_SERVER["SCRIPT_NAME"])) return false;
$test_dir = dirname($_SERVER['SCRIPT_FILENAME']);
$c = 0;
$c++;
if ($c == 1000) return false;
}
$res = dirname($_SERVER['SCRIPT_NAME'].'xxx');
for ($i=1; $i<=$c; $i++) {
}
if ($res == '/') $res = '';
$res .= '/';
if (!$relative) {
$res = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ?
"https" : "http") . "://$_SERVER[HTTP_HOST]" . $res; // TODO: also add port?
}
return $res;
}
private static $system_id_cache = null;
public static function getSystemId($oid=false) {
if (!is_null(self::$system_id_cache)) {
$out = self::$system_id_cache;
} else {
$out = false;
if (self::getPkiStatus(true)) {
$pubKey = OIDplus::config()->getValue('oidplus_public_key');
if (preg_match('@BEGIN PUBLIC KEY\-+(.+)\-+END PUBLIC KEY@ismU', $pubKey, $m)) {
}
}
self::$system_id_cache = $out;
}
return ($oid ? '1.3.6.1.4.1.37476.30.9.' : '').$out;
}
public static function getPkiStatus($try_generate=true) {
$privKey = OIDplus::config()->getValue('oidplus_private_key');
$pubKey = OIDplus::config()->getValue('oidplus_public_key');
if ($try_generate && !verify_private_public_key($privKey, $pubKey)) {
OIDplus
::logger()->log("A!", "Generating new SystemID using a new key pair");
"digest_alg" => "sha512",
"private_key_bits" => 2048,
"private_key_type" => OPENSSL_KEYTYPE_RSA,
);
// Create the private and public key
// Extract the private key from $res to $privKey
// Extract the public key from $res to $pubKey
// Save the key pair to database
OIDplus::config()->setValue('oidplus_private_key', $privKey);
OIDplus::config()->setValue('oidplus_public_key', $pubKey);
// Log the new system ID
if (preg_match('@BEGIN PUBLIC KEY\-+(.+)\-+END PUBLIC KEY@ismU', $pubKey, $m)) {
OIDplus
::logger()->log("A!", "Your SystemID is now $system_id");
}
}
return verify_private_public_key($privKey, $pubKey);
}
public static function getInstallType() {
if (!file_exists(__DIR__
. '/../../oidplus_version.txt') && !is_dir(__DIR__
. '/../../.svn')) {
return 'unknown';
}
if (file_exists(__DIR__
. '/../../oidplus_version.txt') && is_dir(__DIR__
. '/../../.svn')) {
return 'ambigous';
}
if (is_dir(__DIR__
. '/../../.svn')) {
return 'svn-wc';
}
if (file_exists(__DIR__
. '/../../oidplus_version.txt')) {
return 'svn-snapshot';
}
}
public static function getVersion() {
$svn_version = null;
if (file_exists(__DIR__
. '/../../oidplus_version.txt') && is_dir(__DIR__
. '/../../.svn')) {
return false; // ambigous
}
if (is_dir(__DIR__
. '/../../.svn')) {
// Try to find out the SVN version using the shell
$svn_version = 'svn-'.$match[0];
}
// If that failed, try to get the version via SQLite3
$db = new SQLite3(__DIR__ . '/../../.svn/wc.db');
$results = $db->query('SELECT MIN(revision) AS rev FROM NODES_BASE');
while ($row = $results->fetchArray()) {
$svn_version = 'svn-'.$row['rev'];
}
}
}
if (file_exists(__DIR__
. '/../../oidplus_version.txt')) {
return false; // File has unknown format
$svn_version = 'svn-'.$m[1];
}
return $svn_version;
}
private static function isSslAvailable() {
$timeout = 2;
$already_ssl = isset($_SERVER['HTTPS']) && ($_SERVER['HTTPS'] == "on");
$ssl_port = 443;
$cookie_path = OIDplus::getSystemUrl(true);
if (empty($cookie_path)) $cookie_path = '/';
if (OIDPLUS_ENFORCE_SSL == 0) {
// No SSL available
return $already_ssl;
}
if (OIDPLUS_ENFORCE_SSL == 1) {
// Force SSL
if ($already_ssl) {
return true;
} else {
$location = 'https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
header('Location:'.$location);
die('Redirect to HTTPS');
return true;
}
}
if (OIDPLUS_ENFORCE_SSL == 2) {
// Automatic SSL detection
if ($already_ssl) {
// we are already on HTTPS
setcookie('SSL_CHECK', '1', 0, $cookie_path, '', false, true);
return true;
} else {
if (isset($_COOKIE['SSL_CHECK'])) {
// We already had the HTTPS detection done before.
if ($_COOKIE['SSL_CHECK']) {
// HTTPS was detected before, but we are HTTP. Redirect now
$location = 'https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
header('Location:'.$location);
die('Redirect to HTTPS');
return true;
} else {
// No HTTPS available. Do nothing.
return false;
}
} else {
// This is our first check (or the browser didn't accept the SSL_CHECK cookie)
if (@fsockopen($_SERVER['HTTP_HOST'], $ssl_port, $errno, $errstr, $timeout)) {
// HTTPS detected. Redirect now, and remember that we had detected HTTPS
setcookie('SSL_CHECK', '1', 0, $cookie_path, '', false, true);
$location = 'https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
header('Location:'.$location);
die('Redirect to HTTPS');
return true;
} else {
// No HTTPS detected. Do nothing, and next time, don't try to detect HTTPS again.
setcookie('SSL_CHECK', '0', 0, $cookie_path, '', false, true);
return false;
}
}
}
}
}
}