Compare commits
39 Commits
build/migr
...
8243ce2253
| Author | SHA1 | Date | |
|---|---|---|---|
| 8243ce2253 | |||
| 9847979f43 | |||
| c0eb4e0a6d | |||
| 947adda4da | |||
| 6979fe17e7 | |||
| fe82dad557 | |||
| 2fc702a482 | |||
| 8c99a28a85 | |||
| 7c7e762f00 | |||
| 5c4441a35f | |||
|
a525f311a3
|
|||
|
e07a379036
|
|||
|
ec6ed477b9
|
|||
| f9e630e49b | |||
|
960a7dd4bf
|
|||
| 6872348375 | |||
| 7c98d16cc2 | |||
| 06ea0246f5 | |||
|
95e40a4128
|
|||
| cde27d37e3 | |||
| 3709a42e64 | |||
| 7b09a72d5c | |||
|
1f0fcc71c9
|
|||
|
d998b85f9f
|
|||
|
c0f51cbaaf
|
|||
|
f3f521efe2
|
|||
|
feb7a71816
|
|||
|
e15f02be05
|
|||
|
5031799072
|
|||
|
26fac14802
|
|||
|
75694f9200
|
|||
|
522c14793a
|
|||
|
9a074f17d8
|
|||
|
6ec1af2cf7
|
|||
|
ff911bc8bc
|
|||
|
446e5fbc04
|
|||
|
04c46f1e98
|
|||
|
2786f39b9b
|
|||
|
ad479fe0d7
|
25
.vscode/launch.json
vendored
Normal file
25
.vscode/launch.json
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
{
|
||||
// Use IntelliSense to learn about possible attributes.
|
||||
// Hover to view descriptions of existing attributes.
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Launch Flask",
|
||||
"type": "debugpy",
|
||||
"request": "launch",
|
||||
"module": "flask",
|
||||
"env": {
|
||||
"FLASK_APP": "judas_server/web/web_server.py",
|
||||
},
|
||||
"args": [
|
||||
"run",
|
||||
"--host",
|
||||
"0.0.0.0",
|
||||
|
||||
],
|
||||
"console": "internalConsole",
|
||||
"justMyCode": true,
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,20 +1,206 @@
|
||||
:root {
|
||||
--nord-bg0: #2e3440;
|
||||
--nord-bg1: #3b4252;
|
||||
--nord-bg2: #434c5e;
|
||||
--nord-bg3: #4c566a;
|
||||
--nord-fg0: #eceff4;
|
||||
--nord-fg1: #e5e9f0;
|
||||
--nord-fg2: #d8dee9;
|
||||
--nord-acc0: #8fbcbb;
|
||||
--nord-acc1: #88c0d0;
|
||||
--nord-acc2: #81a1c1;
|
||||
--nord-acc3: #5e81ac;
|
||||
--nord-aur0: #bf616a;
|
||||
--nord-aur1: #d08770;
|
||||
--nord-aur2: #ebcb8b;
|
||||
--nord-aur3: #a3be8c;
|
||||
--nord-aur4: #b48ead;
|
||||
|
||||
}
|
||||
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--nord-aur4);
|
||||
font-family: monospace, sans-serif !important;
|
||||
color: var(--nord-fg0);
|
||||
}
|
||||
|
||||
input {
|
||||
font-family: inherit;
|
||||
color: #eceff4;
|
||||
background-color: var(--nord-bg2);
|
||||
border: none;
|
||||
border-radius: 0.25rem;
|
||||
padding: 0.25rem;
|
||||
}
|
||||
|
||||
a {
|
||||
color: var(--nord-acc0);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
#wrapper {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
background-color: #2e3440;
|
||||
color: #eceff4;
|
||||
background-color: var(--nord-bg0);
|
||||
color: var(--nord-fg0);
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
main {
|
||||
padding: 2rem;
|
||||
background-color: #eceff4;
|
||||
color: #2e3440;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1rem;
|
||||
padding: 1rem;
|
||||
background-color: var(--nord-bg1);
|
||||
flex-grow: 1;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
header a {
|
||||
text-decoration: none;
|
||||
color: var(--nord-fg0);
|
||||
}
|
||||
|
||||
.button {
|
||||
display: inline-block;
|
||||
padding: 0.5rem 1rem;
|
||||
background-color: var(--nord-acc0);
|
||||
color: var(--nord-bg0);
|
||||
border: none;
|
||||
border-radius: 0.25rem;
|
||||
text-decoration: none;
|
||||
transition: 0.3s ease-in-out;
|
||||
}
|
||||
|
||||
.button a:hover {
|
||||
color: var(--nord-bg0);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.button:hover {
|
||||
background-color: var(--nord-acc2);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.center {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.error-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin: 1rem;
|
||||
padding: 1rem;
|
||||
background-color: var(--nord-aur0);
|
||||
color: var(--nord-fg0);
|
||||
border: 6px solid var(--nord-aur1);
|
||||
border-radius: 24px;
|
||||
}
|
||||
|
||||
.center-table {
|
||||
margin: 0 auto;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.select-table{
|
||||
border-collapse: collapse;
|
||||
border: 2px solid var(--nord-fg0);
|
||||
}
|
||||
|
||||
.select-table thead {
|
||||
position: sticky;
|
||||
top: -1px;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.select-table th, .select-table td {
|
||||
padding: 0.5rem;
|
||||
text-align: center;
|
||||
border: 1px solid var(--nord-fg1);
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
.select-table th {
|
||||
background-color: var(--nord-bg2);
|
||||
color: var(--nord-fg0);
|
||||
}
|
||||
|
||||
.select-table a {
|
||||
display: block;
|
||||
color: var(--nord-acc0);
|
||||
text-decoration: none;
|
||||
transition: 0.1s ease-in-out;
|
||||
}
|
||||
|
||||
.select-table tr {
|
||||
transition: 0.1s ease-in-out;
|
||||
}
|
||||
|
||||
.select-table tr:hover {
|
||||
background-color: var(--nord-acc1);
|
||||
}
|
||||
|
||||
.select-table tr:hover a {
|
||||
color: var(--nord-bg0);
|
||||
}
|
||||
|
||||
.red-bg {
|
||||
background-color: var(--nord-aur0);
|
||||
}
|
||||
|
||||
.yellow-bg {
|
||||
background-color: var(--nord-aur2);
|
||||
}
|
||||
|
||||
.green-bg {
|
||||
background-color: var(--nord-aur3);
|
||||
}
|
||||
|
||||
.button-container {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.link {
|
||||
transition: 0.3s ease-in-out;
|
||||
}
|
||||
|
||||
.link:hover {
|
||||
color: var(--nord-acc2);
|
||||
}
|
||||
|
||||
.details-table tr td:first-child {
|
||||
font-weight: 900;
|
||||
background-color: var(--nord-bg3);
|
||||
white-space: nowrap;
|
||||
width: 1%;
|
||||
}
|
||||
|
||||
.details-table {
|
||||
border-collapse: collapse;
|
||||
border: 2px solid var(--nord-fg0);
|
||||
}
|
||||
|
||||
.details-table th, .details-table td {
|
||||
padding: 0.5rem;
|
||||
text-align: left;
|
||||
border: 1px solid var(--nord-fg1);
|
||||
border-collapse: collapse;
|
||||
}
|
||||
@@ -9,19 +9,16 @@
|
||||
<body>
|
||||
<div id="wrapper">
|
||||
<header>
|
||||
<h1><a href="{{ url_for('panel') }}">judas panel</a></h1>
|
||||
<p>Welcome, {{ username }}! <a href="{{ url_for('logout') }}">Logout</a></p>
|
||||
<h1><a href="{{ url_for('index') }}">judas</a></h1>
|
||||
<p><a class="button" href="{{ url_for('logout') }}">Logout</a></p>
|
||||
</header>
|
||||
<main>
|
||||
<div class="button-container">
|
||||
<p><a href="{{ url_for('panel') }}" class="link">Back to Panel</a></p>
|
||||
<h2>Details for PC ID: {{ pc.id }}</h2>
|
||||
<h3><a href="{{ url_for('stream', pc_id=pc.id) }}">View Stream</a></h3>
|
||||
<table border="1">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Attribute</th>
|
||||
<th>Value</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<p><a href="{{ url_for('stream', pc_id=pc.id) }}" class="link">View Stream</a></p>
|
||||
</div>
|
||||
<table class="center-table details-table">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Status</td>
|
||||
@@ -33,7 +30,6 @@
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p><a href="{{ url_for('panel') }}">Back to Panel</a></p>
|
||||
</main>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
@@ -9,13 +9,44 @@
|
||||
<body>
|
||||
<div id="wrapper">
|
||||
<header>
|
||||
<h1>judas</h1>
|
||||
<h1><a href="{{ url_for('index') }}">judas</a></h1>
|
||||
{% if logged %}
|
||||
<p>Welcome, {{ username }}! <a href="{{ url_for('logout') }}">Logout</a></p>
|
||||
{% else %}
|
||||
<p><a href="{{ url_for('login') }}">Login</a></p>
|
||||
<p><a class="button" href="{{ url_for('login') }}">Login</a></p>
|
||||
{% endif %}
|
||||
</header>
|
||||
<main class="center">
|
||||
<div>
|
||||
<p>Welcome to</p>
|
||||
<h2 id="typing-text" style="font-size: 3rem;">judas</h2>
|
||||
<p>a remote PC fleet management system</p>
|
||||
</div>
|
||||
<div>
|
||||
<p style="color: #bf616a;"><strong>Notice:</strong> Please use this system responsibly and in accordance with all applicable laws and organizational policies.</p>
|
||||
<p>Please <a href="{{ url_for('login')}}" class="link">log in</a> to manage your remote PCs.</p>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
<script>
|
||||
var i = 0;
|
||||
var txt = document.getElementById("typing-text").innerHTML;
|
||||
var minSpeed = 50;
|
||||
var maxSpeed = 200;
|
||||
|
||||
document.getElementById("typing-text").innerHTML = "";
|
||||
|
||||
function typeWriter() {
|
||||
if (i < txt.length) {
|
||||
document.getElementById("typing-text").innerHTML += txt.charAt(i);
|
||||
i++;
|
||||
|
||||
var randomDelay = Math.floor(Math.random() * (maxSpeed - minSpeed + 1)) + minSpeed;
|
||||
setTimeout(typeWriter, randomDelay);
|
||||
}
|
||||
}
|
||||
|
||||
typeWriter();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
32
judas_server/web/templates/login.html
Normal file
32
judas_server/web/templates/login.html
Normal file
@@ -0,0 +1,32 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>judas - login page</title>
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">
|
||||
</head>
|
||||
<body>
|
||||
<div id="wrapper">
|
||||
<header>
|
||||
<h1><a href="{{ url_for('index') }}">judas</a></h1>
|
||||
</header>
|
||||
<main>
|
||||
<h1>Login</h1>
|
||||
<form method="post" class="center">
|
||||
<label for="password">Password:</label>
|
||||
<input type="password" id="password" name="password" required>
|
||||
<br>
|
||||
<br>
|
||||
<input type="submit" value="Login" class="button">
|
||||
{% if error %}
|
||||
<div class="error-container">
|
||||
<h1>Login failure</h1>
|
||||
<p>{{ error }}</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
</form>
|
||||
</main>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -9,11 +9,13 @@
|
||||
<body>
|
||||
<div id="wrapper">
|
||||
<header>
|
||||
<h1><a href="{{ url_for('panel') }}">judas panel</a></h1>
|
||||
<p>Welcome, {{ username }}! <a href="{{ url_for('logout') }}">Logout</a></p>
|
||||
<h1><a href="{{ url_for('index') }}">judas</a></h1>
|
||||
<p><a class="button" href="{{ url_for('logout') }}">Logout</a></p>
|
||||
</header>
|
||||
<main>
|
||||
<table border="1">
|
||||
<h2 class="center">Select a PC to Control</h2>
|
||||
<p class="center">Choose a PC from the list below to view details or send commands.</p>
|
||||
<table class="center-table select-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>PC ID</th>
|
||||
@@ -25,8 +27,7 @@
|
||||
{% for pc in pcs.values() %}
|
||||
<tr>
|
||||
<td><a href="{{ url_for('details', pc_id=pc.id) }}">{{ pc.id }}</a></td>
|
||||
<td>{{ pc.status if pc.status else 'Unknown' }}</td>
|
||||
<td>{{ pc.last_seen if pc.last_seen else 'Never' }}</td>
|
||||
<td class='{% if pc.status == "online" %}green-bg{% elif pc.status == "offline" %}red-bg{% else %}yellow-bg{% endif %}'>{{ pc.status if pc.status else 'Unknown' }}</td> <td>{{ pc.last_seen if pc.last_seen else 'Never' }}</td>
|
||||
</tr>
|
||||
{% else %}
|
||||
<tr>
|
||||
|
||||
@@ -8,8 +8,8 @@
|
||||
<body>
|
||||
<div id="wrapper">
|
||||
<header>
|
||||
<h1><a href="{{ url_for('panel') }}">judas panel</a></h1>
|
||||
<p>Welcome, {{ username }}! <a href="{{ url_for('logout') }}">Logout</a></p>
|
||||
<h1><a href="{{ url_for('index') }}">judas</a></h1>
|
||||
<p><a class="button" href="{{ url_for('logout') }}">Logout</a></p>
|
||||
</header>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
@@ -17,14 +17,39 @@ login_manager.init_app(app)
|
||||
PC_DETAILS = {
|
||||
"PC1": {
|
||||
"id": "PC1",
|
||||
"status": "Online",
|
||||
"status": "online",
|
||||
"last_seen": "2023-10-01 12:00:00",
|
||||
},
|
||||
"PC2": {
|
||||
"id": "PC2",
|
||||
"status": "Offline",
|
||||
"status": "offline",
|
||||
"last_seen": "2023-10-01 11:00:00",
|
||||
},
|
||||
"PC3": {
|
||||
"id": "PC3",
|
||||
"status": "offline",
|
||||
"last_seen": "2023-10-01 11:00:00",
|
||||
},
|
||||
"PC4": {
|
||||
"id": "PC4",
|
||||
"status": "offline",
|
||||
"last_seen": "2023-10-01 11:00:00",
|
||||
},
|
||||
"PC5": {
|
||||
"id": "PC5",
|
||||
"status": "offline",
|
||||
"last_seen": "2023-10-01 11:00:00",
|
||||
},
|
||||
"PC6": {
|
||||
"id": "PC6",
|
||||
"status": "offline",
|
||||
"last_seen": "2023-10-01 11:00:00",
|
||||
},
|
||||
"PC7": {
|
||||
"id": "PC7",
|
||||
"status": "offline",
|
||||
"last_seen": "2023-10-01 11:00:00",
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -52,12 +77,10 @@ def load_user(user_id: str) -> User | None:
|
||||
|
||||
|
||||
@app.route("/")
|
||||
def index() -> str:
|
||||
def index() -> flask.Response | str:
|
||||
"""Renders the index page with a link to the login page."""
|
||||
if flask_login.current_user.is_authenticated:
|
||||
return flask.render_template(
|
||||
"index.html", logged=True, username=flask_login.current_user.id
|
||||
)
|
||||
return flask.redirect(flask.url_for("panel"))
|
||||
else:
|
||||
return flask.render_template(
|
||||
"index.html", logged=False, login_url=flask.url_for("login")
|
||||
@@ -74,13 +97,11 @@ def login() -> str:
|
||||
flask_login.login_user(user)
|
||||
return flask.redirect(flask.url_for("panel"))
|
||||
else:
|
||||
return "Invalid password", 401
|
||||
return """
|
||||
<form method="post">
|
||||
Password: <input type="password" name="password">
|
||||
<input type="submit" value="Login">
|
||||
</form>
|
||||
"""
|
||||
return flask.render_template(
|
||||
"login.html",
|
||||
error="Invalid password. Please try again.",
|
||||
)
|
||||
return flask.render_template("login.html")
|
||||
|
||||
|
||||
@app.route("/logout")
|
||||
|
||||
@@ -11,7 +11,7 @@ readme = "README.md"
|
||||
license = {text = "GPL-3.0"}
|
||||
|
||||
[tool.pdm.scripts]
|
||||
start = "flask --app judas_server/web/web_server.py run"
|
||||
web = "flask --app judas_server/web/web_server.py run"
|
||||
|
||||
[tool.pdm]
|
||||
distribution = false
|
||||
|
||||
Reference in New Issue
Block a user