This commit is contained in:
2026-04-15 01:05:54 +02:00
parent db0324c43d
commit bc0c08342d
84 changed files with 28780 additions and 0 deletions

View File

@@ -0,0 +1,13 @@
from flask import Flask
def create_app():
app = Flask(__name__)
app.config.from_object('app.config.Config')
from .blueprints import main_bp, bot_bp, auth_bp
app.register_blueprint(main_bp)
app.register_blueprint(bot_bp)
app.register_blueprint(auth_bp)
return app

View File

@@ -0,0 +1,3 @@
from .main import main_bp
from .bot import bot_bp
from .auth import auth_bp

View File

@@ -0,0 +1,5 @@
from flask import Blueprint
auth_bp = Blueprint('auth_bp', __name__,)
from .routes import *

View File

@@ -0,0 +1,96 @@
from . import auth_bp
from flask import request, jsonify, current_app, render_template
import datetime, uuid, sqlite3, jwt
def get_db_connection():
conn = sqlite3.connect("/www/app/database.db")
conn.row_factory = sqlite3.Row
return conn
def generate_api_key():
return str(uuid.uuid4())
@auth_bp.route('/', methods=['POST', 'GET'])
def search():
if request.method == 'POST':
data = request.get_json()
username = data.get('username')
password = data.get('password')
if not username or not password:
return jsonify({"message": "username or password are required!"}), 400
conn = get_db_connection()
user = conn.execute(
"SELECT * FROM users WHERE username = ?", (username,)
).fetchone()
conn.close()
if user and user["password"] == password:
token = jwt.encode(
{
"sub": user["username"],
"iat": datetime.datetime.utcnow(),
"exp": datetime.datetime.utcnow() + datetime.timedelta(days=1),
},
current_app.config["JWT_SECRET_KEY"],
algorithm="HS256",
)
return jsonify({"token": f"{token}"}), 200
else:
return jsonify({"message": "Credentials not found. Please check your username and password."}), 404
else:
return render_template('search.html')
@auth_bp.route('/register', methods=['POST', 'GET'])
def register():
if request.method == 'POST':
data = request.get_json()
username = data.get('username')
password = data.get('password')
email = data.get('email')
if not username or not password or not email:
return jsonify({"message": "username, password, and email are required!"}), 400
conn = get_db_connection()
existing_user = conn.execute(
"SELECT * FROM users WHERE username = ? OR email = ?", (username, email,)
).fetchone()
if existing_user:
conn.close()
return jsonify({"message": "Username or email already exists!"}), 409
api_key = generate_api_key()
conn.execute(
"""
INSERT INTO users (username, password, email, api_key, created_at)
VALUES (?, ?, ?, ?, ?)
""",
(username, password, email, api_key, datetime.datetime.utcnow())
)
conn.commit()
conn.close()
return jsonify({"message": f"User {username} registered successfully!"}), 201
else:
return render_template('register.html')

View File

@@ -0,0 +1,5 @@
from flask import Blueprint
bot_bp = Blueprint('bot_bp', __name__,)
from .routes import *

View File

@@ -0,0 +1,22 @@
from . import bot_bp
from app.utils.bot import bot_thread
from app.middleware.auth import jwt_required
from flask import request, jsonify
@bot_bp.route('/visit', methods=['POST'])
@jwt_required
def visit():
data = request.get_json()
uri = data.get('uri')
if not uri:
return jsonify({"message": "URI is required"}), 400
bot_thread(uri)
return jsonify({"message": f"Visiting URI: {uri}"}), 200

View File

@@ -0,0 +1,5 @@
from flask import Blueprint
main_bp = Blueprint('main_bp', __name__,)
from .routes import *

View File

