Skip to content

Commit

Permalink
docs(ic-http-certification): improve naming in example project
Browse files Browse the repository at this point in the history
  • Loading branch information
nathanosdev committed Sep 23, 2024
1 parent cf56e0a commit f402d18
Show file tree
Hide file tree
Showing 7 changed files with 78 additions and 45 deletions.
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,3 @@ node_modules
.DS_Store
/tmp
pkg
Cargo.lock
9 changes: 9 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

42 changes: 21 additions & 21 deletions examples/http-certification/custom-assets/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ The first step is defining a reusable function to create a response with all of
```rust
fn get_asset_headers(
additional_headers: Vec<HeaderField>,
body: &[u8],
content_length: usize,
cel_expr: String,
) -> Vec<(String, String)> {
// set up the default headers and include additional headers provided by the caller
Expand All @@ -157,7 +157,7 @@ fn get_asset_headers(
("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()),
("content-length".to_string(), body.len().to_string()),
("content-length".to_string(), content_length.to_string()),
(CERTIFICATE_EXPRESSION_HEADER_NAME.to_string(), cel_expr),
];
headers.extend(additional_headers);
Expand All @@ -170,7 +170,7 @@ fn create_asset_response(
body: &[u8],
cel_expr: String,
) -> HttpResponse {
let headers = get_asset_headers(additional_headers, body, cel_expr);
let headers = get_asset_headers(additional_headers, body.len(), cel_expr);

HttpResponse::builder()
.with_status_code(200)
Expand Down Expand Up @@ -386,19 +386,19 @@ fn certify_index_asset() {
}
```

It's also possible to skip certification for certain routes. This can be relatively easily as follows:
It's also possible to skip certification for certain routes. This can be useful for scenarios where it's difficult to predict what the response will look like for a certain route and the content is not very security sensitive. This can be done as follows:

