### 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()); ```