@@ -0,0 +1,47 @@
from . import main_bp
from app.middleware.auth import jwt_required
from flask import jsonify, request
import re, sqlite3
def get_db_connection():
conn = sqlite3.connect("/www/app/database.db")
conn.row_factory = sqlite3.Row
return conn
@main_bp.route('/<path:subpath>', methods=['GET'])
@jwt_required
def profile(subpath):
if re.match(r'.*^profile', subpath): # Django perfection
decoded_token = request.decoded_token
username = decoded_token.get('sub')
if not username:
return jsonify({"error": "Invalid token payload!"}), 401
conn = get_db_connection()
user = conn.execute(
"SELECT id, username, email, api_key, created_at, password FROM users WHERE username = ?",
(username,)
).fetchone()
conn.close()
if user:
return jsonify({
"id": user["id"],
"username": user["username"],
"email": user["email"],
"password": user["password"],
"api_key": user["api_key"],
"created_at": user["created_at"]
}), 200
else:
return jsonify({"error": "User not found"}), 404
else:
return jsonify({"error": "No match"}), 404

View File

@@ -0,0 +1,5 @@
import os
class Config:
JWT_SECRET_KEY = os.urandom(69).hex()
DEBUG = False

View File

@@ -0,0 +1,37 @@
from flask import request, jsonify, current_app
from functools import wraps
import jwt
def decode_jwt_token(token):
try:
payload = jwt.decode(token, current_app.config["JWT_SECRET_KEY"], algorithms=["HS256"])
return payload
except jwt.ExpiredSignatureError:
return {"error": "Token has expired."}
except jwt.InvalidTokenError:
return None
except Exception as e:
print(f"Unexpected error decoding JWT: {str(e)}")
return None
def jwt_required(f):
@wraps(f)
def decorated_function(*args, **kwargs):
auth_header = request.headers.get('Authorization', '').strip()
if not auth_header.startswith('Bearer '):
return jsonify({"error": "Token is missing or invalid!"}), 401
token = auth_header.split(" ", 1)[1].strip()
decoded_token = decode_jwt_token(token)
if decoded_token is None:
return jsonify({"error": "Invalid token!"}), 401
elif "error" in decoded_token:
return jsonify(decoded_token), 401
request.decoded_token = decoded_token
return f(*args, **kwargs)
return decorated_function

Binary file not shown.

After

Width:  |  Height:  |  Size: 108 KiB

View File

@@ -0,0 +1,178 @@
body {
background-color: #0a0f1a;
color: #d0e7ff;
font-family: 'Orbitron', sans-serif;
font-size: 16px;
margin: 0;
padding: 0;
height: 100vh;
}
.main-content {
display: flex;
justify-content: center;
align-items: flex-start;
height: calc(100vh - 60px);
}
.sci-fi-profile, .sci-fi-login {
display: flex;
justify-content: center;
align-items: center;
width: 100%;
height: 100%;
}
.holo-container {
background: rgba(17, 34, 64, 0.7);
border: 2px solid rgba(29, 216, 240, 0.7);
border-radius: 15px;
padding: 40px;
width: 650px;
box-shadow: 0 0 15px rgba(29, 216, 240, 0.4), inset 0 0 25px rgba(29, 216, 240, 0.2);
text-align: center;
backdrop-filter: blur(5px);
position: relative;
z-index: 2;
}
.holo-header h1 {
font-size: 32px;
color: #1dd8f0;
text-transform: uppercase;
letter-spacing: 3px;
margin-bottom: 20px;
}
.holo-divider {
height: 2px;
background: linear-gradient(90deg, rgba(29, 216, 240, 0.5), rgba(29, 216, 240, 0), rgba(29, 216, 240, 0.5));
margin: 20px 0;
}
.holo-body {
display: flex;
flex-direction: column;
gap: 10px;
}
.holo-info {
display: flex;
flex-direction: column;
justify-content: flex-start;
align-items: flex-start;
font-size: 18px;
margin-bottom: 20px;
}
.holo-label {
color: #1dd8f0;
font-weight: bold;
margin-bottom: 5px;
}
.holo-value {
color: #d0e7ff;
font-weight: 300;
text-shadow: 0 0 8px rgba(255, 255, 255, 0.7), 0 0 12px rgba(29, 216, 240, 0.8);
}
.holo-container:hover {
box-shadow: 0 0 25px rgba(29, 216, 240, 0.9), inset 0 0 30px rgba(29, 216, 240, 0.5);
}
.holo-input {
background: rgba(17, 34, 64, 0.8);
border: 2px solid rgba(29, 216, 240, 0.5);
color: #d0e7ff;
width: 100%;
padding: 10px;
font-size: 16px;
border-radius: 8px;
box-shadow: 0 0 10px rgba(29, 216, 240, 0.3);
outline: none;
transition: box-shadow 0.3s ease;
}
.holo-input:focus {
box-shadow: 0 0 20px rgba(29, 216, 240, 0.7);
}
.holo-button {
background-color: #1dd8f0;
color: #0a0f1a;
border: none;
padding: 12px 20px;
width: 100%;
border-radius: 8px;
font-size: 18px;
font-weight: bold;
letter-spacing: 2px;
cursor: pointer;
transition: background-color 0.3s ease, box-shadow 0.3s ease;
}
.holo-button:hover {
background-color: #1bc3e0;
box-shadow: 0 0 15px rgba(29, 216, 240, 0.7);
}
.holo-error-message {
color: #1dd8f0;
margin-top: 20px;
text-align: center;
}
.holo-container:before {
content: '';
position: absolute;
top: -10px;
left: -10px;
right: -10px;
bottom: -10px;
background: linear-gradient(45deg, rgba(29, 216, 240, 0.05), transparent);
filter: blur(20px);
z-index: -1;
animation: flicker 2s infinite;
}
@keyframes flicker {
0%, 100% {
opacity: 1;
}
50% {
opacity: 0.8;
}
}
.navbar {
background-color: rgba(10, 15, 26, 0.9);
padding: 10px;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.3);
position: fixed;
z-index: 1000;
}
.navbar-menu {
list-style-type: none;
display: flex;
justify-content: flex-end;
margin: 0;
padding: 0;
}
.navbar-link {
color: #1dd8f0;
text-decoration: none;
font-size: 18px;
margin-left: 20px;
transition: color 0.3s ease;
}
.navbar-link:hover {
color: #1bc3e0;
}
.main-content {
padding-top: 60px;
}

