Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions node/rustchain_block_producer.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
Implements secure block production for Proof of Antiquity consensus.
"""

import hashlib
import hmac
import json
import logging
import os
Expand Down Expand Up @@ -860,6 +862,23 @@ def _latest_randomness(conn: sqlite3.Connection) -> str:
def create_block_api_routes(app, producer: BlockProducer, validator: BlockValidator):
"""Create Flask routes for block API"""
from flask import jsonify, request
import os as _os

def _get_admin_key() -> str:
return _os.environ.get("RC_ADMIN_KEY", "")

def _require_admin():
"""Return error response if not admin, else None."""
admin_key = request.headers.get("X-Admin-Key", "")
if not admin_key:
return jsonify({"error": "X-Admin-Key header required"}), 401
expected = _get_admin_key()
if not expected:
# If RC_ADMIN_KEY is not set, reject all requests.
return jsonify({"error": "Admin authentication not configured"}), 503
if not hmac.compare_digest(admin_key, expected):
return jsonify({"error": "Invalid admin key"}), 403
return None

@app.route('/block/latest', methods=['GET'])
def get_latest_block():
Expand Down Expand Up @@ -1072,6 +1091,9 @@ def get_blocks_batch():
@app.route('/block/slot', methods=['GET'])
def get_current_slot():
"""Get current slot info"""
err = _require_admin()
if err:
return err
slot = producer.get_current_slot()
expected_producer = producer.get_round_robin_producer(slot)
slot_start = producer.get_slot_start_time(slot)
Expand All @@ -1090,6 +1112,9 @@ def get_current_slot():
@app.route('/block/producers', methods=['GET'])
def list_producers():
"""List current block producers"""
err = _require_admin()
if err:
return err
current_ts = int(time.time())
miners = producer.get_attested_miners(current_ts)

Expand Down
23 changes: 22 additions & 1 deletion node/rustchain_dashboard.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,28 @@
import time
import psutil
import os
import hmac
from datetime import datetime, timedelta
from flask import Flask, send_from_directory, render_template_string, jsonify, request
import requests


def _get_admin_key():
return os.environ.get("RC_ADMIN_KEY", "")


def _require_admin():
"""Return error response if not admin, else None."""
admin_key = request.headers.get("X-Admin-Key", "")
if not admin_key:
return jsonify({"error": "X-Admin-Key header required"}), 401
expected = _get_admin_key()
if not expected:
return jsonify({"error": "Admin authentication not configured"}), 503
if not hmac.compare_digest(admin_key, expected):
return jsonify({"error": "Invalid admin key"}), 403
return None

app = Flask(__name__)

DOWNLOAD_DIR = "/root/rustchain/downloads"
Expand Down Expand Up @@ -604,7 +622,10 @@ def api_stats():

@app.route('/api/wallet/<wallet_address>')
def api_wallet_lookup(wallet_address):
"""Look up wallet balance and info"""
"""Look up wallet balance and info (admin only)."""
err = _require_admin()
if err:
return err
try:
with sqlite3.connect(DB_PATH) as conn:
# Get balance
Expand Down
Loading