Compare commits
23
Commits
3f4e859153
..
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ad9290d2ad | ||
|
|
205f2e2f73 | ||
|
|
ce0777bb33 | ||
|
|
eb67458ab1 | ||
|
|
95f8e22f11 | ||
|
|
b4621fc127 | ||
|
|
9cb50d7d28 | ||
|
|
a33de15f0c | ||
|
|
313ffec92c | ||
|
|
c94122c9fd | ||
|
|
6b5a299079 | ||
|
|
a1bbae383a | ||
|
|
bf552e87cc | ||
|
|
fd1b8d9a0b | ||
|
|
ff2afb4441 | ||
|
|
1a2ee0c176 | ||
|
|
9316818753 | ||
|
|
8ef5f7a941 | ||
|
|
0c73ad14f5 | ||
|
|
1a2e1cc33f | ||
|
|
ae54fabd6b | ||
|
|
0cb0d97529 | ||
|
|
e53e53146c |
No files matched your search
@@ -1 +1,4 @@
|
||||
TOKEN_SIGNATURE=281361f952279bd9530734c67ed04aed2756f0fe00cb998cd6c28324f491484c
|
||||
COOKIE_TOKEN_SIGNATURE=a11a9ea5fd839e616bd08ebc432f641a24ef1f4d74ca478f904e7a3122fc7a05
|
||||
COOKIE_TOKEN_LIFETIME=86400
|
||||
API_TOKEN_SIGNATURE=38bcd8a8e9ac3be83ddfcf4c12c19ccb3be70df00e48d43d4f63f54f014d1946
|
||||
DB_FILE=database.db
|
||||
+235
-36
@@ -1,10 +1,39 @@
|
||||
<?php
|
||||
$debug = true;
|
||||
|
||||
if ($debug) {
|
||||
ini_set("display_errors", 1);
|
||||
ini_set("display_startup_errors", 1);
|
||||
error_reporting(E_ALL);
|
||||
}
|
||||
|
||||
// API Main Library
|
||||
class gbAPI {
|
||||
function __construct($authRequired) {
|
||||
define("APP_PATH", __DIR__ . "/../");
|
||||
public $username;
|
||||
public $input;
|
||||
|
||||
if ($authRequired) {
|
||||
private $db;
|
||||
private $config;
|
||||
private $internal;
|
||||
private $response;
|
||||
private $lastError;
|
||||
|
||||
private function b64url_encode($data) {
|
||||
return rtrim(strtr(base64_encode($data), "+/", "-_"), "=");
|
||||
}
|
||||
|
||||
private function b64url_decode($data) {
|
||||
return base64_decode(strtr($data, "-_", "+/"));
|
||||
}
|
||||
|
||||
function __construct($authRequired, $internal) {
|
||||
if (!defined("APP_PATH")) {
|
||||
define("APP_PATH", __DIR__ . "/../");
|
||||
}
|
||||
|
||||
$this->internal = $internal;
|
||||
|
||||
if ($authRequired && !$internal) {
|
||||
if (!$this->checkAuth()) {
|
||||
$status = 401;
|
||||
$data = [
|
||||
@@ -12,16 +41,67 @@ class gbAPI {
|
||||
"error_text" => "Authentication failed."
|
||||
];
|
||||
|
||||
$this->answer($status, $data);
|
||||
$this->lastError = $data;
|
||||
|
||||
$this->answer($status, $data, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getConfig() {
|
||||
return parse_ini_file(APP_PATH . ".env");
|
||||
function getInput() {
|
||||
if (isset($this->input)) {
|
||||
return $this->input;
|
||||
}elseif ($_SERVER["REQUEST_METHOD"] == "POST") {
|
||||
try {
|
||||
$input = json_decode(file_get_contents("php://input"), true);
|
||||
} catch (JsonException $error) {
|
||||
$error_payload = [
|
||||
"error" => "invalid_body",
|
||||
"error_text" => "Can not read request body: " . $error
|
||||
];
|
||||
|
||||
$this->lastError = $error_payload;
|
||||
|
||||
$this->answer(400, $error_payload, true);
|
||||
}
|
||||
return $input;
|
||||
}else{
|
||||
$error_payload = [
|
||||
"error" => "false_request_method",
|
||||
"error_text" => "Only POST allowed"
|
||||
];
|
||||
|
||||
$this->lastError = $error_payload;
|
||||
|
||||
$this->answer(400, $error_payload, true);
|
||||
}
|
||||
}
|
||||
|
||||
function generateToken($username) {
|
||||
function getConfig() {
|
||||
if (isset($this->config)) {
|
||||
return $config;
|
||||
}else{
|
||||
return parse_ini_file(APP_PATH . ".env");
|
||||
}
|
||||
}
|
||||
|
||||
function generateCookieToken($username) {
|
||||
$config = $this->getConfig();
|
||||
|
||||
// Generate Token
|
||||
$payload = [
|
||||
"user" => $username,
|
||||
"auth" => true,
|
||||
"exp" => time() + $config["COOKIE_TOKEN_LIFETIME"]
|
||||
];
|
||||
$string = $this->b64url_encode(json_encode($payload));
|
||||
$secret = $config["COOKIE_TOKEN_SIGNATURE"];
|
||||
|
||||
$sig = hash_hmac("sha256", $string, $secret);
|
||||
return $string . "." . $sig;
|
||||
}
|
||||
|
||||
function generateAPIToken($username) {
|
||||
$config = $this->getConfig();
|
||||
|
||||
// Generate Token
|
||||
@@ -29,65 +109,184 @@ class gbAPI {
|
||||
"user" => $username,
|
||||
"auth" => true
|
||||
];
|
||||
$string = json_encode($payload);
|
||||
$secret = $config["TOKEN_SIGNATURE"];
|
||||
$string = $this->b64url_encode(json_encode($payload));
|
||||
$secret = $config["API_TOKEN_SIGNATURE"];
|
||||
|
||||
return hash_hmac("sha256", $string, $secret);
|
||||
$sig = hash_hmac("sha256", $string, $secret);
|
||||
return $string . "." . $sig;
|
||||
}
|
||||
|
||||
function checkAuth() {
|
||||
if (!isset($_SERVER["HTTP_X_API_KEY"]) && !isset($_COOKIE["auth_token"])) {
|
||||
return false;
|
||||
}elseif (isset($_COOKIE["auth_token"]) && isset($_COOKIE["username"])) {
|
||||
if (isset($_COOKIE["auth_token"])) {
|
||||
// Get Config
|
||||
$config = $this->getConfig();
|
||||
|
||||
// Check Token
|
||||
$username = $_COOKIE["username"];
|
||||
$expected = $this->generateToken($username);
|
||||
$given = $_COOKIE["auth_token"];
|
||||
if (!is_string($given)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$result = hash_equals($expected, $given);
|
||||
$given_string = explode(".", $given);
|
||||
|
||||
if (count($given_string) !== 2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$sig_expected = hash_hmac("sha256", $given_string[0], $config["COOKIE_TOKEN_SIGNATURE"]);
|
||||
|
||||
@$result = hash_equals($sig_expected, $given_string[1]);
|
||||
if ($result) {
|
||||
return true;
|
||||
$body = json_decode($this->b64url_decode($given_string[0]), true);
|
||||
|
||||
if ($body["exp"] > time()) {
|
||||
$this->username = $body["user"];
|
||||
return true;
|
||||
}else{
|
||||
return false;
|
||||
}
|
||||
}else{
|
||||
return false;
|
||||
}
|
||||
}elseif (isset($_SERVER["HTTP_X_API_KEY"])) {
|
||||
// Get config
|
||||
$config = $this->getConfig();
|
||||
|
||||
// Decode Token
|
||||
$payload = json_decode(base64_decode($_SERVER["HTTP_X_API_KEY"]), true);
|
||||
$username = $payload["username"];
|
||||
$given = $_SERVER["HTTP_X_API_KEY"];
|
||||
|
||||
$given = $payload["auth_token"];
|
||||
$expected = $this->generateToken($username);
|
||||
|
||||
$result = hash_equals($expected, $given);
|
||||
if ($result) {
|
||||
return true;
|
||||
if (!is_string($given)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$given_string = explode(".", $given);
|
||||
|
||||
if (count($given_string) !== 2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$sig_expected = hash_hmac("sha256", $given_string[0], $config["API_TOKEN_SIGNATURE"]);
|
||||
|
||||
@$result = hash_equals($sig_expected, $given_string[1]);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function answer($status, $data = []) {
|
||||
http_response_code($status);
|
||||
Header ("Content-Type: application/json; charset=UTF-8");
|
||||
function answer($status, $data = [], $error = false) {
|
||||
if ($error) {
|
||||
$return = [];
|
||||
|
||||
$data = json_encode($data);
|
||||
$return["status"] = $status;
|
||||
|
||||
$json = '{"status":' . $status . ',"data":' . $data . '}';
|
||||
die($json);
|
||||
foreach ($data as $key => $value) {
|
||||
$return[$key] = $value;
|
||||
}
|
||||
}else{
|
||||
$return = [
|
||||
"status" => $status,
|
||||
"data" => $data
|
||||
];
|
||||
}
|
||||
|
||||
// Check if request is internal or external
|
||||
if ($this->internal) {
|
||||
$this->response = $return;
|
||||
return;
|
||||
}else{
|
||||
http_response_code($status);
|
||||
header("Content-Type: application/json; charset=UTF-8");
|
||||
|
||||
$return = json_encode($return);
|
||||
die($return);
|
||||
}
|
||||
}
|
||||
|
||||
function returnLastError() {
|
||||
if (isset($this->lastError)) {
|
||||
return $this->lastError;
|
||||
}else{
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
function getAnswer() {
|
||||
if (!isset($this->response)) {
|
||||
$error = [
|
||||
"status" => 500,
|
||||
"error" => "empty_return",
|
||||
"error_text" => "API Returned nothing."
|
||||
];
|
||||
|
||||
$this->lastError = $error;
|
||||
|
||||
return $error;
|
||||
}
|
||||
|
||||
return $this->response;
|
||||
}
|
||||
|
||||
function getResponse() {
|
||||
return $this->response;
|
||||
}
|
||||
|
||||
function dbCommand($command, $expectResult, $stmtArgsRequired = false, $stmtArgs = []) {
|
||||
$db_path = APP_PATH . "database.db";
|
||||
if (isset($this->db)) {
|
||||
$db = $this->db;
|
||||
}else{
|
||||
$config = $this->getConfig();
|
||||
$db_name = $config["DB_FILE"];
|
||||
$db_path = APP_PATH . $db_name;
|
||||
|
||||
$db = new PDO("sqlite:" . $db_path);
|
||||
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
||||
if (!is_file($db_path)) {
|
||||
$error_payload = [
|
||||
"error" => "database_not_found",
|
||||
"error_text" => "The Database was not found."
|
||||
];
|
||||
|
||||
$this->lastError = $error_payload;
|
||||
|
||||
$api->answer(500, $error_payload, true);
|
||||
}
|
||||
|
||||
if (!is_writeable($db_path)) {
|
||||
$error_payload = [
|
||||
"error" => "database_not_writeable",
|
||||
"error_text" => "The Database is not writeable."
|
||||
];
|
||||
|
||||
$this->lastError = $error_payload;
|
||||
|
||||
$this->answer(500, $error_payload, true);
|
||||
return;
|
||||
}
|
||||
|
||||
$db = new PDO("sqlite:" . $db_path);
|
||||
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
||||
}
|
||||
|
||||
$stmt = $db->prepare($command);
|
||||
$stmt->execute($stmtArgs);
|
||||
|
||||
if ($expectResult) {
|
||||
$result = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
$result = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getSetting($key) {
|
||||
$command = "SELECT name, value FROM settings WHERE name = :name";
|
||||
|
||||
$value = $this->dbCommand($command, true, true, [":name" => $key]);
|
||||
|
||||
if (isset($value[0]["value"])) {
|
||||
return $value[0]["value"];
|
||||
}else{
|
||||
$this->answer(500, [
|
||||
"error" => "query_returned_nothing",
|
||||
"error_text" => "The SQL Query Returned nothing usable. Check Database Permissions."
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
Executable
+28
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
// Set internal to false so that the answer goes to the client
|
||||
if (!isset($internal)) {
|
||||
$internal = false;
|
||||
define("API_DIR", "../");
|
||||
}
|
||||
|
||||
// Load Main Library
|
||||
require_once API_DIR . "api.php";
|
||||
$api = new gbAPI(true, $internal);
|
||||
|
||||
$auth = $api->checkAuth();
|
||||
|
||||
$lastError = $api->returnLastError();
|
||||
|
||||
if ($lastError == NULL) {
|
||||
if ($auth) {
|
||||
$api->answer(200, [
|
||||
"login" => true,
|
||||
"username" => $api->username
|
||||
]);
|
||||
}else{
|
||||
$api->answer(401, [
|
||||
"login" => false,
|
||||
"username" => ""
|
||||
]);
|
||||
}
|
||||
}
|
||||
+24
-24
@@ -1,50 +1,50 @@
|
||||
<?php
|
||||
// Load API Library
|
||||
require "../api.php";
|
||||
|
||||
$api = new gbAPI(false);
|
||||
|
||||
// Check Request Body
|
||||
if ($_SERVER["REQUEST_METHOD"] !== "POST") {
|
||||
$api->answer(400, [
|
||||
"error" => "false_request_method",
|
||||
"error_text" => "Only POST allowed"
|
||||
]);
|
||||
// Set internal to false so that the answer goes to the client
|
||||
if (!isset($internal)) {
|
||||
$internal = false;
|
||||
define("API_DIR", "../");
|
||||
}
|
||||
|
||||
if (!isset($_POST["username"]) || !isset($_POST["password"])) {
|
||||
// Load API Library
|
||||
require_once API_DIR . "api.php";
|
||||
|
||||
$api = new gbAPI(false, $internal);
|
||||
|
||||
// Check Request Body
|
||||
$input = $api->getInput();
|
||||
|
||||
if (!isset($input["username"]) || !isset($input["password"])) {
|
||||
$api->answer(400, [
|
||||
"error" => "missing_fields",
|
||||
"error_text" => "Some fields are missing"
|
||||
]);
|
||||
], true);
|
||||
return;
|
||||
}
|
||||
|
||||
$username = $_POST["username"];
|
||||
$password = $_POST["password"];
|
||||
$username = $input["username"];
|
||||
$password = $input["password"];
|
||||
|
||||
// Prepare SQL Command
|
||||
$hash = hash("sha256", $password);
|
||||
|
||||
$command = "SELECT username, password FROM users WHERE username = :username AND password = :password";
|
||||
$command = "SELECT username, password FROM users WHERE username = :username";
|
||||
$args = [
|
||||
":username" => $username,
|
||||
":password" => $hash
|
||||
":username" => $username
|
||||
];
|
||||
|
||||
// Execute SQL Command
|
||||
$result = $api->dbCommand($command, true, true, $args);
|
||||
|
||||
// Check Result
|
||||
if ($result && password_verify($password, $result["password"])) {
|
||||
if ($result && password_verify($password, $result[0]["password"])) {
|
||||
// Login successful. Generate Auth Token
|
||||
$token = $api->generateToken($username);
|
||||
$token = $api->generateCookieToken($username);
|
||||
|
||||
// Set cookies
|
||||
setcookie("auth_token", $token, time() + 86400, "/");
|
||||
setcookie("username", $username, time() + 86400, "/");
|
||||
|
||||
$api->answer(200);
|
||||
}else{
|
||||
$api->answer(401, [
|
||||
"error" => "unauthorized",
|
||||
"error_text" => "A user with this password does not exists."
|
||||
]);
|
||||
], true);
|
||||
}
|
||||
Executable
+52
@@ -0,0 +1,52 @@
|
||||
<?php
|
||||
// Set internal to false so that the answer goes to the client
|
||||
if (!isset($internal)) {
|
||||
$internal = false;
|
||||
define("API_DIR", "../");
|
||||
}
|
||||
|
||||
// Load Main Library
|
||||
require_once API_DIR . "api.php";
|
||||
|
||||
$api = new gbAPI(false, $internal);
|
||||
|
||||
$input = $api->getInput();
|
||||
|
||||
if (!isset($input["name"]) || !isset($input["text"])) {
|
||||
$api->answer(400, [
|
||||
"error" => "missing_fields",
|
||||
"error_text" => "Some fields are missing"
|
||||
], true);
|
||||
return;
|
||||
}
|
||||
|
||||
$html_allowed = $api->getSetting("allow_html");
|
||||
|
||||
if ($html_allowed == "true") {
|
||||
$name = $input["name"];
|
||||
$text = $input["text"];
|
||||
}else{
|
||||
$name = htmlspecialchars($input["name"]);
|
||||
$text = htmlspecialchars($input["text"]);
|
||||
}
|
||||
|
||||
$date = date("Y-m-d H:i:s");
|
||||
$approve = $api->getSetting("approve_entrys") == "true" ? true : false;
|
||||
|
||||
if ($approve) {
|
||||
$status = 0;
|
||||
}else{
|
||||
$status = 1;
|
||||
}
|
||||
|
||||
|
||||
// Insert Into Database
|
||||
$command = "INSERT INTO entrys (name, text, date, status) VALUES (:name, :text, :date, :status)";
|
||||
$api->dbCommand($command, false, true, [
|
||||
":name" => $name,
|
||||
":text" => $text,
|
||||
":date" => $date,
|
||||
":status" => $status
|
||||
]);
|
||||
|
||||
$api->answer(200);
|
||||
Executable
+47
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
// Set internal to false so that the answer goes to the client
|
||||
if (!isset($internal)) {
|
||||
$internal = false;
|
||||
define("API_DIR", "../");
|
||||
}
|
||||
|
||||
// Load Main Library
|
||||
require_once API_DIR . "api.php";
|
||||
|
||||
$api = new gbAPI(false, $internal);
|
||||
|
||||
// Get Entrys
|
||||
$command = "SELECT * FROM entrys WHERE status = :status ORDER BY date DESC";
|
||||
$result = $api->dbCommand($command, true, true, [":status" => 1]);
|
||||
|
||||
$entrys = [];
|
||||
|
||||
if (!$result) {
|
||||
$api->answer(200, [
|
||||
"entrys" => [],
|
||||
"empty" => true
|
||||
]);
|
||||
return;
|
||||
}
|
||||
|
||||
foreach($result as $row) {
|
||||
$entry_name = $row["name"];
|
||||
$entry_text = $row["text"];
|
||||
$date = new DateTime($row["date"]);
|
||||
$entry_date = $date->format("d.m.Y H:i:s");
|
||||
|
||||
$entry = [
|
||||
"name" => $entry_name,
|
||||
"text" => $entry_text,
|
||||
"date" => $entry_date
|
||||
];
|
||||
|
||||
$entrys[] = $entry;
|
||||
}
|
||||
|
||||
$json = json_encode($entrys);
|
||||
|
||||
$api->answer(200, [
|
||||
"entrys" => $json,
|
||||
"empty" => false
|
||||
]);
|
||||
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
// Set internal to false so that the answer goes to the client
|
||||
if (!isset($internal)) {
|
||||
$internal = false;
|
||||
define("API_DIR", "../");
|
||||
}
|
||||
|
||||
// Load Main Library
|
||||
require_once API_DIR . "api.php";
|
||||
|
||||
$api = new gbAPI(true, $internal);
|
||||
|
||||
$input = $api->getInput();
|
||||
|
||||
|
||||
// Check given Status
|
||||
if (!isset($input["status"])) {
|
||||
$api->answer(400, [
|
||||
"error" => "missing_fields",
|
||||
"error_text" => "Some fields are missing"
|
||||
], true);
|
||||
return;
|
||||
}
|
||||
|
||||
if ($status !== 0 && $status !== 1 && $status !== 2) {
|
||||
$api->answer(400, [
|
||||
"error" => "status_invalid",
|
||||
"error_text" => "The given status is invalid."
|
||||
], true);
|
||||
}
|
||||
|
||||
$command = "SELECT * FROM entrys WHERE status = :status";
|
||||
|
||||
$response = $api->dbCommand($command, true, true, [
|
||||
":status" => $status
|
||||
]);
|
||||
|
||||
Executable
+24
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
// Set internal to false so that the answer goes to the client
|
||||
if (!isset($internal)) {
|
||||
$internal = false;
|
||||
define("API_DIR", "../");
|
||||
}
|
||||
|
||||
// Load Main Library
|
||||
require_once API_DIR . "api.php";
|
||||
|
||||
$api = new gbAPI(false, $internal);
|
||||
|
||||
// Get App Name
|
||||
$result = $api->getSetting("application_name");
|
||||
if ($result !== NULL) {
|
||||
$api->answer(200, [
|
||||
"application_name" => $result
|
||||
]);
|
||||
}else{
|
||||
$api->answer(500, [
|
||||
"error" => "empty_query",
|
||||
"error_text" => "Database query returned nothing."
|
||||
]);
|
||||
}
|
||||
+71
-17
@@ -1,27 +1,47 @@
|
||||
<?php
|
||||
// Load Main Libary
|
||||
require "../api.php";
|
||||
|
||||
$api = new gbAPI(false);
|
||||
|
||||
// Check Request body
|
||||
if ($_SERVER["REQUEST_METHOD"] !== "POST") {
|
||||
$api->answer(400, [
|
||||
"error" => "false_request_method",
|
||||
"error_text" => "Only POST allowed"
|
||||
]);
|
||||
// Set internal to false so that the answer goes to the client
|
||||
if (!isset($internal)) {
|
||||
$internal = false;
|
||||
define("API_DIR", "../");
|
||||
}
|
||||
|
||||
if (!isset($_POST["username"]) || !isset($_POST["password"]) || !isset($_POST["password_repeat"])) {
|
||||
// Load Main Libary
|
||||
require_once API_DIR . "api.php";
|
||||
|
||||
$api = new gbAPI(false, $internal);
|
||||
|
||||
// Check Request body
|
||||
$input = $api->getInput();
|
||||
|
||||
if (!isset($input["username"]) || !isset($input["password"]) || !isset($input["password_repeat"])) {
|
||||
$api->answer(400, [
|
||||
"error" => "missing_fields",
|
||||
"error_text" => "Some fields are missing"
|
||||
]);
|
||||
return;
|
||||
}
|
||||
|
||||
$username = $_POST["username"];
|
||||
$password = $_POST["password"];
|
||||
$password_repeat = $_POST["password_repeat"];
|
||||
// Check if application already configurated
|
||||
if (is_file(APP_PATH . "database.db")) {
|
||||
$api->answer(503, [
|
||||
"error" => "already_configurated",
|
||||
"error_text" => "The application is already configurated."
|
||||
]);
|
||||
return;
|
||||
}
|
||||
|
||||
// Check PDO drivers
|
||||
if (!extension_loaded("pdo_sqlite") || !extension_loaded("sqlite3")) {
|
||||
$api->answer(500, [
|
||||
"error" => "missing_drives",
|
||||
"error_text" => "Please install the extensions pdo_sqlite and sqlite3."
|
||||
]);
|
||||
return;
|
||||
}
|
||||
|
||||
$username = $input["username"];
|
||||
$password = $input["password"];
|
||||
$password_repeat = $input["password_repeat"];
|
||||
|
||||
// Check Passwords
|
||||
if ($password !== $password_repeat) {
|
||||
@@ -29,10 +49,11 @@ if ($password !== $password_repeat) {
|
||||
"error" => "passwords_dont_match",
|
||||
"error_text" => "The passwords does not match."
|
||||
]);
|
||||
return;
|
||||
}
|
||||
|
||||
// Hash Password
|
||||
$hash = password_hash($password);
|
||||
$hash = password_hash($password, PASSWORD_DEFAULT);
|
||||
|
||||
|
||||
|
||||
@@ -44,7 +65,7 @@ $db_path = APP_PATH . "database.db";
|
||||
$db = new PDO("sqlite:" . $db_path);
|
||||
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
||||
|
||||
$db = exec($sql_file);
|
||||
$db->exec($sql_file);
|
||||
|
||||
|
||||
|
||||
@@ -54,4 +75,37 @@ $command = "INSERT INTO users (username, password, owner) VALUES (:username, :pa
|
||||
$stmt = $db->prepare($command);
|
||||
$stmt->execute([":username" => $username, ":password" => $hash, ":owner" => 1]);
|
||||
|
||||
|
||||
// INSERT SETTINGS
|
||||
$command = "INSERT INTO settings (name, value) VALUES (:name, :value)";
|
||||
|
||||
$settings = [
|
||||
"application_name" => "Guestbook",
|
||||
"allow_html" => "false",
|
||||
"approve_entrys" => "true",
|
||||
"allow_new_entrys" => "true",
|
||||
"template" => "standard"
|
||||
];
|
||||
|
||||
foreach ($settings as $key => $value) {
|
||||
$stmt = $db->prepare($command);
|
||||
$stmt->execute([":name" => $key, ":value" => $value]);
|
||||
}
|
||||
|
||||
// WRITE .env AND GENERATE SECRETS
|
||||
$env = "";
|
||||
|
||||
$cookie_token = bin2hex(random_bytes(32));
|
||||
$env .= "COOKIE_TOKEN_SIGNATURE=" . $cookie_token . "\n";
|
||||
$env .= "COOKIE_TOKEN_LIFETIME=86400\n";
|
||||
|
||||
$api_token = bin2hex(random_bytes(32));
|
||||
$env .= "API_TOKEN_SIGNATURE=" . $api_token . "\n";
|
||||
|
||||
$env .= "DB_FILE=database.db";
|
||||
|
||||
file_put_contents(APP_PATH . ".env", $env);
|
||||
|
||||
|
||||
// RETURN SUCCESS MESSAGE
|
||||
$api->answer(200);
|
||||
Executable
+17
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
// Set internal to false so that the answer goes to the client
|
||||
if (!isset($internal)) {
|
||||
$internal = false;
|
||||
define("API_DIR", "../");
|
||||
}
|
||||
// Load Main Library
|
||||
require_once API_DIR . "api.php";
|
||||
$api = new gbAPI(false, $internal);
|
||||
|
||||
// Get Template
|
||||
$template = $api->getSetting("template");
|
||||
if ($template !== NULL) {
|
||||
$api->answer(200, [
|
||||
"template_name" => $template
|
||||
]);
|
||||
}
|
||||
Executable → Regular
BIN
Binary file not shown.
+15
-10
@@ -1,15 +1,20 @@
|
||||
CREATE TABLE IF NOT EXISTS "users" (
|
||||
"id" INTEGER NOT NULL,
|
||||
"username" VARCHAR NOT NULL,
|
||||
"password" VARCHAR NOT NULL,
|
||||
"owner" INTEGER NOT NULL,
|
||||
PRIMARY KEY("id", "username", "owner")
|
||||
"id" INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
"username" TEXT NOT NULL UNIQUE,
|
||||
"password" TEXT NOT NULL,
|
||||
"owner" INTEGER NOT NULL DEFAULT 0
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS "entrys" (
|
||||
"id" INTEGER NOT NULL,
|
||||
"name" VARCHAR NOT NULL,
|
||||
"text" VARCHAR NOT NULL,
|
||||
"status" INTEGER,
|
||||
PRIMARY KEY("id")
|
||||
"id" INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
"name" TEXT NOT NULL,
|
||||
"text" TEXT NOT NULL,
|
||||
"date" TEXT NOT NULL,
|
||||
"status" INTEGER NOT NULL DEFAULT 0
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS "settings" (
|
||||
"id" INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
"name" TEXT NOT NULL,
|
||||
"value" TEXT NOT NULL
|
||||
);
|
||||
Executable
+25
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
// Set debug to true
|
||||
$debug = true;
|
||||
|
||||
// Load Main Library
|
||||
require "../main.php";
|
||||
|
||||
// Init Main Class
|
||||
$gb = new gb($debug);
|
||||
|
||||
// Load and init HTML Loader Library
|
||||
require FRONTEND_PATH . "html_loader.php";
|
||||
$htmlloader = new HTMLLoader();
|
||||
|
||||
// Check Login
|
||||
$call = new APICall("auth/isauth.php");
|
||||
$response = $call->response;
|
||||
|
||||
if (!$response["data"]["login"]) {
|
||||
$htmlloader->setPage("login");
|
||||
$htmlloader->show([], true);
|
||||
}else{
|
||||
$htmlloader->setPage("admin_home");
|
||||
$htmlloader->show([], true);
|
||||
}
|
||||
+79
-23
@@ -1,46 +1,77 @@
|
||||
<?php
|
||||
class HTMLLoader {
|
||||
private $template;
|
||||
private $page;
|
||||
|
||||
private $templates;
|
||||
private $template_conf;
|
||||
|
||||
function __construct() {
|
||||
// Check if Paths variables exists
|
||||
if (!defined("TEMPLATE_PATH") || !defined("TEMPLATE_CONF") || !defined("APP_DOMAIN")) {
|
||||
die("TEMPLATE_PATH or TEMPLATE_CONF are not defined at " . __FILE__);
|
||||
}
|
||||
|
||||
$this->templates = json_decode(file_get_contents(TEMPLATE_CONF), true);
|
||||
$this->getTemplate();
|
||||
}
|
||||
|
||||
function setTemplate($template) {
|
||||
// Check if template exists
|
||||
$file = file_get_contents(TEMPLATE_CONF);
|
||||
$json = json_decode($file, true);
|
||||
|
||||
if (!array_key_exists($template, $json) && array_key_exists("error", $json)) {
|
||||
$this->showError('Template "' . $template . '" was not found.');
|
||||
exit;
|
||||
}elseif (!array_key_exists("error", $json)){
|
||||
die("Error Template was not found.");
|
||||
if (!array_key_exists($template, $this->templates)) {
|
||||
die("Template " . $template . " not found.");
|
||||
}
|
||||
|
||||
if (!is_dir(TEMPLATE_PATH . $this->templates[$template]["dir_name"])) {
|
||||
die("Template " . $template . " not found.");
|
||||
}
|
||||
|
||||
$this->template = $template;
|
||||
$this->template_conf = file_get_contents(TEMPLATE_PATH . $this->templates[$template]["dir_name"] . "/template.json");
|
||||
}
|
||||
|
||||
function getTemplate() {
|
||||
// Call API
|
||||
$call = new APICall("template/get.php");
|
||||
$response = $call->response;
|
||||
|
||||
if ($response["status"] !== 200) {
|
||||
$this->setTemplate("standard");
|
||||
$this->showError("Template API Returned an error: " . $response["error_text"]);
|
||||
}
|
||||
|
||||
$template = $response["data"]["template_name"];
|
||||
|
||||
$this->template_conf = json_decode(file_get_contents(TEMPLATE_PATH . $this->templates[$template]["dir_name"] . "/template.json"), true);
|
||||
$this->template = $template;
|
||||
}
|
||||
|
||||
function showError($error) {
|
||||
$file = file_get_contents(TEMPLATE_CONF);
|
||||
$json = json_decode($file, true);
|
||||
function setPage($page) {
|
||||
if (!array_key_exists($page, $this->template_conf)) {
|
||||
$this->showError('Page <span class="code">' . $page . '</span> for template <span class="code">' . $this->template . '</span> not found.');
|
||||
}else{
|
||||
$this->page = $page;
|
||||
}
|
||||
}
|
||||
|
||||
$page = $json["error"];
|
||||
$html = file_get_contents(TEMPLATE_PATH . $page["dir_name"] . "/" . $page["html_file"]);
|
||||
function showError($error) {
|
||||
$template_dir = $this->templates[$this->template]["dir_name"];
|
||||
$template_conf = json_decode(file_get_contents(TEMPLATE_PATH . $template_dir . "/template.json"), true);
|
||||
|
||||
$page = $template_conf["error"];
|
||||
$html = file_get_contents(TEMPLATE_PATH . $template_dir . "/" . $page["dir_name"] . "/" . $page["html_file"]);
|
||||
|
||||
$css = "";
|
||||
|
||||
// Get CSS
|
||||
foreach ($page["css_files"] as $file) {
|
||||
// Check if File exists
|
||||
if (!is_file(TEMPLATE_PATH . $page["dir_name"] . "/" . $file)) {
|
||||
$this->showError('CSS File <span class="code">' . $file . '</span> for Template <span class="code">error</span> in <span class="code">' . __FILE__ . "</span> not found.");
|
||||
if (!is_file(TEMPLATE_PATH . $template_dir . "/" . $page["dir_name"] . "/" . $file)) {
|
||||
die("CSS File " . $file . " not found.");
|
||||
}
|
||||
|
||||
// Add CSS Files to HTML
|
||||
$css .= '<link rel="stylesheet" type="text/css" href="http://' . APP_DOMAIN . "/templates/" . $page["dir_name"] . "/" . $file . '">';
|
||||
$css .= '<link rel="stylesheet" type="text/css" href="http://' . APP_DOMAIN . "/templates/" . $template_dir . "/" . $page["dir_name"] . "/" . $file . '">';
|
||||
}
|
||||
|
||||
$html = str_replace("%css%", $css, $html);
|
||||
@@ -51,30 +82,55 @@ class HTMLLoader {
|
||||
die($replace);
|
||||
}
|
||||
|
||||
function show() {
|
||||
function show($args = [], $showAppName = true) {
|
||||
if (!isset($this->template)) {
|
||||
$this->getTemplate();
|
||||
}
|
||||
|
||||
$template = $this->template;
|
||||
$tempalte_conf = $this->template_conf;
|
||||
$template_dir = $this->templates[$template]["dir_name"];
|
||||
|
||||
$file = file_get_contents(TEMPLATE_CONF);
|
||||
$json = json_decode($file, true);
|
||||
$page = $tempalte_conf[$this->page];
|
||||
|
||||
$page = $json[$template];
|
||||
$html = file_get_contents(TEMPLATE_PATH . $page["dir_name"] . "/" . $page["html_file"]);
|
||||
if (!is_file(TEMPLATE_PATH . $template_dir . "/" . $page["dir_name"] . "/" . $page["html_file"])) {
|
||||
$this->showError('HTML File <span class="code">' . $page["html_file"] . '</span> for page <span class="code">' . $page["name"] . '</span> in template <span class="code">' . $template . '</span> does not exists.');
|
||||
}
|
||||
|
||||
$html = file_get_contents(TEMPLATE_PATH . $template_dir . "/" . $page["dir_name"] . "/" . $page["html_file"]);
|
||||
|
||||
if ($showAppName) {
|
||||
$call = new APICall("settings/appname.php");
|
||||
$response = $call->response;
|
||||
if (isset($response["error"])) {
|
||||
$this->showError("Failed to get Application Name: API Returned an error: " . $response["error_text"]);
|
||||
}
|
||||
|
||||
$app_name = $response["data"]["application_name"];
|
||||
|
||||
$html = str_replace("%appname%", $app_name, $html);
|
||||
}
|
||||
|
||||
// Get CSS
|
||||
$css = "";
|
||||
|
||||
foreach ($page["css_files"] as $file) {
|
||||
// Check if File exists
|
||||
if (!is_file(TEMPLATE_PATH . $page["dir_name"] . "/" . $file)) {
|
||||
if (!is_file(TEMPLATE_PATH . $template_dir . "/" . $page["dir_name"] . "/" . $file)) {
|
||||
$this->showError('CSS File <span class="code">' . $file . '</span> for Template <span class="code">' . $this->template . '</span> in <span class="code">' . __FILE__ . "</span> not found.");
|
||||
}
|
||||
|
||||
// Add CSS Files to HTML
|
||||
$css .= '<link rel="stylessheet" text="text/css" href="' . APP_DOMAIN . "/templates/" . $page["dir_name"] . "/" . $file . '">';
|
||||
$css .= '<link rel="stylessheet" text="text/css" href="' . APP_DOMAIN . "/templates/" . $template_dir . "/" . $page["dir_name"] . "/" . $file . '">';
|
||||
}
|
||||
|
||||
$html = str_replace("%css%", $css, $html);
|
||||
|
||||
// Insert Args
|
||||
foreach ($args as $key => $value) {
|
||||
$html = str_replace($key, $value, $html);
|
||||
}
|
||||
|
||||
die($html);
|
||||
}
|
||||
}
|
||||
@@ -8,3 +8,40 @@ require "main.php";
|
||||
// Init GB Class
|
||||
$gb = new gb(true);
|
||||
|
||||
// Load HTMLLoader Library
|
||||
require FRONTEND_PATH . "html_loader.php";
|
||||
$htmlLoader = new HTMLLoader();
|
||||
|
||||
// Build Entry Page
|
||||
$htmlLoader->setPage("entries_frontend");
|
||||
|
||||
// Get entrys
|
||||
$call = new APICall("entry/get.php");
|
||||
$response = $call->response;
|
||||
|
||||
if ($call->getError() !== false) {
|
||||
$htmlLoader->showError("Entry API Returned an error: " . $call->getError());
|
||||
}
|
||||
|
||||
if ($response["data"]["empty"]) {
|
||||
$html_block = "<p>There aren'n any entrys yet. Be the first one!</p>";
|
||||
}else{
|
||||
$entrys = json_decode($response["data"]["entrys"], true);
|
||||
|
||||
$html_block = "";
|
||||
foreach($entrys as $entry) {
|
||||
$name = $entry["name"];
|
||||
$text = $entry["text"];
|
||||
$date = $entry["date"];
|
||||
|
||||
$html_block .= '
|
||||
<div class="entry">
|
||||
<h3 class="md-typescale-display-small">' . $name . '</h3>
|
||||
<p id="date">' . $date . '</p>
|
||||
<p>' . $text . '</p>
|
||||
</div>
|
||||
';
|
||||
}
|
||||
}
|
||||
|
||||
$htmlLoader->show(["%entrys%" => $html_block]);
|
||||
+39
-3
@@ -10,8 +10,9 @@ class gb {
|
||||
|
||||
// Define Paths
|
||||
define("APP_DOMAIN", $_SERVER["SERVER_NAME"]);
|
||||
define("APP_PATH", __DIR__ . "/..");
|
||||
define("APP_PATH", __DIR__ . "/../");
|
||||
define("FRONTEND_PATH", __DIR__ . "/");
|
||||
define("API_DIR", __DIR__ . "/../api/");
|
||||
define("TEMPLATE_PATH", FRONTEND_PATH . "templates/");
|
||||
define("TEMPLATE_CONF", TEMPLATE_PATH . "templates.json");
|
||||
|
||||
@@ -27,7 +28,42 @@ class gb {
|
||||
$html = new HTMLLoader();
|
||||
|
||||
// Set template to Setup an show it
|
||||
$html->setTemplate("setup");
|
||||
$html->show();
|
||||
$html->setTemplate("standard");
|
||||
$html->setPage("setup");
|
||||
$html->show([], false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Internal API Call Library
|
||||
class APICall {
|
||||
public $response;
|
||||
private $error;
|
||||
|
||||
function __construct($path, $data = []) {
|
||||
// Set $internal to true so the api return does not go to the browser
|
||||
$internal = true;
|
||||
|
||||
// Check Path
|
||||
if (!is_file(API_DIR . $path)) {
|
||||
$this->error = "API Path invalid.";
|
||||
return false;
|
||||
}
|
||||
|
||||
// Call API
|
||||
require API_DIR . $path;
|
||||
|
||||
// Get return from the API Library
|
||||
$response = $api->getAnswer();
|
||||
|
||||
$this->response = $response;
|
||||
}
|
||||
|
||||
function getError() {
|
||||
if (isset($this->error)) {
|
||||
return $this->error;
|
||||
}else{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
Whitespace-only changes.
Whitespace-only changes.
@@ -0,0 +1,157 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Document</title>
|
||||
|
||||
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@24,400,0,0">
|
||||
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@400;500;700&display=swap" rel="stylesheet">
|
||||
<script type="importmap">
|
||||
{
|
||||
"imports": {
|
||||
"@material/web/": "https://esm.run/@material/web/"
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<script type="module">
|
||||
import '@material/web/all.js';
|
||||
import { styles as typescaleStyles } from '@material/web/typography/md-typescale-styles.js';
|
||||
|
||||
document.adoptedStyleSheets.push(typescaleStyles.styleSheet);
|
||||
</script>
|
||||
<style>
|
||||
:root {
|
||||
--md-sys-color-primary: rgb(58, 58, 255);
|
||||
--active-menu-point-color: rgb(116, 148, 250);
|
||||
--md-sys-color-surface-container: rgb(223, 228, 255);
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.layout {
|
||||
display: flex;
|
||||
height: 100vh;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.sidebar {
|
||||
flex: 0 0 280px;
|
||||
width: 280px;
|
||||
overflow: hidden;
|
||||
background: var(--md-sys-color-surface-container);
|
||||
border-right: 1px solid var(--md-sys-color-outline-variant);
|
||||
transition: flex-basis .2s ease, width .2s ease;
|
||||
padding: 10px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.sidebar-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 12px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.sidebar md-list {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
md-list-item.active {
|
||||
background-color: var(--active-menu-point-color);
|
||||
border-radius: 28px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
md-list-item {
|
||||
border-radius: 28px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.sidebar.collapsed {
|
||||
flex-basis: 58px;
|
||||
width: 58x;
|
||||
}
|
||||
|
||||
.sidebar.collapsed .title,
|
||||
.sidebar.collapsed .label {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.content {
|
||||
flex: 1;
|
||||
padding: 24px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
@media (max-width: 720px) {
|
||||
body {
|
||||
overflow-x: hidden;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="layout">
|
||||
<aside class="sidebar" id="sidebar">
|
||||
<div class="sidebar-header">
|
||||
<md-icon-button id="toggle" aria-label="Menü ein-/ausklappen">
|
||||
<md-icon>menu</md-icon>
|
||||
</md-icon-button>
|
||||
<span class="md-typescale-body-large title">%appname%</span>
|
||||
</div>
|
||||
|
||||
<md-list>
|
||||
<md-list-item type="link" href="/admin/" class="active">
|
||||
<md-icon slot="start">dashboard</md-icon>
|
||||
<span class="label">Overview</span>
|
||||
</md-list-item>
|
||||
<md-list-item type="link" href="/admin/settings.php">
|
||||
<md-icon slot="start">settings</md-icon>
|
||||
<span class="label">Settings</span>
|
||||
</md-list-item>
|
||||
</md-list>
|
||||
</aside>
|
||||
|
||||
<main class="content">
|
||||
<h1 class="md-typescale-display-large">%appname%</h1>
|
||||
<h3 class="md-typescale-display-medium">Entrys</h3>
|
||||
<md-list>
|
||||
<md-list-item>
|
||||
<div slot="headline">Cucumber</div>
|
||||
<div slot="supporting-text">Cucumbers are long green fruits that are just as long as this multi-line description</div>
|
||||
</md-list-item>
|
||||
</md-list>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<script type="module">
|
||||
const sidebar = document.getElementById('sidebar');
|
||||
const items = sidebar.querySelectorAll('md-list-item');
|
||||
|
||||
const mq = window.matchMedia('(max-width: 720px)');
|
||||
|
||||
const applyBreakpoint = () => {
|
||||
sidebar.classList.toggle('collapsed', mq.matches);
|
||||
};
|
||||
|
||||
applyBreakpoint();
|
||||
mq.addEventListener('change', applyBreakpoint);
|
||||
|
||||
document.getElementById('toggle').addEventListener('click', () => {
|
||||
sidebar.classList.toggle('collapsed');
|
||||
});
|
||||
|
||||
items.forEach(item => {
|
||||
item.addEventListener('click', () => {
|
||||
items.forEach(i => i.classList.remove('active'));
|
||||
item.classList.add('active');
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -0,0 +1,115 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@400;500;700&display=swap" rel="stylesheet">
|
||||
<script type="importmap">
|
||||
{
|
||||
"imports": {
|
||||
"@material/web/": "https://esm.run/@material/web/"
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<script type="module">
|
||||
import '@material/web/all.js';
|
||||
import {styles as typescaleStyles} from '@material/web/typography/md-typescale-styles.js';
|
||||
|
||||
document.adoptedStyleSheets.push(typescaleStyles.styleSheet);
|
||||
</script>
|
||||
|
||||
<title>%appname% // Entries</title>
|
||||
|
||||
<style>
|
||||
:root {
|
||||
--md-sys-color-primary: rgb(58, 58, 255);
|
||||
}
|
||||
|
||||
p {
|
||||
font-family: Verdana, Geneva, Tahoma, sans-serif;
|
||||
}
|
||||
|
||||
hr {
|
||||
border: 1px solid rgb(211, 211, 211);
|
||||
}
|
||||
|
||||
.loader {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
#date {
|
||||
color: gray;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1 class="md-typescale-display-large">%appname%</h1>
|
||||
<md-filled-tonal-button id="entry_add">
|
||||
Add Entry
|
||||
</md-filled-tonal-button>
|
||||
<h2 class="md-typescale-display-medium">All Entrys</h2>
|
||||
%entrys%
|
||||
<md-dialog id="add_entry_dialog">
|
||||
<div slot="headline">
|
||||
Add entry
|
||||
</div>
|
||||
<form slot="content" method="dialog">
|
||||
<md-filled-text-field id="entry_name" label="Name"></md-filled-text-field><br><br>
|
||||
<md-filled-text-field id="entry_text" label="Text" rows="5" style="resize: vertical;" type="textarea"></md-filled-text-field>
|
||||
<div class="loader" id="loader" style="display: none;">
|
||||
<md-circular-progress id="add_entry_load" indeterminate></md-circular-progress>
|
||||
</div>
|
||||
<p id="entry_return"></p>
|
||||
</form>
|
||||
<div slot="actions">
|
||||
<md-filled-button id="entry_submit">Submit</md-filled-button>
|
||||
<md-text-button id="entry_close">Close</md-text-button>
|
||||
</div>
|
||||
</md-dialog>
|
||||
<script>
|
||||
document.getElementById("entry_add").addEventListener("click", function() {
|
||||
document.getElementById("add_entry_dialog").setAttribute("open", "");
|
||||
});
|
||||
|
||||
document.getElementById("entry_close").addEventListener("click", function() {
|
||||
document.getElementById("add_entry_dialog").removeAttribute("open");
|
||||
});
|
||||
|
||||
document.getElementById("entry_submit").addEventListener("click", function() {
|
||||
document.getElementById("entry_name").style.display = "none";
|
||||
document.getElementById("entry_text").style.display = "none";
|
||||
document.getElementById("entry_submit").style.display = "none";
|
||||
document.getElementById("entry_close").style.display = "none";
|
||||
|
||||
document.getElementById("loader").style.display = "flex";
|
||||
|
||||
name = document.getElementById("entry_name").value;
|
||||
text = document.getElementById("entry_text").value;
|
||||
|
||||
fetch("/api/entry/add.php", {
|
||||
method: "POST",
|
||||
body: JSON.stringify({
|
||||
name: name,
|
||||
text: text
|
||||
})
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
document.getElementById("loader").style.display = "none";
|
||||
if (data.status !== 200) {
|
||||
document.getElementById("entry_return").innerHTML = "API returned an error: " + data.error_text;
|
||||
document.getElementById("entry_close").style.display = "block";
|
||||
}else{
|
||||
document.getElementById("entry_return").innerHTML = "Success! Maybe your entry must be aproved by the owner.";
|
||||
document.getElementById("entry_close").style.display = "block";
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
document.getElementById("loader").style.display = "none";
|
||||
document.getElementById("entry_return").innerHTML = "There was an error: " + error;
|
||||
document.getElementById("entry_close").style.display = "block";
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
File renamed without changes.
File renamed without changes.
Executable
+76
@@ -0,0 +1,76 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>%appname% // Login</title>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@400;500;700&display=swap" rel="stylesheet">
|
||||
<script type="importmap">
|
||||
{
|
||||
"imports": {
|
||||
"@material/web/": "https://esm.run/@material/web/"
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<script type="module">
|
||||
import '@material/web/all.js';
|
||||
import {styles as typescaleStyles} from '@material/web/typography/md-typescale-styles.js';
|
||||
|
||||
document.adoptedStyleSheets.push(typescaleStyles.styleSheet);
|
||||
</script>
|
||||
<style>
|
||||
.page-content {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
text-align: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.center {
|
||||
display: block;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="page-content">
|
||||
<div class="center">
|
||||
<h1 class="md-typescale-display-large">%appname%</h1>
|
||||
<h3 class="md-typescale-display-medium">Admin Panel Login</h3><br><br>
|
||||
<p class="md-typescale-body-medium" id="error_msg" style="display: none;"></p>
|
||||
<md-filled-text-field type="text" id="login_username" placeholder="Username"></md-filled-text-field><br><br>
|
||||
<md-filled-text-field type="password" id="login_password" placeholder="Password"></md-filled-text-field><br><br>
|
||||
<md-filled-button id="login_button">Login</md-filled-button>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
document.getElementById("login_button").addEventListener("click", function() {
|
||||
var username = document.getElementById("login_username").value;
|
||||
var password = document.getElementById("login_password").value;
|
||||
|
||||
fetch("/api/auth/login.php", {
|
||||
method:"POST",
|
||||
body: JSON.stringify({
|
||||
username: username,
|
||||
password: password
|
||||
}),
|
||||
headers: {
|
||||
"Content-type": "application/json; charset=UTF-8"
|
||||
}
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.status == 200) {
|
||||
window.location.reload();
|
||||
}else{
|
||||
document.getElementById("error_msg").innerHTML = data.error_text;
|
||||
document.getElementById("error_msg").style.display = "block";
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
document.getElementById("error_msg").innerHTML = error;
|
||||
document.getElementById("error_msg").style.display = "block";
|
||||
})
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -66,6 +66,18 @@
|
||||
<md-filled-button id="close-button">Close</md-filled-button>
|
||||
</div>
|
||||
</md-dialog>
|
||||
<md-dialog id="success-dialog">
|
||||
<div slot="headline">
|
||||
Success!
|
||||
</div>
|
||||
<form slot="content" method="dialog" id="error-dialog-text">
|
||||
Your Guestbook is finaly configurated! You can find the admin Panel on <span id="success-admin-url"></span>.
|
||||
</form>
|
||||
<div slot="actions">
|
||||
<md-filled-button id="success-dialog-home">Open Guestbook</md-filled-button>
|
||||
<md-filled-button id="success-dialog-admin">Open Admin Panel</md-filled-button>
|
||||
</div>
|
||||
</md-dialog>
|
||||
<script>
|
||||
if (window.location.protocol == "http:") {
|
||||
document.getElementById("http-dialog").setAttribute("open", "");
|
||||
@@ -80,7 +92,15 @@
|
||||
|
||||
document.getElementById("close-button").addEventListener("click", function() {
|
||||
document.getElementById("error-dialog").removeAttribute("open");
|
||||
})
|
||||
});
|
||||
|
||||
document.getElementById("success-dialog-home").addEventListener("click", function() {
|
||||
window.location.reload();
|
||||
});
|
||||
|
||||
document.getElementById("success-dialog-admin").addEventListener("click", function() {
|
||||
window.location.href = "/admin";
|
||||
});
|
||||
|
||||
function checkSetup() {
|
||||
const username = document.getElementById("setup-username").value;
|
||||
@@ -108,8 +128,11 @@
|
||||
}
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => function() {
|
||||
if (data.status !== 200) {
|
||||
.then(data => {
|
||||
if (data.status == 200) {
|
||||
document.getElementById("success-admin-url").innerHTML = window.location.href + "admin";
|
||||
document.getElementById("success-dialog").setAttribute("open", "");
|
||||
}else{
|
||||
console.error("Server returned following message: " + data.error);
|
||||
|
||||
document.getElementById("error-dialog-text").innerHTML = data.display_error;
|
||||
Executable
+38
@@ -0,0 +1,38 @@
|
||||
{
|
||||
"error":{
|
||||
"name":"error",
|
||||
"dir_name":"error",
|
||||
"html_file":"error.html",
|
||||
"css_files":[
|
||||
"error.css"
|
||||
]
|
||||
},
|
||||
|
||||
"setup":{
|
||||
"name":"setup",
|
||||
"dir_name":"setup",
|
||||
"html_file":"setup.html",
|
||||
"css_files":[]
|
||||
},
|
||||
|
||||
"entries_frontend":{
|
||||
"name":"entries_frontend",
|
||||
"dir_name":"entries_frontend",
|
||||
"html_file":"entries_frontend.html",
|
||||
"css_files":[]
|
||||
},
|
||||
|
||||
"login":{
|
||||
"name":"login",
|
||||
"dir_name":"login",
|
||||
"html_file":"login.html",
|
||||
"css_files":[]
|
||||
},
|
||||
|
||||
"admin_home":{
|
||||
"name":"admin_home",
|
||||
"dir_name":"admin_home",
|
||||
"html_file":"home.html",
|
||||
"css_files":[]
|
||||
}
|
||||
}
|
||||
@@ -1,18 +1,6 @@
|
||||
{
|
||||
"error":{
|
||||
"name":"error",
|
||||
"dir_name":"error",
|
||||
"html_file":"error.html",
|
||||
"css_files":[
|
||||
"error.css"
|
||||
]
|
||||
},
|
||||
"setup":{
|
||||
"name":"setup",
|
||||
"dir_name":"setup",
|
||||
"html_file":"setup.html",
|
||||
"css_files":[
|
||||
"setup.css"
|
||||
]
|
||||
"standard":{
|
||||
"name":"Standard Template",
|
||||
"dir_name":"standard"
|
||||
}
|
||||
}
|
||||
+23
-4
@@ -6,9 +6,28 @@
|
||||
|
||||
//echo $_SERVER["HTTP_X_API_KEY"];
|
||||
|
||||
$string = '{"user":"marc", "auth":true}';
|
||||
$secret = "281361f952279bd9530734c67ed04aed2756f0fe00cb998cd6c28324f491484c";
|
||||
//$string = '{"user":"marc", "auth":true}';
|
||||
//$secret = "281361f952279bd9530734c67ed04aed2756f0fe00cb998cd6c28324f491484c";
|
||||
|
||||
echo "Hash: " . hash_hmac("sha256", $string, $secret);
|
||||
//echo "Hash: " . hash_hmac("sha256", $string, $secret);
|
||||
|
||||
echo "Decode: " . hash_equals($string, $secret);
|
||||
//echo "Decode: " . hash_equals($string, $secret);
|
||||
|
||||
//print_r(PDO::getAvailableDrivers());
|
||||
|
||||
//print_r(json_decode('{"entrys":[{"name":"marc"}]}', true));
|
||||
|
||||
//print_r(explode(".", "jakob.stinkt"));
|
||||
|
||||
//var_dump(extension_loaded("pdo_sqlite"));
|
||||
//var_dump(extension_loaded("sqlite3"));
|
||||
|
||||
class test {
|
||||
private $test;
|
||||
|
||||
function __construct() {
|
||||
var_dump(isset($this->test));
|
||||
}
|
||||
}
|
||||
|
||||
new test();
|
||||
Reference in new issue
Block a user