From 20a862988221bcff450da58621ebc115eac1dc98 Mon Sep 17 00:00:00 2001 From: Chris Smith Date: Wed, 6 Mar 2024 18:06:27 -0800 Subject: [PATCH 1/4] feat: identity key from URL --- relay_rpc/src/auth/cacao/payload.rs | 132 ++++++++++++++++++++++++++-- 1 file changed, 127 insertions(+), 5 deletions(-) diff --git a/relay_rpc/src/auth/cacao/payload.rs b/relay_rpc/src/auth/cacao/payload.rs index 117f3a8..c5a487b 100644 --- a/relay_rpc/src/auth/cacao/payload.rs +++ b/relay_rpc/src/auth/cacao/payload.rs @@ -2,6 +2,7 @@ use { super::{CacaoError, Version}, crate::auth::did::{extract_did_data, DID_METHOD_KEY}, serde::{Deserialize, Serialize}, + url::Url, }; #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize, Hash)] @@ -24,6 +25,7 @@ impl Payload { const ISS_POSITION_OF_ADDRESS: usize = 4; const ISS_POSITION_OF_NAMESPACE: usize = 2; const ISS_POSITION_OF_REFERENCE: usize = 3; + pub const WALLETCONNECT_IDENTITY_TOKEN: &'static str = "walletconnect_identity_token"; /// TODO: write valdation pub fn validate(&self) -> Result<(), CacaoError> { @@ -77,6 +79,12 @@ impl Payload { .or_else(|_| self.identity_key_from_resources()) } + fn extract_did_key(did_key: &str) -> Result { + extract_did_data(did_key, DID_METHOD_KEY) + .map_err(|_| CacaoError::PayloadIdentityKey) + .map(|data| data.to_owned()) + } + fn identity_key_from_resources(&self) -> Result { let resources = self .resources @@ -84,14 +92,128 @@ impl Payload { .ok_or(CacaoError::PayloadResources)?; let did_key = resources.first().ok_or(CacaoError::PayloadIdentityKey)?; - extract_did_data(did_key, DID_METHOD_KEY) - .map(|data| data.to_string()) - .map_err(|_| CacaoError::PayloadIdentityKey) + Self::extract_did_key(did_key) } fn identity_key_from_audience(&self) -> Result { - extract_did_data(&self.aud, DID_METHOD_KEY) - .map(|data| data.to_string()) + self.identity_key_from_audience_url() + .or_else(|_| self.identity_key_from_audience_did_key()) + } + + fn identity_key_from_audience_did_key(&self) -> Result { + Self::extract_did_key(&self.aud) + } + + fn identity_key_from_audience_url(&self) -> Result { + self.aud + .parse::() .map_err(|_| CacaoError::PayloadIdentityKey) + .and_then(|url| { + url.query_pairs() + .find(|(key, _)| key == Self::WALLETCONNECT_IDENTITY_TOKEN) + .ok_or(CacaoError::PayloadIdentityKey) + .and_then(|(_, value)| Self::extract_did_key(&value)) + }) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn identity_key_from_resources() { + assert_eq!( + Payload { + domain: "example.com".to_owned(), + iss: "did:pkh:eip155:1:0xdFe7d0E324ed017a74aE311E9236E6CaDB24176b".to_owned(), + statement: None, + aud: "".to_owned(), + version: Version::V1, + nonce: "".to_owned(), + iat: "2023-09-07T11:04:23+02:00".to_owned(), + exp: None, + nbf: None, + request_id: None, + resources: Some(vec![ + "did:key:z6MkvjNoiz9AXGH1igzrtB54US5hE9bZPQm1ryKGkCLwWht7".to_owned(), + ]), + } + .identity_key() + .unwrap(), + "z6MkvjNoiz9AXGH1igzrtB54US5hE9bZPQm1ryKGkCLwWht7" + ); + } + + #[test] + fn identity_key_from_aud() { + assert_eq!( + Payload { + domain: "example.com".to_owned(), + iss: "did:pkh:eip155:1:0xdFe7d0E324ed017a74aE311E9236E6CaDB24176b".to_owned(), + statement: None, + aud: "did:key:z6MkvjNoiz9AXGH1igzrtB54US5hE9bZPQm1ryKGkCLwWht7".to_owned(), + version: Version::V1, + nonce: "".to_owned(), + iat: "2023-09-07T11:04:23+02:00".to_owned(), + exp: None, + nbf: None, + request_id: None, + resources: Some(vec![ + "did:key:z6MkvjNoiz9AXGH1igzrtB54US5hE9bZPQm1ryKGkCLwWht8".to_owned(), + ]), + } + .identity_key() + .unwrap(), + "z6MkvjNoiz9AXGH1igzrtB54US5hE9bZPQm1ryKGkCLwWht7" + ); + } + + #[test] + fn identity_key_from_aud_url() { + assert_eq!( + Payload { + domain: "example.com".to_owned(), + iss: "did:pkh:eip155:1:0xdFe7d0E324ed017a74aE311E9236E6CaDB24176b".to_owned(), + statement: None, + aud: "https://example.com?walletconnect_identity_token=did:key:z6MkvjNoiz9AXGH1igzrtB54US5hE9bZPQm1ryKGkCLwWht7".to_owned(), + version: Version::V1, + nonce: "".to_owned(), + iat: "2023-09-07T11:04:23+02:00".to_owned(), + exp: None, + nbf: None, + request_id: None, + resources: Some(vec![ + "did:key:z6MkvjNoiz9AXGH1igzrtB54US5hE9bZPQm1ryKGkCLwWht8".to_owned(), + ]), + } + .identity_key() + .unwrap(), + "z6MkvjNoiz9AXGH1igzrtB54US5hE9bZPQm1ryKGkCLwWht7" + ); + } + + #[test] + fn identity_key_from_aud_url_encoded() { + assert_eq!( + Payload { + domain: "example.com".to_owned(), + iss: "did:pkh:eip155:1:0xdFe7d0E324ed017a74aE311E9236E6CaDB24176b".to_owned(), + statement: None, + aud: "https://example.com?walletconnect_identity_token=did%3Akey%3Az6MkvjNoiz9AXGH1igzrtB54US5hE9bZPQm1ryKGkCLwWht7".to_owned(), + version: Version::V1, + nonce: "".to_owned(), + iat: "2023-09-07T11:04:23+02:00".to_owned(), + exp: None, + nbf: None, + request_id: None, + resources: Some(vec![ + "did:key:z6MkvjNoiz9AXGH1igzrtB54US5hE9bZPQm1ryKGkCLwWht8".to_owned(), + ]), + } + .identity_key() + .unwrap(), + "z6MkvjNoiz9AXGH1igzrtB54US5hE9bZPQm1ryKGkCLwWht7" + ); } } From f644cb0ae74692d530fa03b2a7bb42e8a6f14ecd Mon Sep 17 00:00:00 2001 From: Chris Smith Date: Wed, 6 Mar 2024 20:21:05 -0800 Subject: [PATCH 2/4] fix: match command to CI --- justfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/justfile b/justfile index 2cd7d52..e310120 100644 --- a/justfile +++ b/justfile @@ -53,7 +53,7 @@ clippy: if command -v cargo-clippy >/dev/null; then echo '==> Running clippy' - cargo clippy --workspace --all-features --all-targets -- -D clippy::all -W clippy::style + cargo clippy --workspace --all-features --all-targets -- -D warnings else echo '==> clippy not found in PATH, skipping' echo ' ^^^^^^ To install `rustup component add clippy`, see https://github.com/rust-lang/rust-clippy for details' From fad8c8a35327f811ab25ced73718e4f2bdd4c739 Mon Sep 17 00:00:00 2001 From: Chris Smith Date: Wed, 6 Mar 2024 20:24:23 -0800 Subject: [PATCH 3/4] fix: deprecated methods --- relay_rpc/src/jwt.rs | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/relay_rpc/src/jwt.rs b/relay_rpc/src/jwt.rs index 3eab799..d9a4bf4 100644 --- a/relay_rpc/src/jwt.rs +++ b/relay_rpc/src/jwt.rs @@ -288,7 +288,10 @@ mod test { // IAT in future. let jwt = AuthToken::new(sub.clone()) - .iat(chrono::Utc::now() + chrono::Duration::hours(1)) + .iat( + chrono::Utc::now() + + chrono::Duration::try_hours(1).expect("Safe unwrap: does not return None"), + ) .as_jwt(&keypair) .unwrap(); assert!(matches!( @@ -298,7 +301,11 @@ mod test { // IAT leeway, valid. let jwt = AuthToken::new(sub.clone()) - .iat(chrono::Utc::now() + chrono::Duration::seconds(JWT_VALIDATION_TIME_LEEWAY_SECS)) + .iat( + chrono::Utc::now() + + chrono::Duration::try_seconds(JWT_VALIDATION_TIME_LEEWAY_SECS) + .expect("Safe unwrap: does not return None"), + ) .as_jwt(&keypair) .unwrap(); assert!(Jwt(jwt.into()).decode(&aud).is_ok()); @@ -306,7 +313,9 @@ mod test { // IAT leeway, invalid. let jwt = AuthToken::new(sub.clone()) .iat( - chrono::Utc::now() + chrono::Duration::seconds(JWT_VALIDATION_TIME_LEEWAY_SECS + 1), + chrono::Utc::now() + + chrono::Duration::try_seconds(JWT_VALIDATION_TIME_LEEWAY_SECS + 1) + .expect("Safe unwrap: does not return None"), ) .as_jwt(&keypair) .unwrap(); @@ -317,7 +326,10 @@ mod test { // Past expiration. let jwt = AuthToken::new(sub.clone()) - .iat(chrono::Utc::now() - chrono::Duration::hours(2)) + .iat( + chrono::Utc::now() + - chrono::Duration::try_hours(2).expect("Safe unwrap: does not return None"), + ) .ttl(Duration::from_secs(3600)) .as_jwt(&keypair) .unwrap(); @@ -330,7 +342,8 @@ mod test { let jwt = AuthToken::new(sub.clone()) .iat( chrono::Utc::now() - - chrono::Duration::seconds(3600 + JWT_VALIDATION_TIME_LEEWAY_SECS), + - chrono::Duration::try_seconds(3600 + JWT_VALIDATION_TIME_LEEWAY_SECS) + .expect("Safe unwrap: does not return None"), ) .ttl(Duration::from_secs(3600)) .as_jwt(&keypair) @@ -341,7 +354,8 @@ mod test { let jwt = AuthToken::new(sub.clone()) .iat( chrono::Utc::now() - - chrono::Duration::seconds(3600 + JWT_VALIDATION_TIME_LEEWAY_SECS + 1), + - chrono::Duration::try_seconds(3600 + JWT_VALIDATION_TIME_LEEWAY_SECS + 1) + .expect("Safe unwrap: does not return None"), ) .ttl(Duration::from_secs(3600)) .as_jwt(&keypair) From a3c17454e86e28b0d4c1919ecc08242dbccda3a2 Mon Sep 17 00:00:00 2001 From: Chris Smith Date: Thu, 7 Mar 2024 08:37:30 -0800 Subject: [PATCH 4/4] fix: token -> key --- relay_rpc/src/auth/cacao/payload.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/relay_rpc/src/auth/cacao/payload.rs b/relay_rpc/src/auth/cacao/payload.rs index c5a487b..71cf252 100644 --- a/relay_rpc/src/auth/cacao/payload.rs +++ b/relay_rpc/src/auth/cacao/payload.rs @@ -25,7 +25,7 @@ impl Payload { const ISS_POSITION_OF_ADDRESS: usize = 4; const ISS_POSITION_OF_NAMESPACE: usize = 2; const ISS_POSITION_OF_REFERENCE: usize = 3; - pub const WALLETCONNECT_IDENTITY_TOKEN: &'static str = "walletconnect_identity_token"; + pub const WALLETCONNECT_IDENTITY_KEY: &'static str = "walletconnect_identity_key"; /// TODO: write valdation pub fn validate(&self) -> Result<(), CacaoError> { @@ -110,7 +110,7 @@ impl Payload { .map_err(|_| CacaoError::PayloadIdentityKey) .and_then(|url| { url.query_pairs() - .find(|(key, _)| key == Self::WALLETCONNECT_IDENTITY_TOKEN) + .find(|(key, _)| key == Self::WALLETCONNECT_IDENTITY_KEY) .ok_or(CacaoError::PayloadIdentityKey) .and_then(|(_, value)| Self::extract_did_key(&value)) }) @@ -176,7 +176,7 @@ mod tests { domain: "example.com".to_owned(), iss: "did:pkh:eip155:1:0xdFe7d0E324ed017a74aE311E9236E6CaDB24176b".to_owned(), statement: None, - aud: "https://example.com?walletconnect_identity_token=did:key:z6MkvjNoiz9AXGH1igzrtB54US5hE9bZPQm1ryKGkCLwWht7".to_owned(), + aud: "https://example.com?walletconnect_identity_key=did:key:z6MkvjNoiz9AXGH1igzrtB54US5hE9bZPQm1ryKGkCLwWht7".to_owned(), version: Version::V1, nonce: "".to_owned(), iat: "2023-09-07T11:04:23+02:00".to_owned(), @@ -200,7 +200,7 @@ mod tests { domain: "example.com".to_owned(), iss: "did:pkh:eip155:1:0xdFe7d0E324ed017a74aE311E9236E6CaDB24176b".to_owned(), statement: None, - aud: "https://example.com?walletconnect_identity_token=did%3Akey%3Az6MkvjNoiz9AXGH1igzrtB54US5hE9bZPQm1ryKGkCLwWht7".to_owned(), + aud: "https://example.com?walletconnect_identity_key=did%3Akey%3Az6MkvjNoiz9AXGH1igzrtB54US5hE9bZPQm1ryKGkCLwWht7".to_owned(), version: Version::V1, nonce: "".to_owned(), iat: "2023-09-07T11:04:23+02:00".to_owned(),