Skip to content

Commit

Permalink
refactor(tlsn-examples): update hyper and use http prover (#434)
Browse files Browse the repository at this point in the history
* add notary function to examples lib

* use hyper 1.1 version in examples

* update twitter example to use HTTP prover

* use deferred decryption in twitter example
  • Loading branch information
sinui0 authored Feb 13, 2024
1 parent 98a3c4d commit 0d269ed
Show file tree
Hide file tree
Showing 5 changed files with 271 additions and 450 deletions.
34 changes: 17 additions & 17 deletions tlsn/examples/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,25 @@ version = "0.0.0"
edition = "2021"
publish = false

[dev-dependencies]
tlsn-prover = { workspace = true, features = ["tracing"] }
tlsn-verifier.workspace = true
[dependencies]
tlsn-core.workspace = true
tlsn-tls-core.workspace = true
tlsn-tls-client.workspace = true
notary-server = { path = "../../notary-server" }
mpz-core.workspace = true
tlsn-prover = { workspace = true, features = ["tracing"] }
tlsn-verifier.workspace = true

p256 = { workspace = true, features = ["ecdsa"] }
elliptic-curve = { version = "0.13.5", features = ["pkcs8"] }
webpki-roots.workspace = true

rustls = { version = "0.21" }
rustls-pemfile = { version = "1.0.2" }
tokio-rustls = { version = "0.24.1" }
async-tls = { version = "0.12", default-features = false, features = [
"client",
] }
futures.workspace = true
tokio = { workspace = true, features = [
"rt",
Expand All @@ -23,26 +33,16 @@ tokio = { workspace = true, features = [
"fs",
] }
tokio-util.workspace = true
hyper = { version = "1.1", features = ["client", "http1"] }
http-body-util = "0.1"
hyper-util = { version = "0.1", features = ["full"] }
chrono = "0.4"

tracing.workspace = true
tracing-subscriber.workspace = true

hyper = { version = "0.14", features = ["client", "http1"] }
chrono = "0.4"
p256 = { workspace = true, features = ["ecdsa"] }
elliptic-curve = { version = "0.13.5", features = ["pkcs8"] }
webpki-roots.workspace = true

async-tls = { version = "0.12", default-features = false, features = [
"client",
] }

serde = { version = "1.0.147", features = ["derive"] }
serde_json = "1.0"
eyre = "0.6.8"
rustls = { version = "0.21" }
rustls-pemfile = { version = "1.0.2" }
tokio-rustls = { version = "0.24.1" }
dotenv = "0.15.0"

[[example]]
Expand Down
180 changes: 19 additions & 161 deletions tlsn/examples/discord/discord_dm.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
/// This example shows how to notarize Discord DMs.
///
/// The example uses the notary server implemented in ../../../notary-server
use futures::AsyncWriteExt;
use hyper::{body::to_bytes, client::conn::Parts, Body, Request, StatusCode};
use rustls::{Certificate, ClientConfig, RootCertStore};
use serde::{Deserialize, Serialize};
use std::{env, ops::Range, str, sync::Arc};
// This example shows how to notarize Discord DMs.
//
// The example uses the notary server implemented in ../../../notary-server

use http_body_util::{BodyExt, Empty};
use hyper::{body::Bytes, Request, StatusCode};
use hyper_util::rt::TokioIo;
use std::{env, ops::Range, str};
use tlsn_core::proof::TlsProof;
use tokio::{io::AsyncWriteExt as _, net::TcpStream};
use tokio_rustls::TlsConnector;
use tlsn_examples::request_notarization;
use tokio::io::AsyncWriteExt as _;
use tokio_util::compat::{FuturesAsyncReadCompatExt, TokioAsyncReadCompatExt};
use tracing::debug;

Expand All @@ -24,31 +24,6 @@ const NOTARY_PORT: u16 = 7047;
// Configuration of notarization
const NOTARY_MAX_TRANSCRIPT_SIZE: usize = 16384;

/// Response object of the /session API
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct NotarizationSessionResponse {
pub session_id: String,
}

/// Request object of the /session API
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct NotarizationSessionRequest {
pub client_type: ClientType,
/// Maximum transcript size in bytes
pub max_transcript_size: Option<usize>,
}

/// Types of client that the prover is using
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub enum ClientType {
/// Client that has access to the transport layer
Tcp,
/// Client that cannot directly access transport layer, e.g. browser extension
Websocket,
}

#[tokio::main]
async fn main() {
tracing_subscriber::fmt::init();
Expand All @@ -59,7 +34,8 @@ async fn main() {
let auth_token = env::var("AUTHORIZATION").unwrap();
let user_agent = env::var("USER_AGENT").unwrap();

let (notary_tls_socket, session_id) = setup_notary_connection().await;
let (notary_tls_socket, session_id) =
request_notarization(NOTARY_HOST, NOTARY_PORT, Some(NOTARY_MAX_TRANSCRIPT_SIZE)).await;

// Basic default prover config using the session_id returned from /session endpoint just now
let config = ProverConfig::builder()
Expand All @@ -85,12 +61,13 @@ async fn main() {
let prover_task = tokio::spawn(prover_fut);

// Attach the hyper HTTP client to the TLS connection
let (mut request_sender, connection) = hyper::client::conn::handshake(tls_connection.compat())
.await
.unwrap();
let (mut request_sender, connection) =
hyper::client::conn::http1::handshake(TokioIo::new(tls_connection.compat()))
.await
.unwrap();

// Spawn the HTTP task to be run concurrently
let connection_task = tokio::spawn(connection.without_shutdown());
tokio::spawn(connection);

// Build the HTTP request to fetch the DMs
let request = Request::builder()
Expand All @@ -104,7 +81,7 @@ async fn main() {
.header("User-Agent", user_agent)
.header("Authorization", &auth_token)
.header("Connection", "close")
.body(Body::empty())
.body(Empty::<Bytes>::new())
.unwrap();

debug!("Sending request");
Expand All @@ -118,15 +95,11 @@ async fn main() {
debug!("Request OK");

// Pretty printing :)
let payload = to_bytes(response.into_body()).await.unwrap().to_vec();
let payload = response.into_body().collect().await.unwrap().to_bytes();
let parsed =
serde_json::from_str::<serde_json::Value>(&String::from_utf8_lossy(&payload)).unwrap();
debug!("{}", serde_json::to_string_pretty(&parsed).unwrap());

// Close the connection to the server
let mut client_socket = connection_task.await.unwrap().unwrap().io.into_inner();
client_socket.close().await.unwrap();

// The Prover task should be done now, so we can grab it.
let prover = prover_task.await.unwrap().unwrap();

Expand Down Expand Up @@ -193,121 +166,6 @@ async fn main() {
.unwrap();
}

async fn setup_notary_connection() -> (tokio_rustls::client::TlsStream<TcpStream>, String) {
// Connect to the Notary via TLS-TCP
let pem_file = str::from_utf8(include_bytes!(
"../../../notary-server/fixture/tls/rootCA.crt"
))
.unwrap();
let mut reader = std::io::BufReader::new(pem_file.as_bytes());
let mut certificates: Vec<Certificate> = rustls_pemfile::certs(&mut reader)
.unwrap()
.into_iter()
.map(Certificate)
.collect();
let certificate = certificates.remove(0);

let mut root_store = RootCertStore::empty();
root_store.add(&certificate).unwrap();

let client_notary_config = ClientConfig::builder()
.with_safe_defaults()
.with_root_certificates(root_store)
.with_no_client_auth();
let notary_connector = TlsConnector::from(Arc::new(client_notary_config));

let notary_socket = tokio::net::TcpStream::connect((NOTARY_HOST, NOTARY_PORT))
.await
.unwrap();

let notary_tls_socket = notary_connector
// Require the domain name of notary server to be the same as that in the server cert
.connect("tlsnotaryserver.io".try_into().unwrap(), notary_socket)
.await
.unwrap();

// Attach the hyper HTTP client to the notary TLS connection to send request to the /session endpoint to configure notarization and obtain session id
let (mut request_sender, connection) = hyper::client::conn::handshake(notary_tls_socket)
.await
.unwrap();

// Spawn the HTTP task to be run concurrently
let connection_task = tokio::spawn(connection.without_shutdown());

// Build the HTTP request to configure notarization
let payload = serde_json::to_string(&NotarizationSessionRequest {
client_type: ClientType::Tcp,
max_transcript_size: Some(NOTARY_MAX_TRANSCRIPT_SIZE),
})
.unwrap();

let request = Request::builder()
.uri(format!("https://{NOTARY_HOST}:{NOTARY_PORT}/session"))
.method("POST")
.header("Host", NOTARY_HOST)
// Need to specify application/json for axum to parse it as json
.header("Content-Type", "application/json")
.body(Body::from(payload))
.unwrap();

debug!("Sending configuration request");

let configuration_response = request_sender.send_request(request).await.unwrap();

debug!("Sent configuration request");

assert!(configuration_response.status() == StatusCode::OK);

debug!("Response OK");

// Pretty printing :)
let payload = to_bytes(configuration_response.into_body())
.await
.unwrap()
.to_vec();
let notarization_response =
serde_json::from_str::<NotarizationSessionResponse>(&String::from_utf8_lossy(&payload))
.unwrap();

debug!("Notarization response: {:?}", notarization_response,);

// Send notarization request via HTTP, where the underlying TCP connection will be extracted later
let request = Request::builder()
// 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")
.body(Body::empty())
.unwrap();

debug!("Sending notarization request");

let response = request_sender.send_request(request).await.unwrap();

debug!("Sent notarization request");

assert!(response.status() == StatusCode::SWITCHING_PROTOCOLS);

debug!("Switched protocol OK");

// Claim back the TLS socket after HTTP exchange is done
let Parts {
io: notary_tls_socket,
..
} = connection_task.await.unwrap().unwrap();

(notary_tls_socket, notarization_response.session_id)
}

/// Find the ranges of the public and private parts of a sequence.
///
/// Returns a tuple of `(public, private)` ranges.
Expand Down
Loading

0 comments on commit 0d269ed

Please sign in to comment.