From 3bdc779505d43397d8dde8d215b6922d5c31ca97 Mon Sep 17 00:00:00 2001 From: bwty Date: Thu, 15 Apr 2021 14:33:47 +0700 Subject: [PATCH 1/6] fix(packet): add regex check for numerical value before handing to chrono Signed-off-by: bwty --- crates/interledger-packet/src/packet.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/crates/interledger-packet/src/packet.rs b/crates/interledger-packet/src/packet.rs index 4d86356a1..44bc8fee8 100644 --- a/crates/interledger-packet/src/packet.rs +++ b/crates/interledger-packet/src/packet.rs @@ -129,12 +129,26 @@ impl TryFrom for Prepare { type Error = ParseError; fn try_from(buffer: BytesMut) -> Result { + use once_cell::sync::OnceCell; + use regex::bytes::Regex; + let (content_offset, mut content) = deserialize_envelope(PacketType::Prepare, &buffer)?; let content_len = content.len(); let amount = content.read_u64::()?; let mut expires_at = [0x00; 17]; content.read_exact(&mut expires_at)?; + + static RE: OnceCell = OnceCell::new(); + // Not using digit here as unicode feature needs to be enabled + let re = RE.get_or_init(|| Regex::new(r"[0-9]{17}").unwrap()); + + if !re.is_match(&expires_at) { + return Err(ParseError::InvalidPacket( + "DateTime must be numberical".into(), + )); + } + let expires_at = str::from_utf8(&expires_at[..])?; let expires_at: DateTime = Utc.datetime_from_str(&expires_at, INTERLEDGER_TIMESTAMP_FORMAT)?; From 169f721e53751b365fe8bcf5de26f10e575ee651 Mon Sep 17 00:00:00 2001 From: bwty Date: Thu, 15 Apr 2021 15:24:52 +0700 Subject: [PATCH 2/6] test: datetime ensure error with invalid characters Signed-off-by: bwty --- crates/interledger-packet/src/packet.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/crates/interledger-packet/src/packet.rs b/crates/interledger-packet/src/packet.rs index 44bc8fee8..4aabb9945 100644 --- a/crates/interledger-packet/src/packet.rs +++ b/crates/interledger-packet/src/packet.rs @@ -755,6 +755,14 @@ mod test_prepare { assert!(Prepare::try_from(prep).is_err()); } + #[test] + fn test_invalid_datetime() { + let mut prep = BytesMut::from(PREPARE_BYTES); + // content offset = 4 bytes, amount is 8 bytes, datetime start at prep[12] + prep[12] = 42; // convert a byte from the datetime to a junk character + assert!(Prepare::try_from(prep).is_err()); + } + #[test] fn test_try_from() { assert_eq!( From 37becb7c52fedf366ca9774e9941f5334be6b661 Mon Sep 17 00:00:00 2001 From: bwty Date: Thu, 15 Apr 2021 15:25:32 +0700 Subject: [PATCH 3/6] doc: Prepare package datetime spec Signed-off-by: bwty --- crates/interledger-packet/src/packet.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/crates/interledger-packet/src/packet.rs b/crates/interledger-packet/src/packet.rs index 4aabb9945..69a95937f 100644 --- a/crates/interledger-packet/src/packet.rs +++ b/crates/interledger-packet/src/packet.rs @@ -136,6 +136,8 @@ impl TryFrom for Prepare { let content_len = content.len(); let amount = content.read_u64::()?; + // Fixed Length DateTime format - RFC 0027 + // https://github.com/interledger/rfcs/blob/2dfdcf47ac52489a4ad473a5d869cd9f0217db67/0027-interledger-protocol-4/0027-interledger-protocol-4.md#ilp-prepare let mut expires_at = [0x00; 17]; content.read_exact(&mut expires_at)?; From a06ca2b57d77dc74451e7341c110fa22cda8a51d Mon Sep 17 00:00:00 2001 From: bwty Date: Thu, 15 Apr 2021 15:50:22 +0700 Subject: [PATCH 4/6] fix typo Signed-off-by: bwty --- crates/interledger-packet/src/packet.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/interledger-packet/src/packet.rs b/crates/interledger-packet/src/packet.rs index 69a95937f..4e8dbe334 100644 --- a/crates/interledger-packet/src/packet.rs +++ b/crates/interledger-packet/src/packet.rs @@ -147,7 +147,7 @@ impl TryFrom for Prepare { if !re.is_match(&expires_at) { return Err(ParseError::InvalidPacket( - "DateTime must be numberical".into(), + "DateTime must be numerical".into(), )); } From 945f29bc627927847a8f542cc4314213919f7f6b Mon Sep 17 00:00:00 2001 From: bwty Date: Thu, 15 Apr 2021 19:12:44 +0700 Subject: [PATCH 5/6] fix: test roundtrip for timestamp conversion Signed-off-by: bwty --- crates/interledger-packet/src/packet.rs | 29 ++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/crates/interledger-packet/src/packet.rs b/crates/interledger-packet/src/packet.rs index 4e8dbe334..783db0dd3 100644 --- a/crates/interledger-packet/src/packet.rs +++ b/crates/interledger-packet/src/packet.rs @@ -758,11 +758,30 @@ mod test_prepare { } #[test] - fn test_invalid_datetime() { - let mut prep = BytesMut::from(PREPARE_BYTES); - // content offset = 4 bytes, amount is 8 bytes, datetime start at prep[12] - prep[12] = 42; // convert a byte from the datetime to a junk character - assert!(Prepare::try_from(prep).is_err()); + fn test_invalid_ts() { + use std::convert::TryInto; + for i in 12..(12 + 17) { + let mut prep = BytesMut::from(PREPARE_BYTES); + prep[i] = 9; // convert a byte from the address to a junk character + let x = match Prepare::try_from(prep) { + Ok(x) => x, + Err(_) => { + continue; + } + }; + + let built = PrepareBuilder { + amount: x.amount(), + expires_at: x.expires_at(), + execution_condition: x.execution_condition().try_into().unwrap(), + destination: x.destination(), + data: x.data(), + } + .build(); + + assert_eq!(x, built); + assert_eq!(BytesMut::from(x), BytesMut::from(built)); + } } #[test] From 336c1a312e40ae582ffe98573a0933de8f6f57d7 Mon Sep 17 00:00:00 2001 From: bwty Date: Thu, 15 Apr 2021 21:08:49 +0700 Subject: [PATCH 6/6] fix: test with asserts Signed-off-by: bwty --- crates/interledger-packet/src/packet.rs | 25 +++---------------------- 1 file changed, 3 insertions(+), 22 deletions(-) diff --git a/crates/interledger-packet/src/packet.rs b/crates/interledger-packet/src/packet.rs index 783db0dd3..812e1cae2 100644 --- a/crates/interledger-packet/src/packet.rs +++ b/crates/interledger-packet/src/packet.rs @@ -146,9 +146,7 @@ impl TryFrom for Prepare { let re = RE.get_or_init(|| Regex::new(r"[0-9]{17}").unwrap()); if !re.is_match(&expires_at) { - return Err(ParseError::InvalidPacket( - "DateTime must be numerical".into(), - )); + return Err(ParseError::InvalidPacket("DateTime must be numeric".into())); } let expires_at = str::from_utf8(&expires_at[..])?; @@ -759,28 +757,11 @@ mod test_prepare { #[test] fn test_invalid_ts() { - use std::convert::TryInto; for i in 12..(12 + 17) { let mut prep = BytesMut::from(PREPARE_BYTES); prep[i] = 9; // convert a byte from the address to a junk character - let x = match Prepare::try_from(prep) { - Ok(x) => x, - Err(_) => { - continue; - } - }; - - let built = PrepareBuilder { - amount: x.amount(), - expires_at: x.expires_at(), - execution_condition: x.execution_condition().try_into().unwrap(), - destination: x.destination(), - data: x.data(), - } - .build(); - - assert_eq!(x, built); - assert_eq!(BytesMut::from(x), BytesMut::from(built)); + let err = Prepare::try_from(prep).unwrap_err(); + assert_eq!("Invalid Packet: DateTime must be numeric", &err.to_string()); } }