diff --git a/lib/hero/heroserver/api_handler.v b/lib/hero/heroserver/api_handler.v index 90884766..ff9bf4c7 100644 --- a/lib/hero/heroserver/api_handler.v +++ b/lib/hero/heroserver/api_handler.v @@ -1,82 +1,49 @@ module heroserver -import net.http import json import veb -// Setup API routes -pub fn (mut server HeroServer) setup_api_routes() ! { - // Authentication endpoints - server.app.mount('/auth', auth_handler) - - // API endpoints for each handler type - for handler_type, _ in server.handlers { - server.app.mount('/api/${handler_type}', api_handler) - } -} - -// Authentication handler functions -fn auth_handler(mut ctx Context) veb.Result { - match ctx.req.method { - .post { - // Extract path to determine action - path_parts := ctx.req.url.path.split('/') - if path_parts.len < 3 { - return ctx.request_error('Invalid endpoint') +@['/auth/:action'] +pub fn (mut server HeroServer) auth_handler(mut ctx Context, action string) !veb.Result { + match action { + 'register' { + request := json.decode(RegisterRequest, ctx.req.data) or { + return ctx.request_error('Invalid JSON format') } - - action := path_parts[2] - match action { - 'register' { return handle_register(mut ctx) } - 'authreq' { return handle_auth_request(mut ctx) } - 'auth' { return handle_auth_submit(mut ctx) } - else { return ctx.not_found() } + server.register(request.pubkey)! + return ctx.json({'status': 'success'}) + } + 'authreq' { + request := json.decode(AuthRequest, ctx.req.data) or { + return ctx.request_error('Invalid JSON format') } + response := server.auth_request(request.pubkey)! + return ctx.json(response) + } + 'auth' { + request := json.decode(AuthSubmitRequest, ctx.req.data) or { + return ctx.request_error('Invalid JSON format') + } + response := server.auth_submit(request.pubkey, request.signature)! + return ctx.json(response) } else { - return ctx.request_error('Method not allowed') + return ctx.not_found() } } } -fn handle_register(mut ctx Context) veb.Result { - // Parse JSON request - request := json.decode(RegisterRequest, ctx.req.data) or { - return ctx.request_error('Invalid JSON format') - } - - // Get server from context (you'll need to add this to Context) - // For now, this is a simplified approach - return ctx.json({'status': 'success'}) -} - -fn handle_auth_request(mut ctx Context) veb.Result { - // Parse JSON request - request := json.decode(AuthRequest, ctx.req.data) or { - return ctx.request_error('Invalid JSON format') - } - - // Generate challenge (simplified) - return ctx.json({'challenge': 'sample_challenge'}) -} - -fn handle_auth_submit(mut ctx Context) veb.Result { - // Parse JSON request - request := json.decode(AuthSubmitRequest, ctx.req.data) or { - return ctx.request_error('Invalid JSON format') - } - - // Return session key (simplified) - return ctx.json({'session_key': 'sample_session_key'}) -} - -// API handler for specific handler types -fn api_handler(mut ctx Context) veb.Result { - // Extract session key from header +@['/api/:handler_type/:method_name'] +pub fn (mut server HeroServer) api_handler(mut ctx Context, handler_type string, method_name string) veb.Result { session_key := ctx.get_header(.authorization) or { return ctx.request_error('Missing session key in Authorization header') }.replace('Bearer ', '') - + + // Validate session + mut session := server.validate_session(session_key) or { + return ctx.request_error('Invalid session') + } + // For now, simplified response return ctx.json({'result': 'success'}) } \ No newline at end of file diff --git a/lib/hero/heroserver/auth.v b/lib/hero/heroserver/auth.v index 8558e1ae..0a8f52e6 100644 --- a/lib/hero/heroserver/auth.v +++ b/lib/hero/heroserver/auth.v @@ -3,7 +3,6 @@ module heroserver import crypto.md5 import crypto.rand import time -import encoding.base64 // Register a public key (currently just validates format) pub fn (mut server HeroServer) register(pubkey string) ! { @@ -20,7 +19,7 @@ pub fn (mut server HeroServer) register(pubkey string) ! { pub fn (mut server HeroServer) auth_request(pubkey string) !AuthResponse { // Generate random challenge data random_bytes := rand.bytes(32)! - challenge_data := '${pubkey}:${random_bytes.hex()}:${time.now().unix_time()}' + challenge_data := '${pubkey}:${random_bytes.hex()}:${time.now().unix()}' // Create MD5 hash of challenge challenge := md5.hexhash(challenge_data) @@ -61,7 +60,7 @@ pub fn (mut server HeroServer) auth_submit(pubkey string, signature string) !Aut } // Generate session key - session_data := '${pubkey}:${time.now().unix_time()}:${rand.bytes(16)!.hex()}' + session_data := '${pubkey}:${time.now().unix()}:${rand.bytes(16)!.hex()}' session_key := md5.hexhash(session_data) // Create session diff --git a/lib/hero/heroserver/doc_handler.v b/lib/hero/heroserver/doc_handler.v index c4f36491..bb708d5a 100644 --- a/lib/hero/heroserver/doc_handler.v +++ b/lib/hero/heroserver/doc_handler.v @@ -1,23 +1,9 @@ module heroserver import veb -import freeflowuniverse.herolib.schemas.openrpc -// Documentation controller -pub struct DocController { -mut: - server &HeroServer - handler_type string -} - -// Setup documentation routes -pub fn (mut server HeroServer) setup_doc_routes() ! { - for handler_type, _ in server.handlers { - server.app.mount('/doc/${handler_type}', doc_handler) - } -} - -fn doc_handler(mut ctx Context) veb.Result { +@['/doc/:handler_type'] +pub fn (mut server HeroServer) doc_handler(mut ctx Context, handler_type string) veb.Result { // Simplified documentation response html_content := ' diff --git a/lib/hero/heroserver/doc_model.v b/lib/hero/heroserver/doc_model.v index 8358b04b..100ea9c3 100644 --- a/lib/hero/heroserver/doc_model.v +++ b/lib/hero/heroserver/doc_model.v @@ -1,7 +1,6 @@ module heroserver import freeflowuniverse.herolib.schemas.openrpc -import freeflowuniverse.herolib.schemas.jsonschema // DocSpec is the main object passed to the documentation template. pub struct DocSpec { diff --git a/lib/hero/heroserver/factory.v b/lib/hero/heroserver/factory.v index 3c2f8d7b..974b6a1d 100644 --- a/lib/hero/heroserver/factory.v +++ b/lib/hero/heroserver/factory.v @@ -13,16 +13,12 @@ pub fn new(config HeroServerConfig) !&HeroServer { herocrypt.new_default()! } - // Create VEB app - mut app := veb.new[HeroServer, Context]() - mut server := &HeroServer{ port: config.port host: config.host crypto_client: crypto_client sessions: map[string]Session{} handlers: map[string]&openrpc.Handler{} - app: app challenges: map[string]AuthChallenge{} } @@ -36,26 +32,11 @@ pub fn (mut server HeroServer) register_handler(handler_type string, handler &op // Start the server pub fn (mut server HeroServer) start() ! { - // Setup routes - server.setup_routes()! - // Start VEB server - veb.run[HeroServer, Context](mut server, - host: server.host, - port: server.port - )! + veb.run[HeroServer, Context](mut server, server.port) } // Context struct for VEB pub struct Context { veb.Context -} - -// Add to HeroServer struct -pub fn (mut server HeroServer) setup_routes() ! { - // Setup authentication routes - server.setup_api_routes()! - - // Setup documentation routes - server.setup_doc_routes()! } \ No newline at end of file diff --git a/lib/hero/heroserver/model.v b/lib/hero/heroserver/model.v index 6720d530..542947e5 100644 --- a/lib/hero/heroserver/model.v +++ b/lib/hero/heroserver/model.v @@ -3,8 +3,6 @@ module heroserver import freeflowuniverse.herolib.crypt.herocrypt import freeflowuniverse.herolib.schemas.openrpc import time -import veb -import net.http // Main server configuration @[params] @@ -24,9 +22,7 @@ mut: crypto_client &herocrypt.HeroCrypt sessions map[string]Session // sessionkey -> Session handlers map[string]&openrpc.Handler // handlertype -> handler - challenges map[string]AuthChallenge -pub mut: - app &veb.App + challenges map[string]AuthChallenge } // Authentication challenge data diff --git a/lib/schemas/openrpc/custom.v b/lib/schemas/openrpc/custom.v index b17c89a6..02bc619b 100644 --- a/lib/schemas/openrpc/custom.v +++ b/lib/schemas/openrpc/custom.v @@ -1,6 +1,8 @@ module openrpc - import json +import freeflowuniverse.herolib.schemas.jsonschema +import freeflowuniverse.herolib.schemas.openrpc + // In the OpenRPC specification struct pub fn (spec OpenRPC) methods_by_object() map[string][]Method { @@ -37,12 +39,42 @@ pub fn (method Method) example() (string, string) { mut example_params := map[string]string{} for param in method.params { - example_params[param.name] = param.schema.example_value() + param_schema_ref := param.schema + example_params[param.name] = match param_schema_ref { + openrpc.ContentDescriptor { + match param_schema_ref.schema { + jsonschema.Schema { + param_schema_ref.schema.example_value() + } + jsonschema.Reference { + '' + } + } + } + jsonschema.Reference { + '' + } + } } example_call := json.encode(example_params) - example_response := if method.result { - method.result.schema.example_value() + example_response := if method.result is openrpc.ContentDescriptor { + result_schema_ref := method.result + match result_schema_ref { + openrpc.ContentDescriptor { + match result_schema_ref.schema { + jsonschema.Schema { + result_schema_ref.schema.example_value() + } + jsonschema.Reference { + '{"result": "success"}' + } + } + } + jsonschema.Reference { + '{"result": "success"}' + } + } } else { '{"result": "success"}' }