Added loging page

This commit is contained in:
Lukas Forsberg 2026-01-26 22:24:48 +01:00
parent 38ff44f2e9
commit 79b5737bcb
9 changed files with 88 additions and 133 deletions

View File

@ -1,11 +0,0 @@
{
"httpPort" : 3010,
"services": [
["Calibre", " calibre-server.service"],
["File Server", "file-server.service"],
["Jellyfin", "jellyfin.service"],
["DuckDNS", "duckdns.service"],
["Wiki.js", "wiki.service"],
["qBitTorrent", "qbittorrent-nox@lukas.service"]
]
}

View File

@ -1,7 +1,3 @@
{ {
"httpPort" : 3010, "httpPort" : 3010
"services": [
["Cups", "cups.service"],
["Waydriod", "waydroid-container.service"]
]
} }

View File

@ -1,10 +1,38 @@
<script> <script lang="ts">
let user = ''; import { API_BASE } from '$lib/config';
let password = '';
let loading = false; let user : any = '';
let error = ''; let password : any = '';
let loading : any = false;
let error : any = '';
async function handleLogin() {
let error : any = '';
let loading : Boolean = true;
try {
const res = await fetch(`${API_BASE}/api/shadowrun/characters`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
username: user,
password: password,
})
});
if (res.ok) {
characters = await res.json();
}
alert('Logged in!');
} catch (e) {
error = e.message;
} finally {
loading = false;
}
}
</script> </script>
<form class="login" on:submit|preventDefault={handleLogin}> <form class="login" on:submit|preventDefault={handleLogin}>
@ -29,25 +57,6 @@
</button> </button>
</form> </form>
<script>
async function handleLogin() {
error = '';
loading = true;
try {
// placeholder well add real auth next
if user !== 'test@test.com' || password !== '1234') {
throw new Error('Invalid credentials');
}
alert('Logged in!');
} catch (e) {
error = e.message;
} finally {
loading = false;
}
}
</script>
<style> <style>
.login { .login {

View File

@ -1,14 +1,7 @@
#ifndef __DATABASE_H__ #ifndef __DATABASE_H__
#define __DATABASE_H__ #define __DATABASE_H__
#include "sqlite3.h"
#include <string> #include <string>
#include <vector>
#include <variant>
#include <optional>
#include <set>
#include <map>
#include "crow.h"
#include "sqlite_orm.h" #include "sqlite_orm.h"
#include "ShadowrunDb.hpp" #include "ShadowrunDb.hpp"
#include "loginDb.hpp" #include "loginDb.hpp"

View File

@ -1,60 +1,41 @@
#include <fstream> #include <fstream>
#include <format>
#include "json.hpp" #include "json.hpp"
#include "json_settings.h" #include "json_settings.h"
#include "crow/logging.h"
#include "utils.hpp"
using namespace std; using namespace std;
using json = nlohmann::json; using json = nlohmann::json;
using namespace::AppSettings;
expected<AppSettings, string> AppSettings::loadAppSettings() { Settings AppSettings::deafult(){
constexpr char settings_file[] = "static/settings.json"; return Settings {
ifstream file(settings_file); .httpPort = 3010
if (!file.is_open()) {
return unexpected(format("Failed to open {}",settings_file));
}
// Parse the JSON
json j;
try {
file >> j;
} catch (const json::parse_error& e) {
return unexpected(format("Failed to parse JSON {}",e.what()));
}
if (!j.contains("services") || !j["services"].is_array()) {
return unexpected("JSON does not contain an array called 'services'");
}
AppSettings settings;
for (const auto& item : j["services"]) {
if (item.is_array() && item.size() == 2) {
Service service = {
item[0].get<std::string>(),
item[1].get<std::string>()
}; };
settings.services.push_back(service);
}
}
if (settings.services.empty()){
return unexpected("'services' array in JSON file is empty");
}
if (j.contains("httpPort")) {
settings.httpPort = j["httpPort"].get<int>();
} else {
settings.httpPort = {};
}
return settings;
} }
optional<std::string> AppSettings::getId(string_view name){ Settings AppSettings::load() {
for (auto& service : services) { ifstream file(settingsFile);
if(service.name == name) { if (!file.is_open()) {
return service.service; CROW_LOG_ERROR << "Failed to load settings file" << settingsFile << " Loading default settings";
return AppSettings::deafult();
} }
std::stringstream buffer;
buffer << file.rdbuf(); // Read the whole file into the stringstream
std::string fileContents = buffer.str(); // Convert to std::string
auto result = utils::parseJson(fileContents);
if(!result){
CROW_LOG_ERROR << "failed to parse settings file, Loading default settings";
return AppSettings::deafult();
}
try {
return result.value().get<Settings>();
} catch (...) {
CROW_LOG_ERROR << "failed to parse settings file, Loading default settings";
return AppSettings::deafult();
} }
return {};
} }

View File

@ -1,24 +1,18 @@
#ifndef JSON_SETTINGS_H #ifndef JSON_SETTINGS_H
#define JSON_SETTINGS_H #define JSON_SETTINGS_H
#include <vector> #include "json.hpp"
#include <string>
#include <expected>
#include <optional>
#include <cstdint>
struct Service { namespace AppSettings {
std::string name;
std::string service; static constexpr char settingsFile[] = "assets/settings.json";
struct Settings {
int httpPort;
}; };
struct AppSettings { Settings load();
static std::expected<AppSettings, std::string> loadAppSettings(); Settings deafult();
std::optional<std::string> getId(std::string_view name);
std::vector<Service> services;
std::optional<uint16_t> httpPort;
};
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(Settings, httpPort);
}
#endif // JSON_SETTINGS_H #endif // JSON_SETTINGS_H

View File

@ -41,7 +41,7 @@ void initLogin(crow::SimpleApp& app)
CROW_ROUTE(app, "/login").methods("POST"_method) CROW_ROUTE(app, "/login").methods("POST"_method)
([](const crow::request& req) { ([](const crow::request& req) {
auto body = utils::parseBody(req.body); nlohmann::json body = nlohmann::json::parse(req.body); // parse JSON from HTTP body
if (!body.empty()) if (!body.empty())
return crow::response(400, "Invalid JSON"); return crow::response(400, "Invalid JSON");
@ -50,8 +50,8 @@ void initLogin(crow::SimpleApp& app)
if(usenameIt == body.end() || passwordIt == body.end()) if(usenameIt == body.end() || passwordIt == body.end())
return crow::response(400, "No username or password in body"); return crow::response(400, "No username or password in body");
const std::string& username = usenameIt->second; const std::string& username = *usenameIt;
const std::string& password = passwordIt->second; const std::string& password = *passwordIt;
// Validate credentials // Validate credentials
auto sessionId = loginUser(username, password); auto sessionId = loginUser(username, password);
@ -67,6 +67,8 @@ void initLogin(crow::SimpleApp& app)
"; HttpOnly; Path=/; SameSite=Strict" "; HttpOnly; Path=/; SameSite=Strict"
// add "; Secure" when using HTTPS // add "; Secure" when using HTTPS
); );
res.set_header("Access-Control-Allow-Credentials", "true");
res.set_header("Access-Control-Allow-Origin", "http://localhost:5173");
res.body = "Logged in"; res.body = "Logged in";
return res; return res;

View File

@ -1,6 +1,5 @@
#include <crow.h> #include <crow.h>
#include <string> #include <string>
#include <optional>
#include "json_settings.h" #include "json_settings.h"
#include "utils.hpp" #include "utils.hpp"
#include "login.hpp" #include "login.hpp"
@ -43,26 +42,17 @@ int main() {
return crow::response(200, "text/html", data); return crow::response(200, "text/html", data);
}); });
const uint16_t defaultPort = 3010; auto settings = AppSettings::load();
uint16_t httpPort = defaultPort; auto opt_isPortOpen = utils::isLocalPortOpen(settings.httpPort);
{
auto opt_settings = AppSettings::loadAppSettings();
if (opt_settings.has_value()){
auto& settings = opt_settings.value();
httpPort = settings.httpPort.value_or(defaultPort);
} else {
CROW_LOG_ERROR << "failed to load settings : " << opt_settings.error();
}
auto opt_isPortOpen = utils::isLocalPortOpen(httpPort);
if (opt_isPortOpen.has_value()){ if (opt_isPortOpen.has_value()){
if (opt_isPortOpen.value()){ if (opt_isPortOpen.value()){
CROW_LOG_ERROR << "Local port : " << httpPort << " is already open"; CROW_LOG_ERROR << "Local port : " << settings.httpPort << " is already open";
return 1;
} }
} }
else { else {
CROW_LOG_ERROR << "failed to check if local port is open : " << opt_isPortOpen.error(); CROW_LOG_ERROR << "failed to check if local port is open : " << opt_isPortOpen.error();
} return 1;
} }
shadowrun::initApi(app); shadowrun::initApi(app);
@ -110,5 +100,5 @@ int main() {
}); });
app.loglevel(crow::LogLevel::INFO); app.loglevel(crow::LogLevel::INFO);
app.bindaddr("0.0.0.0").port(httpPort).multithreaded().run(); app.bindaddr("0.0.0.0").port(settings.httpPort).multithreaded().run();
} }

View File

@ -2,6 +2,7 @@
#include <optional> #include <optional>
#include "databasepool.h" #include "databasepool.h"
#include "utils.hpp" #include "utils.hpp"
#include "crow/logging.h"
using namespace std; using namespace std;
using namespace sqlite_orm; using namespace sqlite_orm;