Skip to content

Commit d27ecc2

Browse files
authored
feat: make cacao verification a feature (#18)
1 parent b454c5b commit d27ecc2

File tree

9 files changed

+47
-45
lines changed

9 files changed

+47
-45
lines changed

.github/workflows/ci.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,11 @@ jobs:
3636
rust: nightly
3737
- name: "Tests"
3838
cmd: nextest
39-
args: run --workspace --retries 3
39+
args: run --workspace --all-features --features cacao --retries 3
4040
rust: stable
4141
- name: "Documentation Tests"
4242
cmd: test
43-
args: --workspace --doc
43+
args: --workspace --doc --all-features
4444
rust: stable
4545
env:
4646
RUST_BACKTRACE: full

relay_rpc/Cargo.toml

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@ name = "relay_rpc"
33
version = "0.1.0"
44
edition = "2021"
55

6+
[features]
7+
cacao = ["dep:k256", "dep:sha3"]
8+
69
[dependencies]
710
bs58 = "0.4"
811
data-encoding = "2.3"
@@ -17,6 +20,5 @@ chrono = { version = "0.4", default-features = false, features = ["std", "clock"
1720
regex = "1.7"
1821
once_cell = "1.16"
1922
jsonwebtoken = "8.1"
20-
k256 = "0.13.0"
21-
sha3 = "0.10.6"
22-
hex = "0.4.3"
23+
k256 = { version = "0.13", optional = true }
24+
sha3 = { version = "0.10", optional = true }

relay_rpc/src/auth.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#[cfg(test)]
22
mod tests;
33

4+
#[cfg(feature = "cacao")]
45
pub mod cacao;
56
pub mod did;
67

relay_rpc/src/auth/cacao/mod.rs renamed to relay_rpc/src/auth/cacao.rs

Lines changed: 22 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,15 @@ use {
22
self::{header::Header, payload::Payload, signature::Signature},
33
core::fmt::Debug,
44
serde::{Deserialize, Serialize},
5-
std::fmt::{Display, Write as _},
6-
thiserror::Error as ThisError,
5+
std::fmt::{Display, Write},
76
};
87

98
pub mod header;
109
pub mod payload;
1110
pub mod signature;
1211

13-
/// Errors that can occur during JWT verification
14-
#[derive(Debug, ThisError)]
12+
/// Errors that can occur during Cacao verification.
13+
#[derive(Debug, thiserror::Error)]
1514
pub enum CacaoError {
1615
#[error("Invalid header")]
1716
Header,
@@ -29,6 +28,12 @@ pub enum CacaoError {
2928
Verification,
3029
}
3130

31+
impl From<std::fmt::Error> for CacaoError {
32+
fn from(_: std::fmt::Error) -> Self {
33+
CacaoError::PayloadResources
34+
}
35+
}
36+
3237
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
3338
pub enum Version {
3439
V1 = 1,
@@ -73,8 +78,8 @@ impl Cacao {
7378
const ETHEREUM: &'static str = "Ethereum";
7479

7580
pub fn verify(&self) -> Result<bool, CacaoError> {
76-
self.p.is_valid()?;
77-
self.h.is_valid()?;
81+
self.p.validate()?;
82+
self.h.validate()?;
7883
self.s.verify(self)
7984
}
8085

@@ -91,37 +96,38 @@ impl Cacao {
9196
);
9297

9398
if let Some(statement) = &self.p.statement {
94-
let _ = write!(message, "\n{}\n", statement);
99+
write!(message, "\n{}\n", statement)?;
95100
}
96101

97-
let _ = write!(
102+
write!(
98103
message,
99104
"\nURI: {}\nVersion: {}\nChain ID: {}\nNonce: {}\nIssued At: {}",
100105
self.p.aud,
101106
self.p.version,
102107
self.p.chain_id()?,
103108
self.p.nonce,
104109
self.p.iat
105-
);
110+
)?;
106111

107112
if let Some(exp) = &self.p.exp {
108-
let _ = write!(message, "\nExpiration Time: {}", exp);
113+
write!(message, "\nExpiration Time: {}", exp)?;
109114
}
110115

111116
if let Some(nbf) = &self.p.nbf {
112-
let _ = write!(message, "\nNot Before: {}", nbf);
117+
write!(message, "\nNot Before: {}", nbf)?;
113118
}
114119

115120
if let Some(request_id) = &self.p.request_id {
116-
let _ = write!(message, "\nRequest ID: {}", request_id);
121+
write!(message, "\nRequest ID: {}", request_id)?;
117122
}
118123

119124
if let Some(resources) = &self.p.resources {
120125
if !resources.is_empty() {
121-
let _ = write!(message, "\nResources:");
122-
resources.iter().for_each(|resource| {
123-
let _ = write!(message, "\n- {}", resource);
124-
});
126+
write!(message, "\nResources:")?;
127+
128+
for resource in resources {
129+
write!(message, "\n- {}", resource)?;
130+
}
125131
}
126132
}
127133

relay_rpc/src/auth/cacao/header.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ pub struct Header {
99
}
1010

1111
impl Header {
12-
pub fn is_valid(&self) -> Result<(), CacaoError> {
12+
pub fn validate(&self) -> Result<(), CacaoError> {
1313
match self.t.as_str() {
1414
"eip4361" => Ok(()),
1515
_ => Err(CacaoError::Header),

relay_rpc/src/auth/cacao/payload.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@ impl Payload {
2626
const ISS_POSITION_OF_REFERENCE: usize = 3;
2727

2828
/// TODO: write valdation
29-
pub fn is_valid(&self) -> Result<bool, CacaoError> {
30-
Ok(true)
29+
pub fn validate(&self) -> Result<(), CacaoError> {
30+
Ok(())
3131
}
3232

3333
pub fn address(&self) -> Result<String, CacaoError> {

relay_rpc/src/auth/cacao/signature.rs

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -37,15 +37,16 @@ impl Eip191 {
3737
sha3::{Digest, Keccak256},
3838
};
3939

40-
let signature_bytes = hex::decode(guarantee_no_hex_prefix(signature))
40+
let signature_bytes = data_encoding::HEXLOWER_PERMISSIVE
41+
.decode(strip_hex_prefix(signature).as_bytes())
4142
.map_err(|_| CacaoError::Verification)?;
4243

4344
let sig = Sig::try_from(&signature_bytes[..64]).map_err(|_| CacaoError::Verification)?;
4445
let recovery_id = RecoveryId::try_from(&signature_bytes[64] % 27)
4546
.map_err(|_| CacaoError::Verification)?;
4647

4748
let recovered_key = VerifyingKey::recover_from_digest(
48-
Keccak256::new_with_prefix(&self.eip191_bytes(message)),
49+
Keccak256::new_with_prefix(self.eip191_bytes(message)),
4950
&sig,
5051
recovery_id,
5152
)
@@ -55,21 +56,17 @@ impl Eip191 {
5556
.chain_update(&recovered_key.to_encoded_point(false).as_bytes()[1..])
5657
.finalize()[12..];
5758

58-
let address_encoded = hex::encode(add);
59+
let address_encoded = data_encoding::HEXLOWER_PERMISSIVE.encode(add);
5960

60-
if address_encoded.to_lowercase() != guarantee_no_hex_prefix(address).to_lowercase() {
61+
if address_encoded.to_lowercase() != strip_hex_prefix(address).to_lowercase() {
6162
Err(CacaoError::Verification)
6263
} else {
6364
Ok(true)
6465
}
6566
}
6667
}
6768

68-
/// Remove the 0x prefix from a hex string
69-
fn guarantee_no_hex_prefix(s: &str) -> &str {
70-
if let Some(stripped) = s.strip_prefix("0x") {
71-
stripped
72-
} else {
73-
s
74-
}
69+
/// Remove the "0x" prefix from a hex string.
70+
fn strip_hex_prefix(s: &str) -> &str {
71+
s.strip_prefix("0x").unwrap_or(s)
7572
}

relay_rpc/src/auth/cacao/tests.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use crate::auth::cacao::Cacao;
22

33
/// Test that we can verify a Cacao
44
#[test]
5-
fn cacao_verify_success() {
5+
fn verify_success() {
66
let cacao_serialized = r#"{
77
"h": {
88
"t": "eip4361"
@@ -34,7 +34,7 @@ fn cacao_verify_success() {
3434

3535
/// Test that we can verify a Cacao with uppercase address
3636
#[test]
37-
fn cacao_without_lowercase_address_verify_success() {
37+
fn without_lowercase_address_verify_success() {
3838
let cacao_serialized = r#"{"h":{"t":"eip4361"},"p":{"iss":"did:pkh:eip155:1:0xbD4D1935165012e7D29919dB8717A5e670a1a5b1","domain":"https://staging.keys.walletconnect.com","aud":"https://staging.keys.walletconnect.com","version":"1","nonce":"07487c09be5535dcbc341d8e35e5c9b4d3539a802089c42c5b1172dd9ed63c64","iat":"2023-01-25T15:08:36.846Z","statement":"Test","resources":["did:key:451cf9b97c64fcca05fbb0d4c40b886c94133653df5a2b6bd97bd29a0bbcdb37"]},"s":{"t":"eip191","s":"0x8496ad1dd1ddd5cb78ac26b62a6bd1c6cfff703ea3b11a9da29cfca112357ace75cac8ee28d114f9e166a6935ee9ed83151819a9e0ee738a0547116b1d978e351b"}}"#;
3939
let cacao: Cacao = serde_json::from_str(cacao_serialized).unwrap();
4040
let result = cacao.verify();

relay_rpc/src/auth/did.rs

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,7 @@ pub const DID_PREFIX: &str = "did";
33
pub const DID_METHOD_KEY: &str = "key";
44
pub const DID_METHOD_PKH: &str = "pkh";
55

6-
use thiserror::Error as ThisError;
7-
8-
#[derive(Debug, ThisError)]
6+
#[derive(Debug, thiserror::Error)]
97
pub enum DidError {
108
#[error("Invalid issuer DID prefix")]
119
Prefix,
@@ -17,15 +15,13 @@ pub enum DidError {
1715
Format,
1816
}
1917

20-
pub fn extract_did_data<'a>(did: &'a str, method: &'a str) -> Result<&'a str, DidError> {
21-
let data = did
22-
.strip_prefix(DID_PREFIX)
18+
pub fn extract_did_data<'a>(did: &'a str, method: &str) -> Result<&'a str, DidError> {
19+
did.strip_prefix(DID_PREFIX)
2320
.ok_or(DidError::Prefix)?
2421
.strip_prefix(DID_DELIMITER)
2522
.ok_or(DidError::Format)?
2623
.strip_prefix(method)
2724
.ok_or(DidError::Method)?
2825
.strip_prefix(DID_DELIMITER)
29-
.ok_or(DidError::Format)?;
30-
Ok(data)
26+
.ok_or(DidError::Format)
3127
}

0 commit comments

Comments
 (0)