mirror of
https://github.com/mountain-loop/yaak.git
synced 2026-03-18 07:24:07 +01:00
gRPC authentication
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "\n SELECT\n id, model, workspace_id, folder_id, created_at, updated_at, name, sort_priority,\n url, service, method, message,\n proto_files AS \"proto_files!: sqlx::types::Json<Vec<String>>\"\n FROM grpc_requests\n WHERE id = ?\n ",
|
||||
"query": "\n SELECT\n id, model, workspace_id, folder_id, created_at, updated_at, name, sort_priority,\n url, service, method, message, authentication_type,\n authentication AS \"authentication!: Json<HashMap<String, JsonValue>>\",\n proto_files AS \"proto_files!: sqlx::types::Json<Vec<String>>\"\n FROM grpc_requests\n WHERE id = ?\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
@@ -64,9 +64,19 @@
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"name": "proto_files!: sqlx::types::Json<Vec<String>>",
|
||||
"name": "authentication_type",
|
||||
"ordinal": 12,
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"name": "authentication!: Json<HashMap<String, JsonValue>>",
|
||||
"ordinal": 13,
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"name": "proto_files!: sqlx::types::Json<Vec<String>>",
|
||||
"ordinal": 14,
|
||||
"type_info": "Text"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
@@ -85,8 +95,10 @@
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
true,
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "7398403d3de2dc5c5b4b6392f083041d9a55194bb97819225a2612fdeb60ad42"
|
||||
"hash": "0d9e685f878fc2a0e1803c6aaae3828deebd684fc9f78e9f8595a550f90749fe"
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "\n SELECT\n id, model, workspace_id, folder_id, created_at, updated_at, name, sort_priority,\n url, service, method, message,\n proto_files AS \"proto_files!: sqlx::types::Json<Vec<String>>\"\n FROM grpc_requests\n WHERE workspace_id = ?\n ",
|
||||
"query": "\n SELECT\n id, model, workspace_id, folder_id, created_at, updated_at, name, sort_priority,\n url, service, method, message, authentication_type,\n authentication AS \"authentication!: Json<HashMap<String, JsonValue>>\",\n proto_files AS \"proto_files!: sqlx::types::Json<Vec<String>>\"\n FROM grpc_requests\n WHERE workspace_id = ?\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
@@ -64,9 +64,19 @@
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"name": "proto_files!: sqlx::types::Json<Vec<String>>",
|
||||
"name": "authentication_type",
|
||||
"ordinal": 12,
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"name": "authentication!: Json<HashMap<String, JsonValue>>",
|
||||
"ordinal": 13,
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"name": "proto_files!: sqlx::types::Json<Vec<String>>",
|
||||
"ordinal": 14,
|
||||
"type_info": "Text"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
@@ -85,8 +95,10 @@
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
true,
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "761d27c3ec425c37ad9abe9c732a9c1746c81ca50d2c413e540b74c8c8e908b7"
|
||||
"hash": "545d21ff21bd02468be86746325dc9f1b50f3fe53d7735194d91927b5d14a436"
|
||||
}
|
||||
12
src-tauri/.sqlx/query-c554305252cb21e34aa1e3c1f204c6060c3d2a209689a879824dea4d26e5497e.json
generated
Normal file
12
src-tauri/.sqlx/query-c554305252cb21e34aa1e3c1f204c6060c3d2a209689a879824dea4d26e5497e.json
generated
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "\n INSERT INTO grpc_requests (\n id, name, workspace_id, folder_id, sort_priority, url, service, method, message,\n proto_files, authentication_type, authentication\n )\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\n ON CONFLICT (id) DO UPDATE SET\n updated_at = CURRENT_TIMESTAMP,\n name = excluded.name,\n folder_id = excluded.folder_id,\n sort_priority = excluded.sort_priority,\n url = excluded.url,\n service = excluded.service,\n method = excluded.method,\n message = excluded.message,\n proto_files = excluded.proto_files,\n authentication_type = excluded.authentication_type,\n authentication = excluded.authentication\n ",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Right": 12
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "c554305252cb21e34aa1e3c1f204c6060c3d2a209689a879824dea4d26e5497e"
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "\n INSERT INTO grpc_requests (\n id, name, workspace_id, folder_id, sort_priority, url, service, method, message,\n proto_files\n )\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\n ON CONFLICT (id) DO UPDATE SET\n updated_at = CURRENT_TIMESTAMP,\n name = excluded.name,\n folder_id = excluded.folder_id,\n sort_priority = excluded.sort_priority,\n url = excluded.url,\n service = excluded.service,\n method = excluded.method,\n message = excluded.message,\n proto_files = excluded.proto_files\n ",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Right": 10
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "ee562f85ec28c554c607adde670fc30eaeffeed6883e712bda4b4d6ca49cf740"
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
use std::collections::HashMap;
|
||||
use std::path::PathBuf;
|
||||
use std::str::FromStr;
|
||||
|
||||
use hyper::client::HttpConnector;
|
||||
use hyper::Client;
|
||||
@@ -10,8 +11,9 @@ use serde_json::Deserializer;
|
||||
use tokio_stream::wrappers::ReceiverStream;
|
||||
use tokio_stream::StreamExt;
|
||||
use tonic::body::BoxBody;
|
||||
use tonic::metadata::{MetadataKey, MetadataValue};
|
||||
use tonic::transport::Uri;
|
||||
use tonic::{IntoRequest, IntoStreamingRequest, Response, Status, Streaming};
|
||||
use tonic::{IntoRequest, IntoStreamingRequest, Request, Response, Status, Streaming};
|
||||
|
||||
use crate::codec::DynamicCodec;
|
||||
use crate::proto::{fill_pool, fill_pool_from_files, get_transport, method_desc_to_path};
|
||||
@@ -47,6 +49,7 @@ impl GrpcConnection {
|
||||
service: &str,
|
||||
method: &str,
|
||||
message: &str,
|
||||
metadata: HashMap<String, String>,
|
||||
) -> Result<DynamicMessage, String> {
|
||||
let method = &self.method(&service, &method)?;
|
||||
let input_message = method.input();
|
||||
@@ -58,7 +61,9 @@ impl GrpcConnection {
|
||||
|
||||
let mut client = tonic::client::Grpc::with_origin(self.conn.clone(), self.uri.clone());
|
||||
|
||||
let req = req_message.into_request();
|
||||
let mut req = req_message.into_request();
|
||||
decorate_req(metadata, &mut req).map_err(|e| e.to_string())?;
|
||||
|
||||
let path = method_desc_to_path(method);
|
||||
let codec = DynamicCodec::new(method.clone());
|
||||
client.ready().await.unwrap();
|
||||
@@ -75,12 +80,13 @@ impl GrpcConnection {
|
||||
service: &str,
|
||||
method: &str,
|
||||
stream: ReceiverStream<String>,
|
||||
metadata: HashMap<String, String>,
|
||||
) -> Result<Result<Response<Streaming<DynamicMessage>>, Status>, String> {
|
||||
let method = &self.method(&service, &method)?;
|
||||
let mut client = tonic::client::Grpc::with_origin(self.conn.clone(), self.uri.clone());
|
||||
|
||||
let method2 = method.clone();
|
||||
let req = stream
|
||||
let mut req = stream
|
||||
.map(move |s| {
|
||||
let mut deserializer = Deserializer::from_str(&s);
|
||||
let req_message = DynamicMessage::deserialize(method2.input(), &mut deserializer)
|
||||
@@ -90,6 +96,9 @@ impl GrpcConnection {
|
||||
req_message
|
||||
})
|
||||
.into_streaming_request();
|
||||
|
||||
decorate_req(metadata, &mut req).map_err(|e| e.to_string())?;
|
||||
|
||||
let path = method_desc_to_path(method);
|
||||
let codec = DynamicCodec::new(method.clone());
|
||||
client.ready().await.map_err(|e| e.to_string())?;
|
||||
@@ -101,11 +110,12 @@ impl GrpcConnection {
|
||||
service: &str,
|
||||
method: &str,
|
||||
stream: ReceiverStream<String>,
|
||||
metadata: HashMap<String, String>,
|
||||
) -> Result<DynamicMessage, String> {
|
||||
let method = &self.method(&service, &method)?;
|
||||
let mut client = tonic::client::Grpc::with_origin(self.conn.clone(), self.uri.clone());
|
||||
|
||||
let req = {
|
||||
let mut req = {
|
||||
let method = method.clone();
|
||||
stream
|
||||
.map(move |s| {
|
||||
@@ -119,6 +129,9 @@ impl GrpcConnection {
|
||||
})
|
||||
.into_streaming_request()
|
||||
};
|
||||
|
||||
decorate_req(metadata, &mut req).map_err(|e| e.to_string())?;
|
||||
|
||||
let path = method_desc_to_path(method);
|
||||
let codec = DynamicCodec::new(method.clone());
|
||||
client.ready().await.unwrap();
|
||||
@@ -134,6 +147,7 @@ impl GrpcConnection {
|
||||
service: &str,
|
||||
method: &str,
|
||||
message: &str,
|
||||
metadata: HashMap<String, String>,
|
||||
) -> Result<Result<Response<Streaming<DynamicMessage>>, Status>, String> {
|
||||
let method = &self.method(&service, &method)?;
|
||||
let input_message = method.input();
|
||||
@@ -145,7 +159,9 @@ impl GrpcConnection {
|
||||
|
||||
let mut client = tonic::client::Grpc::with_origin(self.conn.clone(), self.uri.clone());
|
||||
|
||||
let req = req_message.into_request();
|
||||
let mut req = req_message.into_request();
|
||||
decorate_req(metadata, &mut req).map_err(|e| e.to_string())?;
|
||||
|
||||
let path = method_desc_to_path(method);
|
||||
let codec = DynamicCodec::new(method.clone());
|
||||
client.ready().await.map_err(|e| e.to_string())?;
|
||||
@@ -222,10 +238,11 @@ impl GrpcHandle {
|
||||
service: &str,
|
||||
method: &str,
|
||||
message: &str,
|
||||
metadata: HashMap<String, String>,
|
||||
) -> Result<Result<Response<Streaming<DynamicMessage>>, Status>, String> {
|
||||
self.connect(id, uri, proto_files)
|
||||
.await?
|
||||
.server_streaming(service, method, message)
|
||||
.server_streaming(service, method, message, metadata)
|
||||
.await
|
||||
}
|
||||
|
||||
@@ -237,10 +254,11 @@ impl GrpcHandle {
|
||||
service: &str,
|
||||
method: &str,
|
||||
stream: ReceiverStream<String>,
|
||||
metadata: HashMap<String, String>,
|
||||
) -> Result<DynamicMessage, String> {
|
||||
self.connect(id, uri, proto_files)
|
||||
.await?
|
||||
.client_streaming(service, method, stream)
|
||||
.client_streaming(service, method, stream, metadata)
|
||||
.await
|
||||
}
|
||||
|
||||
@@ -252,10 +270,11 @@ impl GrpcHandle {
|
||||
service: &str,
|
||||
method: &str,
|
||||
stream: ReceiverStream<String>,
|
||||
metadata: HashMap<String, String>,
|
||||
) -> Result<Result<Response<Streaming<DynamicMessage>>, Status>, String> {
|
||||
self.connect(id, uri, proto_files)
|
||||
.await?
|
||||
.streaming(service, method, stream)
|
||||
.streaming(service, method, stream, metadata)
|
||||
.await
|
||||
}
|
||||
|
||||
@@ -282,3 +301,13 @@ impl GrpcHandle {
|
||||
Ok(connection)
|
||||
}
|
||||
}
|
||||
|
||||
fn decorate_req<T>(metadata: HashMap<String, String>, req: &mut Request<T>) -> Result<(), String> {
|
||||
for (k, v) in metadata {
|
||||
req.metadata_mut().insert(
|
||||
MetadataKey::from_str(k.as_str()).map_err(|e| e.to_string())?,
|
||||
MetadataValue::from_str(v.as_str()).map_err(|e| e.to_string())?,
|
||||
);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
ALTER TABLE grpc_requests ADD COLUMN authentication TEXT NOT NULL DEFAULT '{}';
|
||||
ALTER TABLE grpc_requests ADD COLUMN authentication_type TEXT;
|
||||
@@ -17,6 +17,7 @@ use std::str::FromStr;
|
||||
|
||||
use ::http::uri::InvalidUri;
|
||||
use ::http::Uri;
|
||||
use base64::Engine;
|
||||
use fern::colors::ColoredLevelConfig;
|
||||
use log::{debug, error, info, warn};
|
||||
use rand::random;
|
||||
@@ -128,12 +129,20 @@ async fn cmd_grpc_reflect(
|
||||
#[tauri::command]
|
||||
async fn cmd_grpc_go(
|
||||
request_id: &str,
|
||||
environment_id: Option<&str>,
|
||||
w: Window,
|
||||
grpc_handle: State<'_, Mutex<GrpcHandle>>,
|
||||
) -> Result<String, String> {
|
||||
let req = get_grpc_request(&w, request_id)
|
||||
.await
|
||||
.map_err(|e| e.to_string())?;
|
||||
let environment = match environment_id {
|
||||
Some(id) => Some(get_environment(&w, id).await.map_err(|e| e.to_string())?),
|
||||
None => None,
|
||||
};
|
||||
let workspace = get_workspace(&w, &req.workspace_id)
|
||||
.await
|
||||
.map_err(|e| e.to_string())?;
|
||||
let conn = {
|
||||
let req = req.clone();
|
||||
upsert_grpc_connection(
|
||||
@@ -261,6 +270,37 @@ async fn cmd_grpc_go(
|
||||
}
|
||||
};
|
||||
let event_handler = w.listen_global(format!("grpc_client_msg_{}", conn.id).as_str(), cb);
|
||||
let mut metadata = HashMap::new();
|
||||
if let Some(b) = &req.authentication_type {
|
||||
let req = req.clone();
|
||||
let environment_ref = environment.as_ref();
|
||||
let empty_value = &serde_json::to_value("").unwrap();
|
||||
let a = req.authentication.0;
|
||||
|
||||
if b == "basic" {
|
||||
let raw_username = a
|
||||
.get("username")
|
||||
.unwrap_or(empty_value)
|
||||
.as_str()
|
||||
.unwrap_or("");
|
||||
let raw_password = a
|
||||
.get("password")
|
||||
.unwrap_or(empty_value)
|
||||
.as_str()
|
||||
.unwrap_or("");
|
||||
let username = render::render(raw_username, &workspace, environment_ref);
|
||||
let password = render::render(raw_password, &workspace, environment_ref);
|
||||
|
||||
let auth = format!("{username}:{password}");
|
||||
let encoded = base64::engine::general_purpose::STANDARD_NO_PAD.encode(auth);
|
||||
metadata.insert("Authorization".to_string(), format!("Basic {}", encoded));
|
||||
} else if b == "bearer" {
|
||||
let raw_token = a.get("token").unwrap_or(empty_value).as_str().unwrap_or("");
|
||||
let token = render::render(raw_token, &workspace, environment_ref);
|
||||
metadata.insert("Authorization".to_string(), format!("Bearer {token}"));
|
||||
}
|
||||
}
|
||||
println!("METADATA: {:?}", metadata);
|
||||
|
||||
let grpc_listen = {
|
||||
let w = w.clone();
|
||||
@@ -272,28 +312,36 @@ async fn cmd_grpc_go(
|
||||
method_desc.is_server_streaming(),
|
||||
) {
|
||||
(true, true) => (
|
||||
Some(connection.streaming(&service, &method, in_msg_stream).await),
|
||||
Some(
|
||||
connection
|
||||
.streaming(&service, &method, in_msg_stream, metadata)
|
||||
.await,
|
||||
),
|
||||
None,
|
||||
),
|
||||
(true, false) => (
|
||||
None,
|
||||
Some(
|
||||
connection
|
||||
.client_streaming(&service, &method, in_msg_stream)
|
||||
.client_streaming(&service, &method, in_msg_stream, metadata)
|
||||
.await,
|
||||
),
|
||||
),
|
||||
(false, true) => (
|
||||
Some(
|
||||
connection
|
||||
.server_streaming(&service, &method, &req.message)
|
||||
.server_streaming(&service, &method, &req.message, metadata)
|
||||
.await,
|
||||
),
|
||||
None,
|
||||
),
|
||||
(false, false) => (
|
||||
None,
|
||||
Some(connection.unary(&service, &method, &req.message).await),
|
||||
Some(
|
||||
connection
|
||||
.unary(&service, &method, &req.message, metadata)
|
||||
.await,
|
||||
),
|
||||
),
|
||||
};
|
||||
|
||||
|
||||
@@ -205,6 +205,8 @@ pub struct GrpcRequest {
|
||||
pub method: Option<String>,
|
||||
pub message: String,
|
||||
pub proto_files: Json<Vec<String>>,
|
||||
pub authentication_type: Option<String>,
|
||||
pub authentication: Json<HashMap<String, JsonValue>>,
|
||||
}
|
||||
|
||||
#[derive(sqlx::FromRow, Debug, Clone, Serialize, Deserialize, Default)]
|
||||
@@ -502,9 +504,9 @@ pub async fn upsert_grpc_request(
|
||||
r#"
|
||||
INSERT INTO grpc_requests (
|
||||
id, name, workspace_id, folder_id, sort_priority, url, service, method, message,
|
||||
proto_files
|
||||
proto_files, authentication_type, authentication
|
||||
)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
ON CONFLICT (id) DO UPDATE SET
|
||||
updated_at = CURRENT_TIMESTAMP,
|
||||
name = excluded.name,
|
||||
@@ -514,7 +516,9 @@ pub async fn upsert_grpc_request(
|
||||
service = excluded.service,
|
||||
method = excluded.method,
|
||||
message = excluded.message,
|
||||
proto_files = excluded.proto_files
|
||||
proto_files = excluded.proto_files,
|
||||
authentication_type = excluded.authentication_type,
|
||||
authentication = excluded.authentication
|
||||
"#,
|
||||
id,
|
||||
trimmed_name,
|
||||
@@ -526,6 +530,8 @@ pub async fn upsert_grpc_request(
|
||||
request.method,
|
||||
request.message,
|
||||
request.proto_files,
|
||||
request.authentication_type,
|
||||
request.authentication,
|
||||
)
|
||||
.execute(&db)
|
||||
.await?;
|
||||
@@ -546,7 +552,8 @@ pub async fn get_grpc_request(
|
||||
r#"
|
||||
SELECT
|
||||
id, model, workspace_id, folder_id, created_at, updated_at, name, sort_priority,
|
||||
url, service, method, message,
|
||||
url, service, method, message, authentication_type,
|
||||
authentication AS "authentication!: Json<HashMap<String, JsonValue>>",
|
||||
proto_files AS "proto_files!: sqlx::types::Json<Vec<String>>"
|
||||
FROM grpc_requests
|
||||
WHERE id = ?
|
||||
@@ -567,7 +574,8 @@ pub async fn list_grpc_requests(
|
||||
r#"
|
||||
SELECT
|
||||
id, model, workspace_id, folder_id, created_at, updated_at, name, sort_priority,
|
||||
url, service, method, message,
|
||||
url, service, method, message, authentication_type,
|
||||
authentication AS "authentication!: Json<HashMap<String, JsonValue>>",
|
||||
proto_files AS "proto_files!: sqlx::types::Json<Vec<String>>"
|
||||
FROM grpc_requests
|
||||
WHERE workspace_id = ?
|
||||
|
||||
Reference in New Issue
Block a user