```rust
const DYNAMIC_REQ_PATH: &str = "/dynamic";
const UNCERTIFIED_REQ_PATH: &str = "/uncertified";

fn certify_dynamic_asset() {
let dynamic_req_tree_path = HttpCertificationPath::exact(DYNAMIC_REQ_PATH);
let dynamic_req_certification = HttpCertification::skip();
fn add_certification_skips() {
let uncertified_req_tree_path = HttpCertificationPath::exact(UNCERTIFIED_REQ_PATH);
let uncertified_req_certification = HttpCertification::skip();

HTTP_TREE.with_borrow_mut(|http_tree| {
http_tree.insert(&HttpCertificationTreeEntry::new(
dynamic_req_tree_path,
&dynamic_req_certification,
uncertified_req_tree_path,
&uncertified_req_certification,
));
});
}
Expand All @@ -418,7 +418,7 @@ With all of the above functions, it is now possible to certify all of the fronte

```rust
fn certify_all_assets() {
certify_dynamic_asset();
add_certification_skips();

certify_index_asset();
certify_asset_glob("assets/**/*.css", "text/css");
Expand All @@ -434,8 +434,8 @@ fn certify_all_assets() {

With all assets certified, they can be served over HTTP. The steps to follow when serving assets are:

- Check if the request path matches the dynamic path.
- If the requested path exactly matches the dynamic path, serve the dynamic response.
- Check if the request path matches the uncertified path.
- If the requested path exactly matches the uncertified path, serve the uncertified response.
- Check if the requested path matches a file (e.g., `/assets/app.js`).
- If the request path exactly matches an existing file, serve that file.
- Otherwise, serve the `index.html` file.
Expand All @@ -452,13 +452,13 @@ fn asset_handler(req: &HttpRequest) -> HttpResponse<'static> {
RESPONSES.with_borrow(|responses| {
ENCODED_RESPONSES.with_borrow(|encoded_responses| {
let (asset_req_path, asset_tree_path, identity_response) =
// if the request path matches the dynamic response's path, serve that
if req_path == DYNAMIC_REQ_PATH {
// if the request path matches the uncertified response's path, serve that
if req_path == UNCERTIFIED_REQ_PATH {
(
DYNAMIC_REQ_PATH.to_string(),
HttpCertificationPath::exact(DYNAMIC_REQ_PATH),
UNCERTIFIED_REQ_PATH.to_string(),
HttpCertificationPath::exact(UNCERTIFIED_REQ_PATH),
CertifiedHttpResponse {
response: create_dynamic_response(),
response: create_uncertified_response(),
certification: HttpCertification::skip(),
},
)
Expand Down Expand Up @@ -538,10 +538,10 @@ fn asset_handler(req: &HttpRequest) -> HttpResponse<'static> {
}
```

Creating the dynamic response is done as follows:
Creating the uncertified response is done as follows:

```rust
fn create_dynamic_response() -> HttpResponse<'static> {
fn create_uncertified_response() -> HttpResponse<'static> {
let body = format!(
r#"
<html>
Expand All @@ -564,7 +564,7 @@ fn create_dynamic_response() -> HttpResponse<'static> {

let headers = get_asset_headers(
additional_headers,
&body,
body.len(),
DefaultCelBuilder::skip_certification().to_string(),
);

Expand Down
34 changes: 17 additions & 17 deletions examples/http-certification/custom-assets/src/backend/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ fn prepare_cel_exprs() {
}

fn certify_all_assets() {
certify_dynamic_asset();
add_certification_skips();

certify_index_asset();
certify_asset_glob("assets/**/*.css", "text/css");
Expand All @@ -85,16 +85,16 @@ fn certify_all_assets() {
update_certified_data();
}

const DYNAMIC_REQ_PATH: &str = "/dynamic";
const UNCERTIFIED_REQ_PATH: &str = "/uncertified";

fn certify_dynamic_asset() {
let dynamic_req_tree_path = HttpCertificationPath::exact(DYNAMIC_REQ_PATH);
let dynamic_req_certification = HttpCertification::skip();
fn add_certification_skips() {
let uncertified_req_tree_path = HttpCertificationPath::exact(UNCERTIFIED_REQ_PATH);
let uncertified_req_certification = HttpCertification::skip();

HTTP_TREE.with_borrow_mut(|http_tree| {
http_tree.insert(&HttpCertificationTreeEntry::new(
dynamic_req_tree_path,
&dynamic_req_certification,
uncertified_req_tree_path,
&uncertified_req_certification,
));
});
}
Expand Down Expand Up @@ -286,13 +286,13 @@ fn asset_handler(req: &HttpRequest) -> HttpResponse<'static> {
RESPONSES.with_borrow(|responses| {
ENCODED_RESPONSES.with_borrow(|encoded_responses| {
let (asset_req_path, asset_tree_path, identity_response) =
// if the request path matches the dynamic response's path, serve that
if req_path == DYNAMIC_REQ_PATH {
// if the request path matches the uncertified response's path, serve that
if req_path == UNCERTIFIED_REQ_PATH {
(
DYNAMIC_REQ_PATH.to_string(),
HttpCertificationPath::exact(DYNAMIC_REQ_PATH),
UNCERTIFIED_REQ_PATH.to_string(),
HttpCertificationPath::exact(UNCERTIFIED_REQ_PATH),
CertifiedHttpResponse {
response: create_dynamic_response(),
response: create_uncertified_response(),
certification: HttpCertification::skip(),
},
)
Expand Down Expand Up @@ -371,7 +371,7 @@ fn asset_handler(req: &HttpRequest) -> HttpResponse<'static> {
})
}

fn create_dynamic_response() -> HttpResponse<'static> {
fn create_uncertified_response() -> HttpResponse<'static> {
let body = format!(
r#"
<html>
Expand All @@ -394,7 +394,7 @@ fn create_dynamic_response() -> HttpResponse<'static> {

let headers = get_asset_headers(
additional_headers,
&body,
body.len(),
DefaultCelBuilder::skip_certification().to_string(),
);

Expand All @@ -407,7 +407,7 @@ fn create_dynamic_response() -> HttpResponse<'static> {

fn get_asset_headers(
additional_headers: Vec<HeaderField>,
body: &[u8],
content_length: usize,
cel_expr: String,
) -> Vec<(String, String)> {
// set up the default headers and include additional headers provided by the caller
Expand All @@ -420,7 +420,7 @@ fn get_asset_headers(
("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()),
("content-length".to_string(), body.len().to_string()),
("content-length".to_string(), content_length.to_string()),
(CERTIFICATE_EXPRESSION_HEADER_NAME.to_string(), cel_expr),
];
headers.extend(additional_headers);
Expand All @@ -433,7 +433,7 @@ fn create_asset_response(
body: &[u8],
cel_expr: String,
) -> HttpResponse {
let headers = get_asset_headers(additional_headers, body, cel_expr);
let headers = get_asset_headers(additional_headers, body.len(), cel_expr);

HttpResponse::builder()
.with_status_code(200)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ describe('HTTP', () => {

it('should successfully skip verification', async () => {
const request: Request = {
url: '/dynamic',
url: '/uncertified',
method: 'GET',
headers: [],
body: new Uint8Array(),
Expand Down
8 changes: 7 additions & 1 deletion examples/http-certification/skip-certification/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,14 @@ This is a relatively simple guide so there's no prerequisites as such, but it's

# Skipping certification

Skipping certification for all responses is a relatively simple task that can be completed in 2 very simple steps.
Skipping certification for all responses is a relatively simple task that can be completed in 2 steps.

First, set the canister's certified data in the canister's `init` lifecycle hook:

```rust
use ic_cdk::*;
use ic_http_certification::utils::skip_certification_certified_data;

#[init]
fn init() {
set_certified_data(&skip_certification_certified_data());
Expand All @@ -34,6 +37,9 @@ This will make sure that the correct certified data is set so that it can be sig
Next, when responding to HTTP requests, add the certificate header that will instruct the HTTP Gateway to skip verification:

```rust
use ic_cdk::{api::data_certificate, *};
use ic_http_certification::utils::add_skip_certification_header;

#[query]
fn http_request() -> HttpResponse<'static> {
let mut response = create_response();
Expand Down
27 changes: 23 additions & 4 deletions packages/ic-http-certification/src/utils/skip_certification.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use super::add_certificate_header;
use super::add_v2_certificate_header;
use crate::{
DefaultCelBuilder, Hash, HttpCertificationPath, HttpResponse,
CERTIFICATE_EXPRESSION_HEADER_NAME,
Expand Down Expand Up @@ -26,6 +26,7 @@ use ic_representation_independent_hash::hash;
///
/// let mut response = HttpResponse::builder().build();
///
/// // this should normally be retrieved using `ic_cdk::api::data_certificate()`.
/// let data_certificate = vec![1, 2, 3];
///
/// add_skip_certification_header(data_certificate, &mut response);
Expand All @@ -45,8 +46,8 @@ use ic_representation_independent_hash::hash;
/// );
/// ```
pub fn add_skip_certification_header(data_certificate: Vec<u8>, response: &mut HttpResponse) {
add_certificate_header(
data_certificate,
add_v2_certificate_header(
&data_certificate,
response,
&skip_certification_asset_tree(),
&HttpCertificationPath::wildcard("").to_expr_path(),
Expand All @@ -68,7 +69,7 @@ pub fn add_skip_certification_header(data_certificate: Vec<u8>, response: &mut H
///
/// let certified_data = skip_certification_certified_data();
///
/// set_certified_date(&certified_data);
/// set_certified_data(&certified_data);
/// ```
pub fn skip_certification_certified_data() -> Hash {
skip_certification_asset_tree().digest()
Expand All @@ -86,3 +87,21 @@ fn skip_certification_asset_tree() -> HashTree {
labeled("<*>", labeled(cel_expr_hash, leaf(vec![]))),
)
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_skip_certification_certified_data() {
let certified_data = skip_certification_certified_data();

assert_eq!(
certified_data,
[
85, 236, 195, 28, 62, 128, 71, 252, 21, 143, 32, 234, 10, 160, 96, 154, 172, 199,
181, 126, 6, 234, 64, 220, 65, 134, 2, 114, 167, 214, 66, 145
]
);
}
}

0 comments on commit f402d18

Please sign in to comment.