Render inherited auth and headers (#217)

This commit is contained in:
Gregory Schier
2025-05-26 07:18:57 -07:00
committed by GitHub
parent 261911b57e
commit 7d1ca1c232
7 changed files with 132 additions and 60 deletions

View File

@@ -1,13 +1,13 @@
use std::collections::BTreeMap; use std::collections::BTreeMap;
use crate::error::Result; use crate::error::Result;
use KeyAndValueRef::{Ascii, Binary};
use tauri::{Manager, Runtime, WebviewWindow}; use tauri::{Manager, Runtime, WebviewWindow};
use yaak_grpc::{KeyAndValueRef, MetadataMap}; use yaak_grpc::{KeyAndValueRef, MetadataMap};
use yaak_models::models::GrpcRequest; use yaak_models::models::GrpcRequest;
use yaak_models::query_manager::QueryManagerExt; use yaak_models::query_manager::QueryManagerExt;
use yaak_plugins::events::{CallHttpAuthenticationRequest, HttpHeader}; use yaak_plugins::events::{CallHttpAuthenticationRequest, HttpHeader};
use yaak_plugins::manager::PluginManager; use yaak_plugins::manager::PluginManager;
use KeyAndValueRef::{Ascii, Binary};
pub(crate) fn metadata_to_map(metadata: MetadataMap) -> BTreeMap<String, String> { pub(crate) fn metadata_to_map(metadata: MetadataMap) -> BTreeMap<String, String> {
let mut entries = BTreeMap::new(); let mut entries = BTreeMap::new();
@@ -20,6 +20,23 @@ pub(crate) fn metadata_to_map(metadata: MetadataMap) -> BTreeMap<String, String>
entries entries
} }
pub(crate) fn resolve_grpc_request<R: Runtime>(
window: &WebviewWindow<R>,
request: &GrpcRequest,
) -> Result<GrpcRequest> {
let mut new_request = request.clone();
let (authentication_type, authentication) =
window.db().resolve_auth_for_grpc_request(request)?;
new_request.authentication_type = authentication_type;
new_request.authentication = authentication;
let metadata = window.db().resolve_metadata_for_grpc_request(request)?;
new_request.metadata = metadata;
Ok(new_request)
}
pub(crate) async fn build_metadata<R: Runtime>( pub(crate) async fn build_metadata<R: Runtime>(
window: &WebviewWindow<R>, window: &WebviewWindow<R>,
request: &GrpcRequest, request: &GrpcRequest,
@@ -28,8 +45,7 @@ pub(crate) async fn build_metadata<R: Runtime>(
let mut metadata = BTreeMap::new(); let mut metadata = BTreeMap::new();
// Add the rest of metadata // Add the rest of metadata
let resolved_metadata = window.db().resolve_metadata_for_grpc_request(&request)?; for h in request.metadata.clone() {
for h in resolved_metadata {
if h.name.is_empty() && h.value.is_empty() { if h.name.is_empty() && h.value.is_empty() {
continue; continue;
} }
@@ -41,28 +57,34 @@ pub(crate) async fn build_metadata<R: Runtime>(
metadata.insert(h.name, h.value); metadata.insert(h.name, h.value);
} }
let (authentication_type, authentication) = match request.authentication_type.clone() {
window.db().resolve_auth_for_grpc_request(&request)?; None => {
// No authentication found. Not even inherited
if let Some(auth_name) = authentication_type.clone() { }
let auth = authentication.clone(); Some(authentication_type) if authentication_type == "none" => {
let plugin_req = CallHttpAuthenticationRequest { // Explicitly no authentication
context_id: format!("{:x}", md5::compute(request.id.clone())), }
values: serde_json::from_value(serde_json::to_value(&auth).unwrap()).unwrap(), Some(authentication_type) => {
method: "POST".to_string(), let auth = request.authentication.clone();
url: request.url.clone(), let plugin_req = CallHttpAuthenticationRequest {
headers: metadata context_id: format!("{:x}", md5::compute(request.id.clone())),
.iter() values: serde_json::from_value(serde_json::to_value(&auth).unwrap()).unwrap(),
.map(|(name, value)| HttpHeader { method: "POST".to_string(),
name: name.to_string(), url: request.url.clone(),
value: value.to_string(), headers: metadata
}) .iter()
.collect(), .map(|(name, value)| HttpHeader {
}; name: name.to_string(),
let plugin_result = value: value.to_string(),
plugin_manager.call_http_authentication(&window, &auth_name, plugin_req).await?; })
for header in plugin_result.set_headers { .collect(),
metadata.insert(header.name, header.value); };
let plugin_result = plugin_manager
.call_http_authentication(&window, &authentication_type, plugin_req)
.await?;
for header in plugin_result.set_headers {
metadata.insert(header.name, header.value);
}
} }
} }

View File

@@ -65,14 +65,7 @@ pub async fn send_http_request<R: Runtime>(
); );
let update_source = UpdateSource::from_window(window); let update_source = UpdateSource::from_window(window);
let request = match render_http_request( let resolved_request = match resolve_http_request(window, unrendered_request) {
&unrendered_request,
&base_environment,
environment.as_ref(),
&cb,
)
.await
{
Ok(r) => r, Ok(r) => r,
Err(e) => { Err(e) => {
return Ok(response_err( return Ok(response_err(
@@ -84,6 +77,21 @@ pub async fn send_http_request<R: Runtime>(
} }
}; };
let request =
match render_http_request(&resolved_request, &base_environment, environment.as_ref(), &cb)
.await
{
Ok(r) => r,
Err(e) => {
return Ok(response_err(
&app_handle,
&*response.lock().await,
e.to_string(),
&update_source,
));
}
};
let mut url_string = request.url.clone(); let mut url_string = request.url.clone();
url_string = ensure_proto(&url_string); url_string = ensure_proto(&url_string);
@@ -230,9 +238,7 @@ pub async fn send_http_request<R: Runtime>(
// ); // );
// } // }
let resolved_headers = window.db().resolve_headers_for_http_request(&request)?; for h in request.headers.clone() {
for h in resolved_headers {
if h.name.is_empty() && h.value.is_empty() { if h.name.is_empty() && h.value.is_empty() {
continue; continue;
} }
@@ -431,10 +437,7 @@ pub async fn send_http_request<R: Runtime>(
} }
}; };
let (authentication_type, authentication) = match request.authentication_type {
window.db().resolve_auth_for_http_request(&request)?;
match authentication_type {
None => { None => {
// No authentication found. Not even inherited // No authentication found. Not even inherited
} }
@@ -444,8 +447,10 @@ pub async fn send_http_request<R: Runtime>(
Some(authentication_type) => { Some(authentication_type) => {
let req = CallHttpAuthenticationRequest { let req = CallHttpAuthenticationRequest {
context_id: format!("{:x}", md5::compute(request.id)), context_id: format!("{:x}", md5::compute(request.id)),
values: serde_json::from_value(serde_json::to_value(&authentication).unwrap()) values: serde_json::from_value(
.unwrap(), serde_json::to_value(&request.authentication).unwrap(),
)
.unwrap(),
url: sendable_req.url().to_string(), url: sendable_req.url().to_string(),
method: sendable_req.method().to_string(), method: sendable_req.method().to_string(),
headers: sendable_req headers: sendable_req
@@ -676,6 +681,23 @@ pub async fn send_http_request<R: Runtime>(
}) })
} }
fn resolve_http_request<R: Runtime>(
window: &WebviewWindow<R>,
request: &HttpRequest,
) -> Result<HttpRequest> {
let mut new_request = request.clone();
let (authentication_type, authentication) =
window.db().resolve_auth_for_http_request(request)?;
new_request.authentication_type = authentication_type;
new_request.authentication = authentication;
let headers = window.db().resolve_headers_for_http_request(request)?;
new_request.headers = headers;
Ok(new_request)
}
fn ensure_proto(url_str: &str) -> String { fn ensure_proto(url_str: &str) -> String {
if url_str.starts_with("http://") || url_str.starts_with("https://") { if url_str.starts_with("http://") || url_str.starts_with("https://") {
return url_str.to_string(); return url_str.to_string();

View File

@@ -1,7 +1,7 @@
extern crate core; extern crate core;
use crate::encoding::read_response_body; use crate::encoding::read_response_body;
use crate::error::Error::GenericError; use crate::error::Error::GenericError;
use crate::grpc::{build_metadata, metadata_to_map}; use crate::grpc::{build_metadata, metadata_to_map, resolve_grpc_request};
use crate::http_request::send_http_request; use crate::http_request::send_http_request;
use crate::notifications::YaakNotifier; use crate::notifications::YaakNotifier;
use crate::render::{render_grpc_request, render_template}; use crate::render::{render_grpc_request, render_template};
@@ -151,10 +151,13 @@ async fn cmd_grpc_reflect<R: Runtime>(
None => None, None => None,
}; };
let unrendered_request = app_handle.db().get_grpc_request(request_id)?; let unrendered_request = app_handle.db().get_grpc_request(request_id)?;
let resolved_request = resolve_grpc_request(&window, &unrendered_request)?;
let base_environment = let base_environment =
app_handle.db().get_base_environment(&unrendered_request.workspace_id)?; app_handle.db().get_base_environment(&unrendered_request.workspace_id)?;
let req = render_grpc_request( let req = render_grpc_request(
&unrendered_request, &resolved_request,
&base_environment, &base_environment,
environment.as_ref(), environment.as_ref(),
&PluginTemplateCallback::new( &PluginTemplateCallback::new(
@@ -195,10 +198,12 @@ async fn cmd_grpc_go<R: Runtime>(
None => None, None => None,
}; };
let unrendered_request = app_handle.db().get_grpc_request(request_id)?; let unrendered_request = app_handle.db().get_grpc_request(request_id)?;
let resolved_request = resolve_grpc_request(&window, &unrendered_request)?;
let base_environment = let base_environment =
app_handle.db().get_base_environment(&unrendered_request.workspace_id)?; app_handle.db().get_base_environment(&unrendered_request.workspace_id)?;
let request = render_grpc_request( let request = render_grpc_request(
&unrendered_request, &resolved_request,
&base_environment, &base_environment,
environment.as_ref(), environment.as_ref(),
&PluginTemplateCallback::new( &PluginTemplateCallback::new(

View File

@@ -1,6 +1,7 @@
use crate::error::Result; use crate::error::Result;
use crate::manager::WebsocketManager; use crate::manager::WebsocketManager;
use crate::render::render_request; use crate::render::render_websocket_request;
use crate::resolve::resolve_websocket_request;
use log::{info, warn}; use log::{info, warn};
use std::str::FromStr; use std::str::FromStr;
use tauri::http::{HeaderMap, HeaderName}; use tauri::http::{HeaderMap, HeaderName};
@@ -119,8 +120,9 @@ pub(crate) async fn send<R: Runtime>(
}; };
let base_environment = let base_environment =
app_handle.db().get_base_environment(&unrendered_request.workspace_id)?; app_handle.db().get_base_environment(&unrendered_request.workspace_id)?;
let request = render_request( let resolved_request = resolve_websocket_request(&window, &unrendered_request)?;
&unrendered_request, let request = render_websocket_request(
&resolved_request,
&base_environment, &base_environment,
environment.as_ref(), environment.as_ref(),
&PluginTemplateCallback::new( &PluginTemplateCallback::new(
@@ -194,8 +196,9 @@ pub(crate) async fn connect<R: Runtime>(
}; };
let base_environment = let base_environment =
app_handle.db().get_base_environment(&unrendered_request.workspace_id)?; app_handle.db().get_base_environment(&unrendered_request.workspace_id)?;
let request = render_request( let resolved_request = resolve_websocket_request(&window, &unrendered_request)?;
&unrendered_request, let request = render_websocket_request(
&resolved_request,
&base_environment, &base_environment,
environment.as_ref(), environment.as_ref(),
&PluginTemplateCallback::new( &PluginTemplateCallback::new(
@@ -206,13 +209,9 @@ pub(crate) async fn connect<R: Runtime>(
) )
.await?; .await?;
let (authentication_type, authentication) =
window.db().resolve_auth_for_websocket_request(&request)?;
let mut headers = HeaderMap::new(); let mut headers = HeaderMap::new();
let resolved_headers = window.db().resolve_headers_for_websocket_request(&request)?; for h in request.headers.clone() {
for h in resolved_headers {
if h.name.is_empty() && h.value.is_empty() { if h.name.is_empty() && h.value.is_empty() {
continue; continue;
} }
@@ -220,13 +219,14 @@ pub(crate) async fn connect<R: Runtime>(
if !h.enabled { if !h.enabled {
continue; continue;
} }
headers.insert( headers.insert(
HeaderName::from_str(&h.name).unwrap(), HeaderName::from_str(&h.name).unwrap(),
HeaderValue::from_str(&h.value).unwrap(), HeaderValue::from_str(&h.value).unwrap(),
); );
} }
match authentication_type { match request.authentication_type {
None => { None => {
// No authentication found. Not even inherited // No authentication found. Not even inherited
} }
@@ -234,7 +234,7 @@ pub(crate) async fn connect<R: Runtime>(
// Explicitly no authentication // Explicitly no authentication
} }
Some(authentication_type) => { Some(authentication_type) => {
let auth = authentication.clone(); let auth = request.authentication.clone();
let plugin_req = CallHttpAuthenticationRequest { let plugin_req = CallHttpAuthenticationRequest {
context_id: format!("{:x}", md5::compute(request_id.to_string())), context_id: format!("{:x}", md5::compute(request_id.to_string())),
values: serde_json::from_value(serde_json::to_value(&auth).unwrap()).unwrap(), values: serde_json::from_value(serde_json::to_value(&auth).unwrap()).unwrap(),
@@ -250,8 +250,9 @@ pub(crate) async fn connect<R: Runtime>(
}) })
.collect(), .collect(),
}; };
let plugin_result = let plugin_result = plugin_manager
plugin_manager.call_http_authentication(&window, &authentication_type, plugin_req).await?; .call_http_authentication(&window, &authentication_type, plugin_req)
.await?;
for header in plugin_result.set_headers { for header in plugin_result.set_headers {
headers.insert( headers.insert(
HeaderName::from_str(&header.name).unwrap(), HeaderName::from_str(&header.name).unwrap(),

View File

@@ -3,6 +3,7 @@ mod connect;
pub mod error; pub mod error;
mod manager; mod manager;
mod render; mod render;
mod resolve;
use crate::commands::{ use crate::commands::{
close, connect, delete_connection, delete_connections, delete_request, duplicate_request, close, connect, delete_connection, delete_connections, delete_request, duplicate_request,

View File

@@ -4,7 +4,7 @@ use yaak_models::models::{Environment, HttpRequestHeader, WebsocketRequest};
use yaak_models::render::make_vars_hashmap; use yaak_models::render::make_vars_hashmap;
use yaak_templates::{parse_and_render, render_json_value_raw, TemplateCallback}; use yaak_templates::{parse_and_render, render_json_value_raw, TemplateCallback};
pub async fn render_request<T: TemplateCallback>( pub async fn render_websocket_request<T: TemplateCallback>(
r: &WebsocketRequest, r: &WebsocketRequest,
base_environment: &Environment, base_environment: &Environment,
environment: Option<&Environment>, environment: Option<&Environment>,

View File

@@ -0,0 +1,21 @@
use crate::error::Result;
use tauri::{Runtime, WebviewWindow};
use yaak_models::models::WebsocketRequest;
use yaak_models::query_manager::QueryManagerExt;
pub(crate) fn resolve_websocket_request<R: Runtime>(
window: &WebviewWindow<R>,
request: &WebsocketRequest,
) -> Result<WebsocketRequest> {
let mut new_request = request.clone();
let (authentication_type, authentication) =
window.db().resolve_auth_for_websocket_request(request)?;
new_request.authentication_type = authentication_type;
new_request.authentication = authentication;
let headers = window.db().resolve_headers_for_websocket_request(request)?;
new_request.headers = headers;
Ok(new_request)
}