AstraOS Ver. 1.20:

Update:
Funktionen patched
This commit is contained in:
MrWhiff 2026-02-26 23:49:56 +01:00
parent 64273d5fa7
commit d89f4731e9
6 changed files with 181 additions and 42 deletions

View file

@ -1,7 +1,7 @@
SECRET_KEY='GYUZ!EPtMkVMD!xUL6*2sPMVeeqoGXxWYhZs3MQJDDoJb8kHfEDbgJVwEsbTJBtXduBm9ujtncL@puXPM4TMFQ2qemJrYHPT93R_RYiZXCK4mrUuzGidCiUXqx9EZP6*ZGD6vAdog.n8CcqtMrtsdbvA_NP4r@33dNPZQjmP93!mNahzjFi3JzfkN.nd3KvLrMDfVs7t' SECRET_KEY='GYUZ!EPtMkVMD!xUL6*2sPMVeeqoGXxWYhZs3MQJDDoJb8kHfEDbgJVwEsbTJBtXduBm9ujtncL@puXPM4TMFQ2qemJrYHPT93R_RYiZXCK4mrUuzGidCiUXqx9EZP6*ZGD6vAdog.n8CcqtMrtsdbvA_NP4r@33dNPZQjmP93!mNahzjFi3JzfkN.nd3KvLrMDfVs7t'
MONGO_URI='mongodb+srv://MrSniff:5169Galaxy@chainsaw.d0shx.mongodb.net/' MONGO_URI='mongodb+srv://MrSniff:5169Galaxy@chainsaw.d0shx.mongodb.net/'
SSH_HOST='89.144.42.175' SSH_HOST='116.203.131.247'
SSH_USER='root' SSH_USER='astraos'
SSH_PASS='iwkms@1812:(' SSH_PASS='iwkms@1812:('
VPNAPI_KEY='015ada9472664329affb2f26d7036d47' VPNAPI_KEY='015ada9472664329affb2f26d7036d47'

View file

