glacier ctf 25

This commit is contained in:
2025-11-28 12:20:39 +01:00
parent 4df936a8d9
commit dc96452364
51 changed files with 105301 additions and 0 deletions

View File

@@ -0,0 +1,89 @@
<?php
session_start();
header("Content-Type: application/json");
$start = microtime(true);
define("TODOS", "/tmp/todos");
define("USERS", "/tmp/users.json");
define("SESS", "LOGIN_ID");
if(!file_exists(USERS)) file_put_contents(USERS, "[]");
if(!is_dir(TODOS)) mkdir(TODOS);
$res = array();
$data = array();
$status = 1;
$path = $_GET["path"];
if($path === "/todos/list") {
$isLoggedIn = isset($_SESSION[SESS]);
if(!$isLoggedIn) goto fail;
$user = $_SESSION[SESS];
if(!file_exists(TODOS . "/" . $user)) file_put_contents(TODOS . "/" . $user, "[]");
$todos = json_decode(file_get_contents(TODOS . "/" . $user), true);
$data["todos"] = array_values($todos);
} elseif($path === "/todos/add") {
$isLoggedIn = isset($_SESSION[SESS]);
if(!$isLoggedIn) goto fail;
$user = $_SESSION[SESS];
if(!file_exists(TODOS . "/" . $user)) file_put_contents(TODOS . "/" . $user, "[]");
$todos = json_decode(file_get_contents(TODOS . "/" . $user));
$name = isset($_POST["name"]) ? filter_input(INPUT_POST, "name") : '';
$desc = isset($_POST["desc"]) ? filter_input(INPUT_POST, "desc") : '';
$todos[] = array(
"id" => uniqid(),
"name" => $name,
"desc" => $desc
);
file_put_contents(TODOS . "/" . $user, json_encode(array_values($todos)));
} elseif($path === "/todos/remove") {
$isLoggedIn = isset($_SESSION[SESS]);
if(!$isLoggedIn) goto fail;
$user = $_SESSION[SESS];
if(!file_exists(TODOS . "/" . $user)) file_put_contents(TODOS . "/" . $user, "[]");
$todos = json_decode(file_get_contents(TODOS . "/" . $user));
$id = isset($_POST["id"]) ? filter_input(INPUT_POST, "id") : '';
file_put_contents(TODOS . "/" . $user, json_encode(array_values(array_filter($todos, function($item) use($id) {
return $item->id !== $id;
}))));
} elseif($path === "/account/info") {
$isLoggedIn = isset($_SESSION[SESS]);
$data["loggedIn"] = $isLoggedIn;
$data["username"] = $_SESSION[SESS];
} elseif($path === "/account/login") {
$username = isset($_POST["username"]) ? filter_input(INPUT_POST, "username") : '';
$password = isset($_POST["password"]) ? filter_input(INPUT_POST, "password") : '';
$users = json_decode(file_get_contents(USERS));
foreach($users as $user)
if($user->username === $username && password_verify($password, $user->password))
goto valid_login;
goto fail;
valid_login:
$_SESSION[SESS] = $username;
} elseif($path === "/account/register") {
$username = isset($_POST["username"]) ? filter_input(INPUT_POST, "username") : '';
$password = isset($_POST["password"]) ? filter_input(INPUT_POST, "password") : '';
$users = json_decode(file_get_contents(USERS));
foreach($users as $user)
if($user->username === $username) goto fail;
$users[] = array(
"username" => $username,
"password" => password_hash($password, PASSWORD_DEFAULT)
);
file_put_contents(USERS, json_encode($users));
} else {
http_response_code(404);
}
goto end;
fail:
http_response_code(500);
$status = 0;
end:
$end = microtime(true);
$res["data"] = $data;
$res["success"] = $status;
$res["exec_time"] = $end - $start;
echo json_encode($res);

View File

