Enhance API functionality: add token generation methods, implement entry management, and improve setup process with settings storage

This commit is contained in:
marc-go committed 2026-10-06 14:46:25 +02:00
1 parent 8ef5f7a941
commit 9316818753
9 files changed
+248 -25

No files matched your search

+24 -4
View File
@@ -28,7 +28,7 @@ class gbAPI {
return parse_ini_file(APP_PATH . ".env"); return parse_ini_file(APP_PATH . ".env");
} }
function generateToken($username) { function generateCookieToken($username) {
$config = $this->getConfig(); $config = $this->getConfig();
// Generate Token // Generate Token
@@ -37,7 +37,21 @@ class gbAPI {
"auth" => true "auth" => true
]; ];
$string = json_encode($payload); $string = json_encode($payload);
$secret = $config["TOKEN_SIGNATURE"]; $secret = $config["COOKIE_TOKEN_SIGNATURE"];
return hash_hmac("sha256", $string, $secret);
}
function generateAPIToken($username) {
$config = $this->getConfig();
// Generate Token
$payload = [
"user" => $username,
"auth" => true
];
$string = json_encode($payload);
$secret = $config["API_TOKEN_SIGNATURE"];
return hash_hmac("sha256", $string, $secret); return hash_hmac("sha256", $string, $secret);
} }
@@ -83,9 +97,11 @@ class gbAPI {
} }
function dbCommand($command, $expectResult, $stmtArgsRequired = false, $stmtArgs = []) { function dbCommand($command, $expectResult, $stmtArgsRequired = false, $stmtArgs = []) {
$db_path = APP_PATH . "database.db"; $config = $this->getConfig();
$db_name = $config["DB_NAME"];
$db_path = APP_PATH . $db_name;
$db = new PDO("sqlite: " . $db_path); $db = new PDO("sqlite:" . $db_path);
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$stmt = $db->prepare($command); $stmt = $db->prepare($command);
@@ -97,4 +113,8 @@ class gbAPI {
return $result; return $result;
} }
} }
function getSetting() {
}
} }
+23
View File
@@ -0,0 +1,23 @@
<?php
// Load Main Library
require "../api.php";
$api = new gbAPI(false);
if ($_SERVER["REQUEST_METHOD"] !== "POST") {
$api->answer(400, [
"error" => "false_request_method",
"error_text" => "Only POST allowed"
]);
}
$input = json_decode(file_get_contents("php://input"), true);
if (!isset($input["name"]) || !isset($input["text"])) {
$api->answer(400, [
"error" => "missing_fields",
"error_text" => "Some fields are missing"
]);
}
$api->getSetting("");
+37
View File
@@ -0,0 +1,37 @@
<?php
// Load Main Library
require "../api.php";
$api = new gbAPI(false);
// Get Entrys
$command = "SELECT * FROM entrys WHERE status = :status";
$result = $api->dbCommand($command, true, true, [":status" => 1]);
$entrys = [];
if (!$result) {
$api->answer(200, [
"entrys" => [],
"empty" => true
]);
}
foreach($result as $row) {
$entry_name = $row["name"];
$entry_text = $row["text"];
$entry = [
"name" => $entry_name,
"text" => $entry_text
];
$entrys[] = $entry;
}
$json = json_encode($entrys);
$api->answer(200, [
"entrys" => $entrys,
"empty" => false
]);
+39 -1
View File
@@ -21,6 +21,14 @@ if (!isset($input["username"]) || !isset($input["password"]) || !isset($input["p
]); ]);
} }
// 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."
]);
}
$username = $input["username"]; $username = $input["username"];
$password = $input["password"]; $password = $input["password"];
$password_repeat = $input["password_repeat"]; $password_repeat = $input["password_repeat"];
@@ -56,5 +64,35 @@ $command = "INSERT INTO users (username, password, owner) VALUES (:username, :pa
$stmt = $db->prepare($command); $stmt = $db->prepare($command);
$stmt->execute([":username" => $username, ":password" => $hash, ":owner" => 1]); $stmt->execute([":username" => $username, ":password" => $hash, ":owner" => 1]);
$api->answer(200);
// INSERT SETTINGS
$command = "INSERT INTO settings (name, value) VALUES (:name, :value)";
$settings = [
":application_name" => "",
":allow_html" => "false",
":approve_entrys" => "true",
":allow_new_entrys" => "true"
];
foreach ($settings as $key => $value) {
$stmt = $db->prepare($command);
$stmt->execute([$key => $value]);
}
// WRITE .env AND GENERATE SECRETS
$env = "";
$cookie_token = bin2hex(random_bytes(32));
$env .= "COOKIE_TOKEN_SIGNATURE=" . $cookie_token;
$api_token = bin2hex(random_bytes(32));
$env .= "API_TOKEN_SIGNATURE=" . $api_token;
$env .= "DB_FILE=database.db";
file_put_contents(APP_PATH . ".env", $env);
// RETURN SUCCESS MESSAGE
$api->answer(200);
BIN
View File
Binary file not shown.
+5
View File
@@ -12,3 +12,8 @@ CREATE TABLE IF NOT EXISTS "entrys" (
"status" INTEGER NOT NULL DEFAULT 0 "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
);
+18 -12
View File
@@ -18,20 +18,26 @@ $htmlLoader->setTemplate("entrys_frontend");
$url = "http://" . APP_DOMAIN . "/api/entrys/get.php"; $url = "http://" . APP_DOMAIN . "/api/entrys/get.php";
$response = file_get_contents($url); $response = file_get_contents($url);
$entrys = json_decode($response, true); $response = json_decode($response, true);
$entrys = $entrys["entrys"]; if ($response["data"]["empty"]) {
$html_block = "<p>There aren'n any entrys yet. Be the first one!</p>";
}else{
$entrys = $response["data"]["entrys"];
$html_block = ""; $html_block = "";
foreach($entrys as $entry) { foreach($entrys as $entry) {
$name = $entry["name"]; $name = $entry["name"];
$text = $entry["text"]; $text = $entry["text"];
$date = $entry["date"];
$html_block .= ' $html_block .= '
<div class="entry"> <div class="entry">
<h3>' . $name . '</h3> <h3>' . $name . '</h3>
<p>' . $text . '</p> <p id="date">' . $date . '</p>
</div> <p>' . $text . '</p>
'; </div>
';
}
} }
$htmlLoader->show(["%entrys%" => $html_block]); $htmlLoader->show(["%entrys%" => $html_block]);
@@ -26,13 +26,86 @@
p { p {
font-family: Verdana, Geneva, Tahoma, sans-serif; font-family: Verdana, Geneva, Tahoma, sans-serif;
} }
hr {
border: 1px solid rgb(211, 211, 211);
}
.loader {
display: flex;
justify-content: center;
align-items: center;
}
</style> </style>
</head> </head>
<body> <body>
<h1 class="md-typescale-display-large">%appname%</h1> <h1 class="md-typescale-display-large">%appname%</h1>
<h3 class="md-typescale-display-medium">All Entrys</h3> <md-filled-tonal-button id="entry_add">
<md-filled-tonal-button>
Add Entry Add Entry
</md-filled-tonal-button> </md-filled-tonal-button>
</body> <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/entrys/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> </html>
+26 -5
View File
@@ -66,6 +66,18 @@
<md-filled-button id="close-button">Close</md-filled-button> <md-filled-button id="close-button">Close</md-filled-button>
</div> </div>
</md-dialog> </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> <script>
if (window.location.protocol == "http:") { if (window.location.protocol == "http:") {
document.getElementById("http-dialog").setAttribute("open", ""); document.getElementById("http-dialog").setAttribute("open", "");
@@ -80,7 +92,15 @@
document.getElementById("close-button").addEventListener("click", function() { document.getElementById("close-button").addEventListener("click", function() {
document.getElementById("error-dialog").removeAttribute("open"); 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() { function checkSetup() {
const username = document.getElementById("setup-username").value; const username = document.getElementById("setup-username").value;
@@ -108,14 +128,15 @@
} }
}) })
.then(response => response.json()) .then(response => response.json())
.then(data => function() { .then(data => {
if (data.status !== 200) { 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); console.error("Server returned following message: " + data.error);
document.getElementById("error-dialog-text").innerHTML = data.display_error; document.getElementById("error-dialog-text").innerHTML = data.display_error;
document.getElementById("error-dialog").setAttribute("open", ""); document.getElementById("error-dialog").setAttribute("open", "");
}else{
alert("Tres bien!");
} }
}) })
} }