Skip to content

Commit

Permalink
docs: add docs for packages
Browse files Browse the repository at this point in the history
  • Loading branch information
nathanosdev committed Jan 31, 2023
1 parent 8e3059d commit c8c69b7
Show file tree
Hide file tree
Showing 15 changed files with 187 additions and 4 deletions.
62 changes: 62 additions & 0 deletions packages/ic-response-verification-wasm/README.md
Original file line number Diff line number Diff line change
@@ -1 +1,63 @@
# Response Verification

Response verification on the [Internet Computer](https://dfinity.org) is the process of
verifying that a canister response from a replica has gone through consensus with other replicas
hosting the same canister.

This package encapsulates the protocol for such verification. It is used by the
[Service Worker](https://github.com/dfinity/ic/tree/master/typescript/service-worker) and
[ICX Proxy](https://github.com/dfinity/ic/tree/master/rs/boundary_node/icx_proxy) and may be
used by other implementations of the
[HTTP Gateway Protocol](https://internetcomputer.org/docs/current/references/ic-interface-spec/#http-gateway)
in the future. These implementations can also be reviewed to see working integrations.

## Usage

```javascript
import initResponseVerification, {
verifyRequestResponsePair,
ResponseVerificationError,
ResponseVerificationErrorCode,
} from "@dfinity/response-verification";

// this is necessary for web, but not for NodeJS consumers
await initResponseVerification();

try {
const result = verifyRequestResponsePair(
request,
response,
canister_id,
current_time_ns,
max_cert_time_offset_ns,
fromHex(IC_ROOT_KEY)
);

// do something with the result
// `result.passed` will be true if verification succeeds, false otherwise, and
// `result.response` will contain the certified response object if verification was successful.
} catch (error) {
if (error instanceof ResponseVerificationError) {
switch (error.code) {
case ResponseVerificationErrorCode.MalformedCbor:
// the cbor returned from the replica was malformed.
// ...
break;

case ResponseVerificationErrorCode.MalformedCertificate:
// the certificate returned from the replica was malformed.
// ...
break;

// Other error cases...
}
}
}
```

See the following for working examples:
- [Web](https://github.com/dfinity/response-verification/tree/main/examples/web)
- [Service Worker](https://github.com/dfinity/response-verification/tree/main/examples/service-worker)
- [NodeJS](https://github.com/dfinity/response-verification/tree/main/examples/nodejs)

Note that when bundling for a service worker with Webpack. The `target` property must be set to `webworker`.
6 changes: 6 additions & 0 deletions packages/ic-response-verification/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,9 @@ Format rust files.
```shell
cargo fmt -p ic-response-verification
```

## Build docs

```shell
cargo doc -p ic-response-verification --no-deps --open
```
3 changes: 3 additions & 0 deletions packages/ic-response-verification/src/cel.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
//! Utilities for parsing CEL expressions into Rust consumable types.
mod error;
pub use error::*;

Expand All @@ -9,6 +11,7 @@ use crate::cel::error::CelParserResult;
use crate::cel::parser::parse_cel_expression;
use crate::types::Certification;

/// Parses a CEL expression string into a [Certification] object.
pub fn cel_to_certification(cel: &str) -> CelParserResult<Option<Certification>> {
parse_cel_expression(cel).and_then(map_cel_ast)
}
31 changes: 31 additions & 0 deletions packages/ic-response-verification/src/cel/error.rs
Original file line number Diff line number Diff line change
@@ -1,65 +1,96 @@
pub type CelParserResult<T = ()> = Result<T, CelParserError>;

/// CEL expression parsing error.
#[derive(thiserror::Error, Debug)]
pub enum CelParserError {
/// The CEL parser encountered an unsupported CEL function.
#[error(r#""{0}" is not a supported CEL function, only default_certification is currently supported"#)]
UnrecognizedFunction(String),

/// The CEL parser expected a parameter at a position, but none was found.
#[error(r#"Parameter at position {parameter_position:?} for function {function_name:?} is missing, expected {parameter_name:?} with type {parameter_type:?}"#)]
MissingFunctionParameter {
/// The name of the function with a missing parameter.
function_name: String,
/// The expected type of the missing parameter.
parameter_type: String,
/// The expected name of the missing parameter.
parameter_name: String,
/// The expected position of the missing parameter.
parameter_position: u8,
},

/// The CEL parser expected a parameter to have a different type than the one it found.
#[error(r#"Parameter at position {parameter_position:?} for function {function_name:?} has the wrong type, expected {parameter_name:?} {expected_parameter_type:?} found {found_parameter_type:?}"#)]
IncorrectFunctionParameterType {
/// The name of the function with an unexpected parameter type.
function_name: String,
/// The name of the parameter with the unexpected type.
parameter_name: String,
/// The expected type of the parameter.
expected_parameter_type: String,
/// The actual type of the parameter.
found_parameter_type: String,
/// The position of the parameter.
parameter_position: u8,
},

/// The CEL parser expected a node to have a different type than the one it found.
#[error(r#"Expected node with name {node_name:?} to have type {expected_type:?}, found {found_type:?}"#)]
UnexpectedNodeType {
/// The name of the node with an unexpected type.
node_name: String,
/// The expected type of the node.
expected_type: String,
/// The actual type of the node.
found_type: String,
},

/// The CEL parser expected a node to have a different name than the one it found.
#[error(r#"Expected node with type {node_type:?} to have name {expected_name:?}, found {found_name:?}"#)]
UnexpectedNodeName {
/// The type of the node with an unexpected name.
node_type: String,
/// The expected name of the node.
expected_name: String,
/// The actual name of hte node.
found_name: String,
},

/// The CEL parser expected an object to have a property with a particular name, but none was found.
#[error(r#"Expected object {object_name:?} to have property {expected_property_name:?}"#)]
MissingObjectProperty {
/// The name of the object with a missing property.
object_name: String,
/// The expected property name.
expected_property_name: String,
},

/// The CEL parser encountered an extraneous property on the request certification's CEL object.
#[error(r#"The request_certification object must only specify one of the no_request_certification or request_certification properties, not both"#)]
ExtraneousRequestCertificationProperty,

/// The CEL parser expected to find a property on the request certification's CEL object, but none was found.
#[error(r#"The request_certification object must specify at least one of the no_request_certification or request_certification properties"#)]
MissingRequestCertificationProperty,

/// The CEL parser encountered an extraneous property on the response certification's CEL object.
#[error(r#"The response_certification object must only specify one of the certified_response_headers or response_header_exclusions properties, not both"#)]
ExtraneousResponseCertificationProperty,

/// The CEL parser expected to find a property on the response certification's CEL object, but none was found.
#[error(r#"The response_certification object must specify at least one of the certified_response_headers or response_header_exclusions properties"#)]
MissingResponseCertificationProperty,

/// The CEL parser encountered an extraneous property on the certification's CEL object.
#[error(r#"The ValidationArgs parameter must only specify one of the no_certification or certification properties, not both"#)]
ExtraneousValidationArgsProperty,

/// The CEL parser expected to find a property on the certification's CEL object, but none was found.
#[error(r#"The ValidationArgs parameter must specify at least one of the no_certification or certification properties"#)]
MissingValidationArgsProperty,

/// The CEL parser encountered a syntax error while parsing the CEL expression. Using the "debug" feature flag can help to debug these syntax errors.
#[error(r#"Cel Syntax Expception: {0}"#)]
CelSyntaxException(String),
}
4 changes: 4 additions & 0 deletions packages/ic-response-verification/src/hash.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
//! Utilities for calculating
//! [Representation Independent Hashes](https://internetcomputer.org/docs/current/references/ic-interface-spec/#hash-of-map)
//! of [crate::Request] and [crate::Response] objects.
mod hash;
pub(crate) use hash::*;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,12 @@ use crate::hash::hash;
use ic_certification::hash_tree::Sha256Digest;
use sha2::{Digest, Sha256};

/// Represents a value to be hashed. Only UTF-8 strings and numbers are currently supported.
#[derive(Debug)]
pub enum Value {
/// An UTF-8 string to be hashed.
String(String),
/// A number to be hashed.
Number(u64),
}

Expand Down
4 changes: 4 additions & 0 deletions packages/ic-response-verification/src/hash/request_hash.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ use crate::hash::representation_independent_hash::{representation_independent_ha
use crate::types::{Request, RequestCertification};
use ic_certification::hash_tree::Sha256Digest;

/// Calculates the
/// [Representation Independent Hash](https://internetcomputer.org/docs/current/references/ic-interface-spec/#hash-of-map)
/// of [crate::types::Request] according to [crate::types::RequestCertification] returned from
/// [crate::cel::cel_to_certification].
pub fn request_hash(
request: &Request,
request_certification: &RequestCertification,
Expand Down
15 changes: 14 additions & 1 deletion packages/ic-response-verification/src/hash/response_hash.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,19 @@ const CERTIFICATE_HEADER_NAME: &str = "IC-Certificate";
const CERTIFICATE_EXPRESSION_HEADER_NAME: &str = "IC-Certificate-Expression";
const RESPONSE_STATUS_PSEUDO_HEADER_NAME: &str = ":ic-cert-status";

/// Representation of response headers filtered by [filter_response_headers].
#[derive(Debug)]
pub struct ResponseHeaders {
/// Filtered headers
pub headers: Vec<(String, String)>,
/// IC-Certificate header
pub certificate: Option<String>,
/// IC-Certificate-Expression header
pub certificate_expression: Option<String>,
}

/// Filters headers of [crate::types::Response] according to [crate::types::ResponseCertification]
/// returned from [crate::cel::cel_to_certification].
pub fn filter_response_headers(
response: &Response,
response_certification: &ResponseCertification,
Expand Down Expand Up @@ -74,6 +81,9 @@ pub fn filter_response_headers(
response_headers
}

/// Calculates the
/// [Representation Independent Hash](https://internetcomputer.org/docs/current/references/ic-interface-spec/#hash-of-map)
/// of [ResponseHeaders] that have been filtered with [filter_response_headers].
pub fn response_headers_hash(
status_code: &u64,
response_headers: &ResponseHeaders,
Expand Down Expand Up @@ -103,7 +113,10 @@ pub fn response_headers_hash(

representation_independent_hash(&headers_to_verify)
}

/// Calculates the
/// [Representation Independent Hash](https://internetcomputer.org/docs/current/references/ic-interface-spec/#hash-of-map)
/// of a [crate::types::Response] according to [crate::types::ResponseCertification] returned from
/// [crate::cel::cel_to_certification].
pub fn response_hash(
response: &Response,
response_certification: &ResponseCertification,
Expand Down
24 changes: 24 additions & 0 deletions packages/ic-response-verification/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,23 @@
//! # Response Verification
//!
//! Response verification on the [Internet Computer](https://dfinity.org) is the process of
//! verifying that a canister response from a replica has gone through consensus with other replicas
//! hosting the same canister.
//!
//! This package encapsulates the protocol for such verification. It is used by the
//! [Service Worker](https://github.com/dfinity/ic/tree/master/typescript/service-worker) and
//! [ICX Proxy](https://github.com/dfinity/ic/tree/master/rs/boundary_node/icx_proxy) and may be
//! used by other implementations of the
//! [HTTP Gateway Protocol](https://internetcomputer.org/docs/current/references/ic-interface-spec/#http-gateway)
//! in the future.
#![deny(
missing_docs,
missing_debug_implementations,
rustdoc::broken_intra_doc_links,
rustdoc::private_intra_doc_links
)]

#[cfg(target_arch = "wasm32")]
use wasm_bindgen::prelude::*;

Expand Down Expand Up @@ -37,7 +57,9 @@ mod logger;
mod test_utils;
mod validation;

/// The minimum verification version supported by this package.
pub const MIN_VERIFICATION_VERSION: u8 = 1;
/// The maximum verification version supported by this package.
pub const MAX_VERIFICATION_VERSION: u8 = 2;

#[cfg(target_arch = "wasm32")]
Expand Down Expand Up @@ -86,6 +108,8 @@ pub fn verify_request_response_pair(
#[cfg(not(target_arch = "wasm32"))]
pub use verify_request_response_pair_impl as verify_request_response_pair;

/// The primary entry point for verifying a request and response pair. This will verify the response
/// with respect to the request, according the [Response Verification Spec]().
pub fn verify_request_response_pair_impl(
request: Request,
response: Response,
Expand Down
4 changes: 4 additions & 0 deletions packages/ic-response-verification/src/logger.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ macro_rules! error {
)
}

/// Logs a message to the console
#[macro_export]
#[cfg(not(target_arch = "wasm32"))]
macro_rules! log {
Expand All @@ -61,6 +62,7 @@ macro_rules! log {
}};
}

/// Logs a warning to the console
#[macro_export]
#[cfg(not(target_arch = "wasm32"))]
macro_rules! warn {
Expand All @@ -69,6 +71,7 @@ macro_rules! warn {
}};
}

/// Logs a trace to the console
#[macro_export]
#[cfg(not(target_arch = "wasm32"))]
macro_rules! trace {
Expand All @@ -77,6 +80,7 @@ macro_rules! trace {
}};
}

/// Logs an error to the console
#[macro_export]
#[cfg(not(target_arch = "wasm32"))]
macro_rules! error {
Expand Down
6 changes: 6 additions & 0 deletions packages/ic-response-verification/src/types.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
//! Public types used for response verification.
/// Types to represent parsed CEL expressions.
pub mod certification;
pub use certification::*;

/// Types to represent response objects used for certification.
pub mod request;
pub use request::*;

/// Types to represent request objects used for certification.
pub mod response;
pub use response::*;

/// Types to represent the result of verifying a request/response pair's certification.
pub mod certification_result;
pub use certification_result::*;
11 changes: 11 additions & 0 deletions packages/ic-response-verification/src/types/certification.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,28 @@
/// Parsed request certification CEL expression parameters.
#[derive(Debug, Eq, PartialEq)]
pub struct RequestCertification {
/// Request headers to include in certification.
pub certified_request_headers: Vec<String>,
/// Request query parameters to include in certification.
pub certified_query_parameters: Vec<String>,
}

/// Parsed response certification CEL expression parameters. Can either include headers using
/// [ResponseCertification::CertifiedHeaders] or exclude them using
/// [ResponseCertification::HeaderExclusions].
#[derive(Debug, Eq, PartialEq)]
pub enum ResponseCertification {
/// Response headers to exclude from certification.
HeaderExclusions(Vec<String>),
/// Response headers to include in certification.
CertifiedHeaders(Vec<String>),
}

/// Parsed request/response pair certification CEL expression.
#[derive(Debug, Eq, PartialEq)]
pub struct Certification {
/// Optional rust representation of the request certification CEL expression parameters.
pub request_certification: Option<RequestCertification>,
/// Rust representation of the response certification CEL expression parameters.
pub response_certification: ResponseCertification,
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,14 @@ interface CertificationResult {
}
"#;

/// Result of verifying the provided request/response pair's certification.
#[derive(Debug, Eq, PartialEq)]
pub struct CertificationResult {
/// True if verification was successful, false otherwise.
pub passed: bool,
/// Response object including the status code, body and headers that were included in the
/// certification and passed verification. If verification failed then this object will be
/// empty.
pub response: Option<Response>,
}

Expand Down
Loading

0 comments on commit c8c69b7

Please sign in to comment.