### Navigate to Certified Counter Project
Source: https://github.com/dfinity/response-verification/blob/main/examples/certification/certified-counter/README.md
Change the current directory to the certified-counter example project.
```shell
cd examples/certification/certified-counter
```
--------------------------------
### Example AssetEncoding Configuration
Source: https://github.com/dfinity/response-verification/blob/main/packages/ic-asset-certification/README.md
Demonstrates how to configure Brotli and Gzip encodings with default file extensions for asset certification.
```rust
vec![AssetEncoding::Brotli.default(), AssetEncoding::Gzip.default()]
```
--------------------------------
### Start Local dfx Environment
Source: https://github.com/dfinity/response-verification/blob/main/examples/http-certification/upgrade-to-update-call/README.md
Starts a local dfx development environment in the background and cleans previous states. This is a prerequisite for deploying and testing canisters.
```shell
dfx start --background --clean
```
--------------------------------
### Example Custom AssetEncoding Configuration
Source: https://github.com/dfinity/response-verification/blob/main/packages/ic-asset-certification/README.md
Shows how to configure Brotli and Gzip encodings with custom file extensions for asset certification.
```rust
vec![AssetEncoding::Brotli.custom("brotli"), AssetEncoding::Gzip.custom("gzip")]
```
--------------------------------
### Install correct NodeJS version
Source: https://github.com/dfinity/response-verification/blob/main/README.md
Installs the version of Node.js specified in the project's NVM configuration. Ensure NVM is installed first.
```shell
nvm install
```
--------------------------------
### Deploy the http_certification_json_api_backend canister
Source: https://github.com/dfinity/response-verification/blob/main/examples/http-certification/json-api/README.md
Deploys the specified canister to the local dfx environment. This command should be run after starting the development environment.
```shell
dfx deploy http_certification_json_api_backend
```
--------------------------------
### Start DFX Background Service
Source: https://github.com/dfinity/response-verification/blob/main/examples/certification/certified-counter/README.md
Starts the DFX (DFINITY Canister SDK) local development server in the background.
```shell
dfx start --background
```
--------------------------------
### Certifying Assets Example
Source: https://github.com/dfinity/response-verification/blob/main/packages/ic-asset-certification/README.md
This snippet demonstrates how to set up and certify various assets with different configurations, including content types, headers, fallbacks, aliases, and encodings. This is a prerequisite for demonstrating deletion.
```rust
use ic_http_certification::StatusCode;
use ic_asset_certification::{Asset, AssetConfig, AssetFallbackConfig, AssetRouter, AssetRedirectKind, AssetEncoding};
let mut asset_router = AssetRouter::default();
let assets = vec![
Asset::new(
"index.html",
b"
Hello World!
".as_slice(),
),
Asset::new(
"index.html.gz",
&[0, 1, 2, 3, 4, 5]
),
Asset::new(
"index.html.br",
&[6, 7, 8, 9, 10, 11]
),
Asset::new(
"app.js",
b"console.log('Hello World!');".as_slice(),
),
Asset::new(
"app.js.gz",
&[12, 13, 14, 15, 16, 17],
),
Asset::new(
"app.js.br",
&[18, 19, 20, 21, 22, 23],
),
Asset::new(
"css/app-ba74b708.css",
b"html,body{min-height:100vh;}".as_slice(),
),
Asset::new(
"css/app-ba74b708.css.gz",
&[24, 25, 26, 27, 28, 29],
),
Asset::new(
"css/app-ba74b708.css.br",
&[30, 31, 32, 33, 34, 35],
),
];
let asset_configs = vec![
AssetConfig::File {
path: "index.html".to_string(),
content_type: Some("text/html".to_string()),
headers: vec![(
"cache-control".to_string(),
"public, no-cache, no-store".to_string(),
)],
fallback_for: vec![AssetFallbackConfig {
scope: "/".to_string(),
status_code: Some(StatusCode::OK),
}],
aliased_by: vec!["/".to_string()],
encodings: vec![
AssetEncoding::Brotli.default_config(),
AssetEncoding::Gzip.default_config(),
],
},
AssetConfig::Pattern {
pattern: "**/*.js".to_string(),
content_type: Some("text/javascript".to_string()),
headers: vec![(
"cache-control".to_string(),
"public, max-age=31536000, immutable".to_string(),
)],
encodings: vec![
AssetEncoding::Brotli.default_config(),
AssetEncoding::Gzip.default_config(),
],
},
AssetConfig::Pattern {
pattern: "**/*.css".to_string(),
content_type: Some("text/css".to_string()),
headers: vec![(
"cache-control".to_string(),
"public, max-age=31536000, immutable".to_string(),
)],
encodings: vec![
AssetEncoding::Brotli.default_config(),
AssetEncoding::Gzip.default_config(),
],
},
AssetConfig::Redirect {
from: "/old".to_string(),
to: "/new".to_string(),
kind: AssetRedirectKind::Permanent,
headers: vec![("content-type".to_string(), "text/plain".to_string())],
},
];
asset_router.certify_assets(assets, asset_configs).unwrap();
```
--------------------------------
### Full Certification Example
Source: https://github.com/dfinity/response-verification/blob/main/packages/ic-http-certification/README.md
Perform a full certification by including both HttpRequest and HttpResponse. Configure which request headers, query parameters, and response headers are certified using the DefaultCelBuilder.
```rust
use ic_http_certification::{HttpCertification, HttpRequest, HttpResponse, DefaultCelBuilder, DefaultResponseCertification};
let cel_expr = DefaultCelBuilder::full_certification()
.with_request_headers(vec!["Accept", "Accept-Encoding", "If-None-Match"])
.with_request_query_parameters(vec!["foo", "bar", "baz"])
.with_response_certification(DefaultResponseCertification::certified_response_headers(vec![
"Cache-Control",
"ETag",
]))
.build();
let request = HttpRequest {
method: "GET".to_string(),
url: "/index.html?foo=a&bar=b&baz=c".to_string(),
headers: vec![
("Accept".to_string(), "application/json".to_string()),
("Accept-Encoding".to_string(), "gzip".to_string()),
("If-None-Match".to_string(), "987654321".to_string()),
],
body: vec![],
};
let response = HttpResponse {
status_code: 200,
headers: vec![
("Cache-Control".to_string(), "no-cache".to_string()),
("ETag".to_string(), "123456789".to_string()),
("IC-CertificateExpression".to_string(), cel_expr.to_string()),
],
body: vec![1, 2, 3, 4, 5, 6],
upgrade: None,
};
let certification = HttpCertification::full(&cel_expr, &request, &response, None);
```
--------------------------------
### Certify List Todos Response
Source: https://github.com/dfinity/response-verification/blob/main/examples/http-certification/json-api/README.md
Example function demonstrating how to create and certify a response for listing to-do items.
```rust
fn certify_list_todos_response() {
let request = HttpRequest::get(TODOS_PATH).build();
let body = TODO_ITEMS.with_borrow(|items| {
ListTodosResponse::ok(
&items
.iter()
.map(|(_id, item)| item.clone())
.collect::>(),
)
.encode()
});
let mut response = create_response(StatusCode::OK, body);
certify_response(request, &mut response, &TODOS_TREE_PATH);
}
```
--------------------------------
### Deploy Canister
Source: https://github.com/dfinity/response-verification/blob/main/examples/http-certification/custom-assets/README.md
Deploys the http_certification_custom_assets_backend canister to the local DFX environment. Ensure the environment is started before running this command.
```shell
dfx deploy http_certification_custom_assets_backend
```
--------------------------------
### Install pnpm Dependencies
Source: https://github.com/dfinity/response-verification/blob/main/examples/certification/certified-counter/README.md
Installs project dependencies using the pnpm package manager.
```shell
pnpm i
```
--------------------------------
### Rust Example: Creating and Verifying a Canister Certificate
Source: https://github.com/dfinity/response-verification/blob/main/packages/ic-certification-testing/README.md
Demonstrates how to use CertificateBuilder to create a certificate for given canister ID and certified data, then verifies it using ic-certificate-verification. Ensure necessary libraries are imported.
```rust
use ic_certification_testing::{CertificateBuilder, CertificateData};
use ic_cbor::CertificateToCbor;
use ic_certificate_verification::VerifyCertificate;
use ic_certification::{Certificate, AsHashTree, RbTree};
use ic_types::CanisterId;
use sha2::{Digest, Sha256};
use std::time::{SystemTime, UNIX_EPOCH};
type Hash = [u8; 32];
fn hash(data: T) -> Hash
where
T: AsRef<[u8]>,
{
let mut hasher = Sha256::new();
hasher.update(data);
hasher.finalize().into()
}
fn get_timestamp() -> u128 {
SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_nanos()
}
fn usage_example() {
let canister_id = CanisterId::from_u64(42);
let mut rb_tree = RbTree::<&'static str, Hash>::new();
let data_key = "key1";
let data_hash = hash("value1");
rb_tree.insert(data_key, data_hash);
let certified_data = rb_tree.root_hash();
let current_timestamp = get_timestamp();
let mut certificate_builder =
CertificateBuilder::new(&canister_id.get().0.to_text(), &certified_data)
.expect("Failed to parse canister id");
let CertificateData {
cbor_encoded_certificate,
root_key,
certificate: _,
} = certificate_builder
.with_time(current_timestamp)
.build()
.expect("Invalid certificate params provided");
let certificate = Certificate::from_cbor(&cbor_encoded_certificate)
.expect("Failed to deserialize certificate");
certificate
.verify(&canister_id.get().to_vec(), &root_key)
.expect("Failed to verify certificate");
}
```
--------------------------------
### Initialize and Post-Upgrade Canister Logic
Source: https://github.com/dfinity/response-verification/blob/main/examples/http-certification/json-api/README.md
This code initializes the canister by certifying static responses and preparing query and update handlers. It runs on both initial installation and upgrades.
```rust
#[init]
fn init() {
// certify all static responses
certify_list_todos_response();
certify_not_allowed_todo_responses();
certify_not_found_response();
// prepare query and update handlers
prepare_query_handlers();
prepare_update_handlers();
}
// run every time a canister is upgraded
#[post_upgrade]
fn post_upgrade() {
// run the same initialization logic
init();
}
```
--------------------------------
### Prepare Query Route Handlers
Source: https://github.com/dfinity/response-verification/blob/main/examples/http-certification/json-api/README.md
Sets up route handlers for query calls. It maps HTTP methods and paths to specific handlers, including a catch-all for GET requests and a handler for methods that modify state.
```rust
fn prepare_query_handlers() {
insert_query_route("POST", "/todos", upgrade_to_update_call_handler);
insert_query_route("PATCH", "/todos/{id}", upgrade_to_update_call_handler);
insert_query_route("DELETE", "/todos/{id}", upgrade_to_update_call_handler);
insert_query_route("GET", "/{*p}", query_handler);
["HEAD", "PUT", "OPTIONS", "TRACE", "CONNECT"]
.iter()
.for_each(|method| {
insert_query_route(method, "/{*p}", query_handler);
});
}
```
--------------------------------
### Enable and install PNPM via Corepack
Source: https://github.com/dfinity/response-verification/blob/main/README.md
Enables and installs the PNPM package manager using Corepack. This ensures PNPM is available for managing project dependencies.
```shell
corepack enable
```
--------------------------------
### Deploy Rust Canister
Source: https://github.com/dfinity/response-verification/blob/main/examples/http-certification/upgrade-to-update-call/README.md
Deploys the Rust backend canister for the HTTP certification upgrade to update call example. Ensure the local dfx environment is running.
```shell
dfx deploy http_certification_upgrade_to_update_call_rust_backend
```
--------------------------------
### Response-Only Certification Example
Source: https://github.com/dfinity/response-verification/blob/main/packages/ic-http-certification/README.md
Perform a response-only certification by including only the HttpResponse. Configure which response headers are certified using the DefaultCelBuilder.
```rust
use ic_http_certification::{HttpCertification, HttpResponse, DefaultCelBuilder, DefaultResponseCertification};
let cel_expr = DefaultCelBuilder::response_only_certification()
.with_response_certification(DefaultResponseCertification::certified_response_headers(vec![
"Cache-Control",
"ETag",
]))
.build();
let response = HttpResponse {
status_code: 200,
headers: vec![
("Cache-Control".to_string(), "no-cache".to_string()),
("ETag".to_string(), "123456789".to_string()),
("IC-CertificateExpression".to_string(), cel_expr.to_string()),
],
body: vec![1, 2, 3, 4, 5, 6],
upgrade: None,
};
let certification = HttpCertification::response_only(&cel_expr, &response, None).unwrap();
```
--------------------------------
### Deploy Motoko Canister
Source: https://github.com/dfinity/response-verification/blob/main/examples/http-certification/upgrade-to-update-call/README.md
Deploys the Motoko backend canister for the HTTP certification upgrade to update call example. This command assumes the local dfx environment is active.
```shell
dfx deploy http_certification_upgrade_to_update_call_motoko_backend
```
--------------------------------
### Access Canister Assets with Curl
Source: https://github.com/dfinity/response-verification/blob/main/examples/http-certification/assets/README.md
Example using curl to make a request to the canister's assets, including resolving the localhost address.
```shell
curl "http://$(dfx canister id http_certification_assets_backend).localhost:$(dfx info webserver-port)" --resolve "$(dfx canister id http_certification_assets_backend).localhost:$(dfx info webserver-port):127.0.0.1"
```
--------------------------------
### Get Canister URL
Source: https://github.com/dfinity/response-verification/blob/main/examples/http-certification/assets/README.md
Command to retrieve the local URL for accessing the deployed canister's assets.
```shell
echo "http://$(dfx canister id http_certification_assets_backend).localhost:$(dfx info webserver-port)"
```
--------------------------------
### Fetch to-do items from the canister
Source: https://github.com/dfinity/response-verification/blob/main/examples/http-certification/json-api/README.md
Fetches all to-do items from the canister using a GET request. It resolves the canister's localhost address and pipes the output to jq for pretty-printing.
```shell
curl -s \
"http://$(dfx canister id http_certification_json_api_backend).localhost:$(dfx info webserver-port)/todos" \
--resolve "$(dfx canister id http_certification_json_api_backend).localhost:$(dfx info webserver-port):127.0.0.1" | jq
```
--------------------------------
### Certify Not Allowed Todo Responses
Source: https://github.com/dfinity/response-verification/blob/main/examples/http-certification/json-api/README.md
Example function demonstrating how to certify responses for disallowed HTTP methods on the to-do path.
```rust
fn certify_not_allowed_todo_responses() {
[
Method::HEAD,
Method::PUT,
Method::PATCH,
Method::OPTIONS,
Method::TRACE,
Method::CONNECT,
]
.into_iter()
.for_each(|method| {
let request = HttpRequest::builder()
.with_method(method)
.with_url(TODOS_PATH)
.build();
```
--------------------------------
### Get Default Security Headers
Source: https://github.com/dfinity/response-verification/blob/main/examples/http-certification/assets/README.md
Generates a default set of security headers based on OWASP recommendations, allowing for additional custom headers to be included.
```rust
fn get_asset_headers(additional_headers: Vec) -> Vec {
// set up the default headers and include additional headers provided by the caller
let mut headers = vec![
("strict-transport-security".to_string(), "max-age=31536000; includeSubDomains".to_string()),
("x-frame-options".to_string(), "DENY".to_string()),
("x-content-type-options".to_string(), "nosniff".to_string()),
("content-security-policy".to_string(), "default-src 'self'; img-src 'self' data:; form-action 'self'; object-src 'none'; frame-ancestors 'none'; upgrade-insecure-requests; block-all-mixed-content".to_string()),
("referrer-policy".to_string(), "no-referrer".to_string()),
("permissions-policy".to_string(), "accelerometer=(),ambient-light-sensor=(),autoplay=(),battery=(),camera=(),display-capture=(),document-domain=(),encrypted-media=(),fullscreen=(),gamepad=(),geolocation=(),gyroscope=(),layout-animations=(self),legacy-image-formats=(self),magnetometer=(),microphone=(),midi=(),oversized-images=(self),payment=(),picture-in-picture=(),publickey-credentials-get=(),speaker-selection=(),sync-xhr=(self),unoptimized-images=(self),unsized-media=(self),usb=(),screen-wake-lock=(),web-share=(),xr-spatial-tracking=()".to_string()),
("cross-origin-embedder-policy".to_string(), "require-corp".to_string()),
("cross-origin-opener-policy".to_string(), "same-origin".to_string()),
];
headers.extend(additional_headers);
headers
}
```
--------------------------------
### Build and Deploy Canisters
Source: https://github.com/dfinity/response-verification/blob/main/examples/certification/certified-counter/README.md
Builds the project's canisters and deploys them to the local DFX environment.
```shell
dfx deploy
```
--------------------------------
### Serve and Certify Assets
Source: https://github.com/dfinity/response-verification/blob/main/packages/ic-asset-certification/README.md
Demonstrates how to serve an asset by certifying it with the AssetRouter and adding the necessary certificate header to the response. This is useful for serving static files with proper certification.
```rust
use ic_http_certification::{HttpRequest, utils::add_v2_certificate_header, StatusCode};
use ic_asset_certification::{Asset, AssetConfig, AssetFallbackConfig, AssetRouter};
let mut asset_router = AssetRouter::default();
let asset = Asset::new(
"index.html",
b"Hello World!
".as_slice(),
);
let asset_config = AssetConfig::File {
path: "index.html".to_string(),
content_type: Some("text/html".to_string()),
headers: vec![
("Cache-Control".to_string(), "public, no-cache, no-store".to_string()),
],
fallback_for: vec![AssetFallbackConfig {
scope: "/".to_string(),
status_code: Some(StatusCode::OK),
}],
aliased_by: vec!["/".to_string()],
encodings: vec![],
};
let http_request = HttpRequest::get("/").build();
asset_router.certify_assets(vec![asset], vec![asset_config]).unwrap();
let (mut response, witness, expr_path) = asset_router.serve_asset(&http_request).unwrap();
// This should normally be retrieved using `ic_cdk::api::data_certificate()`.
let data_certificate = vec![1, 2, 3];
add_v2_certificate_header(
data_certificate,
&mut response,
&witness,
&expr_path,
);
```
--------------------------------
### Initialize and Use HTTP Certification Tree
Source: https://github.com/dfinity/response-verification/blob/main/packages/ic-http-certification/README.md
Demonstrates initializing an `HttpCertificationTree`, creating an `HttpCertification` for a request/response pair, adding it as an entry, generating a witness, and deleting the entry. This process is essential for verifying HTTP responses.
```rust
use ic_http_certification::{HttpCertification, HttpRequest, HttpResponse, DefaultCelBuilder, DefaultResponseCertification, HttpCertificationTree, HttpCertificationTreeEntry, HttpCertificationPath};
let cel_expr = DefaultCelBuilder::full_certification()
.with_request_headers(vec!["Accept", "Accept-Encoding", "If-None-Match"])
.with_request_query_parameters(vec!["foo", "bar", "baz"])
.with_response_certification(DefaultResponseCertification::certified_response_headers(vec![
"Cache-Control",
"ETag",
]))
.build();
let request = HttpRequest {
method: "GET".to_string(),
url: "/index.html?foo=a&bar=b&baz=c".to_string(),
headers: vec![
("Accept".to_string(), "application/json".to_string()),
("Accept-Encoding".to_string(), "gzip".to_string()),
("If-None-Match".to_string(), "987654321".to_string()),
],
body: vec![],
};
let response = HttpResponse {
status_code: 200,
headers: vec![
("Cache-Control".to_string(), "no-cache".to_string()),
("ETag".to_string(), "123456789".to_string()),
("IC-CertificateExpression".to_string(), cel_expr.to_string()),
],
body: vec![1, 2, 3, 4, 5, 6],
upgrade: None,
};
let request_url = "/example.json";
let path = HttpCertificationPath::exact(request_url);
let certification = HttpCertification::full(&cel_expr, &request, &response, None).unwrap();
let mut http_certification_tree = HttpCertificationTree::default();
let entry = HttpCertificationTreeEntry::new(&path, &certification);
// insert the entry into the tree
http_certification_tree.insert(&entry);
// generate a witness for this entry in the tree
let witness = http_certification_tree.witness(&entry, request_url);
// delete the entry from the tree
http_certification_tree.delete(&entry);
```
--------------------------------
### Build Cargo crate docs: ic-cbor
Source: https://github.com/dfinity/response-verification/blob/main/README.md
Builds documentation for the `ic-cbor` Cargo crate without dependencies and opens it in a browser.
```shell
cargo doc -p ic-cbor --no-deps --open
```
--------------------------------
### Initialize Asset Router and HTTP Tree
Source: https://github.com/dfinity/response-verification/blob/main/examples/http-certification/assets/README.md
Demonstrates the initialization of the AssetRouter with an optional HTTPCertificationTree. If direct access to the tree is not needed, it can be initialized with default values.
```rust
thread_local! {
static HTTP_TREE: Rc> = Default::default();
static ASSET_ROUTER: RefCell> = RefCell::new(AssetRouter::with_tree(HTTP_TREE.with(|tree| tree.clone())));
// initializing the asset router with an HTTP certification tree is optional.
// if direct access to the HTTP certification tree is not needed for certifying
// requests and responses outside of the asset router, then this step can be skipped
// and the asset router can be initialized like so:
static ASSET_ROUTER: RefCell> = Default::default();
}
```
--------------------------------
### Build NPM package: @dfinity/response-verification
Source: https://github.com/dfinity/response-verification/blob/main/README.md
Builds the NPM package for `@dfinity/response-verification`. This command is used to prepare the package for distribution or local use.
```shell
pnpm run -F @dfinity/response-verification build
```
--------------------------------
### Get Asset Headers with Skipped Certification
Source: https://github.com/dfinity/response-verification/blob/main/examples/http-certification/custom-assets/README.md
Retrieves headers for an asset, skipping certification. This is useful for custom assets where validation is not required.
```rust
let headers = get_asset_headers(
additional_headers,
body.len(),
DefaultCelBuilder::skip_certification().to_string(),
);
HttpResponse::ok(body, headers).build()
```
--------------------------------
### Navigate to Repository Root
Source: https://github.com/dfinity/response-verification/blob/main/examples/certification/certified-counter/README.md
Returns to the root directory of the DFINITY repository.
```shell
cd ../../
```
--------------------------------
### CEL Expression for Asset Certification
Source: https://github.com/dfinity/response-verification/blob/main/examples/http-certification/custom-assets/README.md
Defines a CEL expression for certifying all assets, including a fallback response. This is simpler than the JSON API example.
```rust
lazy_static! {
static ref ASSET_CEL_EXPR_DEF: DefaultResponseOnlyCelExpression<'static> =
DefaultCelBuilder::response_only_certification()
.with_response_certification(DefaultResponseCertification::response_header_exclusions(
vec![],
))
.build();
static ref ASSET_CEL_EXPR: String = ASSET_CEL_EXPR_DEF.to_string();
}
```
--------------------------------
### Build @dfinity/certificate-verification Package
Source: https://github.com/dfinity/response-verification/blob/main/examples/certification/certified-counter/README.md
Builds the @dfinity/certificate-verification npm package, likely for local development or testing.
```shell
pnpm run --filter @dfinity/certificate-verification build
```
--------------------------------
### Create Canisters
Source: https://github.com/dfinity/response-verification/blob/main/examples/certification/certified-counter/README.md
Creates the necessary canisters for the project using DFX.
```shell
dfx canister create --all
```
--------------------------------
### Build Cargo crate docs: ic-representation-independent-hash
Source: https://github.com/dfinity/response-verification/blob/main/README.md
Builds documentation for the `ic-representation-independent-hash` Cargo crate without dependencies and opens it in a browser.
```shell
cargo doc -p ic-representation-independent-hash --no-deps --open
```
--------------------------------
### Configure 404 HTML File with Multiple Fallbacks and Aliases
Source: https://github.com/dfinity/response-verification/blob/main/packages/ic-asset-certification/README.md
Configures a '404.html' file to serve as a fallback for '/css' and '/js' scopes with a NOT_FOUND status, and sets multiple aliases for it.
```rust
use ic_http_certification::StatusCode;
use ic_asset_certification::{AssetConfig, AssetFallbackConfig};
let config = AssetConfig::File {
path: "404.html".to_string(),
content_type: Some("text/html".to_string()),
headers: vec![
("Cache-Control".to_string(), "public, no-cache, no-store".to_string()),
],
fallback_for: vec![
AssetFallbackConfig {
scope: "/css".to_string(),
status_code: Some(StatusCode::NOT_FOUND),
},
AssetFallbackConfig {
scope: "/js".to_string(),
status_code: Some(StatusCode::NOT_FOUND),
},
],
aliased_by: vec![
"/404".to_string(),
"/404/".to_string(),
"/404.html".to_string(),
"/not-found".to_string(),
"/not-found/".to_string(),
"/not-found/index.html".to_string(),
],
encodings: vec![
AssetEncoding::Brotli.default(),
AssetEncoding::Gzip.default(),
],
};
```
--------------------------------
### Certify Method Not Allowed Response
Source: https://github.com/dfinity/response-verification/blob/main/examples/http-certification/json-api/README.md
Example of certifying a 'Method Not Allowed' HTTP response. This involves creating the response, adding a body, and then certifying it using a predefined tree path.
```rust
let body = ErrorResponse::not_allowed().encode();
let mut response = create_response(StatusCode::METHOD_NOT_ALLOWED, body);
certify_response(request, &mut response, &TODOS_TREE_PATH);
});
}
```
--------------------------------
### Certifying Assets with Multiple Configurations
Source: https://github.com/dfinity/response-verification/blob/main/packages/ic-asset-certification/README.md
This snippet demonstrates how to initialize an AssetRouter and certify various assets, including HTML, JavaScript, and CSS files, with different encodings (Brotli, Gzip) and caching headers. It also includes a redirect configuration.
```rust
use ic_http_certification::StatusCode;
use ic_asset_certification::{Asset, AssetConfig, AssetFallbackConfig, AssetRouter, AssetRedirectKind, AssetEncoding};
let mut asset_router = AssetRouter::default();
let assets = vec![
Asset::new(
"index.html",
b"Hello World!
".as_slice(),
),
Asset::new(
"index.html.gz",
&[0, 1, 2, 3, 4, 5]
),
Asset::new(
"index.html.br",
&[6, 7, 8, 9, 10, 11]
),
Asset::new(
"app.js",
b"console.log('Hello World!');".as_slice(),
),
Asset::new(
"app.js.gz",
&[12, 13, 14, 15, 16, 17],
),
Asset::new(
"app.js.br",
&[18, 19, 20, 21, 22, 23],
),
Asset::new(
"css/app-ba74b708.css",
b"html,body{min-height:100vh;}".as_slice(),
),
Asset::new(
"css/app-ba74b708.css.gz",
&[24, 25, 26, 27, 28, 29],
),
Asset::new(
"css/app-ba74b708.css.br",
&[30, 31, 32, 33, 34, 35],
),
];
let asset_configs = vec![
AssetConfig::File {
path: "index.html".to_string(),
content_type: Some("text/html".to_string()),
headers: vec![(
"cache-control".to_string(),
"public, no-cache, no-store".to_string(),
)],
fallback_for: vec![AssetFallbackConfig {
scope: "/".to_string(),
status_code: Some(StatusCode::OK),
}],
aliased_by: vec!["/".to_string()],
encodings: vec![
AssetEncoding::Brotli.default_config(),
AssetEncoding::Gzip.default_config(),
],
},
AssetConfig::Pattern {
pattern: "**/*.js".to_string(),
content_type: Some("text/javascript".to_string()),
headers: vec![(
"cache-control".to_string(),
"public, max-age=31536000, immutable".to_string(),
)],
encodings: vec![
AssetEncoding::Brotli.default_config(),
AssetEncoding::Gzip.default_config(),
],
},
AssetConfig::Pattern {
pattern: "**/*.css".to_string(),
content_type: Some("text/css".to_string()),
headers: vec![(
"cache-control".to_string(),
"public, max-age=31536000, immutable".to_string(),
)],
encodings: vec![
AssetEncoding::Brotli.default_config(),
AssetEncoding::Gzip.default_config(),
],
},
AssetConfig::Redirect {
from: "/old".to_string(),
to: "/new".to_string(),
kind: AssetRedirectKind::Permanent,
headers: vec![(
"content-type".to_string(),
"text/plain; charset=utf-8".to_string(),
)],
},
];
asset_router.certify_assets(assets, asset_configs).unwrap();
```
--------------------------------
### Certify Not Found Response
Source: https://github.com/dfinity/response-verification/blob/main/examples/http-certification/json-api/README.md
Example of certifying a 'Not Found' HTTP response. This specific certification uses a wildcard path, a different CEL expression type, and stores the response in fallback storage.
```rust
fn certify_not_found_response() {
let body = ErrorResponse::not_found().encode();
let mut response = create_response(StatusCode::NOT_FOUND, body);
let tree_path = HttpCertificationPath::wildcard(NOT_FOUND_PATH);
// insert the `Ic-CertificationExpression` header with the stringified CEL expression as its value
response.add_header((
CERTIFICATE_EXPRESSION_HEADER_NAME.to_string(),
NOT_FOUND_CEL_EXPR.clone(),
));
// create the certification for this response and CEL expression pair
let certification =
HttpCertification::response_only(&NOT_FOUND_CEL_EXPR_DEF, &response, None).unwrap();
FALLBACK_RESPONSES.with_borrow_mut(|responses| {
responses.insert(
NOT_FOUND_PATH.to_string(),
CertifiedHttpResponse {
response,
certification,
},
);
});
HTTP_TREE.with_borrow_mut(|http_tree| {
// insert the certification into the certification tree
http_tree.insert(&HttpCertificationTreeEntry::new(tree_path, &certification));
// set the canister's certified data
set_certified_data(&http_tree.root_hash());
});
}
```
--------------------------------
### Build Cargo crate docs: ic-response-verification
Source: https://github.com/dfinity/response-verification/blob/main/README.md
Builds documentation for the `ic-response-verification` Cargo crate without dependencies and opens it in a browser. Useful for reviewing API documentation.
```shell
cargo doc -p ic-response-verification --no-deps --open
```
--------------------------------
### Create an Asset with Static Content
Source: https://github.com/dfinity/response-verification/blob/main/packages/ic-asset-certification/README.md
Demonstrates creating an Asset object with a specific name and static byte content. Useful for embedding small, fixed assets.
```rust
use ic_asset_certification::Asset;
let asset = Asset::new(
"index.html",
b"Hello World!
".as_slice(),
);
```
--------------------------------
### Test Rust Canister with curl
Source: https://github.com/dfinity/response-verification/blob/main/examples/http-certification/upgrade-to-update-call/README.md
Makes a GET request to the deployed Rust canister using curl. It retrieves the webserver port and canister ID dynamically. This tests the canister's response to an HTTP request.
```shell
curl -v http://localhost:$(dfx info webserver-port)?canisterId=$(dfx canister id http_certification_upgrade_to_update_call_rust_backend)
```
--------------------------------
### Create an Asset from Included Bytes
Source: https://github.com/dfinity/response-verification/blob/main/packages/ic-asset-certification/README.md
Shows how to create an Asset using `include_bytes!` macro for embedding larger assets directly into the canister at compile time. This avoids runtime duplication.
```rust
use ic_asset_certification::Asset;
let pretty_big_asset = include_bytes!("lib.rs");
let asset = Asset::new(
"assets/pretty-big-asset.gz",
pretty_big_asset.as_slice(),
);
```
--------------------------------
### Define Asset Certification Configurations
Source: https://github.com/dfinity/response-verification/blob/main/examples/http-certification/assets/README.md
Sets up configurations for asset certification, including Brotli and Gzip encodings, and defines specific configurations for index.html and JavaScript files.
```rust
const IMMUTABLE_ASSET_CACHE_CONTROL: &str = "public, max-age=31536000, immutable";
const NO_CACHE_ASSET_CACHE_CONTROL: &str = "public, no-cache, no-store";
fn certify_all_assets() {
// 1. Define the asset certification configurations.
let encodings = vec![
AssetEncoding::Brotli.default(),
AssetEncoding::Gzip.default(),
];
let asset_configs = vec![
AssetConfig::File {
path: "index.html".to_string(),
content_type: Some("text/html".to_string()),
headers: get_asset_headers(vec![(
"cache-control".to_string(),
NO_CACHE_ASSET_CACHE_CONTROL.to_string(),
)]),
fallback_for: vec![AssetFallbackConfig {
scope: "/".to_string(),
status_code: Some(StatusCode::OK),
}],
aliased_by: vec!["/".to_string()],
encodings: encodings.clone(),
},
AssetConfig::Pattern {
pattern: "**/*.js".to_string(),
content_type: Some("text/javascript".to_string()),
headers: get_asset_headers(vec![(
"cache-control".to_string(),
IMMUTABLE_ASSET_CACHE_CONTROL.to_string(),
)]),
encodings: encodings.clone(),
},
AssetConfig::Pattern {
```
--------------------------------
### Print Frontend Web URL
Source: https://github.com/dfinity/response-verification/blob/main/examples/certification/certified-counter/README.md
Prints the local web URL for accessing the frontend of the certified-counter application.
```shell
echo "http://$(dfx canister id certification_certified_counter_frontend).localhost:$(dfx info webserver-port)"
```
--------------------------------
### Create an Asset with Dynamically Generated Content
Source: https://github.com/dfinity/response-verification/blob/main/packages/ic-asset-certification/README.md
Illustrates creating an Asset with content generated dynamically at runtime, such as from string formatting. Use this when assets are not known at compile time or require modification.
```rust
use ic_asset_certification::Asset;
let name = "World";
let asset = Asset::new(
"index.html",
format!("Hello {name}!
").into_bytes(),
);
```
--------------------------------
### Configure Vite for Asset Compression
Source: https://github.com/dfinity/response-verification/blob/main/examples/http-certification/custom-assets/README.md
Sets up Vite to generate Gzip and Brotli encoded assets alongside original files. Ensure the 'ext' configuration matches the canister code.
```typescript
import {
defineConfig
} from 'vite';
import solidPlugin from 'vite-plugin-solid';
// import the compression plugin
import { compression } from 'vite-plugin-compression2';
export default defineConfig({
plugins: [
solidPlugin(),
// setup Gzip compression
compression({
algorithm: 'gzip',
// this extension will be referenced later in the canister code
ext: '.gzip',
// ensure to not delete the original files
deleteOriginalAssets: false,
threshold: 0,
}),
// setup Brotli compression
compression({
algorithm: 'brotliCompress',
// this extension will be referenced later in the canister code
ext: '.br',
// ensure to not delete the original files
deleteOriginalAssets: false,
threshold: 0,
}),
],
server: {
port: 3000,
},
build: {
target: 'esnext',
},
});
```
--------------------------------
### Handle HTTP Requests for Assets and Metrics
Source: https://github.com/dfinity/response-verification/blob/main/examples/http-certification/assets/README.md
Implements the `http_request` query endpoint to serve assets or metrics based on the request path. It delegates to `serve_metrics` or `serve_asset` auxiliary functions.
```rust
#[query]
fn http_request(req: HttpRequest) -> HttpResponse {
let path = req.get_path().expect("Failed to parse request path");
// if the request is for the metrics endpoint, serve the metrics
if path == "/metrics" {
return serve_metrics();
}
// otherwise, serve the requested asset
serve_asset(&req)
}
```
--------------------------------
### Deploy Canister
Source: https://github.com/dfinity/response-verification/blob/main/examples/http-certification/assets/README.md
Command to deploy the http_certification_assets_backend canister to the local development environment.
```shell
dfx deploy http_certification_assets_backend
```
--------------------------------
### Test NPM package: @dfinity/response-verification
Source: https://github.com/dfinity/response-verification/blob/main/README.md
Runs tests for the NPM package `@dfinity/response-verification`. Ensures the package functions as expected in a Node.js environment.
```shell
pnpm run -F @dfinity/response-verification test
```
--------------------------------
### Build and Verify a Canister Certificate
Source: https://github.com/dfinity/response-verification/blob/main/packages/ic-certification-testing-wasm/README.md
Demonstrates how to construct a hash tree, build a certificate using CertificateBuilder, and then verify it using verifyCertification. This is useful for testing canister response integrity in a JavaScript client.
```typescript
import { describe, expect, it } from 'vitest';
import { HashTree, reconstruct, Cbor } from '@dfinity/agent';
import { CertificateBuilder } from '@dfinity/certification-testing';
import { verifyCertification } from '@dfinity/certificate-verification';
import { Principal } from '@dfinity/principal';
import { createHash } from 'node:crypto';
const userId = '1234';
const username = 'testuser';
const usernameHash = new Uint8Array(
createHash('sha256').update(username).digest(),
);
const hashTree: HashTree = [
2,
new Uint8Array(Buffer.from(userId)),
[3, usernameHash],
];
const rootHash = await reconstruct(hashTree);
const cborEncodedTree = Cbor.encode(hashTree);
const canisterId = Principal.fromUint8Array(
new Uint8Array([0, 0, 0, 0, 0, 0, 0, 1]),
);
const time = BigInt(Date.now());
const MAX_CERT_TIME_OFFSET_MS = 300_000;
let certificate = new CertificateBuilder(
canisterId.toString(),
new Uint8Array(rootHash),
)
.withTime(time)
.build();
const decodedHashTree = await verifyCertification({
canisterId,
encodedCertificate: certificate.cborEncodedCertificate,
encodedTree: cborEncodedTree,
maxCertificateTimeOffsetMs: MAX_CERT_TIME_OFFSET_MS,
rootKey: certificate.rootKey,
});
expect(decodedHashTree).toEqual(hashTree);
```
--------------------------------
### Define Asset Request Paths
Source: https://github.com/dfinity/response-verification/blob/main/examples/http-certification/custom-assets/README.md
Understand the different path types used for asset certification: `asset_tree_path` for storing in the tree, `asset_file_path` for the source file on disk, and `asset_req_path` for browser requests.
```rust
// `asset_tree_path`: the `HttpCertificationPath` that will be used to store the asset in the tree, for example, `HttpCertificationPath::exact("/assets/app.js")`.
// `asset_file_path`: the relative file path of the asset on disk before being imported into the canister, for example, `assets/app.js`.
// `asset_req_path`: the absolute path that will be used to request the asset `/assets/app.js` from a browser.
```
--------------------------------
### Configure Single HTML File with Fallback and Alias
Source: https://github.com/dfinity/response-verification/blob/main/packages/ic-asset-certification/README.md
Configures an HTML file to be served at '/index.html', act as a fallback for the '/' scope, and be aliased by '/'.
```rust
use ic_http_certification::StatusCode;
use ic_asset_certification::{AssetConfig, AssetFallbackConfig};
let config = AssetConfig::File {
path: "index.html".to_string(),
content_type: Some("text/html".to_string()),
headers: vec![
("Cache-Control".to_string(), "public, no-cache, no-store".to_string()),
],
fallback_for: vec![AssetFallbackConfig {
scope: "/".to_string(),
status_code: Some(StatusCode::OK),
}],
aliased_by: vec!["/".to_string()],
encodings: vec![
AssetEncoding::Brotli.default(),
AssetEncoding::Gzip.default()
],
};
```
--------------------------------
### Configure Asset Pattern
Source: https://github.com/dfinity/response-verification/blob/main/packages/ic-asset-certification/README.md
Use AssetConfig::Pattern to match files using glob patterns. Specify content type, headers, and encodings for matched assets.
```rust
use ic_http_certification::StatusCode;
use ic_asset_certification::AssetConfig;
let config = AssetConfig::Pattern {
pattern: "js/*.js".to_string(),
content_type: Some("application/javascript".to_string()),
headers: vec![
("Cache-Control".to_string(), "public, max-age=31536000, immutable".to_string()),
],
encodings: vec![
AssetEncoding::Brotli.default(),
AssetEncoding::Gzip.default(),
],
};
```
--------------------------------
### Define Exact HTTP Certification Path
Source: https://github.com/dfinity/response-verification/blob/main/packages/ic-http-certification/README.md
Use `HttpCertificationPath::exact()` to create a path that matches a specific request URL precisely. A trailing slash indicates a directory, while its absence indicates a file.
```rust
use ic_http_certification::HttpCertificationPath;
let path = HttpCertificationPath::exact("/js/example.js");
```
--------------------------------
### Certify Specific Request Headers and Query Parameters
Source: https://github.com/dfinity/response-verification/blob/main/packages/ic-http-certification/README.md
Configure certification to include specific request headers and query parameters along with the response.
```rust
use ic_http_certification::DefaultCelBuilder;
let cel_expr = DefaultCelBuilder::full_certification()
.with_request_headers(vec!["Accept", "Accept-Encoding", "If-None-Match"])
.with_request_query_parameters(vec!["foo", "bar", "baz"])
.build();
```
--------------------------------
### Define Wildcard HTTP Certification Path
Source: https://github.com/dfinity/response-verification/blob/main/packages/ic-http-certification/README.md
Use `HttpCertificationPath::wildcard()` to create a path that matches any URL beginning with the specified prefix. This is useful for fallbacks or matching multiple related resources.
```rust
use ic_http_certification::HttpCertificationPath;
let path = HttpCertificationPath::wildcard("/js");
```
--------------------------------
### Create To-Do Item Handler
Source: https://github.com/dfinity/response-verification/blob/main/examples/http-certification/json-api/README.md
Handles the creation of a new to-do item. It decodes the request body, generates a new ID, inserts the item into storage, re-certifies the list response, and returns a CREATED status.
```rust
fn create_todo_item_handler(req: &HttpRequest, _params: &Params) -> HttpResponse<'static> {
let req_body: CreateTodoItemRequest = json_decode(req.body());
let id = NEXT_TODO_ID.with_borrow_mut(|f| {
let id = *f;
*f += 1;
id
});
let todo_item = TODO_ITEMS.with_borrow_mut(|items| {
let todo_item = TodoItem {
id,
title: req_body.title,
completed: false,
};
items.insert(id, todo_item.clone());
todo_item
});
certify_list_todos_response();
let body = CreateTodoItemResponse::ok(&todo_item).encode();
create_response(StatusCode::CREATED, body)
}
```
--------------------------------
### Configure Permanent Redirect
Source: https://github.com/dfinity/response-verification/blob/main/packages/ic-asset-certification/README.md
Use AssetConfig::Redirect to set up a permanent redirect from one path to another. Includes optional headers.
```rust
use ic_asset_certification::{AssetConfig, AssetRedirectKind};
let config = AssetConfig::Redirect {
from: "/old".to_string(),
to: "/new".to_string(),
kind: AssetRedirectKind::Permanent,
headers: vec![(
"content-type".to_string(),
"text/plain; charset=utf-8".to_string(),
)],
};
```
--------------------------------
### Initialize AssetRouter with HttpCertificationTree
Source: https://github.com/dfinity/response-verification/blob/main/packages/ic-asset-certification/README.md
Initialize the AssetRouter with an existing HttpCertificationTree. This is useful when direct access to the tree is needed for certifying requests and responses outside the AssetRouter's direct flow. Ensure initialization happens before certifying any assets.
```rust
use std::{cell::RefCell, rc::Rc};
use ic_http_certification::HttpCertificationTree;
use ic_asset_certification::AssetRouter;
let mut http_certification_tree: Rc> = Default::default();
let mut asset_router = AssetRouter::default();
asset_router.init_with_tree(http_certification_tree.clone());
```