'''
Item: Safety Linux Server Panel
Time: 2025-10-24
Author: 1ceLAND
'''

from flask import Flask, redirect, url_for, render_template, request
import jwt
import uuid
import os
import subprocess

from werkzeug.security import generate_password_hash, check_password_hash

app = Flask(__name__)
app.config['SECRET_KEY'] = str(uuid.uuid4())

# instead of sqlite
accounts = {}

def create_token(user_id, username):
    payload = {
        'user_id': user_id,
        'username': username
    }
    token = jwt.encode(payload, app.config['SECRET_KEY'], algorithm='HS256')
    if isinstance(token, bytes):
        token = token.decode('utf-8')
    return token

def verify_token(token):
    try:
        payload = jwt.decode(token, app.config['SECRET_KEY'], algorithms=['HS256'])
        user_id = payload['user_id']
        username = payload['username']
        return user_id, username
    except:
        return None

def login_required(f):
    from functools import wraps
    @wraps(f)
    def decorated(*args, **kwargs):
        token = request.cookies.get('token')
        if not token:
            return redirect(url_for('login'))
        res = verify_token(token)
        if not res:
            return redirect(url_for('login'))
        user_id, username = res
        return f(user_id, username, *args, **kwargs)
    return decorated

def check_login(u, p):
    for user_id, info in accounts.items():
        if info['username'] == u:
            return check_password_hash(info['password'], p), user_id
    return False, None

@app.route('/')
def index():
    return redirect(url_for('login'))

@app.route('/login', methods=['GET', 'POST'])
def login():
    error_msg = None
    if request.method == 'POST':
        username = request.form['username']
        password = request.form['password']
        ok, user_id = check_login(username, password)
        if ok:
            token = create_token(user_id, username)
            response = redirect(url_for('dashboard'))
            response.set_cookie('token', token, httponly=True)
            return response
        else:
            error_msg = "Username or Password incorrect!"

    return render_template('login.html', error_msg=error_msg)

@app.route('/logout')
def logout():
    response = redirect(url_for('login'))
    response.delete_cookie('token')
    return response

@app.route('/dashboard')
@login_required
def dashboard(user_id, username):
    return render_template('dashboard.html', user_id=user_id, username=username)

import subprocess

SAFE_COMMANDS = ['ls', 'pwd', 'whoami', 'dir', 'more']

@app.route('/dashboard/run', methods=['POST'])
@login_required
def run_command(user_id, username):
    user_id, username = verify_token(request.cookies.get('token'))
    cmd = request.form.get('command', '').strip()
    if not cmd or cmd.split()[0] not in SAFE_COMMANDS:
        return render_template('dashboard.html',
                                user_id=user_id,
                                username=username,
                                error_msg="Error: Command not allowed or empty")
    try:
        result = subprocess.run(cmd, shell=True, capture_output=True, text=True, timeout=5)
        output = result.stdout + result.stderr
        return render_template('dashboard.html',
                                user_id=user_id, 
                                username=username,
                                output=output,
                                command=cmd)
    except Exception as e:
        return render_template('dashboard.html', 
                                username=username,
                                error_msg=f"Error: {str(e)}")

if __name__ == '__main__':
    admin_id = 0
    admin_username = 'admin123'
    admin_password = str(uuid.uuid4())
    
    # password overlay
    for path in ['/password', './password.txt']:
        try:
            if os.path.exists(path) and os.path.isfile(path):
                with open(path, 'rb') as f:
                    raw = f.read()
                if not raw:
                    continue
                text = raw.decode('utf-8', errors='replace').strip()
                candidates = [line.strip() for line in text.splitlines() if line.strip()]
                if candidates:
                    import secrets
                    admin_password = secrets.choice(candidates)
                break
        except:
            pass
    
    print(f' * Admin password: {admin_password}')
    
    accounts[admin_id] = {
        'username': admin_username,
        'password': generate_password_hash(admin_password)
    }
    
    app.run(debug=False, host='0.0.0.0')