Update admin UI with real API integration and secret management

This commit is contained in:
Timur Gordon
2025-10-31 02:29:29 +01:00
parent e493085892
commit 49d36485d0
12 changed files with 827 additions and 115 deletions

View File

@@ -0,0 +1,78 @@
/// Generate test secp256k1 keypairs for supervisor authentication testing
///
/// Run with: cargo run --example generate_test_keys
use secp256k1::{Secp256k1, SecretKey, PublicKey};
use hex;
fn main() {
let secp = Secp256k1::new();
println!("\n╔════════════════════════════════════════════════════════════╗");
println!("║ Test Keypairs for Supervisor Auth ║");
println!("╚════════════════════════════════════════════════════════════╝\n");
println!("⚠️ WARNING: These are TEST keypairs only! Never use in production!\n");
// Generate 5 keypairs with simple private keys for testing
let test_keys = vec![
("Alice (Admin)", "1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef"),
("Bob (User)", "fedcba0987654321fedcba0987654321fedcba0987654321fedcba0987654321"),
("Charlie (Register)", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"),
("Dave (Test)", "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"),
("Eve (Test)", "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc"),
];
for (i, (name, privkey_hex)) in test_keys.iter().enumerate() {
println!("## Keypair {} - {}", i + 1, name);
println!("─────────────────────────────────────────────────────────────");
// Parse private key
let privkey_bytes = hex::decode(privkey_hex).expect("Invalid hex");
let secret_key = SecretKey::from_slice(&privkey_bytes).expect("Invalid private key");
// Derive public key
let public_key = PublicKey::from_secret_key(&secp, &secret_key);
// Serialize keys
let pubkey_uncompressed = hex::encode(public_key.serialize_uncompressed());
let pubkey_compressed = hex::encode(public_key.serialize());
println!("Private Key (hex): 0x{}", privkey_hex);
println!("Public Key (uncomp): 0x{}", pubkey_uncompressed);
println!("Public Key (comp): 0x{}", pubkey_compressed);
println!();
}
println!("\n╔════════════════════════════════════════════════════════════╗");
println!("║ Usage Examples ║");
println!("╚════════════════════════════════════════════════════════════╝\n");
println!("### Using with OpenRPC Client (Rust)\n");
println!("```rust");
println!("use secp256k1::{{Secp256k1, SecretKey}};");
println!("use hex;");
println!();
println!("// Alice's private key for admin access");
println!("let privkey_hex = \"1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef\";");
println!("let privkey_bytes = hex::decode(privkey_hex).unwrap();");
println!("let secret_key = SecretKey::from_slice(&privkey_bytes).unwrap();");
println!();
println!("// Use with client");
println!("let client = SupervisorClient::new_with_keypair(");
println!(" \"http://127.0.0.1:3030\",");
println!(" secret_key");
println!(");");
println!("```\n");
println!("### Testing Different Scopes\n");
println!("1. **Admin Scope** - Use Alice's keypair for full admin access");
println!("2. **User Scope** - Use Bob's keypair for limited user access");
println!("3. **Register Scope** - Use Charlie's keypair for runner registration\n");
println!("### Quick Copy-Paste Keys\n");
println!("Alice (Admin): 1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef");
println!("Bob (User): fedcba0987654321fedcba0987654321fedcba0987654321fedcba0987654321");
println!("Charlie (Reg): aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
println!("Dave (Test): bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb");
println!("Eve (Test): cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc\n");
}

View File

@@ -569,6 +569,25 @@ impl WasmSupervisorClient {
}
}
/// Get logs for a specific job
#[wasm_bindgen]
pub async fn get_job_logs(&self, job_id: &str, lines: Option<usize>) -> Result<JsValue, JsValue> {
let params = if let Some(n) = lines {
serde_json::json!([job_id, n])
} else {
serde_json::json!([job_id, serde_json::Value::Null])
};
match self.call_method("get_job_logs", params).await {
Ok(result) => {
// Convert Vec<String> to JsValue
Ok(serde_wasm_bindgen::to_value(&result)
.map_err(|e| JsValue::from_str(&format!("Failed to convert logs: {}", e)))?)
},
Err(e) => Err(JsValue::from_str(&format!("Failed to get job logs: {:?}", e)))
}
}
/// Remove a runner from the supervisor
pub async fn remove_runner(&self, actor_id: &str) -> Result<(), JsValue> {
let params = serde_json::json!([actor_id]);
@@ -980,10 +999,10 @@ pub fn sign_job_canonical(
let secret_key = SecretKey::from_slice(&secret_bytes)
.map_err(|e| JsValue::from_str(&format!("Invalid private key: {}", e)))?;
// Get the public key
// Get the public key (uncompressed format)
let secp = Secp256k1::new();
let public_key = PublicKey::from_secret_key(&secp, &secret_key);
let public_key_hex = hex::encode(public_key.serialize());
let public_key_hex = hex::encode(public_key.serialize_uncompressed());
// Hash the canonical representation
let mut hasher = Sha256::new();