diff --git a/examples/lockfile/request.lock.json b/examples/lockfile/request.lock.json new file mode 100644 index 0000000..7e4935c --- /dev/null +++ b/examples/lockfile/request.lock.json @@ -0,0 +1,9 @@ +{ + "method": "GET", + "target": "/api", + "version": "HTTP/1.1", + "headerName1": "Host", + "headerValue1": "localhost", + "headerName2": "Accept", + "headerValue2": "application/json" +} \ No newline at end of file diff --git a/examples/lockfile/response.lock.json b/examples/lockfile/response.lock.json new file mode 100644 index 0000000..cf02dd8 --- /dev/null +++ b/examples/lockfile/response.lock.json @@ -0,0 +1,7 @@ +{ + "version": "HTTP/1.1", + "status": "200", + "message": "OK", + "headerName1": "Content-Type", + "headerValue1": "application/json" +} \ No newline at end of file diff --git a/examples/lockfile/test.lock.json b/examples/lockfile/test.lock.json deleted file mode 100644 index e4eada6..0000000 --- a/examples/lockfile/test.lock.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "request": { - "method": "GET", - "target": "/api", - "version": "HTTP/1.1", - "headers": [ - [ - "Host", - "localhost" - ], - [ - "Accept", - "application/json" - ] - ] - }, - "response": { - "version": "HTTP/1.1", - "status": "200", - "message": "OK", - "headers": [ - [ - "Content-Type", - "application/json" - ] - ] - } -} \ No newline at end of file diff --git a/src/http_lock.rs b/src/http_lock.rs index 907c8a3..881d425 100644 --- a/src/http_lock.rs +++ b/src/http_lock.rs @@ -1,32 +1,67 @@ use super::*; +use std::{ + collections::HashMap, + fs::{self, create_dir_all}, +}; #[derive(Debug, Serialize, Deserialize)] -struct HttpData { - request: Request, - response: Response, +#[serde(untagged)] +pub enum HttpData { + Request(Request), + Response(Response), } #[derive(Debug, Serialize, Deserialize)] -struct Request { +pub struct Request { method: String, target: String, version: String, - headers: Vec<(String, String)>, + #[serde(flatten)] + #[serde(deserialize_with = "deserialize_headers")] + headers: HashMap, } #[derive(Debug, Serialize, Deserialize)] -struct Response { +pub struct Response { version: String, status: String, message: String, - headers: Vec<(String, String)>, + #[serde(flatten)] + #[serde(deserialize_with = "deserialize_headers")] + headers: HashMap, } -use std::fs::{self, create_dir_all}; +impl HttpData { + fn headers(&self) -> HashMap { + match self { + HttpData::Request(request) => request.headers.clone(), + HttpData::Response(response) => response.headers.clone(), + } + } +} + +fn deserialize_headers<'de, D>(deserializer: D) -> Result, D::Error> +where + D: serde::Deserializer<'de>, +{ + let mut map = HashMap::new(); + let mut temp_map: HashMap = HashMap::deserialize(deserializer)?; + + let mut i = 1; + while let (Some(name), Some(value)) = ( + temp_map.remove(&format!("headerName{}", i)), + temp_map.remove(&format!("headerValue{}", i)), + ) { + map.insert(name, value); + i += 1; + } + + Ok(map) +} const PRAGMA: &str = "pragma circom 2.1.9;\n\n"; -fn request_locker_circuit( +fn locker_circuit( data: HttpData, output_filename: String, ) -> Result<(), Box> { @@ -41,8 +76,18 @@ fn request_locker_circuit( // template LockHTTP(DATA_BYTES, beginningLen, middleLen, finalLen, headerNameLen1, headerValueLen1, ...) { { - circuit_buffer += "template LockHTTP(DATA_BYTES, beginningLen, middleLen, finalLen "; - for (i, _header) in data.request.headers.iter().enumerate() { + match data { + HttpData::Request(_) => { + circuit_buffer += + "template LockHTTPRequest(DATA_BYTES, methodLen, targetLen, versionLen"; + } + HttpData::Response(_) => { + circuit_buffer += + "template LockHTTPResponse(DATA_BYTES, versionLen, statusLen, messageLen"; + } + } + + for (i, _header) in data.headers().iter().enumerate() { circuit_buffer += &format!(", headerNameLen{}, headerValueLen{}", i + 1, i + 1); } circuit_buffer += ") {"; @@ -66,7 +111,7 @@ fn request_locker_circuit( // Header signals "#; - for (i, _header) in data.request.headers.iter().enumerate() { + for (i, _header) in data.headers().iter().enumerate() { circuit_buffer += &format!( " signal input header{}[headerNameLen{}];\n", i + 1, @@ -114,7 +159,7 @@ fn request_locker_circuit( // Create header match signals { - for (i, _header) in data.request.headers.iter().enumerate() { + for (i, _header) in data.headers().iter().enumerate() { circuit_buffer += &format!(" signal headerNameValueMatch{}[DATA_BYTES];\n", i + 1); circuit_buffer += &format!(" headerNameValueMatch{}[0] <== 0;\n", i + 1); circuit_buffer += &format!(" var hasMatchedHeaderValue{} = 0;\n\n", i + 1); @@ -156,7 +201,7 @@ fn request_locker_circuit( // Header matches { - for (i, _header) in data.request.headers.iter().enumerate() { + for (i, _header) in data.headers().iter().enumerate() { circuit_buffer += &format!(" headerNameValueMatch{}[data_idx] <== HeaderFieldNameValueMatch(DATA_BYTES, headerNameLen{}, headerValueLen{})(data, header{}, value{}, 100, data_idx);\n", i + 1,i + 1,i + 1,i + 1,i + 1); circuit_buffer += &format!( " hasMatchedHeaderValue{} += headerNameValueMatch{}[data_idx];\n", @@ -215,7 +260,7 @@ fn request_locker_circuit( // Verify all headers have matched { - for (i, _header) in data.request.headers.iter().enumerate() { + for (i, _header) in data.headers().iter().enumerate() { circuit_buffer += &format!(" hasMatchedHeaderValue{} === 1;\n", i + 1); } } @@ -242,9 +287,10 @@ fn request_locker_circuit( // TODO: This needs to codegen a circuit now. pub fn http_lock(args: HttpLockArgs) -> Result<(), Box> { let data = std::fs::read(&args.lockfile)?; + let http_data: HttpData = serde_json::from_slice(&data)?; - request_locker_circuit(http_data, args.output_filename)?; + locker_circuit(http_data, args.output_filename)?; Ok(()) }