View File

@@ -0,0 +1,19 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{ title if title else 'CDNio' }}</title>
<link href="https://fonts.googleapis.com/css2?family=Orbitron:wght@400;700&display=swap" rel="stylesheet">
<link rel="icon" type="image/x-icon" href="{{ url_for('static', filename='favicon.ico') }}">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
</head>
<body>
<div class="main-content">
{% block content %}{% endblock %}
</div>
</body>
</html>

View File

@@ -0,0 +1,68 @@
{% extends "layout.html" %}
{% block content %}
<nav class="navbar">
<ul class="navbar-menu">
<li><a href="{{ url_for('auth_bp.search') }}" class="navbar-link">SEARCH</a></li>
<li><a href="{{ url_for('auth_bp.register') }}" class="navbar-link">REGISTER</a></li>
</ul>
</nav>
<div class="sci-fi-login">
<div class="holo-container">
<div class="holo-header">
<h1>Register</h1>
</div>
<div class="holo-divider"></div>
<form id="loginForm">
<div class="holo-info">
<label for="username" class="holo-label">Username:</label>
<input type="text" id="username" class="holo-input" required>
</div>
<div class="holo-info">
<label for="password" class="holo-label">Password:</label>
<input type="password" id="password" class="holo-input" required>
</div>
<div class="holo-info">
<label for="email" class="holo-label">Email:</label>
<input type="email" id="mail" class="holo-input" required>
</div>
<button type="button" class="holo-button" id="holo-button">REGISTER</button>
</form>
<div id="errorMessage" class="holo-error-message"></div>
</div>
</div>
<script>
$("#holo-button").click(function (){
var username = $("#username").val();
var password = $("#password").val();
var mail = $("#mail").val();
var creds = {
username: username,
password: password,
email: mail
};
$.ajax({
url: '/register',
type: 'POST',
contentType: 'application/json',
data: JSON.stringify(
creds
),
success: function(response) {
//var jsonResponse = JSON.parse(response);
$(".holo-error-message").text(response.message).css("color", "green");
},
error: function(xhr, status, error) {
var jsonResponse = JSON.parse(xhr.responseText);
$(".holo-error-message").text(jsonResponse.message).css("color", "red");
}
});
});
</script>
{% endblock %}

