login now works and files are protected
This commit is contained in:
parent
79b5737bcb
commit
fbb54b461e
@ -2,59 +2,57 @@
|
||||
|
||||
<script lang="ts">
|
||||
import { API_BASE } from '$lib/config';
|
||||
import { goto } from '$app/navigation';
|
||||
|
||||
let user : any = '';
|
||||
let password : any = '';
|
||||
let loading : any = false;
|
||||
let error : any = '';
|
||||
let error = "";
|
||||
|
||||
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();
|
||||
let Credentials = {
|
||||
username: "",
|
||||
password: "",
|
||||
}
|
||||
|
||||
alert('Logged in!');
|
||||
async function handleLogin() {
|
||||
try {
|
||||
const res = await fetch(`${API_BASE}/login`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
credentials: 'include',
|
||||
body: JSON.stringify(
|
||||
Credentials )
|
||||
});
|
||||
|
||||
if (!res.ok) {
|
||||
error = await res.text();
|
||||
return;
|
||||
}
|
||||
goto("/shadowrun")
|
||||
} catch (e) {
|
||||
error = e.message;
|
||||
} finally {
|
||||
loading = false;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<form class="login" on:submit|preventDefault={handleLogin}>
|
||||
<form class="login">
|
||||
<h2>Login</h2>
|
||||
|
||||
<label>
|
||||
User
|
||||
<input type="text" bind:value={user} required />
|
||||
<input type="text" bind:value={Credentials.username} required />
|
||||
</label>
|
||||
|
||||
<label>
|
||||
Password
|
||||
<input type="password" bind:value={password} required />
|
||||
<input type="password" bind:value={Credentials.password} required />
|
||||
</label>
|
||||
|
||||
<button on:click={handleLogin}>
|
||||
Login
|
||||
</button>
|
||||
|
||||
{#if error}
|
||||
<p class="error">{error}</p>
|
||||
{/if}
|
||||
|
||||
<button disabled={loading}>
|
||||
{loading ? 'Logging in…' : 'Login'}
|
||||
</button>
|
||||
</form>
|
||||
|
||||
|
||||
|
||||
@ -29,20 +29,21 @@ bool isLoggedIn(const crow::request& req) {
|
||||
std::optional<std::string> loginUser(const std::string& username, const std::string& password)
|
||||
{
|
||||
auto user = getVerifiedUser(username, password);
|
||||
if (user.has_value()) {
|
||||
return sessionHandler.createSession(user.value().id);
|
||||
if (user) {
|
||||
return sessionHandler.createSession(user->id);
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
void initLogin(crow::SimpleApp& app)
|
||||
{
|
||||
|
||||
//createUser("lukas", "Trollar4928");
|
||||
|
||||
CROW_ROUTE(app, "/login").methods("POST"_method)
|
||||
([](const crow::request& req) {
|
||||
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");
|
||||
|
||||
auto usenameIt = body.find("username");
|
||||
|
||||
@ -11,15 +11,27 @@ void initLogin(crow::SimpleApp& app);
|
||||
|
||||
bool isLoggedIn(const crow::request& req);
|
||||
|
||||
// lambda to be used by endpoint that requiere login
|
||||
// login_required lambda that works for any handler with arbitrary args
|
||||
inline auto login_required = [](auto handler){
|
||||
return [handler](const crow::request& req){
|
||||
return [handler](auto&&... args) -> crow::response {
|
||||
// the first argument is always crow::request
|
||||
const crow::request& req = std::get<0>(std::forward_as_tuple(args...));
|
||||
if (!isLoggedIn(req)) {
|
||||
return crow::response(401, "Login required");
|
||||
}
|
||||
return handler(req);
|
||||
|
||||
// call original handler with all arguments
|
||||
auto result = handler(std::forward<decltype(args)>(args)...);
|
||||
|
||||
// ensure crow::response return type
|
||||
if constexpr (std::is_same_v<decltype(result), crow::response>) {
|
||||
return result;
|
||||
} else {
|
||||
return crow::response(result);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
#endif // __LOGIN_H__
|
||||
@ -1,8 +1,11 @@
|
||||
#include "loginDb.hpp"
|
||||
#include "databasepool.h"
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
|
||||
extern "C" {
|
||||
#include "monocypher.h"
|
||||
}
|
||||
@ -59,8 +62,14 @@ int createUser(const std::string& username, const std::string& password){
|
||||
int64_t id;
|
||||
auto db = dbpool.acquire();
|
||||
|
||||
auto user = db->get_optional<User>(
|
||||
where(c(&User::username) == username)
|
||||
for (auto &u : db->get_all<login::User>()) {
|
||||
if (u.username == username){
|
||||
std::cout << "WTF" << std::endl;
|
||||
};
|
||||
}
|
||||
|
||||
auto user = db->get_optional<login::User>(
|
||||
where(c(&login::User::username) == username)
|
||||
);
|
||||
|
||||
if (user.has_value()) {
|
||||
@ -76,11 +85,16 @@ int createUser(const std::string& username, const std::string& password){
|
||||
|
||||
std::optional<User> getUser(const std::string& username){
|
||||
auto db = dbpool.acquire();
|
||||
auto user = db->get_optional<User>(
|
||||
where(c(&User::username) == username)
|
||||
auto user = db->get_all<login::User>(
|
||||
where(c(&login::User::username) == username)
|
||||
);
|
||||
dbpool.release(db);
|
||||
return user;
|
||||
|
||||
if(user.size() > 0){
|
||||
return user[0];
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
std::optional<User> getVerifiedUser(const std::string& username, const std::string& password){
|
||||
@ -88,7 +102,7 @@ std::optional<User> getVerifiedUser(const std::string& username, const std::stri
|
||||
if (!user.has_value())
|
||||
return {};
|
||||
|
||||
if (verifyUser(user.value(), password)){
|
||||
if (verifyUser(*user, password)){
|
||||
return user;
|
||||
}
|
||||
return {};
|
||||
|
||||
@ -3,7 +3,6 @@
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <optional>
|
||||
#include "json.hpp"
|
||||
#include "utils.hpp"
|
||||
namespace login
|
||||
|
||||
55
src/main.cpp
55
src/main.cpp
@ -7,38 +7,12 @@
|
||||
|
||||
using namespace std;
|
||||
|
||||
std::string read_file(const std::string& path) {
|
||||
std::ifstream file(path, std::ios::binary);
|
||||
if (!file) {
|
||||
throw std::runtime_error("Cannot open file: " + path);
|
||||
}
|
||||
std::ostringstream ss;
|
||||
ss << file.rdbuf();
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
// Simple MIME type detection
|
||||
std::string get_mime_type(const std::string& path) {
|
||||
if (path.ends_with(".html")) return "text/html";
|
||||
if (path.ends_with(".js")) return "text/javascript";
|
||||
if (path.ends_with(".css")) return "text/css";
|
||||
if (path.ends_with(".json")) return "application/json";
|
||||
if (path.ends_with(".svg")) return "image/svg+xml";
|
||||
if (path.ends_with(".png")) return "image/png";
|
||||
if (path.ends_with(".jpg") || path.ends_with(".jpeg")) return "image/jpeg";
|
||||
if (path.ends_with(".woff")) return "font/woff";
|
||||
if (path.ends_with(".woff2")) return "font/woff2";
|
||||
if (path.ends_with(".pdf")) return "application/pdf";
|
||||
return "application/octet-stream";
|
||||
}
|
||||
|
||||
int main() {
|
||||
crow::SimpleApp app;
|
||||
const filesystem::path build_dir = "frontend/build/"; // <-- set your build folder
|
||||
|
||||
// Root route
|
||||
CROW_ROUTE(app, "/")([&]() {
|
||||
auto data = read_file(build_dir / "index.html");
|
||||
auto data = utils::read_file(utils::build_dir / "index.html");
|
||||
return crow::response(200, "text/html", data);
|
||||
});
|
||||
|
||||
@ -63,40 +37,19 @@ int main() {
|
||||
([&](const std::string& p) {
|
||||
const filesystem::path assets_dir = "assets/"; // <-- set your build folder
|
||||
filesystem::path file_path = assets_dir / p;
|
||||
|
||||
// If file exists, serve it
|
||||
if (filesystem::exists(file_path)) {
|
||||
auto data = read_file(file_path);
|
||||
auto mime = get_mime_type(file_path.string());
|
||||
return crow::response(200, mime.c_str(), data);
|
||||
}
|
||||
|
||||
// SPA fallback: serve root index.html for unknown routes
|
||||
filesystem::path fallback = build_dir / "index.html";
|
||||
auto data = read_file(fallback);
|
||||
return crow::response(404, "text/html", data);
|
||||
return utils::getFile(file_path);
|
||||
});
|
||||
|
||||
// Catch-all route for static files and SPA fallback
|
||||
CROW_ROUTE(app, "/<path>")
|
||||
([&](const std::string& p) {
|
||||
filesystem::path file_path = build_dir / p;
|
||||
filesystem::path file_path = utils::build_dir / p;
|
||||
|
||||
// If path is a directory, serve index.html inside it
|
||||
if (filesystem::is_directory(file_path))
|
||||
file_path /= "index.html";
|
||||
|
||||
// If file exists, serve it
|
||||
if (filesystem::exists(file_path)) {
|
||||
auto data = read_file(file_path);
|
||||
auto mime = get_mime_type(file_path.string());
|
||||
return crow::response(200, mime.c_str(), data);
|
||||
}
|
||||
|
||||
// SPA fallback: serve root index.html for unknown routes
|
||||
filesystem::path fallback = build_dir / "index.html";
|
||||
auto data = read_file(fallback);
|
||||
return crow::response(404, "text/html", data);
|
||||
return utils::getFile(file_path);
|
||||
});
|
||||
|
||||
app.loglevel(crow::LogLevel::INFO);
|
||||
|
||||
@ -26,16 +26,26 @@ static std::unordered_map<std::string, std::string> parse_query_string(const std
|
||||
return params;
|
||||
}
|
||||
|
||||
static crow::response rsp(const std::string& msg){
|
||||
auto str = format("<div class='alert alert-success'>"
|
||||
"{} </div>", msg);
|
||||
return crow::response{str};
|
||||
void initApi(crow::SimpleApp& app){
|
||||
|
||||
CROW_ROUTE(app, "/assets/shadowrun/<path>")
|
||||
([&](const crow::request& req, const std::string& p) {
|
||||
if (!login::isLoggedIn(req)) {
|
||||
return crow::response(401, "Login required");
|
||||
}
|
||||
|
||||
void initApi(crow::SimpleApp& app)
|
||||
{
|
||||
const filesystem::path assets_dir = "assets/shadowrun/";
|
||||
filesystem::path file_path = assets_dir / p;
|
||||
return utils::getFile(file_path);
|
||||
});
|
||||
|
||||
CROW_ROUTE(app, "/api/shadowrun/characters")
|
||||
([&]() {
|
||||
([&](const crow::request& req) {
|
||||
|
||||
if (!login::isLoggedIn(req)) {
|
||||
return crow::response(401, "Login required");
|
||||
}
|
||||
|
||||
auto characters = getCharacters();
|
||||
auto res =
|
||||
crow::response(200, utils::toJsonArray(characters));
|
||||
@ -45,6 +55,10 @@ void initApi(crow::SimpleApp& app)
|
||||
|
||||
CROW_ROUTE(app, "/api/shadowrun/characters").methods("POST"_method)
|
||||
([](const crow::request& req) {
|
||||
if (!login::isLoggedIn(req)) {
|
||||
return crow::response(401, "Login required");
|
||||
}
|
||||
|
||||
nlohmann::json data = nlohmann::json::parse(req.body); // parse JSON from HTTP body
|
||||
auto name = data["name"];
|
||||
int id = createCharacter(name);
|
||||
@ -60,7 +74,10 @@ void initApi(crow::SimpleApp& app)
|
||||
});
|
||||
|
||||
CROW_ROUTE(app, "/api/shadowrun/characters/<int>")
|
||||
([&](int id) {
|
||||
([&](const crow::request& req, int id) {
|
||||
if (!login::isLoggedIn(req)) {
|
||||
return crow::response(401, "Login required");
|
||||
}
|
||||
auto optCharacter = getChracter(id);
|
||||
if (!optCharacter.has_value())
|
||||
return crow::response(404, "Character not found");
|
||||
@ -71,7 +88,10 @@ void initApi(crow::SimpleApp& app)
|
||||
});
|
||||
|
||||
CROW_ROUTE(app, "/api/shadowrun/characters_data/<int>")
|
||||
([&](int id) {
|
||||
([&](const crow::request& req, int id) {
|
||||
if (!login::isLoggedIn(req)) {
|
||||
return crow::response(401, "Login required");
|
||||
}
|
||||
nlohmann::json j;
|
||||
const auto characterData = getChracterData(id);
|
||||
|
||||
@ -99,6 +119,9 @@ void initApi(crow::SimpleApp& app)
|
||||
|
||||
CROW_ROUTE(app, "/api/shadowrun/characters_data/<int>").methods("POST"_method)
|
||||
([&](const crow::request& req, int id) {
|
||||
if (!login::isLoggedIn(req)) {
|
||||
return crow::response(401, "Login required");
|
||||
}
|
||||
nlohmann::json j = nlohmann::json::parse(req.body);
|
||||
|
||||
for (auto type : magic_enum::enum_values<Type>()) {
|
||||
@ -110,7 +133,6 @@ void initApi(crow::SimpleApp& app)
|
||||
|
||||
auto res = crow::response(200, "Saved Character data");
|
||||
return res;
|
||||
//return crow::response(405, ret.error());
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
@ -6,6 +6,7 @@
|
||||
#include <netinet/in.h>
|
||||
#include <netdb.h>
|
||||
#include "utils.hpp"
|
||||
#include "crow/http_response.h"
|
||||
#include <algorithm>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
@ -141,6 +142,45 @@ string currentTime(){
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
std::string read_file(const std::string& path) {
|
||||
std::ifstream file(path, std::ios::binary);
|
||||
if (!file) {
|
||||
throw std::runtime_error("Cannot open file: " + path);
|
||||
}
|
||||
std::ostringstream ss;
|
||||
ss << file.rdbuf();
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
// Simple MIME type detection
|
||||
std::string get_mime_type(const std::string& path) {
|
||||
if (path.ends_with(".html")) return "text/html";
|
||||
if (path.ends_with(".js")) return "text/javascript";
|
||||
if (path.ends_with(".css")) return "text/css";
|
||||
if (path.ends_with(".json")) return "application/json";
|
||||
if (path.ends_with(".svg")) return "image/svg+xml";
|
||||
if (path.ends_with(".png")) return "image/png";
|
||||
if (path.ends_with(".jpg") || path.ends_with(".jpeg")) return "image/jpeg";
|
||||
if (path.ends_with(".woff")) return "font/woff";
|
||||
if (path.ends_with(".woff2")) return "font/woff2";
|
||||
if (path.ends_with(".pdf")) return "application/pdf";
|
||||
return "application/octet-stream";
|
||||
}
|
||||
|
||||
crow::response getFile(const filesystem::path& file_path){
|
||||
// If file exists, serve it
|
||||
if (filesystem::exists(file_path)) {
|
||||
auto data = read_file(file_path);
|
||||
auto mime = get_mime_type(file_path.string());
|
||||
return crow::response(200, mime.c_str(), data);
|
||||
}
|
||||
|
||||
// SPA fallback: serve root index.html for unknown routes
|
||||
filesystem::path fallback = build_dir / "index.html";
|
||||
auto data = read_file(fallback);
|
||||
return crow::response(404, "text/html", data);
|
||||
}
|
||||
|
||||
std::expected<nlohmann::json, std::string> parseJson(const std::string& input) {
|
||||
try {
|
||||
return nlohmann::json::parse(input);
|
||||
|
||||
@ -5,10 +5,13 @@
|
||||
#include <string>
|
||||
#include <cstdint>
|
||||
#include <filesystem>
|
||||
#include <map>
|
||||
#include <expected>
|
||||
#include "json.hpp"
|
||||
#include "crow.h"
|
||||
|
||||
namespace utils {
|
||||
const std::filesystem::path build_dir = "frontend/build/"; // <-- set your build folder
|
||||
|
||||
std::map<std::string, std::string> parseBody(const std::string& body);
|
||||
|
||||
std::optional<std::string> getBodyName(const std::string& body);
|
||||
@ -45,8 +48,10 @@ namespace utils {
|
||||
catch (const nlohmann::json::exception& e) {
|
||||
return std::unexpected(e.what());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
std::string read_file(const std::string& path);
|
||||
crow::response getFile(const std::filesystem::path& file_path);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user