From c1489fc49112f68319156512f0927fe2278ad0ad Mon Sep 17 00:00:00 2001 From: Mahmoud-Emad Date: Tue, 21 Oct 2025 11:10:30 +0300 Subject: [PATCH] fix: Improve error handling and optional crypto_client - Add explicit error handling for HeroModels initialization - Enhance error messages for HeroDB connection and ping failures - Make crypto_client optional in HeroServer configuration - Initialize crypto_client only when auth_enabled is true - Ensure crypto_client is available before use in auth_submit --- .../hero/heromodels/heroserver_example.vsh | 12 +++++++--- lib/crypt/herocrypt/herocrypt.v | 21 +++++++++++++++-- lib/hero/heroserver/auth.v | 7 +++++- lib/hero/heroserver/factory.v | 23 +++++++++++++++---- lib/hero/heroserver/model.v | 2 +- 5 files changed, 54 insertions(+), 11 deletions(-) diff --git a/examples/hero/heromodels/heroserver_example.vsh b/examples/hero/heromodels/heroserver_example.vsh index b8d5f26d..441a1f0e 100755 --- a/examples/hero/heromodels/heroserver_example.vsh +++ b/examples/hero/heromodels/heroserver_example.vsh @@ -6,8 +6,11 @@ import time fn main() { // Start the server in a background thread with authentication disabled for testing - spawn fn () ! { - heromodels.new(reset: true, name: 'test')! + spawn fn () { + heromodels.new(reset: true, name: 'test') or { + eprintln('Failed to initialize HeroModels: ${err}') + exit(1) + } heromodels.server_start( name: 'test' port: 8080 @@ -17,7 +20,10 @@ fn main() { allowed_origins: [ 'http://localhost:5173', ] - ) or { panic('Failed to start HeroModels server: ${err}') } + ) or { + eprintln('Failed to start HeroModels server: ${err}') + exit(1) + } }() // Keep the main thread alive diff --git a/lib/crypt/herocrypt/herocrypt.v b/lib/crypt/herocrypt/herocrypt.v index 51f54b9e..a015550a 100644 --- a/lib/crypt/herocrypt/herocrypt.v +++ b/lib/crypt/herocrypt/herocrypt.v @@ -16,8 +16,25 @@ pub fn new(url_ string) !&HeroCrypt { if url == '' { url = 'localhost:6381' } - mut redis := redisclient.new(url)! - redis.ping()! + mut redis := redisclient.new(url) or { + return error('Failed to connect to HeroDB at ${url}. + +HeroCrypt requires HeroDB (Redis with AGE encryption extensions) to be running. + +To start HeroDB: + 1. Clone the repository: + hero git clone https://git.ourworld.tf/herocode/herodb + 2. Run the server: + ~/code/git.ourworld.tf/herocode/herodb/run.sh + +Original error: ${err}') + } + redis.ping() or { + return error('Connected to ${url} but failed to ping HeroDB. +Please ensure HeroDB is running and accessible. + +Original error: ${err}') + } return &HeroCrypt{ redis_client: redis } diff --git a/lib/hero/heroserver/auth.v b/lib/hero/heroserver/auth.v index 9f8a4eee..acda4283 100644 --- a/lib/hero/heroserver/auth.v +++ b/lib/hero/heroserver/auth.v @@ -39,6 +39,11 @@ pub fn (mut server HeroServer) auth_request(pubkey string) !AuthResponse { // Submit signed challenge for authentication pub fn (mut server HeroServer) auth_submit(pubkey string, signature string) !AuthSubmitResponse { + // Ensure crypto client is available + mut crypto_client := server.crypto_client or { + return error('Authentication is not available: crypto client not initialized. Please ensure auth_enabled is true and HeroDB is running.') + } + // Get stored challenge challenge_data := server.challenges[pubkey] or { return error('No active challenge for this public key') @@ -53,7 +58,7 @@ pub fn (mut server HeroServer) auth_submit(pubkey string, signature string) !Aut // Verify signature using HeroCrypt // Note: We need the verification key, which should be derived from pubkey // For now, assume pubkey is the verification key in correct format - is_valid := server.crypto_client.verify(pubkey, challenge_data.challenge, signature)! + is_valid := crypto_client.verify(pubkey, challenge_data.challenge, signature)! if !is_valid { return error('Invalid signature') diff --git a/lib/hero/heroserver/factory.v b/lib/hero/heroserver/factory.v index 73967f96..0419a678 100644 --- a/lib/hero/heroserver/factory.v +++ b/lib/hero/heroserver/factory.v @@ -15,11 +15,26 @@ pub fn new(config HeroServerConfig) !&HeroServer { return error('Port ${config.port} is already in use') } - // Initialize crypto client - crypto_client := if c := config.crypto_client { - c + // Initialize crypto client only if authentication is enabled + mut crypto_client := ?&herocrypt.HeroCrypt(none) + if config.auth_enabled { + crypto_client = if c := config.crypto_client { + c + } else { + herocrypt.new_default() or { + return error('Failed to initialize HeroCrypt client for HeroServer. + +${err} + +To resolve this issue, you can either: + 1. Start HeroDB (see error message above for instructions) + 2. Set auth_enabled: false to disable authentication + 3. Provide a custom crypto_client in the configuration') + } + } } else { - herocrypt.new_default()! + // Auth is disabled, use provided crypto_client if any + crypto_client = config.crypto_client } // Create logger with configurable output diff --git a/lib/hero/heroserver/model.v b/lib/hero/heroserver/model.v index c6a5ba0d..a5135831 100644 --- a/lib/hero/heroserver/model.v +++ b/lib/hero/heroserver/model.v @@ -31,7 +31,7 @@ pub struct HeroServer { mut: port int host string - crypto_client &herocrypt.HeroCrypt + crypto_client ?&herocrypt.HeroCrypt // Optional - only needed when auth_enabled is true sessions map[string]Session // sessionkey -> Session handlers map[string]&openrpc.Handler // handlertype -> handler challenges map[string]AuthChallenge