@@ -0,0 +1,81 @@
body {
margin: 0;
font-family: 'Segoe UI', sans-serif;
background: linear-gradient(to bottom, #e0f7fa, #80deea);
background-image: url('/assets/img/bg.jpg');
background-size: cover;
color: #fff;
min-height: 100vh;
backdrop-filter: blur(0px);
}
.container {
max-width: 600px;
margin: 5rem auto;
background: rgba(0, 60, 100, 0.7);
padding: 2rem;
border-radius: 15px;
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.3);
}
h1 {
text-align: center;
margin-bottom: 2rem;
}
input {
width: 100%;
padding: 0.7rem;
margin: 0.5rem 0;
border: none;
border-radius: 8px;
font-size: 1rem;
}
button {
background: #4dd0e1;
color: #003c64;
border: none;
padding: 0.7rem 1.2rem;
margin: 0.5rem 0.2rem;
font-size: 1rem;
border-radius: 8px;
cursor: pointer;
transition: background 0.3s ease;
}
button:hover {
background: #00acc1;
color: #fff;
}
ul {
list-style: none;
padding: 0;
}
li {
background: rgba(255, 255, 255, 0.1);
margin: 0.5rem 0;
padding: 1rem;
border-radius: 10px;
display: flex;
justify-content: space-between;
align-items: center;
}
.hidden {
display: none;
}
.todo-header {
display: flex;
justify-content: space-between;
align-items: center;
}
.auth-buttons {
display: flex;
justify-content: space-between;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 396 KiB

View File

@@ -0,0 +1,52 @@
const API = new class {
register(username, password) {
const formData = new FormData();
formData.append("username", username)
formData.append("password", password)
return fetch("/api.php?path=" + encodeURIComponent("/account/register"), {
method: "POST",
body: formData
})
}
login(username, password) {
const formData = new FormData();
formData.append("username", username)
formData.append("password", password)
return fetch("/api.php?path=" + encodeURIComponent("/account/login"), {
method: "POST",
body: formData,
})
}
info() {
return fetch("/api.php?path=" + encodeURIComponent("/account/info"), {
method: "GET",
})
}
list() {
return fetch("/api.php?path=" + encodeURIComponent("/todos/list"), {
method: "GET",
})
}
add(name, desc) {
const formData = new FormData();
formData.append("name", name)
formData.append("desc", desc)
return fetch("/api.php?path=" + encodeURIComponent("/todos/add"), {
method: "POST",
body: formData
})
}
remove(id) {
const formData = new FormData();
formData.append("id", id)
return fetch("/api.php?path=" + encodeURIComponent("/todos/remove"), {
method: "POST",
body: formData
})
}
}()

View File

@@ -0,0 +1,79 @@
function register() {
const username = document.getElementById('username').value;
const password = document.getElementById('password').value;
API.register(username, password)
.then(res => res.json())
.then(data => {
alert('Registered successfully!');
}).catch(err => alert('Registration failed'));
}
function login() {
const username = document.getElementById('username').value;
const password = document.getElementById('password').value;
API.login(username, password)
.then(res => res.json())
.then(data => {
loadApp();
}).catch(err => alert('Login failed'));
}
function loadApp() {
API.info().then(res => res.json()).then(user => {
document.getElementById('auth').classList.add('hidden');
document.getElementById('todoApp').classList.remove('hidden');
document.getElementById('userDisplay').innerText = user.data.username;
loadTodos();
}).catch(err => alert('Session expired or unauthorized'));
}
function loadTodos() {
API.list()
.then(res => res.json())
.then(data => {
const todos = data.data.todos;
const list = document.getElementById('todoList');
list.innerHTML = '';
todos.forEach(todo => {
const li = document.createElement('li');
li.innerHTML = `
<div>
<strong>${todo.name}</strong><br>
<small>${todo.desc}</small>
</div>
<button onclick="deleteTodo('${todo.id}')">🗑</button>
`;
list.appendChild(li);
});
}).catch(err => alert('Failed to load todos'));
}
function addTodo() {
const name = document.getElementById('todoName').value;
const desc = document.getElementById('todoDesc').value;
API.add(name, desc)
.then(res => res.json())
.then(() => {
document.getElementById('todoName').value = '';
document.getElementById('todoDesc').value = '';
loadTodos();
}).catch(err => alert('Failed to add todo'));
}
function deleteTodo(id) {
API.remove(id)
.then(res => res.json())
.then(() => {
loadTodos();
}).catch(err => alert('Failed to delete todo'));
}
// Try auto-login
window.addEventListener('DOMContentLoaded', () => {
API.info()
.then(res => res.json())
.then(data => {
if (data.data.loggedIn) loadApp();
});
});

View File

@@ -0,0 +1,38 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Glacier TODO App</title>
<link rel="stylesheet" href="./assets/css/style.css">
<script defer src="./assets/js/api.js"></script>
<script defer src="./assets/js/app.js"></script>
</head>
<body>
<div class="container">
<h1>🗻 Glacier TODO</h1>
<div id="auth">
<input type="text" id="username" placeholder="Username">
<input type="password" id="password" placeholder="Password">
<div class="auth-buttons">
<button onclick="register()">Register</button>
<button onclick="login()">Login</button>
</div>
</div>
<div id="todoApp" class="hidden">
<div class="todo-header">
<h2>Welcome, <span id="userDisplay"></span>!</h2>
</div>
<div class="add-todo">
<input type="text" id="todoName" placeholder="Todo title">
<input type="text" id="todoDesc" placeholder="Todo description">
<button onclick="addTodo()">Add</button>
</div>
<ul id="todoList"></ul>
</div>
</div>
</body>
</html>