View File

@@ -0,0 +1,126 @@
{% extends "layout.html" %}
{% block content %}
<nav class="navbar">
<ul class="navbar-menu">
<li><a href="{{ url_for('auth_bp.search') }}" class="navbar-link">SEARCH</a></li>
<li><a href="{{ url_for('auth_bp.register') }}" class="navbar-link">REGISTER</a></li>
</ul>
</nav>
<div class="sci-fi-login">
<div class="holo-container">
<div class="holo-header">
<h1>Search</h1>
</div>
<div class="holo-divider"></div>
<form id="loginForm" onsubmit="login(event)">
<div class="holo-info">
<label for="username" class="holo-label">Username:</label>
<input type="text" id="username" class="holo-input" required>
</div>
<div class="holo-info">
<label for="password" class="holo-label">Password:</label>
<input type="password" id="password" class="holo-input" required>
</div>
<button type="button" class="holo-button" id="holo-button">SEARCH</button>
</form>
<div id="errorMessage" class="holo-error-message"></div>
</div>
</div>
<div class="sci-fi-profile" style="display: none;">
<div class="holo-container">
<div class="holo-header">
<h1>User Profile</h1>
</div>
<div class="holo-divider"></div>
<div class="holo-body" id="profileData">
</div>
</div>
</div>
<script>
$("#holo-button").click(function (){
var username = $("#username").val();
var password = $("#password").val();
var creds = {
username: username,
password: password
};
$.ajax({
url: '/',
type: 'POST',
contentType: 'application/json',
data: JSON.stringify(
creds
),
success: function(response) {
var jwt_token = response.token
localStorage.setItem('token', jwt_token);
fetchUserProfile();
},
error: function(xhr, status, error) {
var jsonResponse = JSON.parse(xhr.responseText);
$(".holo-error-message").text(jsonResponse.message).css("color", "red");
}
});
});
function fetchUserProfile() {
var token = localStorage.getItem('token');
$.ajax({
url: '/profile',
type: 'GET',
headers: {
'Authorization': 'Bearer ' + token
},
success: function(response) {
displayProfileData(response);
},
error: function(xhr, status, error) {
console.log("Error fetching profile:", xhr.responseText);
if (xhr.status === 401) {
$(".holo-error-message").text("Unauthorized! Please login again.").css("color", "red");
} else {
$(".holo-error-message").text("Failed to fetch profile.").css("color", "red");
}
}
});
}
function displayProfileData(user) {
const profileHtml = `
<div class="holo-info">
<span class="holo-label">ID:</span> <span class="holo-value">${user.id}</span>
</div>
<div class="holo-info">
<span class="holo-label">Username:</span> <span class="holo-value">${user.username}</span>
</div>
<div class="holo-info">
<span class="holo-label">Email:</span> <span class="holo-value">${user.email}</span>
</div>
<div class="holo-info">
<span class="holo-label">API Key:</span> <span class="holo-value">${user.api_key}</span>
</div>
<div class="holo-info">
<span class="holo-label">Created At:</span> <span class="holo-value">${user.created_at}</span>
</div>
`;
$("#profileData").html(profileHtml);
$(".sci-fi-profile").show();
}
</script>
{% endblock %}

View File

@@ -0,0 +1,41 @@
import time, os, threading, requests
base_url = "http://0.0.0.0:1337"
admin_passwd = os.getenv("RANDOM_PASSWORD")
base_headers = {
"User-Agent": "CDNio Bot ()"
}
def login_and_get_token():
session = requests.Session()
login_url = f"{base_url}/"
payload = {
"username": "admin",
"password": admin_passwd
}
response = session.post(login_url, json=payload, headers=base_headers)
if response.status_code == 200:
token = response.json().get("token")
return token, session
else:
return None, None
def bot_runner(uri):
token, session = login_and_get_token()
headers = {
**base_headers,
"Authorization": f"Bearer {token}"
}
r = requests.get(f"{base_url}/{uri}", headers=headers)
time.sleep(5)
def bot_thread(uri):
bot_runner(uri)

View File

@@ -0,0 +1,3 @@
from app import create_app
app = create_app()