From 03bd06ac8c0f4b3440e94e2f9b347b6b1e73d036 Mon Sep 17 00:00:00 2001 From: Maggie Choy Date: Mon, 4 Nov 2024 09:47:40 -0800 Subject: [PATCH] fix: openRPC validation (#668) --- core/main/src/firebolt/firebolt_gateway.rs | 2 +- .../firebolt/handlers/provider_registrar.rs | 4 +- core/main/src/state/openrpc_state.rs | 15 +++--- openrpc_validator/src/lib.rs | 53 +++++++++++++++++++ 4 files changed, 63 insertions(+), 11 deletions(-) diff --git a/core/main/src/firebolt/firebolt_gateway.rs b/core/main/src/firebolt/firebolt_gateway.rs index 7adda3c7a..1fb4913fd 100644 --- a/core/main/src/firebolt/firebolt_gateway.rs +++ b/core/main/src/firebolt/firebolt_gateway.rs @@ -343,7 +343,7 @@ fn validate_request( let major_version = open_rpc_state.get_version().major.to_string(); let openrpc_validator = open_rpc_state.get_openrpc_validator(); // Get Method from the validator - if let Some(rpc_method) = openrpc_validator.get_method_by_name(&method_name) { + if let Some(rpc_method) = openrpc_validator.get_method(&method_name) { // Get schema validator let validator = openrpc_validator .params_validator(major_version, &rpc_method.name) diff --git a/core/main/src/firebolt/handlers/provider_registrar.rs b/core/main/src/firebolt/handlers/provider_registrar.rs index 79db752e1..10132a300 100644 --- a/core/main/src/firebolt/handlers/provider_registrar.rs +++ b/core/main/src/firebolt/handlers/provider_registrar.rs @@ -305,7 +305,7 @@ impl ProviderRegistrar { .platform_state .open_rpc_state .get_openrpc_validator() - .get_result_properties_schema_by_name(event) + .get_result_properties_schema(event) { // Populate the event result, injecting the app ID if the field exists in the event schema @@ -457,7 +457,7 @@ impl ProviderRegistrar { .platform_state .open_rpc_state .get_openrpc_validator() - .get_result_properties_schema_by_name(&context.method) + .get_result_properties_schema(&context.method) { // Inject the provider app ID if the field exists in the provided-to response schema, the other field will be // the provider response. The firebolt spec is not ideal in that the provider response data is captured diff --git a/core/main/src/state/openrpc_state.rs b/core/main/src/state/openrpc_state.rs index 086fa2e2e..6e74d4b5b 100644 --- a/core/main/src/state/openrpc_state.rs +++ b/core/main/src/state/openrpc_state.rs @@ -38,7 +38,7 @@ use std::{ sync::{Arc, RwLock}, }; -use openrpc_validator::FireboltOpenRpc as FireboltOpenRpcValidator; +use openrpc_validator::{FireboltOpenRpc as FireboltOpenRpcValidator, RpcMethodValidator}; #[derive(Debug, Clone)] pub enum ApiSurface { @@ -75,7 +75,7 @@ pub struct OpenRpcState { cap_policies: Arc>>, extended_rpc: Arc>>, provider_relation_map: Arc>>, - openrpc_validator: Arc>, + openrpc_validator: Arc>, provider_registrations: Vec, json_schema_cache: Arc>>, } @@ -127,6 +127,8 @@ impl OpenRpcState { let ripple_open_rpc: FireboltOpenRpc = FireboltOpenRpc::default(); let openrpc_validator: FireboltOpenRpcValidator = serde_json::from_str(&open_rpc_path) .expect("Failed parsing FireboltOpenRpcValidator from open RPC file"); + let mut rpc_method_validator = RpcMethodValidator::new(); + rpc_method_validator.add_schema(openrpc_validator); let v = OpenRpcState { firebolt_cap_map: Arc::new(RwLock::new(firebolt_open_rpc.get_methods_caps())), ripple_cap_map: Arc::new(RwLock::new(ripple_open_rpc.get_methods_caps())), @@ -135,12 +137,11 @@ impl OpenRpcState { open_rpc: firebolt_open_rpc.clone(), extended_rpc: Arc::new(RwLock::new(Vec::new())), provider_relation_map: Arc::new(RwLock::new(HashMap::new())), - openrpc_validator: Arc::new(RwLock::new(openrpc_validator)), + openrpc_validator: Arc::new(RwLock::new(rpc_method_validator)), provider_registrations, json_schema_cache: Arc::new(RwLock::new(HashMap::new())), }; v.build_provider_relation_sets(&firebolt_open_rpc.methods); - for path in extn_sdks { if v.add_extension_open_rpc(&path).is_err() { error!("Error adding extn_sdk from {path}"); @@ -176,9 +177,7 @@ impl OpenRpcState { return match serde_json::from_str::(&open_rpc) { Ok(additional_open_rpc_validator) => { let mut validator = self.openrpc_validator.write().unwrap(); - for (k, v) in additional_open_rpc_validator.apis { - validator.apis.insert(k, v); - } + validator.add_schema(additional_open_rpc_validator); return Ok(()); } Err(_) => Err(RippleError::ParseError), @@ -332,7 +331,7 @@ impl OpenRpcState { self.open_rpc.info.clone() } - pub fn get_openrpc_validator(&self) -> FireboltOpenRpcValidator { + pub fn get_openrpc_validator(&self) -> RpcMethodValidator { self.openrpc_validator.read().unwrap().clone() } diff --git a/openrpc_validator/src/lib.rs b/openrpc_validator/src/lib.rs index c681a6dc1..844900df3 100644 --- a/openrpc_validator/src/lib.rs +++ b/openrpc_validator/src/lib.rs @@ -6,6 +6,59 @@ use serde_json::{json, Map, Value}; pub extern crate jsonschema; +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct RpcMethodValidator { + pub validators: Vec, +} + +impl Default for RpcMethodValidator { + fn default() -> Self { + Self::new() + } +} + +impl RpcMethodValidator { + pub fn new() -> RpcMethodValidator { + RpcMethodValidator { validators: vec![] } + } + + pub fn add_schema(&mut self, schema: FireboltOpenRpc) { + self.validators.push(schema); + } + + pub fn get_method(&self, name: &str) -> Option { + for validator in &self.validators { + if let Some(method) = validator.get_method_by_name(name) { + return Some(method); + } + } + None + } + + pub fn get_result_properties_schema(&self, name: &str) -> Option> { + for validator in &self.validators { + if let Some(method) = validator.get_result_properties_schema_by_name(name) { + return Some(method); + } + } + None + } + + pub fn params_validator( + &self, + version: String, + method: &str, + ) -> Result { + for validator in &self.validators { + let validator = validator.params_validator(version.clone(), method); + if validator.is_ok() { + return validator; + } + } + Err(ValidationError::SpecVersionNotFound) + } +} + #[derive(Debug, Serialize, Deserialize, Clone)] pub struct FireboltOpenRpc { pub apis: HashMap,