@ -0,0 +1,111 @@
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>404 - Seite nicht gefunden</title>
<link rel="icon" href="{{ url_for('static', filename='media/AstraOS_Logo.ico') }}" type="image/x-icon">
<script src="https://cdn.tailwindcss.com"></script>
<style>
::-webkit-scrollbar { width: 8px; height: 8px; }
::-webkit-scrollbar-track { background: #0a0a0f; }
::-webkit-scrollbar-thumb { background-color: #4b5563; border-radius: 4px; }
::-webkit-scrollbar-thumb:hover { background-color: #6b7280; }
body {
background: radial-gradient(circle at center, #1b1b26, #0a0a0f 70%);
overflow: hidden;
min-height: 100vh;
color: #e6e6e6;
display: flex;
flex-direction: column; /* Changed to column for footer */
align-items: center;
justify-content: center;
}
.animated-bg {
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
z-index: -1;
pointer-events: none;
overflow: hidden;
}
.dot {
position: absolute;
width: 4px;
height: 4px;
border-radius: 50%;
background: rgba(192, 132, 252, 0.2);
animation: float 20s infinite linear;
}
@keyframes float {
0% { transform: translateY(100vh) scale(1); }
100% { transform: translateY(-10vh) scale(1.5); }
}
.card {
background-color: rgba(10, 10, 15, 0.6);
border: 1px solid rgba(255, 255, 255, 0.1);
border-radius: 1.5rem; /* Increased border-radius */
box-shadow: 0 0 30px rgba(192, 132, 252, 0.2); /* Glowing shadow */
position: relative;
overflow: hidden;
}
.gradient-text {
background: -webkit-linear-gradient(45deg, #a855f7, #d8b4fe);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
footer {
position: absolute;
bottom: 1rem;
width: 100%;
text-align: center;
color: rgba(255, 255, 255, 0.3);
font-size: 0.875rem;
}
</style>
</head>
<body class="bg-gray-900 text-gray-100 font-sans">
<div class="animated-bg"></div>
<div class="main-content">
<div class="container-fluid">
<div class="row justify-content-center align-items-center">
<div class="col-md-6 text-center">
<div class="card">
<div class="card-body p-8 relative z-10">
<h1 class="display-1 font-bold gradient-text">404</h1>
<h2 class="mb-4 text-2xl font-semibold">Seite nicht gefunden</h2>
<p class="text-gray-400">Die von Ihnen angeforderte Seite konnte nicht gefunden werden.</p>
</div>
</div>
</div>
</div>
</div>
</div>
<footer>
<p>&copy; 2026 Astra OS. Alle Rechte vorbehalten. | Hosted by Astra OS</p>
</footer>
<script>
document.addEventListener('DOMContentLoaded', () => {
const bg = document.querySelector('.animated-bg');
const numDots = 100;
for (let i = 0; i < numDots; i++) {
const dot = document.createElement('div');
dot.classList.add('dot');
dot.style.left = `${Math.random() * 100}vw`;
dot.style.top = `${Math.random() * 100}vh`;
dot.style.animationDuration = `${Math.random() * 15 + 10}s`;
dot.style.animationDelay = `${Math.random() * 5}s`;
dot.style.transform = `scale(${Math.random() * 1.5 + 0.5})`;
bg.appendChild(dot);
}
});
</script>
</body>
</html>

View file

@ -46,6 +46,7 @@
</form> </form>
</div> </div>
<div class="bg-black/40 rounded-xl backdrop-blur-lg p-8 {% if maintenance_active %}border border-yellow-500/30{% else %}border border-purple-500/20{% endif %}"> <div class="bg-black/40 rounded-xl backdrop-blur-lg p-8 {% if maintenance_active %}border border-yellow-500/30{% else %}border border-purple-500/20{% endif %}">
<h3 class="text-2xl font-semibold mb-6 {% if maintenance_active %}text-yellow-300{% else %}text-purple-300{% endif %}">Discord-Verknüpfung</h3> <h3 class="text-2xl font-semibold mb-6 {% if maintenance_active %}text-yellow-300{% else %}text-purple-300{% endif %}">Discord-Verknüpfung</h3>
{% if user.discord_id %} {% if user.discord_id %}

View file

@ -179,7 +179,7 @@
Dashboard Dashboard
</a> </a>
<a href="{{ url_for('status_page') }}" <a href="https://status.mrsniff.de/status/astraos"
class="px-3 py-2 rounded-md transition flex-shrink-0 class="px-3 py-2 rounded-md transition flex-shrink-0
{% if active_page == 'status_page' %}{% if maintenance_active %}bg-yellow-500/10 text-yellow-300{% else %}bg-purple-500/10 text-purple-300{% endif %}{% else %} {% if active_page == 'status_page' %}{% if maintenance_active %}bg-yellow-500/10 text-yellow-300{% else %}bg-purple-500/10 text-purple-300{% endif %}{% else %}
{% if maintenance_active %}hover:bg-yellow-500/10 hover:text-yellow-300{% else %}hover:bg-purple-500/10 hover:text-purple-300{% endif %}{% endif %}"> {% if maintenance_active %}hover:bg-yellow-500/10 hover:text-yellow-300{% else %}hover:bg-purple-500/10 hover:text-purple-300{% endif %}{% endif %}">
@ -332,7 +332,7 @@
{% block content %}{% endblock %} {% block content %}{% endblock %}
</main> </main>
<footer> <footer>
&copy; 2025 AstraOS &copy; 2026 AstraOS
</footer> </footer>
</div> </div>
</div> </div>

View file

@ -81,7 +81,6 @@
<label for="password" class="block text-sm font-medium text-gray-300">Neues Passwort</label> <label for="password" class="block text-sm font-medium text-gray-300">Neues Passwort</label>
<input type="password" name="password" id="password" :required="!userToEdit" :placeholder="userToEdit ? 'Leer lassen, um nicht zu ändern' : ''" class="mt-1 w-full px-3 py-2 bg-gray-800 border border-gray-700 rounded-lg text-white focus:outline-none focus:ring-2 {% if maintenance_active %}focus:ring-yellow-500{% else %}focus:ring-purple-500{% endif %}"> <input type="password" name="password" id="password" :required="!userToEdit" :placeholder="userToEdit ? 'Leer lassen, um nicht zu ändern' : ''" class="mt-1 w-full px-3 py-2 bg-gray-800 border border-gray-700 rounded-lg text-white focus:outline-none focus:ring-2 {% if maintenance_active %}focus:ring-yellow-500{% else %}focus:ring-purple-500{% endif %}">
</div> </div>
<!-- Custom Role Selector -->
<div x-data='{ <div x-data='{
open: false, open: false,
roles: {{ roles | tojson }}, roles: {{ roles | tojson }},

View file

@ -24,7 +24,7 @@ app = Flask(__name__,
template_folder='Frontend/HTML', template_folder='Frontend/HTML',
static_folder='Frontend') static_folder='Frontend')
socketio = SocketIO(app, async_mode=async_mode) socketio = SocketIO(app, async_mode=async_mode)
BOT_UPLOAD_FOLDER = '/root/chainsaw' BOT_UPLOAD_FOLDER = '/home/astraos/Astra-OS-Panel/bots'
try: try:
os.makedirs(BOT_UPLOAD_FOLDER, exist_ok=True) os.makedirs(BOT_UPLOAD_FOLDER, exist_ok=True)
try: try:
@ -139,6 +139,53 @@ except Exception as e:
accounts_collection = None accounts_collection = None
logs_collection = None logs_collection = None
def _venv_paths():
venv_bin = "/home/astraos/Astra-OS-Panel/venv/bin"
return {
"python": os.path.join(venv_bin, "python3"),
# pip NICHT direkt verwenden (Shebang kann auf falschen Interpreter zeigen)
"pip": os.path.join(venv_bin, "pip"),
}
def _build_bot_command(filepath: str):
venv = _venv_paths()
vpy = venv["python"]
# Keine Auto-Installation bei jedem Start; nur Bot ausführen.
return f"{vpy} -u {filepath}"
def _spawn_bot_process(bot_id: str, filepath: str, bot_name: str = "N/A", emit_to_socket: bool = False):
command = _build_bot_command(filepath)
if emit_to_socket:
socketio.emit('console_output', {'type': 'system', 'data': f'[startup] Command: {command}\n'}, room=bot_id)
process = subprocess.Popen(
command,
shell=True,
executable='/bin/bash',
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True,
encoding='utf-8',
errors='replace'
)
running_bots[bot_id] = {'process': process, 'history': []}
thread = threading.Thread(target=stream_bot_output, args=(bot_id, process))
thread.daemon = True
thread.start()
if discord_bots_collection is not None:
discord_bots_collection.update_one({'_id': ObjectId(bot_id)}, {'$set': {'status': 'running'}})
if emit_to_socket:
socketio.emit('status_update', {'bot_id': bot_id, 'status': 'running'}, room=bot_id)
socketio.emit('console_output', {'type': 'system', 'data': f'--- Bot-Prozess gestartet (PID: {process.pid}) ---'}, room=bot_id)
print(f"INFO: Bot '{bot_name}' (PID: {process.pid}) wurde gestartet.")
return process
def start_bots_on_startup(): def start_bots_on_startup():
if discord_bots_collection is None: if discord_bots_collection is None:
print("WARNUNG: Bot-Autostart übersprungen, da keine DB-Verbindung besteht.") print("WARNUNG: Bot-Autostart übersprungen, da keine DB-Verbindung besteht.")
@ -159,21 +206,9 @@ def start_bots_on_startup():
continue continue
try: try:
process = subprocess.Popen( _spawn_bot_process(bot_id, filepath, bot_name=bot_info.get('name', 'N/A'), emit_to_socket=False)
['python', '-u', filepath],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True,
encoding='utf-8',
errors='replace'
)
running_bots[bot_id] = {'process': process, 'history': []}
thread = threading.Thread(target=stream_bot_output, args=(bot_id, process))
thread.daemon = True
thread.start()
print(f"INFO: Bot '{bot_info['name']}' (PID: {process.pid}) wurde gestartet.")
except Exception as e: except Exception as e:
print(f"FEHLER: Bot '{bot_info['name']}' konnte nicht gestartet werden: {e}") print(f"FEHLER: Bot '{bot_info.get('name','N/A')}' konnte nicht gestartet werden: {e}")
def stream_bot_output(bot_id, process): def stream_bot_output(bot_id, process):
def stream_to_socket(pipe, log_type): def stream_to_socket(pipe, log_type):
@ -196,9 +231,9 @@ def stream_bot_output(bot_id, process):
stdout_thread.start() stdout_thread.start()
stderr_thread.start() stderr_thread.start()
process.wait() process.wait()
if bot_id in running_bots: if bot_id in running_bots and running_bots.get(bot_id) is not None:
del running_bots[bot_id] del running_bots[bot_id]
if discord_bots_collection: if discord_bots_collection is not None:
discord_bots_collection.update_one({'_id': ObjectId(bot_id)}, {'$set': {'status': 'stopped'}}) discord_bots_collection.update_one({'_id': ObjectId(bot_id)}, {'$set': {'status': 'stopped'}})
socketio.emit('status_update', {'bot_id': bot_id, 'status': 'stopped'}, room=bot_id) socketio.emit('status_update', {'bot_id': bot_id, 'status': 'stopped'}, room=bot_id)
socketio.emit('console_output', {'bot_id': bot_id, 'type': 'system', 'data': '--- Bot-Prozess beendet ---'}, room=bot_id) socketio.emit('console_output', {'bot_id': bot_id, 'type': 'system', 'data': '--- Bot-Prozess beendet ---'}, room=bot_id)
@ -959,9 +994,9 @@ def stream_bot_output(bot_id, process):
stdout_thread.start() stdout_thread.start()
stderr_thread.start() stderr_thread.start()
process.wait() process.wait()
if bot_id in running_bots: if bot_id in running_bots and running_bots.get(bot_id) is not None:
del running_bots[bot_id] del running_bots[bot_id]
if discord_bots_collection: if discord_bots_collection is not None:
discord_bots_collection.update_one({'_id': ObjectId(bot_id)}, {'$set': {'status': 'stopped'}}) discord_bots_collection.update_one({'_id': ObjectId(bot_id)}, {'$set': {'status': 'stopped'}})
socketio.emit('status_update', {'bot_id': bot_id, 'status': 'stopped'}, room=bot_id) socketio.emit('status_update', {'bot_id': bot_id, 'status': 'stopped'}, room=bot_id)
socketio.emit('console_output', {'bot_id': bot_id, 'type': 'system', 'data': '--- Bot-Prozess beendet ---'}, room=bot_id) socketio.emit('console_output', {'bot_id': bot_id, 'type': 'system', 'data': '--- Bot-Prozess beendet ---'}, room=bot_id)
@ -1006,7 +1041,7 @@ def delete_bot(bot_id):
if not bot_info: if not bot_info:
flash("Bot nicht gefunden.", "danger") flash("Bot nicht gefunden.", "danger")
return redirect(url_for('discord_bots')) return redirect(url_for('discord_bots'))
if bot_id in running_bots: if bot_id in running_bots and running_bots.get(bot_id) is not None:
process = running_bots[bot_id]['process'] process = running_bots[bot_id]['process']
try: try:
process.terminate() process.terminate()
@ -1043,7 +1078,7 @@ def handle_join_console(data):
bot_id = data['bot_id'] bot_id = data['bot_id']
join_room(bot_id) join_room(bot_id)
emit('console_output', {'type': 'system', 'data': f'Verbunden mit Konsole für Bot {bot_id}.'}) emit('console_output', {'type': 'system', 'data': f'Verbunden mit Konsole für Bot {bot_id}.'})
if bot_id in running_bots and 'history' in running_bots[bot_id]: if bot_id in running_bots and running_bots.get(bot_id) is not None and 'history' in running_bots[bot_id]:
for log in running_bots[bot_id]['history']: for log in running_bots[bot_id]['history']:
emit('console_output', log) emit('console_output', log)
@socketio.on('leave_console') @socketio.on('leave_console')
@ -1059,31 +1094,20 @@ def handle_toggle_bot(data):
if not bot_info: if not bot_info:
emit('console_output', {'type': 'error', 'data': 'Bot nicht in der Datenbank gefunden.'}, room=bot_id) emit('console_output', {'type': 'error', 'data': 'Bot nicht in der Datenbank gefunden.'}, room=bot_id)
return return
if action == 'start' and bot_id not in running_bots: if action == 'start' and bot_id not in running_bots:
filepath = bot_info.get('filepath') filepath = bot_info.get('filepath')
if not os.path.exists(filepath): if not os.path.exists(filepath):
emit('console_output', {'type': 'error', 'data': f'Bot-Datei nicht gefunden: {filepath}'}, room=bot_id) emit('console_output', {'type': 'error', 'data': f'Bot-Datei nicht gefunden: {filepath}'}, room=bot_id)
return return
try: try:
process = subprocess.Popen( _spawn_bot_process(bot_id, filepath, bot_name=bot_info.get('name', 'N/A'), emit_to_socket=True)
['python', '-u', filepath],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True,
encoding='utf-8',
errors='replace'
)
running_bots[bot_id] = {'process': process, 'history': []}
thread = threading.Thread(target=stream_bot_output, args=(bot_id, process))
thread.daemon = True
thread.start()
discord_bots_collection.update_one({'_id': ObjectId(bot_id)}, {'$set': {'status': 'running'}})
add_log("Bot gestartet", f"Bot Name: {bot_info.get('name', 'N/A')}") add_log("Bot gestartet", f"Bot Name: {bot_info.get('name', 'N/A')}")
emit('status_update', {'bot_id': bot_id, 'status': 'running'}, room=bot_id)
emit('console_output', {'type': 'system', 'data': f'--- Bot-Prozess gestartet (PID: {process.pid}) ---'}, room=bot_id)
except Exception as e: except Exception as e:
emit('console_output', {'type': 'error', 'data': f'Fehler beim Starten des Bots: {e}'}, room=bot_id) emit('console_output', {'type': 'error', 'data': f'Fehler beim Starten des Bots: {e}'}, room=bot_id)
elif action == 'stop' and bot_id in running_bots:
elif action == 'stop' and bot_id in running_bots and running_bots.get(bot_id) is not None:
process = running_bots[bot_id]['process'] process = running_bots[bot_id]['process']
try: try:
process.terminate() process.terminate()
@ -1172,6 +1196,10 @@ def update_maintenance():
add_log("Wartungseinstellungen aktualisiert", f"Aktiviert: {is_enabled}, Nachricht: {status_message}") add_log("Wartungseinstellungen aktualisiert", f"Aktiviert: {is_enabled}, Nachricht: {status_message}")
flash("Wartungseinstellungen wurden aktualisiert.", "success") flash("Wartungseinstellungen wurden aktualisiert.", "success")
return redirect(url_for('maintenance_management')) return redirect(url_for('maintenance_management'))
@app.errorhandler(404)
def page_not_found(e):
return render_template('404.html'), 404
if __name__ == '__main__': if __name__ == '__main__':
app.config['SESSION_COOKIE_SECURE'] = False app.config['SESSION_COOKIE_SECURE'] = False
print("INFO: Starte den Server im Entwicklungsmodus ohne HTTPS.") print("INFO: Starte den Server im Entwicklungsmodus ohne HTTPS.")