|
|
|
|
@@ -1,7 +1,8 @@
|
|
|
|
|
use futures::channel::oneshot;
|
|
|
|
|
use anyhow::bail;
|
|
|
|
|
use futures::AsyncWriteExt;
|
|
|
|
|
use gloo_net::http::{Headers, Request as BrowserRequest};
|
|
|
|
|
use std::ops::Range;
|
|
|
|
|
use tlsn_prover::tls::{Prover, ProverConfig};
|
|
|
|
|
use wasm_bindgen_futures::spawn_local;
|
|
|
|
|
use web_time::Instant;
|
|
|
|
|
|
|
|
|
|
use ws_stream_wasm::*;
|
|
|
|
|
@@ -9,23 +10,26 @@ use ws_stream_wasm::*;
|
|
|
|
|
use crate::hyper_io::FuturesIo;
|
|
|
|
|
use crate::request_opt::RequestOptions;
|
|
|
|
|
use crate::requests::{ClientType, NotarizationSessionRequest, NotarizationSessionResponse};
|
|
|
|
|
use crate::spawn_with_handle;
|
|
|
|
|
|
|
|
|
|
pub use wasm_bindgen_rayon::init_thread_pool;
|
|
|
|
|
|
|
|
|
|
use crate::fetch_as_json_string;
|
|
|
|
|
pub use crate::request_opt::VerifyResult;
|
|
|
|
|
use futures::AsyncWriteExt;
|
|
|
|
|
use http_body_util::{BodyExt, Full};
|
|
|
|
|
use hyper::{body::Bytes, Request, StatusCode};
|
|
|
|
|
|
|
|
|
|
use js_sys::Array;
|
|
|
|
|
use strum::EnumMessage;
|
|
|
|
|
use tlsn_core::proof::TlsProof;
|
|
|
|
|
use url::Url;
|
|
|
|
|
use wasm_bindgen::prelude::*;
|
|
|
|
|
use web_sys::{Headers, RequestInit, RequestMode};
|
|
|
|
|
use web_sys::RequestMode;
|
|
|
|
|
|
|
|
|
|
use tracing::{debug, info, trace};
|
|
|
|
|
use tracing::{debug, error, info};
|
|
|
|
|
|
|
|
|
|
type Result<T, Error = JsError> = std::result::Result<T, Error>;
|
|
|
|
|
|
|
|
|
|
trait Io: futures::AsyncRead + futures::AsyncWrite + Send + Unpin + 'static {}
|
|
|
|
|
impl<T> Io for T where T: futures::AsyncRead + futures::AsyncWrite + Send + Unpin + 'static {}
|
|
|
|
|
|
|
|
|
|
#[derive(strum_macros::EnumMessage, Debug, Clone, Copy)]
|
|
|
|
|
#[allow(dead_code)]
|
|
|
|
|
@@ -76,172 +80,77 @@ pub async fn prover(
|
|
|
|
|
val: JsValue,
|
|
|
|
|
secret_headers: JsValue,
|
|
|
|
|
secret_body: JsValue,
|
|
|
|
|
) -> Result<String, JsValue> {
|
|
|
|
|
debug!("target_url: {}", target_url_str);
|
|
|
|
|
let target_url = Url::parse(target_url_str)
|
|
|
|
|
.map_err(|e| JsValue::from_str(&format!("Could not parse target_url: {:?}", e)))?;
|
|
|
|
|
) -> Result<String, JsError> {
|
|
|
|
|
info!("new version");
|
|
|
|
|
|
|
|
|
|
debug!(
|
|
|
|
|
"target_url.host: {}",
|
|
|
|
|
target_url
|
|
|
|
|
.host()
|
|
|
|
|
.ok_or(JsValue::from_str("Could not get target host"))?
|
|
|
|
|
);
|
|
|
|
|
let options: RequestOptions = serde_wasm_bindgen::from_value(val)
|
|
|
|
|
.map_err(|e| JsValue::from_str(&format!("Could not deserialize options: {:?}", e)))?;
|
|
|
|
|
debug!("target_url: {}", target_url_str);
|
|
|
|
|
let target_url = Url::parse(target_url_str)?;
|
|
|
|
|
let target_host = target_url
|
|
|
|
|
.host()
|
|
|
|
|
.ok_or(JsError::new("target url missing host"))?
|
|
|
|
|
.to_string();
|
|
|
|
|
|
|
|
|
|
debug!("target_url.host: {}", &target_host);
|
|
|
|
|
|
|
|
|
|
let options: RequestOptions = serde_wasm_bindgen::from_value(val)?;
|
|
|
|
|
debug!("options.notary_url: {}", options.notary_url.as_str());
|
|
|
|
|
|
|
|
|
|
let secret_headers: Vec<String> = serde_wasm_bindgen::from_value(secret_headers)?;
|
|
|
|
|
let secret_body: Vec<String> = serde_wasm_bindgen::from_value(secret_body)?;
|
|
|
|
|
|
|
|
|
|
let start_time = Instant::now();
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Connect Notary with websocket
|
|
|
|
|
*/
|
|
|
|
|
let (session_id, notary_io) = connect_notary(
|
|
|
|
|
&options.notary_url,
|
|
|
|
|
options.max_sent_data,
|
|
|
|
|
options.max_recv_data,
|
|
|
|
|
)
|
|
|
|
|
.await
|
|
|
|
|
.map_err(|e| JsError::new(&e.to_string()))?;
|
|
|
|
|
|
|
|
|
|
let mut opts = RequestInit::new();
|
|
|
|
|
opts.method("POST");
|
|
|
|
|
// opts.method("GET");
|
|
|
|
|
opts.mode(RequestMode::Cors);
|
|
|
|
|
// Basic default prover config
|
|
|
|
|
let mut builder = ProverConfig::builder();
|
|
|
|
|
|
|
|
|
|
// set headers
|
|
|
|
|
let headers = Headers::new()
|
|
|
|
|
.map_err(|e| JsValue::from_str(&format!("Could not create headers: {:?}", e)))?;
|
|
|
|
|
let notary_url = Url::parse(options.notary_url.as_str())
|
|
|
|
|
.map_err(|e| JsValue::from_str(&format!("Could not parse notary_url: {:?}", e)))?;
|
|
|
|
|
let notary_ssl = notary_url.scheme() == "https" || notary_url.scheme() == "wss";
|
|
|
|
|
let notary_host = notary_url.authority();
|
|
|
|
|
let notary_path = notary_url.path();
|
|
|
|
|
let notary_path_str = if notary_path == "/" { "" } else { notary_path };
|
|
|
|
|
builder.id(session_id).server_dns(target_host);
|
|
|
|
|
|
|
|
|
|
headers
|
|
|
|
|
.append("Host", notary_host)
|
|
|
|
|
.map_err(|e| JsValue::from_str(&format!("Could not append Host header: {:?}", e)))?;
|
|
|
|
|
headers
|
|
|
|
|
.append("Content-Type", "application/json")
|
|
|
|
|
.map_err(|e| {
|
|
|
|
|
JsValue::from_str(&format!("Could not append Content-Type header: {:?}", e))
|
|
|
|
|
})?;
|
|
|
|
|
opts.headers(&headers);
|
|
|
|
|
if let Some(max_sent_data) = options.max_sent_data {
|
|
|
|
|
builder.max_sent_data(max_sent_data);
|
|
|
|
|
}
|
|
|
|
|
if let Some(max_recv_data) = options.max_recv_data {
|
|
|
|
|
builder.max_recv_data(max_recv_data);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
info!("notary_host: {}", notary_host);
|
|
|
|
|
// set body
|
|
|
|
|
let payload = serde_json::to_string(&NotarizationSessionRequest {
|
|
|
|
|
client_type: ClientType::Websocket,
|
|
|
|
|
max_sent_data: options.max_sent_data,
|
|
|
|
|
max_recv_data: options.max_recv_data,
|
|
|
|
|
})
|
|
|
|
|
.map_err(|e| JsValue::from_str(&format!("Could not serialize request: {:?}", e)))?;
|
|
|
|
|
opts.body(Some(&JsValue::from_str(&payload)));
|
|
|
|
|
let prover = Prover::new(builder.build()?).setup(notary_io).await?;
|
|
|
|
|
|
|
|
|
|
// url
|
|
|
|
|
let url = format!(
|
|
|
|
|
"{}://{}{}/session",
|
|
|
|
|
if notary_ssl { "https" } else { "http" },
|
|
|
|
|
notary_host,
|
|
|
|
|
notary_path_str
|
|
|
|
|
);
|
|
|
|
|
debug!("Request: {}", url);
|
|
|
|
|
let rust_string = fetch_as_json_string(&url, &opts)
|
|
|
|
|
.await
|
|
|
|
|
.map_err(|e| JsValue::from_str(&format!("Could not fetch session: {:?}", e)))?;
|
|
|
|
|
let notarization_response =
|
|
|
|
|
serde_json::from_str::<NotarizationSessionResponse>(&rust_string)
|
|
|
|
|
.map_err(|e| JsValue::from_str(&format!("Could not deserialize response: {:?}", e)))?;
|
|
|
|
|
debug!("Response: {}", rust_string);
|
|
|
|
|
|
|
|
|
|
debug!("Notarization response: {:?}", notarization_response,);
|
|
|
|
|
let notary_wss_url = format!(
|
|
|
|
|
"{}://{}{}/notarize?sessionId={}",
|
|
|
|
|
if notary_ssl { "wss" } else { "ws" },
|
|
|
|
|
notary_host,
|
|
|
|
|
notary_path_str,
|
|
|
|
|
notarization_response.session_id
|
|
|
|
|
);
|
|
|
|
|
let (_, notary_ws_stream) = WsMeta::connect(notary_wss_url, None)
|
|
|
|
|
.await
|
|
|
|
|
.expect_throw("assume the notary ws connection succeeds");
|
|
|
|
|
let notary_ws_stream_into = notary_ws_stream.into_io();
|
|
|
|
|
|
|
|
|
|
log_phase(ProverPhases::BuildProverConfig);
|
|
|
|
|
|
|
|
|
|
let target_host = target_url
|
|
|
|
|
.host_str()
|
|
|
|
|
.ok_or(JsValue::from_str("Could not get target host"))?;
|
|
|
|
|
|
|
|
|
|
// Basic default prover config
|
|
|
|
|
let mut builder = ProverConfig::builder();
|
|
|
|
|
|
|
|
|
|
if let Some(max_sent_data) = options.max_sent_data {
|
|
|
|
|
builder.max_sent_data(max_sent_data);
|
|
|
|
|
}
|
|
|
|
|
if let Some(max_recv_data) = options.max_recv_data {
|
|
|
|
|
builder.max_recv_data(max_recv_data);
|
|
|
|
|
}
|
|
|
|
|
let config = builder
|
|
|
|
|
.id(notarization_response.session_id)
|
|
|
|
|
.server_dns(target_host)
|
|
|
|
|
.build()
|
|
|
|
|
.map_err(|e| JsValue::from_str(&format!("Could not build prover config: {:?}", e)))?;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Create a Prover and set it up with the Notary
|
|
|
|
|
// This will set up the MPC backend prior to connecting to the server.
|
|
|
|
|
log_phase(ProverPhases::SetUpProver);
|
|
|
|
|
let prover = Prover::new(config)
|
|
|
|
|
.setup(notary_ws_stream_into)
|
|
|
|
|
.await
|
|
|
|
|
.map_err(|e| JsValue::from_str(&format!("Could not set up prover: {:?}", e)))?;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
Connect Application Server with websocket proxy
|
|
|
|
|
*/
|
|
|
|
|
log_phase(ProverPhases::ConnectWsProxy);
|
|
|
|
|
|
|
|
|
|
let (_, client_ws_stream) = WsMeta::connect(options.websocket_proxy_url, None)
|
|
|
|
|
debug!("connecting to server");
|
|
|
|
|
let (_, server_io) = WsMeta::connect(&options.websocket_proxy_url, None)
|
|
|
|
|
.await
|
|
|
|
|
.expect_throw("assume the client ws connection succeeds");
|
|
|
|
|
debug!("connected to server");
|
|
|
|
|
|
|
|
|
|
// Bind the Prover to the server connection.
|
|
|
|
|
// The returned `mpc_tls_connection` is an MPC TLS connection to the Server: all data written
|
|
|
|
|
// to/read from it will be encrypted/decrypted using MPC with the Notary.
|
|
|
|
|
log_phase(ProverPhases::BindProverToConnection);
|
|
|
|
|
let (mpc_tls_connection, prover_fut) =
|
|
|
|
|
prover.connect(client_ws_stream.into_io()).await.unwrap();
|
|
|
|
|
let mpc_tls_connection = unsafe { FuturesIo::new(mpc_tls_connection) };
|
|
|
|
|
let (tls_connection, prover_fut) = prover.connect(server_io.into_io()).await?;
|
|
|
|
|
let tls_connection = unsafe { FuturesIo::new(tls_connection) };
|
|
|
|
|
|
|
|
|
|
let prover_ctrl = prover_fut.control();
|
|
|
|
|
|
|
|
|
|
log_phase(ProverPhases::SpawnProverThread);
|
|
|
|
|
let (prover_sender, prover_receiver) = oneshot::channel();
|
|
|
|
|
let handled_prover_fut = async {
|
|
|
|
|
let result = prover_fut.await;
|
|
|
|
|
let _ = prover_sender.send(result);
|
|
|
|
|
};
|
|
|
|
|
spawn_local(handled_prover_fut);
|
|
|
|
|
let prover_handle = spawn_with_handle(prover_fut);
|
|
|
|
|
|
|
|
|
|
// Attach the hyper HTTP client to the TLS connection
|
|
|
|
|
log_phase(ProverPhases::AttachHttpClient);
|
|
|
|
|
let (mut request_sender, connection) =
|
|
|
|
|
hyper::client::conn::http1::handshake(mpc_tls_connection)
|
|
|
|
|
.await
|
|
|
|
|
.map_err(|e| JsValue::from_str(&format!("Could not handshake: {:?}", e)))?;
|
|
|
|
|
hyper::client::conn::http1::handshake(tls_connection).await?;
|
|
|
|
|
|
|
|
|
|
// Spawn the HTTP task to be run concurrently
|
|
|
|
|
log_phase(ProverPhases::SpawnHttpTask);
|
|
|
|
|
let (connection_sender, connection_receiver) = oneshot::channel();
|
|
|
|
|
let connection_fut = connection.without_shutdown();
|
|
|
|
|
let handled_connection_fut = async {
|
|
|
|
|
let result = connection_fut.await;
|
|
|
|
|
let _ = connection_sender.send(result);
|
|
|
|
|
};
|
|
|
|
|
spawn_local(handled_connection_fut);
|
|
|
|
|
let connection_handle = spawn_with_handle(connection.without_shutdown());
|
|
|
|
|
|
|
|
|
|
log_phase(ProverPhases::BuildRequest);
|
|
|
|
|
let mut req_with_header = Request::builder()
|
|
|
|
|
.uri(target_url_str)
|
|
|
|
|
.uri(target_url.as_str())
|
|
|
|
|
.method(options.method.as_str());
|
|
|
|
|
|
|
|
|
|
for (key, value) in options.headers {
|
|
|
|
|
for (key, value) in &options.headers {
|
|
|
|
|
info!("adding header: {} - {}", key.as_str(), value.as_str());
|
|
|
|
|
req_with_header = req_with_header.header(key.as_str(), value.as_str());
|
|
|
|
|
}
|
|
|
|
|
@@ -251,80 +160,47 @@ pub async fn prover(
|
|
|
|
|
req_with_header.body(Full::new(Bytes::default()))
|
|
|
|
|
} else {
|
|
|
|
|
info!("added body - {}", options.body.as_str());
|
|
|
|
|
req_with_header.body(Full::from(options.body))
|
|
|
|
|
req_with_header.body(Full::from(options.body.clone()))
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
let unwrapped_request = req_with_body
|
|
|
|
|
.map_err(|e| JsValue::from_str(&format!("Could not build request: {:?}", e)))?;
|
|
|
|
|
let unwrapped_request = req_with_body?;
|
|
|
|
|
|
|
|
|
|
log_phase(ProverPhases::StartMpcConnection);
|
|
|
|
|
|
|
|
|
|
// Defer decryption of the response.
|
|
|
|
|
prover_ctrl
|
|
|
|
|
.defer_decryption()
|
|
|
|
|
.await
|
|
|
|
|
.map_err(|e| JsValue::from_str(&format!("failed to enable deferred decryption: {}", e)))?;
|
|
|
|
|
prover_ctrl.defer_decryption().await?;
|
|
|
|
|
|
|
|
|
|
// Send the request to the Server and get a response via the MPC TLS connection
|
|
|
|
|
let response = request_sender
|
|
|
|
|
.send_request(unwrapped_request)
|
|
|
|
|
.await
|
|
|
|
|
.map_err(|e| JsValue::from_str(&format!("Could not send request: {:?}", e)))?;
|
|
|
|
|
let response = request_sender.send_request(unwrapped_request).await?;
|
|
|
|
|
|
|
|
|
|
log_phase(ProverPhases::ReceivedResponse);
|
|
|
|
|
if response.status() != StatusCode::OK {
|
|
|
|
|
return Err(JsValue::from_str(&format!(
|
|
|
|
|
JsError::new(&format!(
|
|
|
|
|
"Response status is not OK: {:?}",
|
|
|
|
|
response.status()
|
|
|
|
|
)));
|
|
|
|
|
));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
log_phase(ProverPhases::ParseResponse);
|
|
|
|
|
// Pretty printing :)
|
|
|
|
|
let payload = response
|
|
|
|
|
.into_body()
|
|
|
|
|
.collect()
|
|
|
|
|
.await
|
|
|
|
|
.map_err(|e| JsValue::from_str(&format!("Could not get response body: {:?}", e)))?
|
|
|
|
|
.to_bytes();
|
|
|
|
|
let parsed = serde_json::from_str::<serde_json::Value>(&String::from_utf8_lossy(&payload))
|
|
|
|
|
.map_err(|e| JsValue::from_str(&format!("Could not parse response: {:?}", e)))?;
|
|
|
|
|
let response_pretty = serde_json::to_string_pretty(&parsed)
|
|
|
|
|
.map_err(|e| JsValue::from_str(&format!("Could not serialize response: {:?}", e)))?;
|
|
|
|
|
let payload = response.into_body().collect().await?.to_bytes();
|
|
|
|
|
let parsed = serde_json::from_str::<serde_json::Value>(&String::from_utf8_lossy(&payload))?;
|
|
|
|
|
let response_pretty = serde_json::to_string_pretty(&parsed)?;
|
|
|
|
|
info!("Response: {}", response_pretty);
|
|
|
|
|
|
|
|
|
|
// Close the connection to the server
|
|
|
|
|
log_phase(ProverPhases::CloseConnection);
|
|
|
|
|
let mut client_socket = connection_receiver
|
|
|
|
|
.await
|
|
|
|
|
.map_err(|e| {
|
|
|
|
|
JsValue::from_str(&format!(
|
|
|
|
|
"Could not receive from connection_receiver: {:?}",
|
|
|
|
|
e
|
|
|
|
|
))
|
|
|
|
|
})?
|
|
|
|
|
.map_err(|e| JsValue::from_str(&format!("Could not get TlsConnection: {:?}", e)))?
|
|
|
|
|
.io
|
|
|
|
|
.into_inner();
|
|
|
|
|
client_socket
|
|
|
|
|
.close()
|
|
|
|
|
.await
|
|
|
|
|
.map_err(|e| JsValue::from_str(&format!("Could not close socket: {:?}", e)))?;
|
|
|
|
|
let mut tls_connection = connection_handle.await?.io.into_inner();
|
|
|
|
|
tls_connection.close().await?;
|
|
|
|
|
|
|
|
|
|
// The Prover task should be done now, so we can grab it.
|
|
|
|
|
log_phase(ProverPhases::StartNotarization);
|
|
|
|
|
let prover = prover_receiver
|
|
|
|
|
.await
|
|
|
|
|
.map_err(|e| {
|
|
|
|
|
JsValue::from_str(&format!("Could not receive from prover_receiver: {:?}", e))
|
|
|
|
|
})?
|
|
|
|
|
.map_err(|e| JsValue::from_str(&format!("Could not get Prover: {:?}", e)))?;
|
|
|
|
|
let prover = prover_handle.await?;
|
|
|
|
|
let mut prover = prover.start_notarize();
|
|
|
|
|
|
|
|
|
|
let secret_headers_vecs = string_list_to_bytes_vec(&secret_headers)?;
|
|
|
|
|
let secret_headers_slices: Vec<&[u8]> = secret_headers_vecs
|
|
|
|
|
let secret_headers_slices: Vec<&[u8]> = secret_headers
|
|
|
|
|
.iter()
|
|
|
|
|
.map(|vec| vec.as_slice())
|
|
|
|
|
.map(|header| header.as_bytes())
|
|
|
|
|
.collect();
|
|
|
|
|
|
|
|
|
|
// Identify the ranges in the transcript that contain revealed_headers
|
|
|
|
|
@@ -333,9 +209,7 @@ pub async fn prover(
|
|
|
|
|
secret_headers_slices.as_slice(),
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
let secret_body_vecs = string_list_to_bytes_vec(&secret_body)?;
|
|
|
|
|
let secret_body_slices: Vec<&[u8]> =
|
|
|
|
|
secret_body_vecs.iter().map(|vec| vec.as_slice()).collect();
|
|
|
|
|
let secret_body_slices: Vec<&[u8]> = secret_body.iter().map(|body| body.as_bytes()).collect();
|
|
|
|
|
|
|
|
|
|
// Identify the ranges in the transcript that contain the only data we want to reveal later
|
|
|
|
|
let (recv_public_ranges, recv_private_ranges) = find_ranges(
|
|
|
|
|
@@ -352,46 +226,25 @@ pub async fn prover(
|
|
|
|
|
// Commit to the outbound and inbound transcript, isolating the data that contain secrets
|
|
|
|
|
let sent_pub_commitment_ids = sent_public_ranges
|
|
|
|
|
.iter()
|
|
|
|
|
.map(|range| {
|
|
|
|
|
builder.commit_sent(range).map_err(|e| {
|
|
|
|
|
JsValue::from_str(&format!("Error committing sent pub range: {:?}", e))
|
|
|
|
|
})
|
|
|
|
|
})
|
|
|
|
|
.map(|range| builder.commit_sent(range))
|
|
|
|
|
.collect::<Result<Vec<_>, _>>()?;
|
|
|
|
|
|
|
|
|
|
sent_private_ranges.iter().try_for_each(|range| {
|
|
|
|
|
builder
|
|
|
|
|
.commit_sent(range)
|
|
|
|
|
.map_err(|e| {
|
|
|
|
|
JsValue::from_str(&format!("Error committing sent private range: {:?}", e))
|
|
|
|
|
})
|
|
|
|
|
.map(|_| ())
|
|
|
|
|
})?;
|
|
|
|
|
sent_private_ranges
|
|
|
|
|
.iter()
|
|
|
|
|
.try_for_each(|range| builder.commit_sent(range).map(|_| ()))?;
|
|
|
|
|
|
|
|
|
|
let recv_pub_commitment_ids = recv_public_ranges
|
|
|
|
|
.iter()
|
|
|
|
|
.map(|range| {
|
|
|
|
|
builder.commit_recv(range).map_err(|e| {
|
|
|
|
|
JsValue::from_str(&format!("Error committing recv public ranges: {:?}", e))
|
|
|
|
|
})
|
|
|
|
|
})
|
|
|
|
|
.map(|range| builder.commit_recv(range))
|
|
|
|
|
.collect::<Result<Vec<_>, _>>()?;
|
|
|
|
|
|
|
|
|
|
recv_private_ranges.iter().try_for_each(|range| {
|
|
|
|
|
builder
|
|
|
|
|
.commit_recv(range)
|
|
|
|
|
.map_err(|e| {
|
|
|
|
|
JsValue::from_str(&format!("Error committing recv private range: {:?}", e))
|
|
|
|
|
})
|
|
|
|
|
.map(|_| ())
|
|
|
|
|
})?;
|
|
|
|
|
recv_private_ranges
|
|
|
|
|
.iter()
|
|
|
|
|
.try_for_each(|range| builder.commit_recv(range).map(|_| ()))?;
|
|
|
|
|
|
|
|
|
|
// Finalize, returning the notarized session
|
|
|
|
|
log_phase(ProverPhases::Finalize);
|
|
|
|
|
let notarized_session = prover
|
|
|
|
|
.finalize()
|
|
|
|
|
.await
|
|
|
|
|
.map_err(|e| JsValue::from_str(&format!("Error finalizing prover: {:?}", e)))?;
|
|
|
|
|
let notarized_session = prover.finalize().await?;
|
|
|
|
|
|
|
|
|
|
log_phase(ProverPhases::NotarizationComplete);
|
|
|
|
|
|
|
|
|
|
@@ -405,31 +258,85 @@ pub async fn prover(
|
|
|
|
|
sent_pub_commitment_ids
|
|
|
|
|
.iter()
|
|
|
|
|
.chain(recv_pub_commitment_ids.iter())
|
|
|
|
|
.try_for_each(|id| {
|
|
|
|
|
proof_builder
|
|
|
|
|
.reveal_by_id(*id)
|
|
|
|
|
.map_err(|e| JsValue::from_str(&format!("Could not reveal commitment: {:?}", e)))
|
|
|
|
|
.map(|_| ())
|
|
|
|
|
})?;
|
|
|
|
|
.try_for_each(|id| proof_builder.reveal_by_id(*id).map(|_| ()))?;
|
|
|
|
|
|
|
|
|
|
let substrings_proof = proof_builder
|
|
|
|
|
.build()
|
|
|
|
|
.map_err(|e| JsValue::from_str(&format!("Could not build proof: {:?}", e)))?;
|
|
|
|
|
let substrings_proof = proof_builder.build()?;
|
|
|
|
|
|
|
|
|
|
let proof = TlsProof {
|
|
|
|
|
session: session_proof,
|
|
|
|
|
substrings: substrings_proof,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
let res = serde_json::to_string_pretty(&proof)
|
|
|
|
|
.map_err(|e| JsValue::from_str(&format!("Could not serialize proof: {:?}", e)))?;
|
|
|
|
|
let res = serde_json::to_string_pretty(&proof)?;
|
|
|
|
|
|
|
|
|
|
let duration = start_time.elapsed();
|
|
|
|
|
|
|
|
|
|
info!("!@# request took {} seconds", duration.as_secs());
|
|
|
|
|
|
|
|
|
|
Ok(res)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async fn connect_notary(
|
|
|
|
|
url: &str,
|
|
|
|
|
max_sent_data: Option<usize>,
|
|
|
|
|
max_recv_data: Option<usize>,
|
|
|
|
|
) -> Result<(String, impl Io), anyhow::Error> {
|
|
|
|
|
// set headers
|
|
|
|
|
let notary_url = Url::parse(url)?;
|
|
|
|
|
let notary_ssl = notary_url.scheme() == "https" || notary_url.scheme() == "wss";
|
|
|
|
|
let notary_host = notary_url.authority();
|
|
|
|
|
let notary_path = notary_url.path();
|
|
|
|
|
let notary_path_str = if notary_path == "/" { "" } else { notary_path };
|
|
|
|
|
|
|
|
|
|
let headers = Headers::new();
|
|
|
|
|
headers.append("Host", notary_host);
|
|
|
|
|
headers.append("Content-Type", "application/json");
|
|
|
|
|
|
|
|
|
|
debug!("sending notarization request");
|
|
|
|
|
|
|
|
|
|
let url = format!(
|
|
|
|
|
"{}://{}{}/session",
|
|
|
|
|
if notary_ssl { "https" } else { "http" },
|
|
|
|
|
notary_host,
|
|
|
|
|
notary_path_str
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
let response = BrowserRequest::post(&url)
|
|
|
|
|
.mode(RequestMode::Cors)
|
|
|
|
|
.headers(headers)
|
|
|
|
|
.body(serde_json::to_string(&NotarizationSessionRequest {
|
|
|
|
|
client_type: ClientType::Websocket,
|
|
|
|
|
max_sent_data,
|
|
|
|
|
max_recv_data,
|
|
|
|
|
})?)?
|
|
|
|
|
.send()
|
|
|
|
|
.await?;
|
|
|
|
|
|
|
|
|
|
if response.ok() {
|
|
|
|
|
debug!("Notarization request succeeded");
|
|
|
|
|
} else {
|
|
|
|
|
error!("Notarization request failed: {:?}", response.status());
|
|
|
|
|
bail!("Notarization request failed: {:?}", response.status());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let payload: NotarizationSessionResponse = response.json().await?;
|
|
|
|
|
debug!("Notarization response: {:?}", &payload);
|
|
|
|
|
|
|
|
|
|
let notary_wss_url = format!(
|
|
|
|
|
"{}://{}{}/notarize?sessionId={}",
|
|
|
|
|
if notary_ssl { "wss" } else { "ws" },
|
|
|
|
|
notary_host,
|
|
|
|
|
notary_path_str,
|
|
|
|
|
&payload.session_id
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
let (_, notary_ws_stream) = WsMeta::connect(notary_wss_url, None)
|
|
|
|
|
.await
|
|
|
|
|
.expect_throw("assume the notary ws connection succeeds");
|
|
|
|
|
|
|
|
|
|
Ok((payload.session_id, notary_ws_stream.into_io()))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Find the ranges of the public and private parts of a sequence.
|
|
|
|
|
///
|
|
|
|
|
/// Returns a tuple of `(public, private)` ranges.
|
|
|
|
|
@@ -461,19 +368,3 @@ fn find_ranges(seq: &[u8], private_seq: &[&[u8]]) -> (Vec<Range<usize>>, Vec<Ran
|
|
|
|
|
|
|
|
|
|
(public_ranges, private_ranges)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn string_list_to_bytes_vec(secrets: &JsValue) -> Result<Vec<Vec<u8>>, JsValue> {
|
|
|
|
|
let array: Array = Array::from(secrets);
|
|
|
|
|
let length = array.length();
|
|
|
|
|
let mut byte_slices: Vec<Vec<u8>> = Vec::new();
|
|
|
|
|
|
|
|
|
|
for i in 0..length {
|
|
|
|
|
let secret_js: JsValue = array.get(i);
|
|
|
|
|
let secret_str: String = secret_js
|
|
|
|
|
.as_string()
|
|
|
|
|
.ok_or(JsValue::from_str("Could not convert secret to string"))?;
|
|
|
|
|
let secret_bytes = secret_str.into_bytes();
|
|
|
|
|
byte_slices.push(secret_bytes);
|
|
|
|
|
}
|
|
|
|
|
Ok(byte_slices)
|
|
|
|
|
}
|
|
|
|
|
|