From 07b8a115b133ed4ffa869f430c363114cb3ba574 Mon Sep 17 00:00:00 2001 From: Charles Cunningham Date: Fri, 25 Mar 2022 17:09:07 +0100 Subject: [PATCH] remove siwe feature gate, fix siwe history issues and rename siwe mod --- Cargo.toml | 2 +- src/lib.rs | 8 +-- src/siwe.rs | 140 ------------------------------------------ src/siwe_cacao.rs | 151 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 155 insertions(+), 146 deletions(-) mode change 100755 => 100644 src/siwe.rs create mode 100755 src/siwe_cacao.rs diff --git a/Cargo.toml b/Cargo.toml index f29d9f9..61b088a 100755 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,7 +12,7 @@ repository = "https://github.com/spruceid/cacao/" [features] eip4361 = ["hex", "ethers-core"] zcap = ["ssi"] -default = ["eip4361", "zcap", "siwe"] +default = ["eip4361", "zcap"] [dependencies] siwe = { version = "0.2" } diff --git a/src/lib.rs b/src/lib.rs index 6d200f1..ea993cf 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,13 +3,11 @@ use chrono::{DateTime, Utc}; use http::uri::Authority; use iri_string::types::{UriAbsoluteString, UriString}; pub use siwe::TimeStamp; -use std::str::FromStr; use thiserror::Error; pub mod generic; -#[cfg(feature = "siwe")] -pub mod siwe; +pub mod siwe_cacao; pub struct CACAO where @@ -102,8 +100,8 @@ pub enum Version { pub struct Payload { pub domain: Authority, pub iss: UriAbsoluteString, - pub statement: String, - pub aud: UriAbsoluteString, + pub statement: Option, + pub aud: UriString, pub version: Version, pub nonce: String, pub iat: TimeStamp, diff --git a/src/siwe.rs b/src/siwe.rs old mode 100755 new mode 100644 index 52ffc38..e69de29 --- a/src/siwe.rs +++ b/src/siwe.rs @@ -1,140 +0,0 @@ -use super::{BasicSignature, Payload, SignatureScheme, VerificationError, Version}; -use async_trait::async_trait; -use ethers_core::{types::H160, utils::to_checksum}; -use hex::FromHex; -use siwe::{Message, VerificationError as SVE, Version as SVersion}; - -impl Into for Version { - fn into(self) -> SVersion { - match self { - Self::V1 => SVersion::V1, - } - } -} - -impl From for Version { - fn from(v: SVersion) -> Self { - match v { - SVersion::V1 => Self::V1, - } - } -} - -impl From for VerificationError { - fn from(e: SVE) -> Self { - match e { - SVE::Crypto(_) | SVE::Signer => Self::Crypto, - SVE::Serialization(_) => Self::Serialization, - } - } -} - -impl TryInto for Payload { - type Error = (); - fn try_into(self) -> Result { - let (chain_id, address) = match &self.iss.as_str().split(":").collect::>()[..] { - &["did", "pkh", "eip155", c, h] => { - (c.to_string(), FromHex::from_hex(&h[2..]).map_err(|_| ())?) - } - _ => return Err(()), - }; - Ok(Message { - domain: self.domain, - address, - chain_id, - statement: self.statement, - uri: self.aud, - version: self.version.into(), - nonce: self.nonce, - issued_at: self.iat, - not_before: self.nbf, - expiration_time: self.exp, - request_id: self.request_id, - resources: self.resources, - }) - } -} - -impl From for Payload { - fn from(m: Message) -> Self { - Self { - domain: m.domain, - iss: format!( - "did:pkh:eip155:{}:0x{}", - m.chain_id, - to_checksum(&H160(&m.address), None) - ) - .parse() - .unwrap(), - statement: m.statement, - aud: m.uri, - version: m.version.into(), - nonce: m.nonce, - iat: m.issued_at, - nbf: m.not_before, - exp: m.expiration_time, - request_id: m.request_id, - resources: m.resources, - } - } -} - -pub struct SignInWithEthereum; - -#[async_trait] -impl SignatureScheme for SignInWithEthereum { - type Signature = BasicSignature<[u8; 65]>; - fn id() -> String { - "eip4361-eip191".into() - } - async fn verify(payload: &Payload, sig: &Self::Signature) -> Result<(), VerificationError> { - if !payload.valid_now() { - return Err(VerificationError::NotCurrentlyValid); - }; - let m: Message = payload - .clone() - .try_into() - .map_err(|_| VerificationError::MissingVerificationMaterial)?; - m.verify_eip191(sig.s)?; - Ok(()) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::BasicSignature; - use hex::FromHex; - use siwe::eip4361::Message; - use std::str::FromStr; - - #[async_std::test] - async fn validation() { - // from https://github.com/blockdemy/eth_personal_sign - let message: Payload = Message::from_str( - r#"localhost:4361 wants you to sign in with your Ethereum account: -0x6Da01670d8fc844e736095918bbE11fE8D564163 - -SIWE Notepad Example - -URI: http://localhost:4361 -Version: 1 -Chain ID: 1 -Nonce: kEWepMt9knR6lWJ6A -Issued At: 2021-12-07T18:28:18.807Z"#, - ) - .unwrap() - .into(); - let correct = <[u8; 65]>::from_hex(r#"6228b3ecd7bf2df018183aeab6b6f1db1e9f4e3cbe24560404112e25363540eb679934908143224d746bbb5e1aa65ab435684081f4dbb74a0fec57f98f40f5051c"#).unwrap(); - SignInWithEthereum::verify(&message, &BasicSignature { s: correct }) - .await - .unwrap(); - - let incorrect = <[u8; 65]>::from_hex(r#"7228b3ecd7bf2df018183aeab6b6f1db1e9f4e3cbe24560404112e25363540eb679934908143224d746bbb5e1aa65ab435684081f4dbb74a0fec57f98f40f5051c"#).unwrap(); - assert!( - SignInWithEthereum::verify(&message, &BasicSignature { s: incorrect }) - .await - .is_err() - ); - } -} diff --git a/src/siwe_cacao.rs b/src/siwe_cacao.rs new file mode 100755 index 0000000..dd910ce --- /dev/null +++ b/src/siwe_cacao.rs @@ -0,0 +1,151 @@ +use super::{BasicSignature, Payload, SignatureScheme, VerificationError, Version}; +use async_trait::async_trait; +use ethers_core::{types::H160, utils::to_checksum}; +use hex::FromHex; +use siwe::{Message, VerificationError as SVE, Version as SVersion}; + +impl Into for Version { + fn into(self) -> SVersion { + match self { + Self::V1 => SVersion::V1, + } + } +} + +impl From for Version { + fn from(v: SVersion) -> Self { + match v { + SVersion::V1 => Self::V1, + } + } +} + +impl From for VerificationError { + fn from(e: SVE) -> Self { + match e { + SVE::Crypto(_) | SVE::Signer => Self::Crypto, + SVE::Serialization(_) => Self::Serialization, + SVE::Time => Self::NotCurrentlyValid, + } + } +} + +#[derive(thiserror::Error, Debug)] +pub enum SIWEPayloadConversionError { + #[error(transparent)] + InvalidAddress(#[from] hex::FromHexError), + #[error(transparent)] + InvalidChainId(#[from] std::num::ParseIntError), + #[error("Invalid DID, expected did:pkh")] + InvalidDID, +} + +impl TryInto for Payload { + type Error = SIWEPayloadConversionError; + fn try_into(self) -> Result { + let (chain_id, address) = match &self.iss.as_str().split(":").collect::>()[..] { + &["did", "pkh", "eip155", c, h] if h.get(..2) == Some("0x") => { + (c.parse()?, FromHex::from_hex(&h[2..])?) + } + _ => return Err(Self::Error::InvalidDID), + }; + Ok(Message { + domain: self.domain, + address, + chain_id, + statement: self.statement, + uri: self.aud, + version: self.version.into(), + nonce: self.nonce, + issued_at: self.iat, + not_before: self.nbf, + expiration_time: self.exp, + request_id: self.request_id, + resources: self.resources, + }) + } +} + +impl From for Payload { + fn from(m: Message) -> Self { + Self { + domain: m.domain, + iss: format!( + "did:pkh:eip155:{}:{}", + m.chain_id, + to_checksum(&H160(m.address), None) + ) + .parse() + .unwrap(), + statement: m.statement, + aud: m.uri, + version: m.version.into(), + nonce: m.nonce, + iat: m.issued_at, + nbf: m.not_before, + exp: m.expiration_time, + request_id: m.request_id, + resources: m.resources, + } + } +} + +pub struct SignInWithEthereum; + +#[async_trait] +impl SignatureScheme for SignInWithEthereum { + type Signature = BasicSignature<[u8; 65]>; + fn id() -> String { + "eip4361-eip191".into() + } + async fn verify(payload: &Payload, sig: &Self::Signature) -> Result<(), VerificationError> { + if !payload.valid_now() { + return Err(VerificationError::NotCurrentlyValid); + }; + let m: Message = payload + .clone() + .try_into() + .map_err(|e| VerificationError::MissingVerificationMaterial)?; + m.verify_eip191(&sig.s)?; + Ok(()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::BasicSignature; + use hex::FromHex; + use siwe::Message; + use std::str::FromStr; + + #[async_std::test] + async fn validation() { + // from https://github.com/blockdemy/eth_personal_sign + let message: Payload = Message::from_str( + r#"localhost:4361 wants you to sign in with your Ethereum account: +0x6Da01670d8fc844e736095918bbE11fE8D564163 + +SIWE Notepad Example + +URI: http://localhost:4361 +Version: 1 +Chain ID: 1 +Nonce: kEWepMt9knR6lWJ6A +Issued At: 2021-12-07T18:28:18.807Z"#, + ) + .unwrap() + .into(); + let correct = <[u8; 65]>::from_hex(r#"6228b3ecd7bf2df018183aeab6b6f1db1e9f4e3cbe24560404112e25363540eb679934908143224d746bbb5e1aa65ab435684081f4dbb74a0fec57f98f40f5051c"#).unwrap(); + SignInWithEthereum::verify(&message, &BasicSignature { s: correct }) + .await + .unwrap(); + + let incorrect = <[u8; 65]>::from_hex(r#"7228b3ecd7bf2df018183aeab6b6f1db1e9f4e3cbe24560404112e25363540eb679934908143224d746bbb5e1aa65ab435684081f4dbb74a0fec57f98f40f5051c"#).unwrap(); + assert!( + SignInWithEthereum::verify(&message, &BasicSignature { s: incorrect }) + .await + .is_err() + ); + } +}