diff --git a/.github/workflows/build_client_native.yaml b/.github/workflows/build_client_native.yaml
index 27fe16b9d..f7b1f24d2 100644
--- a/.github/workflows/build_client_native.yaml
+++ b/.github/workflows/build_client_native.yaml
@@ -27,20 +27,20 @@ jobs:
rust-cache-key: client_native
- run: |
- cargo build -p client --release
+ cargo build -p web-prover-client --release
- uses: actions/upload-artifact@v4
if: matrix.os == 'ubuntu-latest'
with:
- name: "client.linux.amd64"
- path: "target/release/client"
+ name: "web-prover-client.linux.amd64"
+ path: "target/release/web-prover-client"
retention-days: 7
if-no-files-found: "error"
- uses: actions/upload-artifact@v4
if: matrix.os == 'macos-latest'
with:
- name: "client.macos.arm64"
- path: "target/release/client"
+ name: "web-prover-client.macos.arm64"
+ path: "target/release/web-prover-client"
retention-days: 7
if-no-files-found: "error"
diff --git a/.github/workflows/build_notary.yaml b/.github/workflows/build_notary.yaml
index 394b84644..ac5e6d9a8 100644
--- a/.github/workflows/build_notary.yaml
+++ b/.github/workflows/build_notary.yaml
@@ -26,12 +26,12 @@ jobs:
with:
rust-cache-key: client_notary
- - run: cargo build -p notary --release
+ - run: cargo build -p web-prover-notary --release
- uses: actions/upload-artifact@v4
if: matrix.os == 'ubuntu-latest'
with:
name: "notary.linux.amd64"
- path: "target/release/notary"
+ path: "target/release/web-prover-notary"
retention-days: 7
if-no-files-found: "error"
diff --git a/.github/workflows/check.yaml b/.github/workflows/check.yaml
new file mode 100644
index 000000000..0eb68ad71
--- /dev/null
+++ b/.github/workflows/check.yaml
@@ -0,0 +1,56 @@
+name: Check
+
+on:
+ workflow_call:
+
+jobs:
+ check:
+ runs-on: ubuntu-latest
+ strategy:
+ fail-fast: false
+ matrix:
+ check: [clippy, test, udeps]
+ crate: [web-prover-notary, web-prover-client, web-prover-core]
+ include:
+ - check: fmt
+ crate: all
+ steps:
+ - uses: actions/checkout@v4
+
+ # Setup Rust with cache key based on check type
+ - uses: ./.github/actions/setup-rust-ubuntu
+ with:
+ rust-cache-key: ${{ matrix.check }}
+
+ # Install necessary tools based on check type
+ - name: Install cargo-binstall
+ if: matrix.check == 'udeps'
+ uses: cargo-bins/cargo-binstall@main
+
+ - name: Install cargo-udeps
+ if: matrix.check == 'udeps'
+ run: cargo binstall --no-confirm cargo-udeps
+
+ - name: Install rustfmt
+ if: matrix.check == 'fmt'
+ run: rustup component add rustfmt
+
+ # Run the appropriate check
+ - name: Run clippy
+ if: matrix.check == 'clippy'
+ continue-on-error: true
+ run: cargo clippy -p ${{ matrix.crate }} -- -D warnings
+
+ - name: Run tests
+ if: matrix.check == 'test'
+ run: cargo test -p ${{ matrix.crate }}
+
+ - name: Check fmt
+ if: matrix.check == 'fmt'
+ continue-on-error: true
+ run: cargo fmt --all -- --check
+
+ - name: Check unused dependencies
+ if: matrix.check == 'udeps'
+ continue-on-error: true
+ run: cargo udeps -p ${{ matrix.crate }}
\ No newline at end of file
diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yaml
deleted file mode 100644
index 987547d38..000000000
--- a/.github/workflows/lint.yaml
+++ /dev/null
@@ -1,37 +0,0 @@
-name: Lint
-
-on:
- workflow_call:
-
-jobs:
- clippy:
- continue-on-error: true
- runs-on: ubuntu-latest
- strategy:
- fail-fast: false
- matrix:
- crate:
- - notary
- - client
- steps:
- - uses: actions/checkout@v4
-
- - uses: ./.github/actions/setup-rust-ubuntu
- with:
- rust-cache-key: clippy
-
- - run: cargo clippy -p ${{ matrix.crate }}
-
- fmt:
- continue-on-error: true
- runs-on: ubuntu-latest
- steps:
- - uses: actions/checkout@v4
-
- - uses: ./.github/actions/setup-rust-ubuntu
- with:
- rust-cache-key: fmt
-
- - run: rustup component add rustfmt
-
- - run: cargo fmt --all -- --check
diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml
index fbd58bd21..2116c0c87 100644
--- a/.github/workflows/release.yaml
+++ b/.github/workflows/release.yaml
@@ -27,8 +27,8 @@ jobs:
shell: bash
run: |
mkdir -p releases/clients
- cp target/release/client.linux.amd64/client releases/clients/client.linux.amd64
- cp target/release/client.macos.arm64/client releases/clients/client.macos.arm64
+ cp target/release/web-prover-client.linux.amd64/web-prover-client releases/clients/client.linux.amd64
+ cp target/release/web-prover-client.macos.arm64/web-prover-client releases/clients/client.macos.arm64
cd releases/clients
tar -czf client.linux.amd64.tar.gz client.linux.amd64
rm client.linux.amd64
diff --git a/.github/workflows/staging-deploy-gcs/notary-config.toml b/.github/workflows/staging-deploy-gcs/notary-config.toml
index 2287aa1a5..5d71817e7 100644
--- a/.github/workflows/staging-deploy-gcs/notary-config.toml
+++ b/.github/workflows/staging-deploy-gcs/notary-config.toml
@@ -1,2 +1,2 @@
-listen ="0.0.0.0:443"
-acme_email ="eng@pluto.xyz"
\ No newline at end of file
+acme_email="eng@pluto.xyz"
+listen ="0.0.0.0:443"
diff --git a/.github/workflows/staging-deploy/notary-config.toml b/.github/workflows/staging-deploy/notary-config.toml
index 3489960d9..109ed81d0 100644
--- a/.github/workflows/staging-deploy/notary-config.toml
+++ b/.github/workflows/staging-deploy/notary-config.toml
@@ -1,3 +1,3 @@
+acme_email ="eng@pluto.xyz"
listen ="0.0.0.0:443"
notary_signing_key="/opt/notary/etc/fixture/certs/notary.key"
-acme_email ="eng@pluto.xyz"
\ No newline at end of file
diff --git a/.github/workflows/web-prover.yaml b/.github/workflows/web-prover.yaml
index b6d702688..800afc877 100644
--- a/.github/workflows/web-prover.yaml
+++ b/.github/workflows/web-prover.yaml
@@ -12,8 +12,8 @@ concurrency:
jobs:
- lint:
- uses: ./.github/workflows/lint.yaml
+ check:
+ uses: ./.github/workflows/check.yaml
build_notary:
uses: ./.github/workflows/build_notary.yaml
diff --git a/Cargo.lock b/Cargo.lock
index 07565980f..a913814e4 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -706,36 +706,6 @@ version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6"
-[[package]]
-name = "client"
-version = "0.7.0"
-dependencies = [
- "base64 0.22.1",
- "bytes",
- "clap",
- "futures",
- "hex",
- "http-body-util",
- "hyper",
- "hyper-util",
- "reqwest",
- "rustls",
- "rustls-pki-types",
- "serde",
- "serde_json",
- "serde_with",
- "thiserror 1.0.69",
- "tokio",
- "tokio-rustls",
- "tokio-util",
- "tracing",
- "tracing-subscriber",
- "url",
- "uuid",
- "web-prover-core",
- "webpki-roots",
-]
-
[[package]]
name = "colorchoice"
version = "1.0.3"
@@ -2018,49 +1988,6 @@ dependencies = [
"minimal-lexical",
]
-[[package]]
-name = "notary"
-version = "0.7.0"
-dependencies = [
- "alloy-primitives",
- "async-trait",
- "axum",
- "axum-core",
- "base64 0.21.7",
- "chrono",
- "clap",
- "client",
- "config",
- "eyre",
- "futures",
- "futures-util",
- "hex",
- "http",
- "hyper",
- "hyper-util",
- "k256",
- "nom",
- "reqwest",
- "rs_merkle",
- "rustls",
- "rustls-acme",
- "rustls-pemfile",
- "serde",
- "serde_json",
- "thiserror 1.0.69",
- "tokio",
- "tokio-rustls",
- "tokio-stream",
- "tokio-util",
- "tower 0.4.13",
- "tower-http",
- "tower-service",
- "tracing",
- "tracing-subscriber",
- "uuid",
- "web-prover-core",
-]
-
[[package]]
name = "nu-ansi-term"
version = "0.46.0"
@@ -3907,6 +3834,36 @@ version = "0.2.93"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484"
+[[package]]
+name = "web-prover-client"
+version = "0.7.0"
+dependencies = [
+ "base64 0.22.1",
+ "bytes",
+ "clap",
+ "futures",
+ "hex",
+ "http-body-util",
+ "hyper",
+ "hyper-util",
+ "reqwest",
+ "rustls",
+ "rustls-pki-types",
+ "serde",
+ "serde_json",
+ "serde_with",
+ "thiserror 1.0.69",
+ "tokio",
+ "tokio-rustls",
+ "tokio-util",
+ "tracing",
+ "tracing-subscriber",
+ "url",
+ "uuid",
+ "web-prover-core",
+ "webpki-roots",
+]
+
[[package]]
name = "web-prover-core"
version = "0.7.0"
@@ -3922,6 +3879,49 @@ dependencies = [
"url",
]
+[[package]]
+name = "web-prover-notary"
+version = "0.7.0"
+dependencies = [
+ "alloy-primitives",
+ "async-trait",
+ "axum",
+ "axum-core",
+ "base64 0.21.7",
+ "chrono",
+ "clap",
+ "config",
+ "eyre",
+ "futures",
+ "futures-util",
+ "hex",
+ "http",
+ "hyper",
+ "hyper-util",
+ "k256",
+ "nom",
+ "reqwest",
+ "rs_merkle",
+ "rustls",
+ "rustls-acme",
+ "rustls-pemfile",
+ "serde",
+ "serde_json",
+ "thiserror 1.0.69",
+ "tokio",
+ "tokio-rustls",
+ "tokio-stream",
+ "tokio-util",
+ "tower 0.4.13",
+ "tower-http",
+ "tower-service",
+ "tracing",
+ "tracing-subscriber",
+ "uuid",
+ "web-prover-client",
+ "web-prover-core",
+]
+
[[package]]
name = "web-prover-tests"
version = "0.1.0"
diff --git a/Cargo.toml b/Cargo.toml
index 25a1a0248..00d6ad663 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,24 +1,20 @@
-[workspace.package]
-name ="webprover"
-edition="2021"
-
[workspace]
-members =["client", "notary", "web-prover-core", "tests"]
+members =["client", "notary", "core", "tests"]
resolver="2"
[workspace.dependencies]
# Local re-exporting
-client ={ path="client" }
-notary ={ path="notary" }
-web-prover-core={ path="web-prover-core" }
+web-prover-client={ path="client" }
+web-prover-core ={ path="core" }
+web-prover-notary={ path="notary" }
# Serde
serde ={ version="1.0.204", features=["derive"] }
serde_json="1.0.120"
# Logging
+futures ="0.3"
+rayon ="1.10.0"
tracing ="0.1.40"
tracing-subscriber={ version="0.3.18", features=["env-filter"] }
-rayon ="1.10.0"
-futures ="0.3"
# CLI
clap={ version="4.5.13", features=["derive"] }
@@ -26,31 +22,31 @@ clap={ version="4.5.13", features=["derive"] }
thiserror="1.0.61"
# HTTP
+http-body-util="0.1"
hyper ={ version="1.6", features=["full"] }
hyper-util ={ version="0.1", features=["full"] }
-http-body-util="0.1"
# Async
tokio ={ version="1.39.1", features=["full"] }
-tokio-util ={ version="0.7" }
tokio-rustls={ version="0.26.0", default-features=false, features=["logging", "tls12"] }
+tokio-util ={ version="0.7" }
-uuid ={ version="1.10.0", default-features=false, features=["v4", "serde"] }
+chrono ="0.4"
derive_more={ version="2.0.1", features=["full"] }
url ="2.5.4"
-chrono ="0.4"
+uuid ={ version="1.10.0", default-features=false, features=["v4", "serde"] }
tracing-test="0.2"
[profile.dev]
+incremental =true
opt-level =1
split-debuginfo="unpacked"
-incremental =true
[profile.release]
-opt-level =0
-lto =false
codegen-units=1
+debug =true # Propagate more information up through FFI
+lto =false
+opt-level =0
panic ="abort"
strip =true
-debug =true # Propagate more information up through FFI
diff --git a/README.md b/README.md
index a5ca0dc9a..f1d6a0034 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,16 @@
+
+
+
+ Pluto
+
+
+
+
+
+
+
+---
+
# Web Prover
[](https://github.com/pluto/web-prover/actions/workflows/web-prover.yaml)
diff --git a/book/book.toml b/book/book.toml
index 4e472e3f5..12cb9e7da 100644
--- a/book/book.toml
+++ b/book/book.toml
@@ -1,15 +1,15 @@
[book]
authors =["Pluto"]
+description ="Backend for Web Proofs"
language ="en"
multilingual=false
src ="."
title ="Web Prover"
-description ="Backend for Web Proofs"
[build]
build-dir ="."
-extra-watch-dirs =[] # Don't watch any extra directories
create-missing =false # Don't create missing files
+extra-watch-dirs =[] # Don't watch any extra directories
use-default-preprocessors=false
[preprocessor.links]
@@ -29,8 +29,8 @@ warning-policy ="ignore"
[output.html]
default-theme ="dark"
-preferred-dark-theme="ayu"
git-repository-url ="https://github.com/pluto/web-prover"
+preferred-dark-theme="ayu"
# [output.html.playground]
# editable=true
diff --git a/client/Cargo.toml b/client/Cargo.toml
index bc740bd77..3f908ddeb 100644
--- a/client/Cargo.toml
+++ b/client/Cargo.toml
@@ -1,35 +1,35 @@
[package]
-name ="client"
-version="0.7.0"
-edition="2021"
build ="build.rs"
+edition="2021"
+name ="web-prover-client"
publish=false
+version="0.7.0"
[features]
default =[]
-websocket=[]
tracing =[]
+websocket=[]
# used to disable cert verification, useful for development
unsafe_skip_cert_verification=[]
# Shared dependencies for all targets
[dependencies]
-web-prover-core={ workspace=true }
bytes ="1"
-webpki-roots ="0.26.1"
pki-types ={ package="rustls-pki-types", version="1.7" }
+web-prover-core={ workspace=true }
+webpki-roots ="0.26.1"
# Serde
serde ={ workspace=true }
serde_json={ workspace=true }
# Web
hex ="0.4"
-url ="2.5"
-hyper ={ workspace=true, features=["client", "http1"] }
http-body-util={ workspace=true }
+hyper ={ workspace=true, features=["client", "http1"] }
+url ="2.5"
# Logging and errors
+thiserror ={ workspace=true }
tracing ={ workspace=true }
tracing-subscriber={ workspace=true }
-thiserror ={ workspace=true }
# Async
futures={ workspace=true }
# Other
@@ -38,15 +38,15 @@ tokio-util={ version="0.7", features=[
"compat",
] } # compat is used to work with AsyncRead and AsyncWrite from other crates
-uuid ={ workspace=true }
clap ={ workspace=true }
serde_with={ version="3.12.0", features=["base64"] }
+uuid ={ workspace=true }
# Web
hyper-util={ workspace=true }
# Async
-tokio-rustls={ version="0.26", default-features=false, features=["logging", "tls12"] }
-tokio ={ workspace=true, features=["rt", "rt-multi-thread", "macros", "net", "io-std", "fs"] }
rustls ={ version="0.23", default-features=false, features=["ring"] }
+tokio ={ workspace=true, features=["rt", "rt-multi-thread", "macros", "net", "io-std", "fs"] }
+tokio-rustls={ version="0.26", default-features=false, features=["logging", "tls12"] }
# TLSN
reqwest={ version="0.12", features=["json", "rustls-tls"] }
diff --git a/client/src/config.rs b/client/src/config.rs
index 4f751f482..b9b81a42b 100644
--- a/client/src/config.rs
+++ b/client/src/config.rs
@@ -9,7 +9,7 @@ use serde_with::{
use url::Url;
use web_prover_core::manifest::Manifest;
-use crate::errors::ClientErrors;
+use crate::error::WebProverClientError;
/// Proving data containing [`Manifest`] and serialized witnesses used for WASM
#[derive(Deserialize, Clone, Debug)]
@@ -60,11 +60,11 @@ impl Config {
///
/// # Errors
/// - Returns `ClientErrors::Other` if the host is not found in the target URL.
- pub fn target_host(&self) -> Result {
+ pub fn target_host(&self) -> Result {
let target_url = Url::parse(&self.target_url)?;
let host = target_url
.host_str()
- .ok_or_else(|| ClientErrors::Other("Host not found in target URL".to_owned()))?
+ .ok_or_else(|| WebProverClientError::Other("Host not found in target URL".to_owned()))?
.to_string();
Ok(host)
}
@@ -81,11 +81,11 @@ impl Config {
///
/// # Errors
/// - Returns `ClientErrors::Other` if the port is not found in the target URL.
- pub fn target_port(&self) -> Result {
+ pub fn target_port(&self) -> Result {
let target_url = Url::parse(&self.target_url)?;
let port = target_url
.port_or_known_default()
- .ok_or_else(|| ClientErrors::Other("Port not found in target URL".to_owned()))?;
+ .ok_or_else(|| WebProverClientError::Other("Port not found in target URL".to_owned()))?;
Ok(port)
}
@@ -99,7 +99,7 @@ impl Config {
///
/// # Errors
/// - Returns `ClientErrors::Other` if the URL is invalid.
- pub fn target_is_https(&self) -> Result {
+ pub fn target_is_https(&self) -> Result {
let target_url = Url::parse(&self.target_url)?;
Ok(target_url.scheme() == "https")
}
diff --git a/client/src/errors.rs b/client/src/error.rs
similarity index 75%
rename from client/src/errors.rs
rename to client/src/error.rs
index 4c060d69c..d536a75a0 100644
--- a/client/src/errors.rs
+++ b/client/src/error.rs
@@ -1,12 +1,18 @@
use std::array::TryFromSliceError;
use thiserror::Error;
-impl From for ClientErrors {
- fn from(err: TryFromSliceError) -> ClientErrors { ClientErrors::Other(err.to_string()) }
+impl From for WebProverClientError {
+ fn from(err: TryFromSliceError) -> WebProverClientError {
+ WebProverClientError::Other(err.to_string())
+ }
}
+// TODO (autoparallel): Combining enums is a good practice. This error enum could also all be moved
+// to the `web-prover-core` crate so there is one spot for all the errors. This makes error handling
+// more consistent and easier to manage.
+
#[derive(Debug, Error)]
-pub enum ClientErrors {
+pub enum WebProverClientError {
#[cfg(not(target_arch = "wasm32"))]
#[error(transparent)]
RustTls(#[from] rustls::Error),
diff --git a/client/src/lib.rs b/client/src/lib.rs
index 8e087e5a5..f7472eb40 100644
--- a/client/src/lib.rs
+++ b/client/src/lib.rs
@@ -1,6 +1,6 @@
extern crate core;
pub mod config;
-pub mod errors;
+pub mod error;
use std::collections::HashMap;
use serde::{Deserialize, Serialize};
@@ -10,7 +10,7 @@ use web_prover_core::{
proof::{SignedVerificationReply, TeeProof},
};
-use crate::errors::ClientErrors;
+use crate::error::WebProverClientError;
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct ProxyConfig {
@@ -21,7 +21,7 @@ pub struct ProxyConfig {
pub manifest: Manifest,
}
-pub async fn proxy(config: config::Config) -> Result {
+pub async fn proxy(config: config::Config) -> Result {
let session_id = config.session_id.clone();
let url = format!(
@@ -57,7 +57,7 @@ pub async fn proxy(config: config::Config) -> Result {
pub async fn verify(
config: crate::config::Config,
verify_body: T,
-) -> Result {
+) -> Result {
let url = format!(
"https://{}:{}/v1/{}/verify",
config.notary_host.clone(),
diff --git a/client/src/main.rs b/client/src/main.rs
index 471fabad5..9c828f96b 100644
--- a/client/src/main.rs
+++ b/client/src/main.rs
@@ -1,6 +1,6 @@
use clap::Parser;
-use client::{config::Config, errors::ClientErrors};
use tracing::Level;
+use web_prover_client::{config::Config, error::WebProverClientError};
#[derive(Parser)]
#[clap(name = "Web Proof Client")]
@@ -14,7 +14,7 @@ struct Args {
}
#[tokio::main]
-async fn main() -> Result<(), ClientErrors> {
+async fn main() -> Result<(), WebProverClientError> {
let args = Args::parse();
let log_level = match args.log_level.to_lowercase().as_str() {
@@ -32,7 +32,7 @@ async fn main() -> Result<(), ClientErrors> {
let mut config: Config = serde_json::from_str(&config_json)?;
config.set_session_id();
- let proof = client::proxy(config).await?;
+ let proof = web_prover_client::proxy(config).await?;
let proof_json = serde_json::to_string_pretty(&proof)?;
println!("Proving Successful: proof_len={:?}", proof_json.len());
Ok(())
diff --git a/web-prover-core/Cargo.toml b/core/Cargo.toml
similarity index 100%
rename from web-prover-core/Cargo.toml
rename to core/Cargo.toml
index 329b11243..bc8c47611 100644
--- a/web-prover-core/Cargo.toml
+++ b/core/Cargo.toml
@@ -1,16 +1,16 @@
[package]
+edition="2021"
name ="web-prover-core"
version="0.7.0"
-edition="2021"
[dependencies]
+derive_more={ workspace=true }
serde ={ workspace=true }
serde_json ={ workspace=true }
-tracing ={ workspace=true }
thiserror ={ workspace=true }
tiny-keccak={ version="2.0.2", features=["keccak"] }
+tracing ={ workspace=true }
url ={ workspace=true }
-derive_more={ workspace=true }
# Using `regress` crate for compatibility with ECMAScript regular expressions in Manifest validation
-regress="0.10.3"
regex ="1.11.1"
+regress="0.10.3"
diff --git a/core/src/error.rs b/core/src/error.rs
new file mode 100644
index 000000000..11565216f
--- /dev/null
+++ b/core/src/error.rs
@@ -0,0 +1,28 @@
+//! # Error Types
+//!
+//! This module defines the error types used throughout the `web-prover-core` crate.
+//!
+//! The primary error type is [`WebProverCoreError`], which encompasses all possible
+//! error conditions that can occur within the crate.
+
+use thiserror::Error;
+
+/// Represents the various error conditions that can occur within the `web-prover-core` crate.
+///
+/// This enum provides specific error variants for different failure scenarios, making
+/// error handling more precise and informative.
+#[derive(Debug, Error)]
+pub enum WebProverCoreError {
+ /// The error is an invalid manifest
+ ///
+ /// This error occurs when a manifest fails validation checks. The string
+ /// parameter provides details about the specific validation failure.
+ #[error("Invalid manifest: {0}")]
+ InvalidManifest(String),
+
+ /// Serde operation failed
+ ///
+ /// This error occurs when serialization or deserialization operations fail.
+ #[error("Serde error occurred: {0}")]
+ SerdeError(#[from] serde_json::Error),
+}
diff --git a/web-prover-core/src/http.rs b/core/src/http.rs
similarity index 72%
rename from web-prover-core/src/http.rs
rename to core/src/http.rs
index e6a85dce1..7899fff21 100644
--- a/web-prover-core/src/http.rs
+++ b/core/src/http.rs
@@ -1,57 +1,100 @@
//! # HTTP Module
//!
//! The `http` module provides utilities for handling HTTP-related operations in the proof system.
+//! It defines structures and functions for representing, parsing, and validating HTTP requests
+//! and responses.
//!
-//! ## Structs
+//! ## Key Components
//!
-//! - `ResponseBody`: Represents the body of an HTTP response, containing a vector of JSON keys.
-//! - `Response`: Represents an HTTP response, including status, version, message, headers, and
-//! body.
+//! ### Request Handling
+//!
+//! - [`ManifestRequest`]: Defines the expected HTTP request pattern in a manifest
+//! - [`TemplateVar`]: Defines template variables that can be used in requests
+//!
+//! ### Response Handling
+//!
+//! - [`ManifestResponse`]: Defines the expected HTTP response pattern in a manifest
+//! - [`ManifestResponseBody`]: Represents the body of an expected HTTP response
+//! - [`NotaryResponse`]: Represents an actual HTTP response from a notary service
+//! - [`NotaryResponseBody`]: Represents the body of an actual HTTP response
+//!
+//! ### JSON Path Handling
+//!
+//! - [`JsonKey`]: Represents a key in a JSON path (either a string key or array index)
+//!
+//! ## Constants
+//!
+//! - [`MAX_HTTP_HEADERS`]: Maximum number of HTTP headers allowed
+//! - [`HTTP_1_1`]: HTTP/1.1 version string
//!
//! ## Functions
//!
-//! - `default_version`: Returns the default HTTP version string.
-//! - `default_message`: Returns the default HTTP response message string.
+//! - [`default_version`]: Returns the default HTTP version string
+//! - [`default_message`]: Returns the default HTTP response message string
use std::collections::HashMap;
use serde::{Deserialize, Serialize};
use tracing::debug;
+/// Represents a key in a JSON path, which can be either a string key for objects
+/// or a numeric index for arrays.
+///
+/// This enum is used to define paths for traversing JSON structures when validating
+/// response bodies against expected patterns.
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(untagged)]
pub enum JsonKey {
- /// Object key
+ /// A string key used to access properties in a JSON object
String(String),
- /// Array index
+ /// A numeric index used to access elements in a JSON array
Num(usize),
}
-use crate::errors::ManifestError;
+use crate::error::WebProverCoreError;
-/// Max HTTP headers
+/// Maximum number of HTTP headers allowed in a request or response
pub const MAX_HTTP_HEADERS: usize = 25;
-/// HTTP/1.1
+/// HTTP/1.1 version string constant
pub const HTTP_1_1: &str = "HTTP/1.1";
/// A type of response body used to describe conditions in the client `Manifest`.
+///
+/// This structure defines the expected format and content of an HTTP response body
+/// in a manifest, particularly focusing on JSON path traversal for validation.
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
pub struct ManifestResponseBody {
- /// JSON Path containing expected traversal keys and expected value
+ /// JSON Path containing expected traversal keys and expected value.
+ ///
+ /// This vector defines a path through a JSON structure that should be present
+ /// in the response. Each element in the vector represents a key or index in the
+ /// path, with the last element typically being the expected value.
#[serde(rename = "json")] // TODO: Remove after migrating to a JSON DSL
pub json_path: Vec,
}
impl TryFrom<&[u8]> for ManifestResponseBody {
- type Error = ManifestError;
+ type Error = WebProverCoreError;
+ /// Attempts to create a `ManifestResponseBody` from a byte slice.
+ ///
+ /// If the byte slice is empty, returns a default `ManifestResponseBody` with an empty path.
+ /// Otherwise, attempts to parse the bytes as a JSON array of `JsonKey` elements.
+ ///
+ /// # Arguments
+ ///
+ /// * `body_bytes` - The byte slice containing the JSON representation of the path
+ ///
+ /// # Returns
+ ///
+ /// A `Result` containing either the parsed `ManifestResponseBody` or an error
fn try_from(body_bytes: &[u8]) -> Result {
if body_bytes.is_empty() {
return Ok(Self { json_path: vec![] });
}
// Attempt to parse the body as JSON path.
let json_path: Vec = serde_json::from_slice(body_bytes).map_err(|_| {
- ManifestError::InvalidManifest("Failed to parse body as valid JSON".to_string())
+ WebProverCoreError::InvalidManifest("Failed to parse body as valid JSON".to_string())
})?;
Ok(Self { json_path })
}
@@ -59,22 +102,40 @@ impl TryFrom<&[u8]> for ManifestResponseBody {
/// A type of response body returned by a notary. Must match `ManifestResponseBody` designated
/// by the client.
+///
+/// This structure represents the actual JSON response body received from a notary service,
+/// which will be validated against the expected pattern defined in a `ManifestResponseBody`.
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct NotaryResponseBody {
/// Raw JSON value returned by a notary.
+ ///
+ /// This field contains the parsed JSON response from the notary service.
+ /// It is `None` if the response body was empty or could not be parsed as JSON.
pub json: Option,
}
impl TryFrom<&[u8]> for NotaryResponseBody {
- type Error = ManifestError;
+ type Error = WebProverCoreError;
+ /// Attempts to create a `NotaryResponseBody` from a byte slice.
+ ///
+ /// If the byte slice is empty, returns a `NotaryResponseBody` with `json` set to `None`.
+ /// Otherwise, attempts to parse the bytes as a JSON value.
+ ///
+ /// # Arguments
+ ///
+ /// * `body_bytes` - The byte slice containing the JSON response
+ ///
+ /// # Returns
+ ///
+ /// A `Result` containing either the parsed `NotaryResponseBody` or an error
fn try_from(body_bytes: &[u8]) -> Result {
if body_bytes.is_empty() {
return Ok(Self { json: None });
}
// Attempt to parse the body as JSON.
let json: serde_json::Value = serde_json::from_slice(body_bytes).map_err(|_| {
- ManifestError::InvalidManifest("Failed to parse body as valid JSON".to_string())
+ WebProverCoreError::InvalidManifest("Failed to parse body as valid JSON".to_string())
})?;
Ok(Self { json: Some(json) })
}
@@ -91,6 +152,14 @@ impl NotaryResponseBody {
///
/// The function traverses the JSON step-by-step, returning `true` if all keys match,
/// or `false` otherwise.
+ ///
+ /// # Arguments
+ ///
+ /// * `json_path` - A slice of `JsonKey` elements defining the expected path
+ ///
+ /// # Returns
+ ///
+ /// `true` if the JSON response matches the expected path, `false` otherwise
fn matches_path(&self, json_path: &[JsonKey]) -> bool {
if json_path.is_empty() {
debug!("Invalid json_path: Path is empty");
@@ -145,6 +214,17 @@ impl NotaryResponseBody {
false
}
+ /// Handles validation for string keys in the JSON path.
+ ///
+ /// # Arguments
+ ///
+ /// * `current` - The current JSON value being examined
+ /// * `expected` - The expected string key or value
+ /// * `is_last` - Whether this is the last element in the path
+ ///
+ /// # Returns
+ ///
+ /// `true` if the key exists or the value matches (if last), `false` otherwise
fn handle_string_key(&self, current: &serde_json::Value, expected: &str, is_last: bool) -> bool {
match current {
serde_json::Value::String(actual) => is_last && actual == expected,
@@ -156,6 +236,17 @@ impl NotaryResponseBody {
}
}
+ /// Handles validation for numeric keys in the JSON path.
+ ///
+ /// # Arguments
+ ///
+ /// * `current` - The current JSON value being examined
+ /// * `expected` - The expected array index or numeric value
+ /// * `is_last` - Whether this is the last element in the path
+ ///
+ /// # Returns
+ ///
+ /// `true` if the index exists or the value matches (if last), `false` otherwise
fn handle_numeric_key(
&self,
current: &serde_json::Value,
@@ -187,26 +278,41 @@ impl NotaryResponseBody {
}
}
-/// A response the made by the notary for a request from the client. Must match client response.
+/// A response made by the notary for a request from the client. Must match client response.
+///
+/// This structure represents a complete HTTP response from a notary service, including
+/// both the response metadata (status, headers, etc.) and the parsed body.
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct NotaryResponse {
- /// Client-designated response recovered from the notary
- pub response: ManifestResponse,
- /// Raw response body from the notary
+ /// Client-designated response recovered from the notary.
+ ///
+ /// This field contains the parsed HTTP response metadata, including status code,
+ /// headers, and other information.
+ pub response: ManifestResponse,
+
+ /// Raw response body from the notary.
+ ///
+ /// This field contains the parsed JSON body of the response, which will be
+ /// validated against the expected pattern.
pub notary_response_body: NotaryResponseBody,
}
impl NotaryResponse {
/// Recovers all `Response` fields from the given payloads and creates a `Response` struct.
///
- /// - `header_bytes`: The bytes representing the HTTP response headers and metadata.
- /// - `body_bytes`: The bytes representing the HTTP response body.
- pub fn from_payload(bytes: &[u8]) -> Result {
+ /// # Arguments
+ ///
+ /// * `bytes` - The complete HTTP response as a byte slice, including headers and body
+ ///
+ /// # Returns
+ ///
+ /// A `Result` containing either the parsed `NotaryResponse` or an error
+ pub fn from_payload(bytes: &[u8]) -> Result {
let delimiter = b"\r\n\r\n";
let split_position = bytes
.windows(delimiter.len())
.position(|window| window == delimiter)
- .ok_or_else(|| ManifestError::InvalidManifest("Invalid HTTP format".to_string()))?;
+ .ok_or_else(|| WebProverCoreError::InvalidManifest("Invalid HTTP format".to_string()))?;
let (header_bytes, rest) = bytes.split_at(split_position);
let body_bytes = &rest[delimiter.len()..];
@@ -227,12 +333,12 @@ impl NotaryResponse {
///
/// # Returns
///
- /// The parsed HTTP response header.
+ /// A tuple containing the parsed headers, status code, HTTP version, and status message.
fn parse_header(
header_bytes: &[u8],
- ) -> Result<(HashMap, String, String, String), ManifestError> {
+ ) -> Result<(HashMap, String, String, String), WebProverCoreError> {
let headers_str = std::str::from_utf8(header_bytes).map_err(|_| {
- ManifestError::InvalidManifest("Failed to interpret headers as valid UTF-8".to_string())
+ WebProverCoreError::InvalidManifest("Failed to interpret headers as valid UTF-8".to_string())
})?;
let mut headers = HashMap::new();
let mut status = String::new();
@@ -247,7 +353,7 @@ impl NotaryResponse {
// Process the first line as the HTTP response start-line
let parts: Vec<&str> = line.split_whitespace().collect();
if parts.len() < 3 {
- return Err(ManifestError::InvalidManifest(
+ return Err(WebProverCoreError::InvalidManifest(
"Invalid HTTP response start-line".to_string(),
));
}
@@ -259,15 +365,26 @@ impl NotaryResponse {
if let Some((key, value)) = line.split_once(": ") {
headers.insert(key.to_string(), value.to_string());
} else {
- return Err(ManifestError::InvalidManifest(format!("Invalid header line: {}", line)));
+ return Err(WebProverCoreError::InvalidManifest(format!(
+ "Invalid header line: {}",
+ line
+ )));
}
}
}
Ok((headers, status, version, message))
}
- /// Tests matching between notary response, `self`, and client-designated response, `other`.
+ /// Tests matching between notary response, `self`, and client-designated response, `other`.
/// Returns true if at least all values in `other` are also present in `self`.
+ ///
+ /// # Arguments
+ ///
+ /// * `other` - The client-designated response to match against
+ ///
+ /// # Returns
+ ///
+ /// `true` if the notary response matches the client manifest, `false` otherwise
pub fn matches_client_manifest(&self, other: &ManifestResponse) -> bool {
if self.response.status != other.status
|| self.response.version != other.version
@@ -309,53 +426,62 @@ impl NotaryResponse {
}
}
-/// Default HTTP version
+/// Returns the default HTTP version string (HTTP/1.1)
pub fn default_version() -> String { HTTP_1_1.to_string() }
-/// Default HTTP message
+
+/// Returns the default HTTP response message string ("OK")
pub fn default_message() -> String { "OK".to_string() }
/// Returns an empty `HashMap` as the default value for `vars`
fn default_empty_vars() -> HashMap { HashMap::new() }
/// HTTP Response items required for circuits
+///
+/// This structure defines the expected HTTP response pattern in a manifest,
+/// including status code, headers, and body validation rules.
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct ManifestResponse {
- /// HTTP response status
- pub status: String,
- /// HTTP version
+ /// HTTP response status code as a string (e.g., "200", "201")
+ pub status: String,
+
+ /// HTTP version string (e.g., "HTTP/1.1")
#[serde(default = "default_version")]
pub version: String,
- /// HTTP response message
+
+ /// HTTP response status message (e.g., "OK", "Created")
#[serde(default = "default_message")]
pub message: String,
- /// HTTP headers to lock
+
+ /// HTTP headers to validate in the response
pub headers: HashMap,
- /// HTTP body keys
- pub body: ManifestResponseBody,
+
+ /// HTTP body validation rules
+ pub body: ManifestResponseBody,
}
impl ManifestResponse {
/// Validates the HTTP response
///
- /// This function validates the HTTP response.
- ///
- /// # Arguments
- ///
- /// * `self`: The HTTP response to validate.
+ /// This function validates the HTTP response against a set of rules:
+ /// - Status code must be supported (currently 200 or 201)
+ /// - HTTP version must be valid (currently only HTTP/1.1)
+ /// - Message must be of valid length
+ /// - Headers must include Content-Type with a supported value
+ /// - JSON path must be valid when Content-Type is application/json
///
/// # Returns
///
- /// The validated HTTP response.
- pub fn validate(&self) -> Result<(), ManifestError> {
+ /// `Ok(())` if the response is valid, or an error describing the validation failure
+ pub fn validate(&self) -> Result<(), WebProverCoreError> {
// TODO: What are legal statuses?
const VALID_STATUSES: [&str; 2] = ["200", "201"];
if !VALID_STATUSES.contains(&self.status.as_str()) {
- return Err(ManifestError::InvalidManifest("Unsupported HTTP status".to_string()));
+ return Err(WebProverCoreError::InvalidManifest("Unsupported HTTP status".to_string()));
}
// TODO: What HTTP versions are supported?
if self.version != "HTTP/1.1" {
- return Err(ManifestError::InvalidManifest(
+ return Err(WebProverCoreError::InvalidManifest(
"Invalid HTTP version: ".to_string() + &self.version,
));
}
@@ -363,14 +489,14 @@ impl ManifestResponse {
// TODO: What is the max supported message length?
// TODO: Not covered by serde's #default annotation. Is '""' a valid message?
if self.message.len() > 1024 || self.message.is_empty() {
- return Err(ManifestError::InvalidManifest(
+ return Err(WebProverCoreError::InvalidManifest(
"Invalid message length: ".to_string() + &self.message,
));
}
// We always expect at least one header, "Content-Type"
if self.headers.len() > MAX_HTTP_HEADERS || self.headers.is_empty() {
- return Err(ManifestError::InvalidManifest(
+ return Err(WebProverCoreError::InvalidManifest(
"Invalid headers length: ".to_string() + &self.headers.len().to_string(),
));
}
@@ -378,7 +504,7 @@ impl ManifestResponse {
let content_type =
self.headers.get("Content-Type").or_else(|| self.headers.get("content-type"));
if content_type.is_none() {
- return Err(ManifestError::InvalidManifest("Missing 'Content-Type' header".to_string()));
+ return Err(WebProverCoreError::InvalidManifest("Missing 'Content-Type' header".to_string()));
}
let content_type = content_type.unwrap();
@@ -387,19 +513,21 @@ impl ManifestResponse {
content_type == legal_type || content_type.starts_with(&format!("{};", legal_type))
});
if !is_valid_content_type {
- return Err(ManifestError::InvalidManifest(
+ return Err(WebProverCoreError::InvalidManifest(
"Invalid Content-Type header: ".to_string() + content_type,
));
}
// When Content-Type is application/json, we expect at least one JSON item
if content_type == "application/json" && self.body.json_path.is_empty() {
- return Err(ManifestError::InvalidManifest("Expected at least one JSON item".to_string()));
+ return Err(WebProverCoreError::InvalidManifest(
+ "Expected at least one JSON item".to_string(),
+ ));
}
const MAX_JSON_PATH_LENGTH: usize = 100;
if self.body.json_path.len() > MAX_JSON_PATH_LENGTH {
- return Err(ManifestError::InvalidManifest(
+ return Err(WebProverCoreError::InvalidManifest(
"Invalid JSON path length: ".to_string() + &self.body.json_path.len().to_string(),
));
}
@@ -409,64 +537,87 @@ impl ManifestResponse {
}
/// Template variable type
+///
+/// This structure defines constraints for template variables that can be used
+/// in HTTP requests, allowing for dynamic content with validation rules.
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct TemplateVar {
- /// Regex for validation (if applicable)
- pub regex: Option,
- /// Length constraint (if applicable)
+ /// Regular expression pattern for validating the variable value
+ ///
+ /// If provided, the value of the variable must match this regex pattern.
+ pub regex: Option,
+
+ /// Required length of the variable value
+ ///
+ /// If provided, the value of the variable must be exactly this length.
pub length: Option,
- /// Type constraint (e.g., base64, hex)
+
+ /// Type constraint for the variable
+ ///
+ /// If provided, specifies the expected format of the variable (e.g., "base64", "hex").
pub r#type: Option,
}
/// HTTP Request items required for circuits
+///
+/// This structure defines the expected HTTP request pattern in a manifest,
+/// including method, URL, headers, and body.
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct ManifestRequest {
- /// HTTP method (GET or POST)
- pub method: String,
+ /// HTTP method (e.g., "GET", "POST")
+ pub method: String,
+
/// HTTP request URL
- pub url: String,
- /// HTTP version
+ pub url: String,
+
+ /// HTTP version string (e.g., "HTTP/1.1")
#[serde(default = "default_version")]
pub version: String,
- /// Request headers to lock
+
+ /// Request headers to include
pub headers: HashMap,
- /// Request JSON body
- pub body: Option,
- /// Request JSON vars to be used in templates
+
+ /// Request JSON body (if any)
+ pub body: Option,
+
+ /// Template variables that can be used in the request
+ ///
+ /// These variables allow for dynamic content in the request while
+ /// maintaining validation rules.
#[serde(default = "default_empty_vars")]
- pub vars: HashMap,
+ pub vars: HashMap,
}
impl ManifestRequest {
- /// This function validates the HTTP request.
- ///
- /// # Arguments
+ /// Validates the HTTP request against a set of rules.
///
- /// * `self`: The HTTP request to validate.
+ /// This function checks:
+ /// - Method must be supported (currently GET or POST)
+ /// - URL must be valid and use HTTPS
+ /// - HTTP version must be valid (currently only HTTP/1.1)
///
/// # Returns
///
- /// The validated HTTP request.
- pub fn validate(&self) -> Result<(), ManifestError> {
+ /// `Ok(())` if the request is valid, or an error describing the validation failure
+ pub fn validate(&self) -> Result<(), WebProverCoreError> {
// TODO: What HTTP methods are supported?
const ALLOWED_METHODS: [&str; 2] = ["GET", "POST"];
if !ALLOWED_METHODS.contains(&self.method.as_str()) {
- return Err(ManifestError::InvalidManifest("Invalid HTTP method".to_string()));
+ return Err(WebProverCoreError::InvalidManifest("Invalid HTTP method".to_string()));
}
// Not a valid URL
if url::Url::parse(&self.url).is_err() {
- return Err(ManifestError::InvalidManifest("Invalid URL: ".to_string() + &self.url));
+ return Err(WebProverCoreError::InvalidManifest("Invalid URL: ".to_string() + &self.url));
}
if !self.url.starts_with("https://") {
- return Err(ManifestError::InvalidManifest("Only HTTPS URLs are allowed".to_string()));
+ return Err(WebProverCoreError::InvalidManifest("Only HTTPS URLs are allowed".to_string()));
}
// TODO: What HTTP versions are supported?
if self.version != "HTTP/1.1" {
- return Err(ManifestError::InvalidManifest(
+ return Err(WebProverCoreError::InvalidManifest(
"Invalid HTTP version: ".to_string() + &self.version,
));
}
@@ -474,16 +625,29 @@ impl ManifestRequest {
Ok(())
}
- fn validate_vars(&self) -> Result<(), ManifestError> {
+ // TODO (autoparallel): This function is not used anywhere at the moment, but i did not want to
+ // delete it.
+
+ /// Validates template variables in the request.
+ ///
+ /// This function performs comprehensive validation of template variables:
+ /// 1. Ensures all tokens used in the body and headers are declared in `vars`
+ /// 2. Ensures all variables declared in `vars` are actually used in the request
+ /// 3. Validates each variable against its constraints (regex, length, type)
+ ///
+ /// # Returns
+ ///
+ /// `Ok(())` if all variables are valid, or an error describing the validation failure
+ #[allow(unused)]
+ fn validate_vars(&self) -> Result<(), WebProverCoreError> {
let mut all_tokens = vec![];
// Parse and validate tokens in the body
if let Some(body_tokens) = self.body.as_ref().map(extract_tokens) {
for token in &body_tokens {
if !self.vars.contains_key(token) {
- return Err(ManifestError::InvalidManifest(format!(
- "Token `<% {} %>` not declared in `vars`",
- token
+ return Err(WebProverCoreError::InvalidManifest(format!(
+ "Token `<% {token} %>` not declared in `vars`",
)));
}
}
@@ -495,7 +659,7 @@ impl ManifestRequest {
let header_tokens = extract_tokens(&serde_json::Value::String(value.clone()));
for token in &header_tokens {
if !self.vars.contains_key(token) {
- return Err(ManifestError::InvalidManifest(format!(
+ return Err(WebProverCoreError::InvalidManifest(format!(
"Token `<% {} %>` not declared in `vars`",
token
)));
@@ -504,22 +668,23 @@ impl ManifestRequest {
all_tokens.extend(header_tokens);
}
+ // Ensure all declared variables are actually used somewhere in the request
for var_key in self.vars.keys() {
if !all_tokens.contains(var_key) {
- return Err(ManifestError::InvalidManifest(format!(
+ return Err(WebProverCoreError::InvalidManifest(format!(
"Token `<% {} %>` not declared in `body` or `headers`",
var_key
)));
}
}
- // Validate each `vars` entry
+ // Validate each `vars` entry against its constraints
for (key, var_def) in &self.vars {
- // Validate regex (if defined)
+ // Validate regex pattern (if defined)
if let Some(regex_pattern) = var_def.regex.as_ref() {
// Using `regress` crate for compatibility with ECMAScript regular expressions
let _regex = regress::Regex::new(regex_pattern).map_err(|_| {
- ManifestError::InvalidManifest(format!("Invalid regex pattern for `{}`", key))
+ WebProverCoreError::InvalidManifest(format!("Invalid regex pattern for `{}`", key))
})?;
// TODO: It will definitely not match it here because it's a template variable, not an
// actual variable
@@ -534,11 +699,11 @@ impl ManifestRequest {
// }
}
- // Validate length (if applicable)
+ // Validate length constraint (if applicable)
if let Some(length) = var_def.length {
if let Some(value) = self.body.as_ref().and_then(|b| b.get(key)) {
if value.as_str().unwrap_or("").len() != length {
- return Err(ManifestError::InvalidManifest(format!(
+ return Err(WebProverCoreError::InvalidManifest(format!(
"Value for token `<% {} %>` does not meet length constraint",
key
)));
@@ -546,19 +711,27 @@ impl ManifestRequest {
}
}
- // TODO: Validate the token "type" constraint
+ // TODO: Validate the token "type" constraint (e.g., base64, hex)
}
Ok(())
}
/// Parses the HTTP request from the given bytes.
- pub fn from_payload(bytes: &[u8]) -> Result {
+ ///
+ /// # Arguments
+ ///
+ /// * `bytes` - The complete HTTP request as a byte slice, including headers and body
+ ///
+ /// # Returns
+ ///
+ /// A `Result` containing either the parsed `ManifestRequest` or an error
+ pub fn from_payload(bytes: &[u8]) -> Result {
// todo: dedup me
let delimiter = b"\r\n\r\n";
let split_position = bytes
.windows(delimiter.len())
.position(|window| window == delimiter)
- .ok_or_else(|| ManifestError::InvalidManifest("Invalid HTTP format".to_string()))?;
+ .ok_or_else(|| WebProverCoreError::InvalidManifest("Invalid HTTP format".to_string()))?;
let (header_bytes, rest) = bytes.split_at(split_position);
let body_bytes = &rest[delimiter.len()..];
@@ -567,7 +740,7 @@ impl ManifestRequest {
let body = if !body_bytes.is_empty() {
serde_json::from_slice(body_bytes)
- .map_err(|_| ManifestError::InvalidManifest("Invalid body bytes".to_string()))?
+ .map_err(|_| WebProverCoreError::InvalidManifest("Invalid body bytes".to_string()))?
} else {
None
};
@@ -576,21 +749,31 @@ impl ManifestRequest {
}
/// Parses the HTTP request start-line and headers from the given bytes.
+ ///
+ /// # Arguments
+ ///
+ /// * `header_bytes` - The bytes containing the HTTP request headers
+ ///
+ /// # Returns
+ ///
+ /// A tuple containing the parsed method, URL, HTTP version, and headers
fn parse_header(
header_bytes: &[u8],
- ) -> Result<(String, String, String, HashMap), ManifestError> {
+ ) -> Result<(String, String, String, HashMap), WebProverCoreError> {
let header_str = std::str::from_utf8(header_bytes).map_err(|_| {
- ManifestError::InvalidManifest("Failed to interpret headers as valid UTF-8".to_string())
+ WebProverCoreError::InvalidManifest("Failed to interpret headers as valid UTF-8".to_string())
})?;
let mut lines = header_str.lines();
let start_line = lines.next().ok_or_else(|| {
- ManifestError::InvalidManifest("Missing start-line in the HTTP request.".to_string())
+ WebProverCoreError::InvalidManifest("Missing start-line in the HTTP request.".to_string())
})?;
let parts: Vec<&str> = start_line.split_whitespace().collect();
if parts.len() < 3 {
- return Err(ManifestError::InvalidManifest("Invalid HTTP request start-line.".to_string()));
+ return Err(WebProverCoreError::InvalidManifest(
+ "Invalid HTTP request start-line.".to_string(),
+ ));
}
let method = parts[0].to_string();
@@ -605,7 +788,7 @@ impl ManifestRequest {
if let Some((key, value)) = line.split_once(": ") {
headers.insert(key.to_string(), value.to_string());
} else {
- return Err(ManifestError::InvalidManifest(format!("Invalid header line: {}", line)));
+ return Err(WebProverCoreError::InvalidManifest(format!("Invalid header line: {}", line)));
}
}
@@ -613,10 +796,22 @@ impl ManifestRequest {
}
/// Checks if the current request is a subset of the given `other` request.
+ ///
/// For the request to be a subset:
/// - All headers in `self` must exist in `other` with matching values.
/// - All vars in `self` must exist in `other` with matching constraints.
/// - All remaining fields like `method`, `url`, and `body` must also match.
+ ///
+ /// This function is useful for determining if a request satisfies the requirements
+ /// specified in another request template.
+ ///
+ /// # Arguments
+ ///
+ /// * `other` - The request to check against
+ ///
+ /// # Returns
+ ///
+ /// `true` if this request is a subset of the other request, `false` otherwise
pub fn is_subset_of(&self, other: &ManifestRequest) -> bool {
// Check if all headers in `self` exist in `other` with the same value
for (key, value) in &self.headers {
@@ -648,11 +843,24 @@ impl ManifestRequest {
}
}
+/// Extracts template variable tokens from a JSON value.
+///
+/// This function recursively searches through a JSON value (string, object, or array)
+/// to find all template variable tokens in the format `<% token_name %>`.
+///
+/// # Arguments
+///
+/// * `value` - The JSON value to search for tokens
+///
+/// # Returns
+///
+/// A vector of strings containing the extracted token names (without the `<% %>` delimiters)
fn extract_tokens(value: &serde_json::Value) -> Vec {
let mut tokens = vec![];
match value {
serde_json::Value::String(s) => {
+ // For string values, use regex to find all tokens in the format <% token_name %>
let token_regex = regex::Regex::new(r"<%\s*(\w+)\s*%>").unwrap();
for capture in token_regex.captures_iter(s) {
if let Some(token) = capture.get(1) {
@@ -673,7 +881,7 @@ fn extract_tokens(value: &serde_json::Value) -> Vec {
tokens.extend(extract_tokens(v));
}
},
- _ => {},
+ _ => {}, // Ignore other JSON value types (numbers, booleans, null)
}
tokens
@@ -693,8 +901,10 @@ pub mod tests {
macro_rules! request {
// Match with optional parameters
($($key:ident: $value:expr),* $(,)?) => {{
+ // Make clippy happy
+ #[allow(unused_mut) ]
let mut request = ManifestRequest {
- method: "GET".to_string(),
+ method: "GET".to_string(),
url: "https://example.com".to_string(),
version: "HTTP/1.1".to_string(),
headers: std::collections::HashMap::from([
@@ -846,7 +1056,7 @@ pub mod tests {
let result = NotaryResponse::from_payload(&[header_bytes, invalid_body_bytes].concat());
assert!(result.is_err());
- if let Err(ManifestError::InvalidManifest(msg)) = result {
+ if let Err(WebProverCoreError::InvalidManifest(msg)) = result {
assert!(msg.contains("Failed to parse body as valid JSON"));
} else {
panic!("Expected an invalid manifest error for body parsing");
@@ -864,7 +1074,7 @@ pub mod tests {
assert!(result.is_err());
match result {
- Err(ManifestError::InvalidManifest(msg)) => {
+ Err(WebProverCoreError::InvalidManifest(msg)) => {
assert!(msg.contains("Unsupported HTTP status"));
},
_ => panic!("Expected invalid manifest error for unsupported HTTP status"),
@@ -879,7 +1089,7 @@ pub mod tests {
let result = invalid_response.validate();
assert!(result.is_err());
- if let Err(ManifestError::InvalidManifest(msg)) = result {
+ if let Err(WebProverCoreError::InvalidManifest(msg)) = result {
assert!(msg.contains("Invalid message length"));
} else {
panic!("Expected invalid manifest error for empty message");
@@ -966,7 +1176,7 @@ pub mod tests {
assert!(result.is_err());
match result {
- Err(ManifestError::InvalidManifest(msg)) => {
+ Err(WebProverCoreError::InvalidManifest(msg)) => {
assert!(msg.contains("Failed to interpret headers as valid UTF-8"));
},
_ => panic!("Expected invalid UTF-8 headers error"),
@@ -982,7 +1192,7 @@ pub mod tests {
assert!(result.is_err());
match result {
- Err(ManifestError::InvalidManifest(msg)) => {
+ Err(WebProverCoreError::InvalidManifest(msg)) => {
assert!(msg.contains("Invalid HTTP request start-line"));
},
_ => panic!("Expected invalid start-line error"),
@@ -999,7 +1209,7 @@ pub mod tests {
let result = request.validate();
assert!(result.is_err());
match result {
- Err(ManifestError::InvalidManifest(msg)) => {
+ Err(WebProverCoreError::InvalidManifest(msg)) => {
assert!(msg.contains("Only HTTPS URLs are allowed"));
},
_ => panic!("Expected error for non-HTTPS URL"),
@@ -1026,7 +1236,7 @@ pub mod tests {
assert!(result.is_err());
match result {
- Err(ManifestError::InvalidManifest(msg)) => {
+ Err(WebProverCoreError::InvalidManifest(msg)) => {
assert!(msg.contains("Invalid body bytes"));
},
_ => panic!("Expected invalid body parsing error"),
@@ -1046,7 +1256,7 @@ pub mod tests {
assert!(result.is_err());
match result {
- Err(ManifestError::InvalidManifest(msg)) => {
+ Err(WebProverCoreError::InvalidManifest(msg)) => {
assert!(msg.contains("Token `<% missing_token %>` not declared in `vars`"));
},
_ => panic!("Expected missing token error"),
diff --git a/core/src/lib.rs b/core/src/lib.rs
new file mode 100644
index 000000000..1d3b8ba8e
--- /dev/null
+++ b/core/src/lib.rs
@@ -0,0 +1,56 @@
+//! # Web Prover Core
+//!
+//! `web-prover-core` is a foundational crate for creating and validating proofs of web
+//! interactions. It provides the core data structures and validation logic needed to create
+//! verifiable proofs that specific HTTP requests were made and specific responses were received.
+//!
+//! ## Overview
+//!
+//! This crate implements the core functionality for a system that allows users to:
+//!
+//! 1. Define a "manifest" that specifies expected HTTP requests and responses
+//! 2. Execute those requests in a trusted execution environment (TEE)
+//! 3. Generate cryptographic proofs that the specified interactions occurred
+//! 4. Verify those proofs
+//!
+//! ## Key Components
+//!
+//! - **Manifest**: Defines the expected HTTP request and response patterns
+//! - **HTTP**: Utilities for parsing and validating HTTP requests and responses
+//! - **Proof**: Data structures for representing cryptographic proofs
+//! - **Error**: Error types specific to the web prover system
+//!
+//! ## Example Usage
+//!
+//! ```rust,no_run
+//! use web_prover_core::{
+//! http::{ManifestRequest, ManifestResponse},
+//! manifest::Manifest,
+//! };
+//!
+//! // Parse a manifest from JSON
+//! let manifest_json = r#"{"request": {...}, "response": {...}}"#;
+//! let manifest: Manifest = serde_json::from_str(manifest_json).unwrap();
+//!
+//! // Validate the manifest
+//! manifest.validate().unwrap();
+//!
+//! // Generate a digest for the manifest
+//! let digest = manifest.to_keccak_digest().unwrap();
+//! ```
+//!
+//! ## Modules
+//!
+//! - [`manifest`](manifest/index.html): Core manifest data structures and validation
+//! - [`http`](http/index.html): HTTP request and response handling
+//! - [`proof`](proof/index.html): Proof generation and verification
+//! - [`error`](error/index.html): Error types for the crate
+
+#![warn(missing_docs, clippy::missing_docs_in_private_items)]
+
+pub mod error;
+pub mod http;
+pub mod manifest;
+
+pub mod proof;
+#[cfg(test)] mod test_utils;
diff --git a/web-prover-core/src/manifest.rs b/core/src/manifest.rs
similarity index 86%
rename from web-prover-core/src/manifest.rs
rename to core/src/manifest.rs
index efb631b0c..5466d6118 100644
--- a/web-prover-core/src/manifest.rs
+++ b/core/src/manifest.rs
@@ -1,9 +1,24 @@
+//! # Manifest
+//!
+//! This module defines the core `Manifest` structure that specifies the expected
+//! HTTP request and response patterns for web proofs.
+//!
+//! A manifest serves as a template and validation criteria for HTTP interactions.
+//! It defines:
+//!
+//! - The expected HTTP request (method, URL, headers, body)
+//! - The expected HTTP response (status, headers, body)
+//! - Validation rules for both request and response
+//!
+//! Manifests can be serialized to and deserialized from JSON, and can be hashed
+//! to create a unique identifier.
+
use derive_more::From;
use serde::{Deserialize, Serialize};
use tiny_keccak::{Hasher, Keccak};
use crate::{
- errors::ManifestError,
+ error::WebProverCoreError,
http::{ManifestRequest, ManifestResponse},
};
@@ -28,7 +43,7 @@ pub struct Manifest {
impl Manifest {
/// Validates `Manifest` request and response fields. They are validated against valid statuses,
/// http methods, and template variables.
- pub fn validate(&self) -> Result<(), ManifestError> {
+ pub fn validate(&self) -> Result<(), WebProverCoreError> {
// TODO: Validate manifest version, id, title, description, prepareUrl
self.request.validate()?;
self.response.validate()?;
@@ -42,7 +57,7 @@ impl Manifest {
}
/// Compute a `Keccak256` hash of the serialized Manifest
- pub fn to_keccak_digest(&self) -> Result<[u8; 32], ManifestError> {
+ pub fn to_keccak_digest(&self) -> Result<[u8; 32], WebProverCoreError> {
let as_bytes: Vec = self.try_into()?;
let mut hasher = Keccak::v256();
let mut output = [0u8; 32];
@@ -77,14 +92,13 @@ mod tests {
use std::collections::HashMap;
use crate::{
- errors::ProofError,
- program::{
- http::{JsonKey, ManifestRequest, ManifestResponse, ManifestResponseBody, TemplateVar},
- manifest::HTTP_1_1,
- plain_manifest::Manifest,
+ error::WebProverCoreError,
+ http::{
+ JsonKey, ManifestRequest, ManifestResponse, ManifestResponseBody, TemplateVar, HTTP_1_1,
},
+ manifest::Manifest,
request, response,
- tests::inputs::TEST_MANIFEST,
+ test_utils::TEST_MANIFEST,
};
macro_rules! create_manifest {
@@ -186,7 +200,7 @@ mod tests {
let manifest = create_manifest!(request!(method: "INVALID".to_string()), response!(),);
let result = manifest.validate();
assert!(result.is_err());
- if let Err(ManifestError::InvalidManifest(message)) = result {
+ if let Err(WebProverCoreError::InvalidManifest(message)) = result {
assert_eq!(message, "Invalid HTTP method");
} else {
panic!("Expected ManifestError::InvalidManifest");
@@ -198,7 +212,7 @@ mod tests {
let manifest = create_manifest!(request!(url: "ftp://example.com".to_string()), response!(),);
let result = manifest.validate();
assert!(result.is_err());
- if let Err(ManifestError::InvalidManifest(message)) = result {
+ if let Err(WebProverCoreError::InvalidManifest(message)) = result {
assert_eq!(message, "Only HTTPS URLs are allowed");
} else {
panic!("Expected ManifestError::InvalidManifest");
@@ -210,7 +224,7 @@ mod tests {
let manifest = create_manifest!(request!(), response!(status: "500".to_string()),);
let result = manifest.validate();
assert!(result.is_err());
- if let Err(ManifestError::InvalidManifest(message)) = result {
+ if let Err(WebProverCoreError::InvalidManifest(message)) = result {
assert_eq!(message, "Unsupported HTTP status");
} else {
panic!("Expected ManifestError::InvalidManifest");
@@ -247,7 +261,7 @@ mod tests {
);
let result = manifest.validate();
assert!(result.is_err());
- if let Err(ManifestError::InvalidManifest(message)) = result {
+ if let Err(WebProverCoreError::InvalidManifest(message)) = result {
assert_eq!(message, "Invalid Content-Type header: invalid/type");
} else {
panic!("Expected ManifestError::InvalidManifest");
diff --git a/core/src/proof.rs b/core/src/proof.rs
new file mode 100644
index 000000000..bc32ea734
--- /dev/null
+++ b/core/src/proof.rs
@@ -0,0 +1,152 @@
+//! # Proof
+//!
+//! This module defines the data structures used to represent cryptographic proofs
+//! of web interactions.
+//!
+//! A proof consists of:
+//!
+//! - Data about the manifest that was executed
+//! - Cryptographic signatures verifying the execution
+//!
+//! ## Overview
+//!
+//! The proof system is designed to cryptographically verify that a specific HTTP interaction
+//! occurred as defined in a manifest. This is accomplished through:
+//!
+//! 1. Generating a unique hash of the manifest
+//! 2. Executing the HTTP request in a trusted execution environment (TEE)
+//! 3. Creating a signed proof that includes the manifest hash and response data
+//! 4. Providing cryptographic signatures that can be verified by third parties
+//!
+//! ## Key Components
+//!
+//! - [`TeeProof`]: The top-level proof structure that combines proof data with signatures
+//! - [`TeeProofData`]: Contains the essential data being proven (manifest hash)
+//! - [`SignedVerificationReply`]: Contains cryptographic signatures and verification data
+//!
+//! ## Verification Process
+//!
+//! To verify a proof:
+//!
+//! 1. Extract the manifest hash from `TeeProofData`
+//! 2. Verify the signature in `SignedVerificationReply` using the provided signer address
+//! 3. Confirm that the digest in the signature matches the expected value
+//! 4. Optionally verify the Merkle proof if the implementation uses a Merkle tree
+
+use std::convert::TryFrom;
+
+use serde::{Deserialize, Serialize};
+
+/// Represents a cryptographically signed verification response from a trusted execution
+/// environment.
+///
+/// This structure contains all the cryptographic elements needed to verify that a specific
+/// manifest was executed in a trusted environment.
+#[derive(Serialize, Deserialize, Clone, Debug)]
+pub struct SignedVerificationReply {
+ /// A list of hashes representing the leaves of a Merkle tree.
+ ///
+ /// These leaves can be used to construct a Merkle proof, which efficiently verifies
+ /// that a specific piece of data is included in a larger dataset without requiring
+ /// the entire dataset.
+ pub merkle_leaves: Vec,
+
+ /// The cryptographic digest (hash) of the data being verified, typically in hex format.
+ ///
+ /// This digest uniquely identifies the content being proven and is what gets signed
+ /// by the trusted execution environment.
+ pub digest: String,
+
+ /// The complete ECDSA signature as a single string.
+ ///
+ /// This signature is generated by the trusted execution environment and proves that
+ /// the environment attests to the validity of the digest.
+ pub signature: String,
+
+ /// The r component of the ECDSA signature.
+ ///
+ /// In ECDSA, a signature consists of two values (r,s). This field contains the r value,
+ /// typically represented as a hexadecimal string.
+ pub signature_r: String,
+
+ /// The s component of the ECDSA signature.
+ ///
+ /// In ECDSA, a signature consists of two values (r,s). This field contains the s value,
+ /// typically represented as a hexadecimal string.
+ pub signature_s: String,
+
+ /// The recovery ID for the ECDSA signature.
+ ///
+ /// This value (typically 0 or 1) is used to recover the public key from the signature.
+ /// It's essential for Ethereum-style signature verification.
+ pub signature_v: u8,
+
+ /// The Ethereum address of the signer.
+ ///
+ /// This address represents the public key that signed the digest. Verifiers can use
+ /// this address to confirm that the signature was created by a trusted entity.
+ pub signer: String,
+}
+
+/// The top-level proof structure that combines the proof data with its cryptographic signature.
+///
+/// A `TeeProof` represents a complete, verifiable proof that a specific manifest was executed
+/// in a trusted execution environment (TEE).
+#[derive(Debug, Deserialize, Serialize, Clone)]
+pub struct TeeProof {
+ /// The core data being proven, including the manifest hash.
+ ///
+ /// This field contains the essential information about what is being proven,
+ /// specifically the cryptographic hash of the manifest that was executed.
+ pub data: TeeProofData,
+
+ /// Cryptographic signatures and verification data that authenticate the proof.
+ ///
+ /// This field contains all the cryptographic elements needed to verify that the
+ /// proof was generated by a trusted execution environment.
+ pub signature: SignedVerificationReply,
+}
+
+impl TryFrom<&[u8]> for TeeProof {
+ type Error = serde_json::Error;
+
+ /// Attempts to deserialize a byte slice into a `TeeProof`.
+ ///
+ /// This implementation allows for easy conversion from JSON bytes to a structured proof.
+ ///
+ /// # Errors
+ ///
+ /// Returns a `serde_json::Error` if deserialization fails.
+ fn try_from(bytes: &[u8]) -> Result { serde_json::from_slice(bytes) }
+}
+
+impl TryFrom for Vec {
+ type Error = serde_json::Error;
+
+ /// Attempts to serialize a `TeeProof` into a byte vector.
+ ///
+ /// This implementation allows for easy conversion from a structured proof to JSON bytes.
+ ///
+ /// # Errors
+ ///
+ /// Returns a `serde_json::Error` if serialization fails.
+ fn try_from(proof: TeeProof) -> Result { serde_json::to_vec(&proof) }
+}
+
+/// Contains the essential data being proven by a `TeeProof`.
+///
+/// This structure holds the cryptographic hash of the manifest that was executed,
+/// which serves as a unique identifier for the specific HTTP interaction that was proven.
+#[derive(Debug, Deserialize, Serialize, Clone)]
+pub struct TeeProofData {
+ /// A byte vector containing the cryptographic hash of the manifest.
+ ///
+ /// This hash uniquely identifies the manifest and can be used to verify that the
+ /// correct manifest was executed. It's typically a Keccak-256 hash (32 bytes)
+ /// that serves as a fingerprint of the entire manifest content.
+ ///
+ /// Verifiers can independently compute this hash from the original manifest and
+ /// compare it with the value in the proof to ensure they're verifying the
+ /// expected interaction.
+ pub manifest_hash: Vec,
+}
diff --git a/web-prover-core/src/test_utils.rs b/core/src/test_utils.rs
similarity index 100%
rename from web-prover-core/src/test_utils.rs
rename to core/src/test_utils.rs
diff --git a/fixture/notary-config.toml b/fixture/notary-config.toml
index 8c29a01f4..0d9846751 100644
--- a/fixture/notary-config.toml
+++ b/fixture/notary-config.toml
@@ -1,4 +1,4 @@
listen ="0.0.0.0:7443"
+notary_signing_key="./fixture/certs/notary.key"
server_cert ="./fixture/certs/server-cert.pem"
server_key ="./fixture/certs/server-key.pem"
-notary_signing_key="./fixture/certs/notary.key"
\ No newline at end of file
diff --git a/notary/Cargo.toml b/notary/Cargo.toml
index d7b4964ce..77e62e3d8 100644
--- a/notary/Cargo.toml
+++ b/notary/Cargo.toml
@@ -1,46 +1,46 @@
[package]
-name ="notary"
-version="0.7.0"
-edition="2021"
build ="build.rs"
+edition="2021"
+name ="web-prover-notary"
+version="0.7.0"
[dependencies]
-web-prover-core ={ workspace=true }
chrono ={ workspace=true }
-client ={ workspace=true }
+futures ={ workspace=true }
+futures-util ="0.3.30"
hyper ={ workspace=true, features=["client", "http1", "server"] }
hyper-util ={ workspace=true }
+nom ="7.0"
+rustls ={ version="0.23.11", default-features=false, features=["logging", "tls12", "std", "ring"] }
+rustls-pemfile ="2.1.2"
serde ={ workspace=true }
serde_json ={ workspace=true }
-rustls ={ version="0.23.11", default-features=false, features=["logging", "tls12", "std", "ring"] }
tokio ={ workspace=true }
-tokio-util ={ workspace=true, features=["compat"] }
-tracing ={ workspace=true }
-tracing-subscriber={ workspace=true }
-futures ={ workspace=true }
-futures-util ="0.3.30"
tokio-rustls ={ workspace=true, features=["ring"] }
+tokio-util ={ workspace=true, features=["compat"] }
tower-http ={ version="0.5.2", features=["cors"] }
tower-service ="0.3.2"
-rustls-pemfile ="2.1.2"
-nom ="7.0"
+tracing ={ workspace=true }
+tracing-subscriber={ workspace=true }
+web-prover-client ={ workspace=true }
+web-prover-core ={ workspace=true }
+alloy-primitives={ version="0.8.2", features=["k256"] }
async-trait ="0.1.67"
axum ={ version="0.7", features=["ws", "json"] }
axum-core ="0.4"
-eyre ="0.6.8"
base64 ="0.21.0"
-http ="1.1"
-config ="0.14.0"
clap ={ workspace=true }
-rustls-acme ={ version="0.10", default-features=false, features=["ring", "tokio"] }
-tokio-stream ={ version="0.1", features=["net"] }
-thiserror ={ workspace=true }
+config ="0.14.0"
+eyre ="0.6.8"
hex ="0.4"
-rs_merkle ="1.4.2"
-alloy-primitives={ version="0.8.2", features=["k256"] }
+http ="1.1"
k256 ={ version="0.13.3", features=["ecdsa", "pem"] }
reqwest ={ version="0.12", features=["json"] }
+rs_merkle ="1.4.2"
+rustls-acme ={ version="0.10", default-features=false, features=["ring", "tokio"] }
+thiserror ={ workspace=true }
+tokio-stream ={ version="0.1", features=["net"] }
uuid ={ workspace=true }
[dev-dependencies]
diff --git a/notary/src/errors.rs b/notary/src/error.rs
similarity index 78%
rename from notary/src/errors.rs
rename to notary/src/error.rs
index d68bdfc76..536318c8d 100644
--- a/notary/src/errors.rs
+++ b/notary/src/error.rs
@@ -5,7 +5,12 @@ use axum::{
use eyre::Report;
use thiserror::Error;
use tracing::error;
-use web_prover_core::errors::ManifestError;
+use web_prover_core::error::WebProverCoreError;
+
+// TODO (autoparallel): I think these error enums should be combined into `WebProverNotaryError`.
+// Combining enums is a good practice. They could also all be moved to the `web-prover-core` crate
+// so there is one spot for all the errors. This makes error handling more consistent and easier to
+// manage.
#[derive(Debug, Error)]
pub enum ProxyError {
@@ -51,7 +56,7 @@ pub enum NotaryServerError {
ProxyError(#[from] ProxyError),
#[error(transparent)]
- ManifestError(#[from] ManifestError),
+ ManifestError(#[from] WebProverCoreError),
}
/// Trait implementation to convert this error into an axum http response
diff --git a/notary/src/main.rs b/notary/src/main.rs
index 396293e40..1491f4a83 100644
--- a/notary/src/main.rs
+++ b/notary/src/main.rs
@@ -1,8 +1,7 @@
use std::{
- collections::HashMap,
fs,
io::{self},
- sync::{Arc, Mutex},
+ sync::Arc,
};
use axum::{
@@ -12,7 +11,7 @@ use axum::{
routing::{get, post},
Router,
};
-use errors::NotaryServerError;
+use error::NotaryServerError;
use hyper::{body::Incoming, server::conn::http1};
use hyper_util::rt::TokioIo;
use k256::{ecdsa::SigningKey, elliptic_curve::rand_core, pkcs8::DecodePrivateKey};
@@ -30,17 +29,14 @@ use tracing::{error, info};
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
mod config;
-mod errors;
+mod error;
mod proxy;
mod verifier;
struct SharedState {
notary_signing_key: SigningKey,
- sessions: Arc>>,
}
-struct Session {}
-
/// Main entry point for the notary server application.
///
/// This function:
@@ -88,10 +84,8 @@ async fn main() -> Result<(), NotaryServerError> {
let listener = TcpListener::bind(&c.listen).await?;
info!("Listening on https://{}", &c.listen);
- let shared_state = Arc::new(SharedState {
- notary_signing_key: load_notary_signing_key(&c.notary_signing_key),
- sessions: Default::default(),
- });
+ let shared_state =
+ Arc::new(SharedState { notary_signing_key: load_notary_signing_key(&c.notary_signing_key) });
let router = Router::new()
.route("/health", get(|| async move { (StatusCode::OK, "Ok").into_response() }))
diff --git a/notary/src/proxy.rs b/notary/src/proxy.rs
index be60140f6..4853ef849 100644
--- a/notary/src/proxy.rs
+++ b/notary/src/proxy.rs
@@ -18,7 +18,7 @@ use web_prover_core::{
};
use crate::{
- errors::NotaryServerError,
+ error::NotaryServerError,
verifier::{sign_verification, VerifyOutput},
SharedState,
};
@@ -31,9 +31,9 @@ pub struct NotarizeQuery {
pub async fn proxy(
query: Query,
State(state): State>,
- extract::Json(payload): extract::Json,
+ extract::Json(payload): extract::Json,
) -> Result, NotaryServerError> {
- let session_id = query.session_id.clone();
+ let session_id = query.session_id;
info!("Starting proxy with ID: {}", session_id);
diff --git a/notary/src/verifier.rs b/notary/src/verifier.rs
index cca07c20b..771720e6e 100644
--- a/notary/src/verifier.rs
+++ b/notary/src/verifier.rs
@@ -5,7 +5,7 @@ use rs_merkle::{Hasher, MerkleTree};
use serde::{Deserialize, Serialize};
use web_prover_core::{manifest::Manifest, proof::SignedVerificationReply};
-use crate::{errors::NotaryServerError, SharedState, State};
+use crate::{error::NotaryServerError, SharedState, State};
#[derive(Clone)]
struct KeccakHasher;
diff --git a/taplo.toml b/taplo.toml
index f58bb47b4..39051ed0c 100644
--- a/taplo.toml
+++ b/taplo.toml
@@ -13,7 +13,7 @@ column_width=100
# remove whitespace around '='
compact_entries=true
# alphabetically sort entries not separated by line breaks
-reorder_keys=false
+reorder_keys=true
# align entries vertically (default: true)
# align_comments =false
# expand arrays into multiple lines (default: true)
diff --git a/tests/Cargo.toml b/tests/Cargo.toml
index 547249b65..3efc8cfe6 100644
--- a/tests/Cargo.toml
+++ b/tests/Cargo.toml
@@ -1,9 +1,9 @@
[package]
+edition="2021"
name ="web-prover-tests"
version="0.1.0"
-edition="2021"
[dependencies]
+serde_json={ workspace=true }
tokio ={ workspace=true }
tracing ={ workspace=true }
-serde_json={ workspace=true }
diff --git a/web-prover-core/src/errors.rs b/web-prover-core/src/errors.rs
deleted file mode 100644
index 6e69c2fb9..000000000
--- a/web-prover-core/src/errors.rs
+++ /dev/null
@@ -1,15 +0,0 @@
-//! Error type for the `web-prover-core` crate.
-
-use thiserror::Error;
-
-/// Represents the various error conditions that can occur within the `proofs` crate.
-#[derive(Debug, Error)]
-pub enum ManifestError {
- /// The error is an invalid manifest
- #[error("Invalid manifest: {0}")]
- InvalidManifest(String),
-
- /// Serde operation failed
- #[error("Serde error occurred: {0}")]
- SerdeError(#[from] serde_json::Error),
-}
diff --git a/web-prover-core/src/lib.rs b/web-prover-core/src/lib.rs
deleted file mode 100644
index bf4b92c4d..000000000
--- a/web-prover-core/src/lib.rs
+++ /dev/null
@@ -1,6 +0,0 @@
-pub mod errors;
-pub mod http;
-pub mod manifest;
-
-pub mod proof;
-pub mod test_utils;
diff --git a/web-prover-core/src/proof.rs b/web-prover-core/src/proof.rs
deleted file mode 100644
index 33d8b5986..000000000
--- a/web-prover-core/src/proof.rs
+++ /dev/null
@@ -1,37 +0,0 @@
-use std::convert::TryFrom;
-
-use serde::{Deserialize, Serialize};
-
-#[derive(Serialize, Deserialize, Clone, Debug)]
-pub struct SignedVerificationReply {
- pub merkle_leaves: Vec,
- pub digest: String,
- pub signature: String,
- pub signature_r: String,
- pub signature_s: String,
- pub signature_v: u8,
- pub signer: String,
-}
-
-#[derive(Debug, Deserialize, Serialize, Clone)]
-pub struct TeeProof {
- pub data: TeeProofData,
- pub signature: SignedVerificationReply,
-}
-
-impl TryFrom<&[u8]> for TeeProof {
- type Error = serde_json::Error;
-
- fn try_from(bytes: &[u8]) -> Result { serde_json::from_slice(bytes) }
-}
-
-impl TryFrom for Vec {
- type Error = serde_json::Error;
-
- fn try_from(proof: TeeProof) -> Result { serde_json::to_vec(&proof) }
-}
-
-#[derive(Debug, Deserialize, Serialize, Clone)]
-pub struct TeeProofData {
- pub manifest_hash: Vec,
-}