Accept session id from url params in API /notarize (#16)

* feat: accept sessionId in url

Required by the browser to pass session id with Websocket API

* feat: server accept session id entirely through url params

* Update openapi.yaml and README for url param sessionId

* Update src/domain/notary.rs

Co-authored-by: Christopher Chong <t.kleinchong@gmail.com>

* Update tests/integration_test.rs

Co-authored-by: Christopher Chong <t.kleinchong@gmail.com>

---------

Co-authored-by: Christopher Chong <t.kleinchong@gmail.com>
This commit is contained in:
Kevin Mai-Husan Chia
2023-10-11 11:02:29 +08:00
committed by GitHub
parent a94f809d5c
commit fbb344d78c
5 changed files with 38 additions and 34 deletions

View File

@@ -75,10 +75,10 @@ Defined in the [OpenAPI specification](./openapi.yaml).
##### Description
To perform notarization using the session id (unique id returned upon calling the `/session` endpoint successfully) submitted as a custom header.
##### Custom Header
`X-Session-Id`
##### Query Parameter
`sessionId`
##### Custom Header Type
##### Query Parameter Type
String
---

View File

@@ -73,8 +73,8 @@ paths:
enum:
- "TCP"
required: true
- in: header
name: X-Session-Id
- in: query
name: sessionId
description: Unique ID returned from server upon calling POST /session
schema:
type: string

View File

@@ -23,6 +23,14 @@ pub struct NotarizationSessionRequest {
pub max_transcript_size: Option<usize>,
}
/// Request query of the /notarize API
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct NotarizationRequestQuery {
/// Session id that is returned from /session API
pub session_id: String,
}
/// Types of client that the prover is using
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub enum ClientType {

View File

@@ -4,8 +4,8 @@ pub mod websocket;
use async_trait::async_trait;
use axum::{
extract::{rejection::JsonRejection, FromRequestParts, State},
http::{header, request::Parts, HeaderMap, StatusCode},
extract::{rejection::JsonRejection, FromRequestParts, Query, State},
http::{header, request::Parts, StatusCode},
response::{IntoResponse, Json, Response},
};
use axum_macros::debug_handler;
@@ -17,7 +17,10 @@ use tracing::{debug, error, info, trace};
use uuid::Uuid;
use crate::{
domain::notary::{NotarizationSessionRequest, NotarizationSessionResponse, NotaryGlobals},
domain::notary::{
NotarizationRequestQuery, NotarizationSessionRequest, NotarizationSessionResponse,
NotaryGlobals,
},
error::NotaryServerError,
service::{
axum_websocket::{header_eq, WebSocketUpgrade},
@@ -62,30 +65,15 @@ where
}
/// Handler to upgrade protocol from http to either websocket or underlying tcp depending on the type of client
/// the session_id header is also extracted here to fetch the configuration parameters
/// the session_id parameter is also extracted here to fetch the configuration parameters
/// that have been submitted in the previous request to /session made by the same client
pub async fn upgrade_protocol(
protocol_upgrade: ProtocolUpgrade,
mut headers: HeaderMap,
State(notary_globals): State<NotaryGlobals>,
Query(params): Query<NotarizationRequestQuery>,
) -> Response {
info!("Received upgrade protocol request");
// Extract the session_id from the headers
let session_id = match headers.remove("X-Session-Id") {
Some(session_id) => match session_id.to_str() {
Ok(session_id) => session_id.to_string(),
Err(err) => {
let err_msg = format!("X-Session-Id header submitted is not a string: {}", err);
error!(err_msg);
return NotaryServerError::BadProverRequest(err_msg).into_response();
}
},
None => {
let err_msg = "Missing X-Session-Id in upgrade protocol request".to_string();
error!(err_msg);
return NotaryServerError::BadProverRequest(err_msg).into_response();
}
};
let session_id = params.session_id;
// Fetch the configuration data from the store using the session_id
let max_transcript_size = match notary_globals.store.lock().await.get(&session_id) {
Some(max_transcript_size) => max_transcript_size.to_owned(),

View File

@@ -150,15 +150,19 @@ async fn test_tcp_prover() {
// Send notarization request via HTTP, where the underlying TCP connection will be extracted later
let request = Request::builder()
.uri(format!("https://{notary_host}:{notary_port}/notarize"))
// Need to specify the session_id so that notary server knows the right configuration to use
// as the configuration is set in the previous HTTP call
.uri(format!(
"https://{}:{}/notarize?sessionId={}",
notary_host,
notary_port,
notarization_response.session_id.clone()
))
.method("GET")
.header("Host", notary_host)
.header("Connection", "Upgrade")
// Need to specify this upgrade header for server to extract tcp connection later
.header("Upgrade", "TCP")
// Need to specify the session_id so that notary server knows the right configuration to use
// as the configuration is set in the previous HTTP call
.header("X-Session-Id", notarization_response.session_id.clone())
.body(Body::empty())
.unwrap();
@@ -323,15 +327,19 @@ async fn test_websocket_prover() {
// client while using its high level request function — there does not seem to have a crate that can let you
// make a request without establishing TCP connection where you can claim the TCP connection later after making the request
let request = http::Request::builder()
.uri(format!("wss://{notary_host}:{notary_port}/notarize"))
// Need to specify the session_id so that notary server knows the right configuration to use
// as the configuration is set in the previous HTTP call
.uri(format!(
"wss://{}:{}/notarize?sessionId={}",
notary_host,
notary_port,
notarization_response.session_id.clone()
))
.header("Host", notary_host.clone())
.header("Sec-WebSocket-Key", uuid::Uuid::new_v4().to_string())
.header("Sec-WebSocket-Version", "13")
.header("Connection", "Upgrade")
.header("Upgrade", "Websocket")
// Need to specify the session_id so that notary server knows the right configuration to use
// as the configuration is set in the previous HTTP call
.header("X-Session-Id", notarization_response.session_id.clone())
.body(())
.unwrap();