mirror of
https://github.com/Routstr/routstr-core.git
synced 2026-08-09 19:04:47 +00:00
171 lines
5.3 KiB
Python
171 lines
5.3 KiB
Python
import os
|
|
from datetime import datetime, timezone
|
|
|
|
|
|
from fastapi import APIRouter, Request
|
|
from fastapi.responses import HTMLResponse
|
|
|
|
from .cashu import _initialize_wallet
|
|
|
|
admin_router = APIRouter(prefix="/admin")
|
|
|
|
|
|
def login_form() -> str:
|
|
return """<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<style>
|
|
body {
|
|
font-family: Arial, sans-serif;
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
height: 100vh;
|
|
margin: 0;
|
|
}
|
|
form {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 10px;
|
|
}
|
|
input[type="password"] {
|
|
padding: 8px;
|
|
}
|
|
button {
|
|
padding: 8px;
|
|
cursor: pointer;
|
|
}
|
|
</style>
|
|
<script>
|
|
function handleSubmit(e) {
|
|
e.preventDefault();
|
|
const password = document.getElementById('password').value;
|
|
document.cookie = `admin_password=${password}; path=/; max-age=86400`;
|
|
window.location.reload();
|
|
}
|
|
</script>
|
|
</head>
|
|
<body>
|
|
<form onsubmit="handleSubmit(event)">
|
|
<input type="password" id="password" placeholder="Admin Password" required>
|
|
<button type="submit">Login</button>
|
|
</form>
|
|
</body>
|
|
</html>
|
|
"""
|
|
|
|
|
|
def info(content: str) -> str:
|
|
return f"""<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<style>
|
|
body {{
|
|
font-family: Arial, sans-serif;
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
height: 100vh;
|
|
margin: 0;
|
|
}}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div style="text-align: center;">
|
|
{content}
|
|
</div>
|
|
</body>
|
|
</html>
|
|
"""
|
|
|
|
def admin_auth() -> str:
|
|
if os.getenv("ADMIN_PASSWORD", "") == "":
|
|
return info("Please set a secure ADMIN_PASSWORD= in your ENV variables.")
|
|
else:
|
|
return login_form()
|
|
|
|
|
|
from sqlmodel import select
|
|
from .db import ApiKey, create_session
|
|
|
|
async def dashboard(request: Request) -> str:
|
|
|
|
# fetch cashu / api-key data from database
|
|
async with create_session() as session:
|
|
result = await session.exec(select(ApiKey))
|
|
api_keys = result.all()
|
|
|
|
api_keys_table_rows = []
|
|
for key in api_keys:
|
|
if key.key_expiry_time is not None:
|
|
expiry_time_utc = datetime.fromtimestamp(key.key_expiry_time, tz=timezone.utc)
|
|
expiry_time_human_readable = expiry_time_utc.strftime('%Y-%m-%d %H:%M:%S')
|
|
api_keys_table_rows.append(
|
|
f"<tr><td>{key.hashed_key}</td><td>{key.balance}</td><td>{key.total_spent}</td><td>{key.total_requests}</td><td>{key.refund_address}</td><td>{key.key_expiry_time} ({expiry_time_human_readable} UTC)</td></tr>"
|
|
)
|
|
else:
|
|
expiry_time_human_readable = ""
|
|
api_keys_table_rows.append(
|
|
f"<tr><td>{key.hashed_key}</td><td>{key.balance}</td><td>{key.total_spent}</td><td>{key.total_requests}</td><td>{key.refund_address}</td><td>{key.key_expiry_time}</td></tr>"
|
|
)
|
|
|
|
api_keys_table_rows = "".join(api_keys_table_rows)
|
|
|
|
|
|
# Calculate the total balance of all API keys
|
|
total_user_balance = int(sum(key.balance / 1000 for key in api_keys))
|
|
|
|
# Fetch balance from cashu
|
|
wallet = await _initialize_wallet()
|
|
wallet_balance = wallet.balance
|
|
|
|
# calculate owner balance
|
|
owner_balance = wallet_balance - total_user_balance
|
|
|
|
|
|
return f"""<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<style>
|
|
table {{
|
|
width: 100%;
|
|
border-collapse: collapse;
|
|
}}
|
|
th, td {{
|
|
border: 1px solid black;
|
|
padding: 8px;
|
|
text-align: left;
|
|
}}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<h1>Admin Dashboard</h1>
|
|
<h2>Current Cashu Balance</h2>
|
|
<p>Your Balance: {owner_balance} sats</p>
|
|
<p>The balance is calculated by subtracting the combined user balance from the total Cashu wallet balance.</p>
|
|
<p>Total Cashu Balance: {wallet_balance} sats</p>
|
|
<p>User Balance: {total_user_balance} sats</p>
|
|
<h2>User's API Keys</h2>
|
|
<table>
|
|
<tr>
|
|
<th>Hashed Key</th>
|
|
<th>Balance (mSats)</th>
|
|
<th>Total Spent (mSats)</th>
|
|
<th>Total Requests</th>
|
|
<th>Refund Address</th>
|
|
<th>Refund Time</th>
|
|
</tr>
|
|
{api_keys_table_rows}
|
|
</table>
|
|
</body>
|
|
</html>
|
|
"""
|
|
|
|
@admin_router.get("/", response_class=HTMLResponse)
|
|
async def admin(request: Request):
|
|
admin_cookie = request.cookies.get("admin_password")
|
|
if admin_cookie and admin_cookie == os.getenv("ADMIN_PASSWORD"):
|
|
return await dashboard(request)
|
|
return admin_auth()
|
|
|