diff --git a/.htaccess b/.htaccess
index a7528a3..3db7ac6 100644
--- a/.htaccess
+++ b/.htaccess
@@ -1,8 +1,5 @@
php_flag display_errors on
Options -Indexes
-ErrorDocument 404 /s/404
-
-RewriteEngine on
-RewriteRule ^s/(.*)?$ index.php?s=$1&$2 [L,QSA]
-
+RewriteEngine On
+RewriteRule ^api/(.*)?$ index.php?api=$1&$2 [L,QSA]
diff --git a/core/Api/ExecuteSelect.class.php b/core/Api/ExecuteSelect.class.php
index 99d468b..b54f4fc 100644
--- a/core/Api/ExecuteSelect.class.php
+++ b/core/Api/ExecuteSelect.class.php
@@ -16,21 +16,19 @@ class ExecuteSelect extends Request {
$this->variableParamCount = true;
}
- public function getDescription() { return 'Führt ein SELECT Statement aus.'; }
- public function getSection() { return "Internal"; }
-
- public function execute($aValues = array()) {
- if(!parent::execute($aValues)) {
+ public function execute($values = array()) {
+ if(!parent::execute($values)) {
return false;
}
+ $sql = $this->user->getSQL();
$this->success = false;
$this->result['rows'] = array();
if(count($this->params) === 1) {
- $res = $this->user->getSQL()->query($this->getParam('query'));
+ $res = $sql->query($this->getParam('query'));
if(!$res) {
- $this->lastError = 'Database Error: query() failed with ' . $this->user->getSQL()->getLastError();
+ $this->lastError = 'Database Error: query() failed with ' . $sql->getLastError();
return false;
}
@@ -77,7 +75,7 @@ class ExecuteSelect extends Request {
$tmp = array();
foreach($aSqlParams as $key => $value) $tmp[$key] = &$aSqlParams[$key];
- if($stmt = $this->user->getSQL()->connection->prepare($this->getParam('query'))) {
+ if($stmt = $sql->connection->prepare($this->getParam('query'))) {
if(call_user_func_array(array($stmt, "bind_param"), $tmp))
{
if($stmt->execute()) {
@@ -89,18 +87,18 @@ class ExecuteSelect extends Request {
$res->close();
$this->success = true;
} else {
- $this->lastError = 'Database Error: execute() failed with ' . $this->user->getSQL()->getLastError();
+ $this->lastError = 'Database Error: execute() failed with ' . $sql->getLastError();
}
} else {
- $this->lastError = 'Database Error: get_result() failed with ' . $this->user->getSQL()->getLastError();
+ $this->lastError = 'Database Error: get_result() failed with ' . $sql->getLastError();
}
} else {
- $this->lastError = 'Database Error: bind_param() failed with ' . $this->user->getSQL()->getLastError();
+ $this->lastError = 'Database Error: bind_param() failed with ' . $sql->getLastError();
}
$stmt->close();
} else {
- $this->lastError = 'Database Error: prepare failed with() ' . $this->user->getSQL()->getLastError();
+ $this->lastError = 'Database Error: prepare failed with() ' . $sql->getLastError();
}
}
diff --git a/core/Api/ExecuteStatement.class.php b/core/Api/ExecuteStatement.class.php
index 309af75..7162fbc 100644
--- a/core/Api/ExecuteStatement.class.php
+++ b/core/Api/ExecuteStatement.class.php
@@ -16,8 +16,8 @@ class ExecuteStatement extends Request {
$this->variableParamCount = true;
}
- public function execute($aValues = array()) {
- if(!parent::execute($aValues)) {
+ public function execute($values = array()) {
+ if(!parent::execute($values)) {
return false;
}
diff --git a/core/Api/GetLanguages.class.php b/core/Api/GetLanguages.class.php
new file mode 100644
index 0000000..aec1f86
--- /dev/null
+++ b/core/Api/GetLanguages.class.php
@@ -0,0 +1,36 @@
+user);
+ $this->success = $request->execute(array('query' => $query));
+ $this->lastError = $request->getLastError();
+
+ if($this->success) {
+ $this->result['languages'] = array();
+ if(count($request->getResult()['rows']) === 0) {
+ $this->lastError = L("No languages found");
+ } else {
+ foreach($request->getResult()['rows'] as $row) {
+ $this->result['languages'][$row['uid']] = $row;
+ }
+ }
+ }
+
+ return $this->success;
+ }
+};
+
+?>
diff --git a/core/Api/Login.class.php b/core/Api/Login.class.php
new file mode 100644
index 0000000..281f5cf
--- /dev/null
+++ b/core/Api/Login.class.php
@@ -0,0 +1,75 @@
+ new StringType('username', 32),
+ 'password' => new StringType('password'),
+ ));
+ $this->forbidMethod("GET");
+ }
+
+ private function wrongCredentials() {
+ $runtime = microtime(true) - $this->startedAt;
+ $sleepTime = round(3e6 - $runtime);
+ if($sleepTime > 0) usleep($sleepTime);
+ return $this->createError(L('Wrong username or password'));
+ }
+
+ public function execute($values = array()) {
+ if(!parent::execute($values)) {
+ return false;
+ }
+
+ if($this->user->isLoggedIn()) {
+ $this->lastError = L('You are already logged in');
+ $this->success = true;
+ return true;
+ }
+
+ $this->startedAt = microtime(true);
+ $this->success = false;
+ $username = $this->getParam('username');
+ $password = $this->getParam('password');
+
+ $query = 'SELECT User.uid, User.password, User.salt FROM User WHERE User.name=?';
+ $request = new ExecuteSelect($this->user);
+ $this->success = $request->execute(array('query' => $query, $username));
+ $this->lastError = $request->getLastError();
+
+ if($this->success) {
+ $this->success = false;
+ if(count($request->getResult()['rows']) === 0) {
+ return $this->wrongCredentials();
+ $this->lastError = L('Wrong username or password');
+ } else {
+ $row = $request->getResult()['rows'][0];
+ $salt = $row['salt'];
+ $uid = $row['uid'];
+ $hash = hash('sha256', $password . $salt);
+ if($hash === $row['password']) {
+ if(!($this->success = $this->user->createSession($uid))) {
+ return $this->createError("Error creating Session");
+ } else {
+ $this->result['logoutIn'] = $this->user->getSession()->getExpiresSeconds();
+ }
+ }
+ else {
+ return $this->wrongCredentials();
+ }
+ }
+ }
+
+ return $this->success;
+ }
+};
+
+?>
diff --git a/core/Api/Logout.class.php b/core/Api/Logout.class.php
new file mode 100644
index 0000000..4fb6149
--- /dev/null
+++ b/core/Api/Logout.class.php
@@ -0,0 +1,24 @@
+loginRequired = true;
+ $this->apiKeyAllowed = false;
+ }
+
+ public function execute($values = array()) {
+ if(!parent::execute($values)) {
+ return false;
+ }
+
+ $this->success = true;
+ $this->user->logout();
+ return true;
+ }
+};
+
+?>
diff --git a/core/Api/Request.class.php b/core/Api/Request.class.php
index dd54166..cb82284 100644
--- a/core/Api/Request.class.php
+++ b/core/Api/Request.class.php
@@ -53,9 +53,9 @@ class Request {
return "($str)";
}
- public function parseParams($aValues) {
+ public function parseParams($values) {
foreach($this->params as $name => $param) {
- $value = (isset($aValues[$name]) ? $aValues[$name] : NULL);
+ $value = (isset($values[$name]) ? $values[$name] : NULL);
if(!$param->optional && is_null($value)) {
$this->lastError = 'Missing parameter: ' . $name;
@@ -73,8 +73,8 @@ class Request {
return true;
}
- public function parseVariableParams($aValues) {
- foreach($aValues as $name => $value) {
+ public function parseVariableParams($values) {
+ foreach($values as $name => $value) {
if(isset($this->params[$name])) continue;
$type = Parameter\Parameter::parseType($value);
$param = new Parameter\Parameter($name, $type, true);
@@ -83,7 +83,7 @@ class Request {
}
}
- public function execute($aValues = array()) {
+ public function execute($values = array()) {
$this->params = $this->aDefaultParams;
$this->success = false;
$this->result = array();
@@ -94,10 +94,10 @@ class Request {
}
if($this->externCall) {
- $aValues = $_REQUEST;
+ $values = $_REQUEST;
if($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_SERVER["CONTENT_TYPE"]) && in_array("application/json", explode(";", $_SERVER["CONTENT_TYPE"]))) {
$jsonData = json_decode(file_get_contents('php://input'), true);
- $aValues = array_merge($aValues, $jsonData);
+ $values = array_merge($values, $jsonData);
}
}
@@ -121,8 +121,8 @@ class Request {
if($this->loginRequired) {
$authorized = false;
- if(isset($aValues['api_key']) && $this->apiKeyAllowed) {
- $apiKey = $aValues['api_key'];
+ if(isset($values['api_key']) && $this->apiKeyAllowed) {
+ $apiKey = $values['api_key'];
$authorized = $this->user->authorize($apiKey);
}
@@ -133,11 +133,11 @@ class Request {
}
}
- if(!$this->parseParams($aValues))
+ if(!$this->parseParams($values))
return false;
if($this->variableParamCount)
- $this->parseVariableParams($aValues);
+ $this->parseVariableParams($values);
if(!$this->user->getSQL()->isConnected()) {
$this->lastError = $this->user->getSQL()->getLastError();
diff --git a/core/Api/SetLanguage.php b/core/Api/SetLanguage.php
new file mode 100644
index 0000000..4c59911
--- /dev/null
+++ b/core/Api/SetLanguage.php
@@ -0,0 +1,75 @@
+ new Parameter('langId', Parameter::TYPE_INT, true, NULL),
+ 'langCode' => new StringType('langCode', 5, true, NULL),
+ ));
+ }
+
+ private function checkLanguage() {
+ $langId = $this->getParam("langId");
+ $langCode = $this->getParam("langCode");
+
+ if(is_null($langId) && is_null($langCode)) {
+ return $this->createError(L("Either langId or langCode must be given"));
+ }
+
+ $query = "SELECT uid, code, name FROM Language WHERE uid=? OR code=?";
+ $request = new ExecuteSelect($this->user);
+ $this->success = $request->execute(array("query" => $query, $langId, $langCode));
+ $this->lastError = $request->getLastError();
+
+ if($this->success) {
+ if(count($request->getResult()['rows']) == 0) {
+ return $this->createError(L("This Language does not exist"));
+ } else {
+ $row = $request->getResult()['rows'][0];
+ $this->language = \Objects\Language::newInstance($row['uid'], $row['code'], $row['name']);
+ if(!$this->language) {
+ return $this->createError(L("Error while loading language"));
+ }
+ }
+ }
+
+ return $this->success;
+ }
+
+ private function updateLanguage() {
+ $languageId = $this->language->getId();
+ $userId = $this->user->getId();
+
+ $query = "UPDATE User SET uidLanguage = ? WHERE uid = ?";
+ $request = new ExecuteStatement($this->user);
+ $this->success = $request->execute(array("query" => $query, $languageId, $userId));
+ $this->lastError = $request->getLastError();
+ return $this->success;
+ }
+
+ public function execute($values = array()) {
+ if(!parent::execute($values)) {
+ return false;
+ }
+
+ if(!$this->checkLanguage())
+ return false;
+
+ if($this->user->isLoggedIn()) {
+ $this->updateLanguage();
+ }
+
+ $this->user->setLangauge($this->language);
+ return $this->success;
+ }
+};
+
+?>
diff --git a/core/Configuration/database.sql b/core/Configuration/database.sql
index 7833a24..3b4ee9d 100644
--- a/core/Configuration/database.sql
+++ b/core/Configuration/database.sql
@@ -30,7 +30,7 @@ CREATE TABLE IF NOT EXISTS UserGroup (
UNIQUE(`uid`, `gid`)
);
-CREATE TABLE Session IF NOT EXISTS (
+CREATE TABLE IF NOT EXISTS Session (
`uid` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,
`expires` timestamp NOT NULL,
`uidUser` int(11) NOT NULL,
@@ -52,8 +52,13 @@ CREATE TABLE IF NOT EXISTS Language (
`name` VARCHAR(32) UNIQUE NOT NULL
);
+INSERT INTO Language (`uid`, `code`, `name`) VALUES
+ (1, 'en_US', 'American English'),
+ (2, 'de_DE', 'Deutsch Standard')
+ ON DUPLICATE KEY UPDATE name=name;
+
CREATE TABLE IF NOT EXISTS ExternalSiteCache (
`url` VARCHAR(256) PRIMARY KEY,
`data` TEXT NOT NULL,
- `expires` TIMESTAMP DEFAULT NULL
+ `expires` DATETIME DEFAULT NULL
);
diff --git a/core/Documents/Admin.class.php b/core/Documents/Admin.class.php
new file mode 100644
index 0000000..14b0425
--- /dev/null
+++ b/core/Documents/Admin.class.php
@@ -0,0 +1,70 @@
+databseRequired = false;
+ }
+ }
+}
+
+namespace Documents\Admin {
+
+ class Head extends \Elements\Head {
+
+ public function __construct($document) {
+ parent::__construct($document);
+ }
+
+ protected function initSources() {
+ $this->loadJQuery();
+ $this->loadBootstrap();
+ $this->loadFontawesome();
+ $this->addJS(\Elements\Script::CORE);
+ $this->addCSS(\Elements\Link::CORE);
+ $this->addJS(\Elements\Script::ADMIN);
+ $this->addCSS(\Elements\Link::ADMIN);
+ }
+
+ protected function initMetas() {
+ return array(
+ array('name' => 'viewport', 'content' => 'width=device-width, initial-scale=1.0'),
+ array('name' => 'format-detection', 'content' => 'telephone=yes'),
+ array('charset' => 'utf-8'),
+ array("http-equiv" => 'expires', 'content' => '0'),
+ array("name" => 'robots', 'content' => 'noarchive'),
+ );
+ }
+
+ protected function initRawFields() {
+ return array();
+ }
+
+ protected function initTitle() {
+ return "WebBase - Administration";
+ }
+ }
+
+ class Body extends \Elements\Body {
+
+ public function __construct($document) {
+ parent::__construct($document);
+ }
+
+ public function getCode() {
+ $html = parent::getCode();
+
+ $document = $this->getDocument();
+ if(!$document->getUser()->isLoggedIn()) {
+ $html .= new \Views\Login($document);
+ } else {
+ $html .= "You are logged in :]";
+ }
+
+ return $html;
+ }
+ }
+}
+
+?>
diff --git a/core/Documents/Install.class.php b/core/Documents/Install.class.php
index 7aa122a..77a2f3e 100644
--- a/core/Documents/Install.class.php
+++ b/core/Documents/Install.class.php
@@ -97,24 +97,23 @@ namespace Documents\Install {
return self::DATABASE_CONFIGURATION;
}
- $query = "SELECT * FROM User";
- $sql = $user->getSQL();
- if(!is_null($sql) && $sql->isConnected()) {
- $res = $sql->query($query);
- if($res) {
- if($res->num_rows === 0) {
- $step = self::CREATE_USER;
- } else {
- $step = self::ADD_MAIL_SERVICE;
- }
+ $request = new \Api\ExecuteSelect($user);
+ $success = $request->execute(array("query" => "SELECT COUNT(*) AS count FROM User"));
+ $this->errorString = $request->getLastError();
+
+ if($success) {
+ if($request->getResult()['rows'][0]["count"] > 0) {
+ $step = self::ADD_MAIL_SERVICE;
+ } else {
+ return self::CREATE_USER;
}
} else {
- $step = self::DATABASE_CONFIGURATION;
+ return self::DATABASE_CONFIGURATION;
}
- if($step == self::ADD_MAIL_SERVICE && $config->isFilePresent("Mail")) {
+ if($step === self::ADD_MAIL_SERVICE && $config->isFilePresent("Mail")) {
$step = self::FINISH_INSTALLATION;
- if(!$config->isFilePresent("JWT") && $config->create("JWT", generateRandomString(32))) {
+ if(!$config->isFilePresent("JWT") && !$config->create("JWT", generateRandomString(32))) {
$this->errorString = "Unable to create jwt file";
}
}
@@ -532,7 +531,8 @@ namespace Documents\Install {
array("title" => "Username", "name" => "username", "type" => "text", "required" => true),
array("title" => "Password", "name" => "password", "type" => "password", "required" => true),
array("title" => "Confirm Password", "name" => "confirmPassword", "type" => "password", "required" => true),
- )
+ ),
+ "previousButton" => true
),
self::ADD_MAIL_SERVICE => array(
"title" => "Optional: Add Mail Service",
@@ -550,7 +550,8 @@ namespace Documents\Install {
)
)),
),
- "skip" => true
+ "skip" => true,
+ "previousButton" => true
),
self::FINISH_INSTALLATION => array(
"title" => "Finish Installation",
@@ -562,8 +563,8 @@ namespace Documents\Install {
return "";
}
- $prevDisabled = ($this->currentStep <= self::DATABASE_CONFIGURATION);
$currentView = $views[$this->currentStep];
+ $prevDisabled = !isset($currentView["previousButton"]) || !$currentView["previousButton"];
$spinnerIcon = $this->createIcon("spinner");
$title = $currentView["title"];
@@ -695,6 +696,7 @@ namespace Documents\Install {
$progressSidebar = $this->createProgressSidebar();
$progressMainview = $this->createProgessMainview();
$errorStyle = ($this->errorString ? '' : ' style="display:none"');
+ $errorClass = ($this->errorString ? ' alert-danger' : '');
$html .= "
@@ -718,7 +720,7 @@ namespace Documents\Install {
$progressMainview
-
$this->errorString
+
$this->errorString
diff --git a/core/Driver/SQL.class.php b/core/Driver/SQL.class.php
index d5c3e89..80a1bf1 100644
--- a/core/Driver/SQL.class.php
+++ b/core/Driver/SQL.class.php
@@ -97,6 +97,15 @@ class SQL {
return false;
}
+ while (($success = $this->connection->next_result())) {
+ if (!$this->connection->more_results()) break;
+ }
+
+ if(!$success) {
+ $this->lastError = mysqli_error($this->connection);
+ return false;
+ }
+
return true;
}
diff --git a/core/Elements/Link.class.php b/core/Elements/Link.class.php
index 18e9176..5424d05 100644
--- a/core/Elements/Link.class.php
+++ b/core/Elements/Link.class.php
@@ -17,7 +17,7 @@ class Link extends Source {
// const HIGHLIGHT = '/css/highlight.css';
// const HIGHLIGHT_THEME = '/css/theme.css';
const CORE = "/css/style.css";
- // const ADMIN = "/css/admin.css";
+ const ADMIN = "/css/admin.css";
// const HOME = "/css/home.css";
// const REVEALJS = "/css/reveal.css";
// const REVEALJS_THEME_MOON = "/css/reveal_moon.css";
diff --git a/core/Elements/Script.class.php b/core/Elements/Script.class.php
index 022351c..f8a2592 100644
--- a/core/Elements/Script.class.php
+++ b/core/Elements/Script.class.php
@@ -8,7 +8,7 @@ class Script extends Source {
const CORE = "/js/script.js";
// const HOME = "/js/home.js";
- // const ADMIN = "/js/admin.js";
+ const ADMIN = "/js/admin.js";
// const SORTTABLE = "/js/sorttable.js";
const JQUERY = "/js/jquery.min.js";
// const JQUERY_UI = "/js/jquery-ui.js";
diff --git a/core/Objects/Language.class.php b/core/Objects/Language.class.php
index c20e380..928f3b5 100644
--- a/core/Objects/Language.class.php
+++ b/core/Objects/Language.class.php
@@ -1,133 +1,135 @@
languageId = $languageId;
- $this->langCode = $langCode;
- $this->langName = $langName;
- $this->entries = array();
- $this->modules = array();
- }
-
- public function getId() { return $this->languageId; }
- public function getCode() { return $this->langCode; }
- public function getShortCode() { return substr($this->langCode, 0, 2); }
- public function getName() { return $this->langName; }
- public function getIconPath() { return "/img/icons/lang/$this->langCode.gif"; }
- public function getEntries() { return $this->entries; }
- public function getModules() { return $this->modules; }
-
- public function loadModule($module) {
- if(!is_object($module))
- $module = new $module;
-
- $aModuleEntries = $module->getEntries($this->langCode);
- $this->entries = array_merge($this->entries, $aModuleEntries);
- $this->modules[] = $module;
- }
-
- public function translate($key) {
- if(isset($this->entries[$key]))
- return $this->entries[$key];
-
- return $key;
- }
-
- public function sendCookie() {
- setcookie('lang', $this->langCode, 0, "/", "");
- }
-
- public function jsonSerialize() {
- return array(
- 'uid' => $this->languageId,
- 'code' => $this->langCode,
- 'name' => $this->langName,
- );
- }
-
- public static function newInstance($languageId, $langCode, $langName) {
-
- if(!preg_match(Language::LANG_CODE_PATTERN, $langCode)) {
- return false;
+ public function __construct($languageId, $langCode, $langName) {
+ $this->languageId = $languageId;
+ $this->langCode = $langCode;
+ $this->langName = $langName;
+ $this->entries = array();
+ $this->modules = array();
}
- // TODO: include dynamically wanted Language
- return new Language($languageId, $langCode, $langName);
+ public function getId() { return $this->languageId; }
+ public function getCode() { return $this->langCode; }
+ public function getShortCode() { return substr($this->langCode, 0, 2); }
+ public function getName() { return $this->langName; }
+ public function getIconPath() { return "/img/icons/lang/$this->langCode.gif"; }
+ public function getEntries() { return $this->entries; }
+ public function getModules() { return $this->modules; }
- // $className = $langCode
- // return new $className($languageId, $langCode);
- }
+ public function loadModule($module) {
+ if(!is_object($module))
+ $module = new $module;
- public function load() {
- global $LANGUAGE;
- $LANGUAGE = $this;
- }
+ $aModuleEntries = $module->getEntries($this->langCode);
+ $this->entries = array_merge($this->entries, $aModuleEntries);
+ $this->modules[] = $module;
+ }
- public static function DEFAULT_LANGUAGE() {
- if(isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
- $acceptLanguage = $_SERVER['HTTP_ACCEPT_LANGUAGE'];
- $aSplit = explode(',',$acceptLanguage);
- foreach($aSplit as $code) {
- if(strlen($code) == 2) {
- $code = $code . '_' . strtoupper($code);
- }
+ public function translate($key) {
+ if(isset($this->entries[$key]))
+ return $this->entries[$key];
- $code = str_replace("-", "_", $code);
- if(strlen($code) != 5)
- continue;
+ return $key;
+ }
- $lang = Language::newInstance(0, $code, "");
- if($lang)
- return $lang;
+ public function sendCookie() {
+ setcookie('lang', $this->langCode, 0, "/", "");
+ }
+
+ public function jsonSerialize() {
+ return array(
+ 'uid' => $this->languageId,
+ 'code' => $this->langCode,
+ 'name' => $this->langName,
+ );
+ }
+
+ public static function newInstance($languageId, $langCode, $langName) {
+
+ if(!preg_match(Language::LANG_CODE_PATTERN, $langCode)) {
+ return false;
}
+
+ // TODO: include dynamically wanted Language
+ return new Language($languageId, $langCode, $langName);
+
+ // $className = $langCode
+ // return new $className($languageId, $langCode);
}
- return Language::newInstance(1, "en_US", "American English");
+ public function load() {
+ global $LANGUAGE;
+ $LANGUAGE = $this;
+ }
+
+ public static function DEFAULT_LANGUAGE() {
+ if(isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
+ $acceptLanguage = $_SERVER['HTTP_ACCEPT_LANGUAGE'];
+ $aSplit = explode(',',$acceptLanguage);
+ foreach($aSplit as $code) {
+ if(strlen($code) == 2) {
+ $code = $code . '_' . strtoupper($code);
+ }
+
+ $code = str_replace("-", "_", $code);
+ if(strlen($code) != 5)
+ continue;
+
+ $lang = Language::newInstance(0, $code, "");
+ if($lang)
+ return $lang;
+ }
+ }
+
+ return Language::newInstance(1, "en_US", "American English");
+ }
+ };
+}
+
+namespace {
+ function L($key) {
+ if(!array_key_exists('LANGUAGE', $GLOBALS))
+ return $key;
+
+ global $LANGUAGE;
+ return $LANGUAGE->translate($key);
}
-};
-function L($key) {
- if(!array_key_exists('LANGUAGE', $GLOBALS))
- return $key;
+ function LANG_NAME() {
+ if(!array_key_exists('LANGUAGE', $GLOBALS))
+ return "LANG_NAME";
- global $LANGUAGE;
- return $LANGUAGE->translate($key);
+ global $LANGUAGE;
+ return $LANGUAGE->getName();
+ }
+
+ function LANG_CODE() {
+ if(!array_key_exists('LANGUAGE', $GLOBALS))
+ return "LANG_CODE";
+
+ global $LANGUAGE;
+ return $LANGUAGE->getCode();
+ }
+
+ function SHORT_LANG_CODE() {
+ if(!array_key_exists('LANGUAGE', $GLOBALS))
+ return "SHORT_LANG_CODE";
+
+ global $LANGUAGE;
+ return $LANGUAGE->getShortCode();
+ }
}
-
-function LANG_NAME() {
- if(!array_key_exists('LANGUAGE', $GLOBALS))
- return "LANG_NAME";
-
- global $LANGUAGE;
- return $LANGUAGE->getName();
-}
-
-function LANG_CODE() {
- if(!array_key_exists('LANGUAGE', $GLOBALS))
- return "LANG_CODE";
-
- global $LANGUAGE;
- return $LANGUAGE->getCode();
-}
-
-function SHORT_LANG_CODE() {
- if(!array_key_exists('LANGUAGE', $GLOBALS))
- return "SHORT_LANG_CODE";
-
- global $LANGUAGE;
- return $LANGUAGE->getShortCode();
-}
-
?>
diff --git a/core/Objects/Session.class.php b/core/Objects/Session.class.php
index 2441146..2de2af8 100644
--- a/core/Objects/Session.class.php
+++ b/core/Objects/Session.class.php
@@ -19,18 +19,27 @@ class Session extends ApiObject {
}
private function updateMetaData() {
- $userAgent = get_browser($_SERVER['HTTP_USER_AGENT'], true);
$this->expires = time() + Session::DURATION * 60;
$this->ipAddress = $_SERVER['REMOTE_ADDR'];
- $this->os = $userAgent['platform'];
- $this->browser = $userAgent['parent'];
+ try {
+ $userAgent = @get_browser($_SERVER['HTTP_USER_AGENT'], true);
+ $this->os = $userAgent['platform'] ?? "Unknown";
+ $this->browser = $userAgent['parent'] ?? "Unknown";
+ } catch(\Exception $ex) {
+ $this->os = "Unknown";
+ $this->browser = "Unknown";
+ }
}
public function sendCookie() {
$this->updateMetaData();
- $token = array('userId' => $this->user->getId(), 'sessionId' => $this->sessionId);
- $sessionCookie = JWT::encode($token, getJwtKey());
- setcookie('session', $sessionCookie, $this->expires, "/", "", true);
+ $jwt = $this->user->getConfiguration()->getJwt();
+ if($jwt) {
+ $token = array('userId' => $this->user->getId(), 'sessionId' => $this->sessionId);
+ $sessionCookie = \External\JWT::encode($token, $jwt->getKey());
+ $secure = strcmp(getProtocol(), "https") === 0;
+ setcookie('session', $sessionCookie, $this->expires, "/", "", $secure);
+ }
}
public function getExpiresTime() {
@@ -56,7 +65,7 @@ class Session extends ApiObject {
$this->updateMetaData();
$query = 'INSERT INTO Session (expires, uidUser, ipAddress, os, browser)
VALUES (DATE_ADD(NOW(), INTERVAL ? MINUTE),?,?,?,?)';
- $request = new CExecuteStatement($this->user);
+ $request = new \Api\ExecuteStatement($this->user);
$success = $request->execute(array(
'query' => $query,
@@ -77,7 +86,7 @@ class Session extends ApiObject {
public function destroy() {
$query = 'DELETE FROM Session WHERE Session.uid=? OR Session.expires<=NOW()';
- $request = new CExecuteStatement($this->user);
+ $request = new \Api\ExecuteStatement($this->user);
$success = $request->execute(array('query' => $query, $this->sessionId));
return $success;
}
@@ -88,7 +97,7 @@ class Session extends ApiObject {
SET Session.expires=DATE_ADD(NOW(), INTERVAL ? MINUTE), Session.ipAddress=?,
Session.os=?, Session.browser=?
WHERE Session.uid=?';
- $request = new CExecuteStatement($this->user);
+ $request = new \Api\ExecuteStatement($this->user);
$success = $request->execute(array(
'query' => $query,
Session::DURATION,
diff --git a/core/Objects/User.class.php b/core/Objects/User.class.php
index ea577b6..e3ddc79 100644
--- a/core/Objects/User.class.php
+++ b/core/Objects/User.class.php
@@ -80,8 +80,10 @@ class User extends ApiObject {
}
public function updateLanguage($lang) {
- $request = new CSetLanguage($this);
- return $request->execute(array("langCode" => $lang));
+ if($this->sql) {
+ $request = new \Api\SetLanguage($this);
+ return $request->execute(array("langCode" => $lang));
+ }
}
public function sendCookies() {
@@ -93,12 +95,12 @@ class User extends ApiObject {
}
public function readData($userId, $sessionId, $sessionUpdate = true) {
- $query = 'SELECT User.name as userName, Language.uid as langId, Language.code as langCode
+ $query = 'SELECT User.name as userName, Language.uid as langId, Language.code as langCode, Language.name as langName
FROM User
INNER JOIN Session ON User.uid=Session.uidUser
LEFT JOIN Language ON User.uidLanguage=Language.uid
WHERE User.uid=? AND Session.uid=? AND Session.expires>now()';
- $request = new CExecuteSelect($this);
+ $request = new \Api\ExecuteSelect($this);
$success = $request->execute(array('query' => $query, $userId, $sessionId));
if($success) {
@@ -108,12 +110,12 @@ class User extends ApiObject {
$row = $request->getResult()['rows'][0];
$this->username = $row['userName'];
$this->uid = $userId;
- $this->session = new CSession($this, $sessionId);
+ $this->session = new Session($this, $sessionId);
if($sessionUpdate) $this->session->update();
$this->loggedIn = true;
if(!is_null($row['langId'])) {
- $this->setLangauge(CLanguage::newInstance($row['langId'], $row['langCode']));
+ $this->setLangauge(Language::newInstance($row['langId'], $row['langCode'], $row['langName']));
}
}
}
@@ -128,7 +130,7 @@ class User extends ApiObject {
&& ($jwt = $this->configuration->getJWT())) {
try {
$token = $_COOKIE['session'];
- $decoded = (array)External\JWT::decode($token, $jwt->getKey());
+ $decoded = (array)\External\JWT::decode($token, $jwt->getKey());
if(!is_null($decoded)) {
$userId = (isset($decoded['userId']) ? $decoded['userId'] : NULL);
$sessionId = (isset($decoded['sessionId']) ? $decoded['sessionId'] : NULL);
@@ -143,9 +145,9 @@ class User extends ApiObject {
if(isset($_GET['lang']) && is_string($_GET["lang"]) && !empty($_GET["lang"])) {
$this->updateLanguage($_GET['lang']);
- } else if(isset($_COOKIE['lang']) && is_string($_COOKIE["lang"]) && !empty($_COOKIE["lang"])) {
+ }/* else if(isset($_COOKIE['lang']) && is_string($_COOKIE["lang"]) && !empty($_COOKIE["lang"])) {
$this->updateLanguage($_COOKIE['lang']);
- }
+ }*/
}
public function createSession($userId) {
@@ -164,7 +166,7 @@ class User extends ApiObject {
LEFT JOIN Language ON User.uidLanguage=Language.uid
WHERE api_key=? AND valid_until > now() AND User.uid = ApiKey.uidUser';
- $request = new CExecuteSelect($this);
+ $request = new \Api\ExecuteSelect($this);
$success = $request->execute(array('query' => $query, $apiKey));
if($success) {
diff --git a/core/View.class.php b/core/View.class.php
index c6293f9..664a887 100644
--- a/core/View.class.php
+++ b/core/View.class.php
@@ -226,4 +226,5 @@ abstract class View {
}
};
+
?>
diff --git a/core/Views/LanguageFlags.class.php b/core/Views/LanguageFlags.class.php
new file mode 100644
index 0000000..72916b7
--- /dev/null
+++ b/core/Views/LanguageFlags.class.php
@@ -0,0 +1,54 @@
+getDocument()->getUser());
+ $params = explode("&", $queryString);
+ $query = array();
+ foreach($params as $param) {
+ $aParam = explode("=", $param);
+ $key = $aParam[0];
+
+ if($key == "s" && startsWith($requestUri, "/s/"))
+ continue;
+
+ $val = (isset($aParam[1]) ? $aParam[1] : "");
+ if(!empty($key)) {
+ $query[$key] = $val;
+ }
+ }
+
+ $url = parse_url($requestUri, PHP_URL_PATH) . "?";
+ if($request->execute()) {
+ foreach($request->getResult()['languages'] as $lang) {
+ $langCode = $lang['code'];
+ $langName = $lang['name'];
+ $query['lang'] = $langCode;
+ $queryString = http_build_query($query);
+
+ $flags[] = $this->createLink(
+ "$url$queryString",
+ ""
+ );
+ }
+ } else {
+ $flags[] = $this->createErrorText($request->getLastError());
+ }
+
+ return implode('', $flags);
+ }
+}
+
+?>
diff --git a/core/Views/Login.class.php b/core/Views/Login.class.php
new file mode 100644
index 0000000..46ae1c8
--- /dev/null
+++ b/core/Views/Login.class.php
@@ -0,0 +1,57 @@
+getDocument());
+ $iconBack = $this->createIcon("arrow-circle-left", "right");
+ $domain = $_SERVER['HTTP_HOST'];
+ $protocol = getProtocol();
+
+ $accountCreated = "";
+ if(isset($_GET["accountCreated"])) {
+ $accountCreated .= '
+
+ Your account was successfully created, you may now login with your credentials
+
';
+ }
+
+ $html = "
+
+
+
Admin Control Panel
+
+
+
";
+
+ return $html;
+
+ return $html;
+ }
+}
+
+?>
diff --git a/core/core.php b/core/core.php
index 082eb5c..4eb87e5 100644
--- a/core/core.php
+++ b/core/core.php
@@ -24,6 +24,10 @@
return $result;
}
+ function getProtocol() {
+ return stripos($_SERVER['SERVER_PROTOCOL'],'https') === 0 ? 'https://' : 'http://';
+ }
+
function includeDir($dir, $aIgnore = array(), $recursive = false) {
$aIgnore[] = '.';
$aIgnore[] = '..';
diff --git a/css/admin.css b/css/admin.css
new file mode 100644
index 0000000..08c2c09
--- /dev/null
+++ b/css/admin.css
@@ -0,0 +1,229 @@
+.loginContainer {
+ border-radius: 5px;
+ width: 600px;
+ position: relative;
+}
+
+.loginForm {
+ padding: 25px;
+ border: 1px solid #bbb;
+ border-radius: 5px;
+ background-color: #bbb;
+ color: black;
+}
+
+.loginForm input {
+ margin-bottom: 10px;
+}
+
+.loginForm button, .loginForm div {
+ margin-top: 15px;
+ margin-bottom: 0;
+}
+
+.loginForm input[type="checkbox"] {
+ padding: 0;
+ margin-bottom: 0;
+ vertical-align: bottom;
+}
+
+.device-table > tbody > tr:hover {
+ cursor: pointer;
+ background-color: grey;
+}
+
+.device-table > tbody > tr > td:nth-child(3) {
+ text-align: center;
+}
+
+.apikey-table > tbody > tr > td:last-child {
+ float: right;
+}
+
+.apikey-table > tbody > tr > td:first-child {
+ word-break: break-all;
+}
+
+.apikey-table > tbody > tr:hover {
+ background-color: grey;
+ cursor: pointer;
+}
+
+.sidebar {
+ margin: 0;
+ padding: 0;
+ color: white;
+ text-align: center;
+}
+
+.sidebar a {
+ color: white;
+}
+
+.status { font-size: 12px; }
+.status-ok { color: #38e40d; }
+.status-error { color: red; }
+.status-offline { color: gray; }
+
+.sidebar .nav-item {
+ line-height: 30px;
+ border-bottom: 1px solid gray;
+}
+
+.nav-link {
+ grid-template-columns: 20px auto 20px;
+}
+
+.nav-link-center {
+ grid-column-start: 2;
+ grid-column-end: 2;
+}
+
+.sidebar-title {
+ font-size: 18px;
+ margin-bottom: 0.5em;
+ font-weight: bold;
+}
+
+.sidebar-top {
+ height: 100px;
+ padding: 10px;
+ border-bottom: 5px solid gray;
+ background-color: #555;
+}
+
+.sidebar-bottom {
+ height: 100px;
+ padding: 10px;
+ position: absolute;
+ bottom: 0;
+ border-top: 5px solid gray;
+ width: 100%;
+ grid-template-rows: 50% 50%;
+}
+
+.grid {
+ display: grid;
+}
+
+.grid > span {
+ align-self: center;
+}
+
+.sidebar-bottom > a {
+ grid-template-columns: 20px auto;
+ align-self: center;
+}
+
+.sidebar-bottom > a:hover {
+ text-decoration: none;
+ font-weight: bold;
+}
+
+.sidebar .active .nav-link-center {
+ text-decoration: underline;
+ font-weight: bold;
+}
+
+.sidebar .nav-item:hover {
+ background-color: gray;
+}
+
+.nav-device {
+ background-color: #5a5a5a;
+}
+
+.service {
+ margin: 10px;
+}
+
+.service > .card-header {
+ color: black;
+ cursor: pointer;
+ display: grid;
+ grid-template-columns: 20px auto;
+}
+
+.service-icon {
+ width: 32px;
+ height: 32px;
+}
+
+.fs-listview > tbody > tr:hover {
+ cursor: pointer;
+}
+
+.fs-listview > tbody > tr.downloading > td, .fs-gridview > div.downloading > span {
+ font-style: italic;
+ color: gray;
+}
+
+.fs-toolbar {
+ display: grid;
+ grid-template-columns: 1px 40px 40px 1px auto 1px 40px 1px 40px 40px 1px;
+}
+
+.fs-toolbar > i {
+ align-self: center;
+ cursor: pointer;
+}
+
+.fs-toolbar > span {
+ text-align: left;
+ align-self: center;
+}
+
+.fs-gridview {
+ display: grid;
+ grid-template-columns: repeat(4, auto);
+}
+
+.fs-gridview div {
+ align-self: center;
+ text-align: center;
+}
+
+.fs-gridview > div {
+ padding: 5px;
+ display: grid;
+ grid-template-rows: 48px auto;
+}
+
+.fs-gridview > div:hover {
+ background: #ddd;
+ cursor: pointer;
+}
+
+.vr {
+ border-left: 1px solid #dee2e6;
+ height: 100%;
+}
+
+.camera-stream {
+ cursor: pointer;
+}
+
+.temperature-controls {
+ display: grid;
+ grid-template-columns: auto 30px;
+}
+
+.temperature-controls > div {
+ align-self: center;
+ text-align: left;
+}
+
+.shell-tabs > li > a {
+ color: black;
+ line-height: inherit;
+ outline: none;
+}
+
+.shell {
+ text-align: left
+}
+
+.speaker-controls {
+ display:grid;
+ grid-template-columns: auto auto auto;
+}
diff --git a/index.php b/index.php
index 1ffdfd5..5d2dbeb 100644
--- a/index.php
+++ b/index.php
@@ -10,6 +10,10 @@ function getWebRoot() {
return dirname(__FILE__);
}
+function createError($msg) {
+ return json_encode(array("success" => false, "msg" => $msg));
+}
+
spl_autoload_extensions(".php");
spl_autoload_register(function($class) {
$full_path = getClassPath($class);
@@ -27,11 +31,42 @@ $config = new Configuration\Configuration();
$installation = (!$config->load());
$user = new Objects\User($config);
-if ($installation) {
- $document = new Documents\Install($user);
+if(isset($_GET["api"]) && is_string($_GET["api"])) {
+ header("Content-Type: application/json");
+ if($installation) {
+ $response = createError("Not installed");
+ } else {
+ $apiFunction = $_GET["api"];
+ if(empty($apiFunction)) {
+ header("403 Forbidden");
+ $response = "";
+ } else if(!preg_match("/[a-zA-Z]+(\/[a-zA-Z]+)*/", $apiFunction)) {
+ $response = createError("Invalid Method");
+ } else {
+ $apiFunction = strtoupper($apiFunction[0]) . substr($apiFunction, 1);
+ $class = "\\Api\\$apiFunction";
+ $file = getClassPath($class);
+ if(!file_exists($file)) {
+ header("404 Not Found");
+ $response = createError("Not found");
+ } else {
+ $request = new $class($user, true);
+ $success = $request->execute();
+ $msg = $request->getLastError();
+ $response = $request->getJsonResult();
+ }
+ }
+ }
} else {
- print("DON'T INSTALL");
+ if ($installation) {
+ $document = new Documents\Install($user);
+ } else {
+ $document = new Documents\Admin($user);
+ }
+
+ $response = $document->getCode();
}
-die($document->getCode());
+$user->sendCookies();
+die($response);
?>
diff --git a/js/admin.js b/js/admin.js
new file mode 100644
index 0000000..4cb2ff0
--- /dev/null
+++ b/js/admin.js
@@ -0,0 +1,25 @@
+$(document).ready(function() {
+ $("#username").keypress(function(e) { if(e.which == 13) $("#password").focus(); });
+ $("#password").keypress(function(e) { if(e.which == 13) $("#btnLogin").click(); });
+ $("#btnLogin").click(function() {
+ var username = $("#username").val();
+ var password = $("#password").val();
+ var errorDiv = $("#loginError");
+ var createdDiv = $("#accountCreated");
+ var btn = $(this);
+
+ errorDiv.hide();
+ btn.prop("disabled", true);
+ btn.html("Logging in… ");
+ jsCore.apiCall("login", {"username": username, "password": password}, function(data) {
+ window.location.reload();
+ }, function(err) {
+ btn.html("Login");
+ btn.prop("disabled", false);
+ $("#password").val("");
+ createdDiv.hide();
+ errorDiv.html(err);
+ errorDiv.show();
+ });
+ });
+});
diff --git a/js/script.js b/js/script.js
index e8b29e1..2c31c99 100644
--- a/js/script.js
+++ b/js/script.js
@@ -11,7 +11,7 @@ var Core = function() {
callback = typeof callback !== 'undefined' ? callback : function(data) { };
onerror = typeof onerror !== 'undefined' ? onerror : function(msg) { bootbox.alert("Ein Fehler ist aufgetreten: " + msg); };
- $.post('/php/api/' + func + '.php', aParams, function(data) {
+ $.post('/api/' + func, aParams, function(data) {
console.log(func + "(): success=" + data.success + " msg=" + data.msg);
if(data.hasOwnProperty('logoutIn') && $("#logoutTimer").length > 0) {
$("#logoutTimer").attr("data-time", data.logoutIn);
@@ -24,7 +24,7 @@ var Core = function() {
}
}, "json").fail(function(jqXHR, textStatus, errorThrown) {
console.log("API-Function Error: " + func + " Status: " + textStatus + " error thrown: " + errorThrown);
- onerror.call(this, "Ein Fehler ist aufgetreten. API-Funktion: " + func + " Status: " + textStatus + " - " + errorThrown);
+ onerror.call(this, "An error occurred. API-Function: " + func + " Status: " + textStatus + " - " + errorThrown);
});
};
@@ -32,7 +32,7 @@ var Core = function() {
var name = cname + "=";
var decodedCookie = decodeURIComponent(document.cookie);
var ca = decodedCookie.split(";");
- for(var i = 0; i