From 44d70d10dcf9aeae60891d268bdf0a36800d8124 Mon Sep 17 00:00:00 2001 From: SoraSuegami Date: Wed, 23 Oct 2024 22:59:46 +0900 Subject: [PATCH] Add more failing tests for dns_client --- src/dns_client/src/lib.rs | 264 +++++++++++++++++++++++++++ src/ic_dns_oracle_backend/src/lib.rs | 24 ++- 2 files changed, 279 insertions(+), 9 deletions(-) diff --git a/src/dns_client/src/lib.rs b/src/dns_client/src/lib.rs index 6de8ce1..8624f7b 100644 --- a/src/dns_client/src/lib.rs +++ b/src/dns_client/src/lib.rs @@ -285,4 +285,268 @@ mod test { let canister_http_requests = pic.get_canister_http(); assert_eq!(canister_http_requests.len(), 0); } + + #[test] + fn test_dns_client_expect_error_no_answer() { + let pic = PocketIcBuilder::new() + .with_nns_subnet() + .with_ii_subnet() // this subnet has ECDSA keys + .with_application_subnet() + .build(); + + let topology = pic.topology(); + let app_subnet = topology.get_app_subnets()[0]; + + // Create an empty canister as the anonymous principal and add cycles. + let canister_id = pic.create_canister_on_subnet(None, None, app_subnet); + pic.add_cycles(canister_id, 2_000_000_000_000); + let wasm_bytes = + include_bytes!("../../../target/wasm32-unknown-unknown/release/dns_client.wasm") + .to_vec(); + pic.install_canister(canister_id, wasm_bytes, vec![], None); + + // Submit an update call to the test canister making a canister http outcall + // and mock a canister http outcall response. + let call_id = pic + .submit_call( + canister_id, + Principal::anonymous(), + "get_dkim_public_key", + Encode!(&"20230601", &"gmail.com", &1_000_000_000_000u64).unwrap(), + ) + .unwrap(); + // We need a pair of ticks for the test canister method to make the http outcall + // and for the management canister to start processing the http outcall. + pic.tick(); + pic.tick(); + let canister_http_requests = pic.get_canister_http(); + assert_eq!(canister_http_requests.len(), 1); + let canister_http_request = &canister_http_requests[0]; + println!("{:?}", canister_http_request); + let body = r#" + { + "Status": 0, + "TC": false, + "RD": true, + "RA": true, + "AD": false, + "CD": false, + "Question": [ + { + "name": "20230601._domainkey.gmail.com.", + "type": 16 + } + ], + "Answer": [ + ], + "Comment": "Response from 216.239.32.10." + } + "#; + let mock_canister_http_response = MockCanisterHttpResponse { + subnet_id: canister_http_request.subnet_id, + request_id: canister_http_request.request_id, + response: CanisterHttpResponse::CanisterHttpReply(CanisterHttpReply { + status: 200, + headers: vec![], + body: body.as_bytes().to_vec(), + }), + additional_responses: vec![], + }; + pic.mock_canister_http_response(mock_canister_http_response); + + // Now the test canister will receive the http outcall response + // and reply to the ingress message from the test driver. + let reply = pic.await_call(call_id).unwrap(); + println!("{:?}", reply); + match reply { + WasmResult::Reply(data) => { + let http_response: Result = decode_one(&data).unwrap(); + assert!(http_response.is_err()); + } + WasmResult::Reject(msg) => panic!("Unexpected reject {}", msg), + }; + // There should be no more pending canister http outcalls. + let canister_http_requests = pic.get_canister_http(); + assert_eq!(canister_http_requests.len(), 0); + } + + #[test] + fn test_dns_client_expect_error_invalid_key_type() { + let pic = PocketIcBuilder::new() + .with_nns_subnet() + .with_ii_subnet() // this subnet has ECDSA keys + .with_application_subnet() + .build(); + + let topology = pic.topology(); + let app_subnet = topology.get_app_subnets()[0]; + + // Create an empty canister as the anonymous principal and add cycles. + let canister_id = pic.create_canister_on_subnet(None, None, app_subnet); + pic.add_cycles(canister_id, 2_000_000_000_000); + let wasm_bytes = + include_bytes!("../../../target/wasm32-unknown-unknown/release/dns_client.wasm") + .to_vec(); + pic.install_canister(canister_id, wasm_bytes, vec![], None); + + // Submit an update call to the test canister making a canister http outcall + // and mock a canister http outcall response. + let call_id = pic + .submit_call( + canister_id, + Principal::anonymous(), + "get_dkim_public_key", + Encode!(&"20230601", &"gmail.com", &1_000_000_000_000u64).unwrap(), + ) + .unwrap(); + // We need a pair of ticks for the test canister method to make the http outcall + // and for the management canister to start processing the http outcall. + pic.tick(); + pic.tick(); + let canister_http_requests = pic.get_canister_http(); + assert_eq!(canister_http_requests.len(), 1); + let canister_http_request = &canister_http_requests[0]; + println!("{:?}", canister_http_request); + let body = r#" + { + "Status": 0, + "TC": false, + "RD": true, + "RA": true, + "AD": false, + "CD": false, + "Question": [ + { + "name": "20230601._domainkey.gmail.com.", + "type": 16 + } + ], + "Answer": [ + { + "name": "20230601._domainkey.gmail.com.", + "type": 16, + "TTL": 3600, + "data": "v=DKIM1; k=eddsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAntvSKT1hkqhKe0xcaZ0x+QbouDsJuBfby/S82jxsoC/SodmfmVs2D1KAH3mi1AqdMdU12h2VfETeOJkgGYq5ljd996AJ7ud2SyOLQmlhaNHH7Lx+Mdab8/zDN1SdxPARDgcM7AsRECHwQ15R20FaKUABGu4NTbR2fDKnYwiq5jQyBkLWP+LgGOgfUF4T4HZb2PY2bQtEP6QeqOtcW4rrsH24L7XhD+HSZb1hsitrE0VPbhJzxDwI4JF815XMnSVjZgYUXP8CxI1Y0FONlqtQYgsorZ9apoW1KPQe8brSSlRsi9sXB/tu56LmG7tEDNmrZ5XUwQYUUADBOu7t1niwXwIDAQAB" + } + ], + "Comment": "Response from 216.239.32.10." + } + "#; + let mock_canister_http_response = MockCanisterHttpResponse { + subnet_id: canister_http_request.subnet_id, + request_id: canister_http_request.request_id, + response: CanisterHttpResponse::CanisterHttpReply(CanisterHttpReply { + status: 200, + headers: vec![], + body: body.as_bytes().to_vec(), + }), + additional_responses: vec![], + }; + pic.mock_canister_http_response(mock_canister_http_response); + + // Now the test canister will receive the http outcall response + // and reply to the ingress message from the test driver. + let reply = pic.await_call(call_id).unwrap(); + println!("{:?}", reply); + match reply { + WasmResult::Reply(data) => { + let http_response: Result = decode_one(&data).unwrap(); + assert!(http_response.is_err()); + } + WasmResult::Reject(msg) => panic!("Unexpected reject {}", msg), + }; + // There should be no more pending canister http outcalls. + let canister_http_requests = pic.get_canister_http(); + assert_eq!(canister_http_requests.len(), 0); + } + + #[test] + fn test_dns_client_expect_error_invalid_base64_format() { + let pic = PocketIcBuilder::new() + .with_nns_subnet() + .with_ii_subnet() // this subnet has ECDSA keys + .with_application_subnet() + .build(); + + let topology = pic.topology(); + let app_subnet = topology.get_app_subnets()[0]; + + // Create an empty canister as the anonymous principal and add cycles. + let canister_id = pic.create_canister_on_subnet(None, None, app_subnet); + pic.add_cycles(canister_id, 2_000_000_000_000); + let wasm_bytes = + include_bytes!("../../../target/wasm32-unknown-unknown/release/dns_client.wasm") + .to_vec(); + pic.install_canister(canister_id, wasm_bytes, vec![], None); + + // Submit an update call to the test canister making a canister http outcall + // and mock a canister http outcall response. + let call_id = pic + .submit_call( + canister_id, + Principal::anonymous(), + "get_dkim_public_key", + Encode!(&"20230601", &"gmail.com", &1_000_000_000_000u64).unwrap(), + ) + .unwrap(); + // We need a pair of ticks for the test canister method to make the http outcall + // and for the management canister to start processing the http outcall. + pic.tick(); + pic.tick(); + let canister_http_requests = pic.get_canister_http(); + assert_eq!(canister_http_requests.len(), 1); + let canister_http_request = &canister_http_requests[0]; + println!("{:?}", canister_http_request); + let body = r#" + { + "Status": 0, + "TC": false, + "RD": true, + "RA": true, + "AD": false, + "CD": false, + "Question": [ + { + "name": "20230601._domainkey.gmail.com.", + "type": 16 + } + ], + "Answer": [ + { + "name": "20230601._domainkey.gmail.com.", + "type": 16, + "TTL": 3600, + "data": "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAntvSKT1hkqhKe0xcaZ0x+QbouDsJuBfby/S82jxsoC/SodmfmVs2D1KAH3mi1AqdMdU12h2VfETeOJkgGYq5ljd996AJ7ud2SyOLQmlhaNHH7Lx+Mdab8/zDN1SdxPARDgcM7AsRECHwQ15R20FaKUABGu4NTbR2fDKnYwiq5jQyBkLWP+LgGOgfUF4T4HZb2PY2bQtEP6QeqOtcW4rrsH24L7XhD+HSZb1hsitrE0VPbhJzxDwI4JF815XMnSVjZgYUXP8CxI1Y0FONlqtQYgsorZ9apoW1KPQe8brSSlRsi9sXB/tu56LmG7tEDNmrZ5XUwQYUUADBOu7t1niwXwIDAQ!" + } + ], + "Comment": "Response from 216.239.32.10." + } + "#; + let mock_canister_http_response = MockCanisterHttpResponse { + subnet_id: canister_http_request.subnet_id, + request_id: canister_http_request.request_id, + response: CanisterHttpResponse::CanisterHttpReply(CanisterHttpReply { + status: 200, + headers: vec![], + body: body.as_bytes().to_vec(), + }), + additional_responses: vec![], + }; + pic.mock_canister_http_response(mock_canister_http_response); + + // Now the test canister will receive the http outcall response + // and reply to the ingress message from the test driver. + let reply = pic.await_call(call_id).unwrap(); + println!("{:?}", reply); + match reply { + WasmResult::Reply(data) => { + let http_response: Result = decode_one(&data).unwrap(); + assert!(http_response.is_err()); + } + WasmResult::Reject(msg) => panic!("Unexpected reject {}", msg), + }; + // There should be no more pending canister http outcalls. + let canister_http_requests = pic.get_canister_http(); + assert_eq!(canister_http_requests.len(), 0); + } } diff --git a/src/ic_dns_oracle_backend/src/lib.rs b/src/ic_dns_oracle_backend/src/lib.rs index a415ff7..7d10ac7 100644 --- a/src/ic_dns_oracle_backend/src/lib.rs +++ b/src/ic_dns_oracle_backend/src/lib.rs @@ -482,7 +482,8 @@ async fn _sign_dkim_public_key( .expect("failed to append log") }); /// Sign the message. - let signature = ic_evm_sign::sign_msg(message.as_bytes().to_vec(), Principal::anonymous()).await?; + let signature = + ic_evm_sign::sign_msg(message.as_bytes().to_vec(), Principal::anonymous()).await?; LOG.with(|log| { log.borrow_mut() .append(&format!("fn _sign_dkim_public_key: [after ic_evm_signing]")) @@ -859,8 +860,7 @@ mod test { let reply = pic.await_call(call_id).unwrap(); let signer_addr = match reply { WasmResult::Reply(data) => { - let res: String = - decode_one(&data).unwrap(); + let res: String = decode_one(&data).unwrap(); res // assert_eq!(http_response.unwrap(), "0x9edbd2293d6192a84a7b4c5c699d31f906e8b83b09b817dbcbf4bcda3c6ca02fd2a1d99f995b360f52801f79a2d40a9d31d535da1d957c44de389920198ab996377df7a009eee7764b238b42696168d1c7ecbc7e31d69bf3fcc337549dc4f0110e070cec0b111021f0435e51db415a2940011aee0d4db4767c32a76308aae634320642d63fe2e018e81f505e13e0765bd8f6366d0b443fa41ea8eb5c5b8aebb07db82fb5e10fe1d265bd61b22b6b13454f6e1273c43c08e0917cd795cc9d25636606145cff02c48d58d0538d96ab50620b28ad9f5aa685b528f41ef1bad24a546c8bdb1707fb6ee7a2e61bbb440cd9ab6795d4c106145000c13aeeedd678b05f"); } @@ -928,8 +928,7 @@ mod test { println!("{:?}", reply); let res = match reply { WasmResult::Reply(data) => { - let res: Result = - decode_one(&data).unwrap(); + let res: Result = decode_one(&data).unwrap(); res.unwrap() // assert_eq!(http_response.unwrap(), "0x9edbd2293d6192a84a7b4c5c699d31f906e8b83b09b817dbcbf4bcda3c6ca02fd2a1d99f995b360f52801f79a2d40a9d31d535da1d957c44de389920198ab996377df7a009eee7764b238b42696168d1c7ecbc7e31d69bf3fcc337549dc4f0110e070cec0b111021f0435e51db415a2940011aee0d4db4767c32a76308aae634320642d63fe2e018e81f505e13e0765bd8f6366d0b443fa41ea8eb5c5b8aebb07db82fb5e10fe1d265bd61b22b6b13454f6e1273c43c08e0917cd795cc9d25636606145cff02c48d58d0538d96ab50620b28ad9f5aa685b528f41ef1bad24a546c8bdb1707fb6ee7a2e61bbb440cd9ab6795d4c106145000c13aeeedd678b05f"); } @@ -946,16 +945,23 @@ mod test { let signature = hex::decode(&res.signature[2..]).unwrap(); let signature_bytes: [u8; 64] = signature[0..64].try_into().unwrap(); let signature_bytes_64 = libsecp256k1::Signature::parse_standard(&signature_bytes).unwrap(); - let recovery_id = libsecp256k1::RecoveryId::parse(u8::try_from(signature[64]).unwrap() - 27).unwrap(); + let recovery_id = + libsecp256k1::RecoveryId::parse(u8::try_from(signature[64]).unwrap() - 27).unwrap(); let message = format!( "SET:domain={};public_key_hash={};", res.domain, res.public_key_hash ); let message_hash = msg_to_hash(&message.as_bytes()); - let public_key = - libsecp256k1::recover(&libsecp256k1::Message::parse(&message_hash), &signature_bytes_64, &recovery_id).unwrap(); - let recovered_addr = ic_evm_sign::get_address_from_public_key(public_key.serialize_compressed().to_vec()).unwrap(); + let public_key = libsecp256k1::recover( + &libsecp256k1::Message::parse(&message_hash), + &signature_bytes_64, + &recovery_id, + ) + .unwrap(); + let recovered_addr = + ic_evm_sign::get_address_from_public_key(public_key.serialize_compressed().to_vec()) + .unwrap(); println!("recovered_addr {:?}", recovered_addr); assert_eq!(recovered_addr.to_string(), signer_addr); }