This is an automated email from the ASF dual-hosted git repository.
tison pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/opendal-reqsign.git
The following commit(s) were added to refs/heads/main by this push:
new 873fac1 chore: bump major version and encapsulate Timestamp (#643)
873fac1 is described below
commit 873fac195c1b678fa0f47f59d26f32e9015e419a
Author: tison <[email protected]>
AuthorDate: Fri Oct 3 21:40:53 2025 +0800
chore: bump major version and encapsulate Timestamp (#643)
Signed-off-by: tison <[email protected]>
---
Cargo.toml | 22 +-
context/command-execute-tokio/Cargo.toml | 2 +-
context/file-read-tokio/Cargo.toml | 2 +-
context/http-send-reqwest/Cargo.toml | 2 +-
core/Cargo.toml | 2 +-
core/src/time.rs | 234 ++++++++++++++++-----
reqsign/Cargo.toml | 2 +-
services/aliyun-oss/Cargo.toml | 3 +-
services/aliyun-oss/src/credential.rs | 5 +-
.../provide_credential/assume_role_with_oidc.rs | 6 +-
services/aliyun-oss/src/sign_request.rs | 20 +-
services/aws-v4/Cargo.toml | 3 +-
services/aws-v4/src/credential.rs | 5 +-
.../aws-v4/src/provide_credential/assume_role.rs | 3 +-
.../assume_role_with_web_identity.rs | 3 +-
services/aws-v4/src/provide_credential/imds.rs | 10 +-
services/aws-v4/src/provide_credential/process.rs | 14 +-
.../src/provide_credential/s3_express_session.rs | 10 +-
services/aws-v4/src/provide_credential/sso.rs | 9 +-
services/aws-v4/src/sign_request.rs | 41 ++--
services/azure-storage/Cargo.toml | 3 +-
services/azure-storage/src/account_sas.rs | 15 +-
services/azure-storage/src/credential.rs | 5 +-
.../src/provide_credential/azure_cli.rs | 8 +-
.../src/provide_credential/azure_pipelines.rs | 12 +-
.../src/provide_credential/client_certificate.rs | 7 +-
.../src/provide_credential/client_secret.rs | 6 +-
.../azure-storage/src/provide_credential/imds.rs | 3 +-
.../src/provide_credential/workload_identity.rs | 14 +-
services/azure-storage/src/sign_request.rs | 16 +-
services/google/Cargo.toml | 3 +-
services/google/src/credential.rs | 21 +-
.../src/provide_credential/authorized_user.rs | 13 +-
.../src/provide_credential/external_account.rs | 10 +-
.../impersonated_service_account.rs | 10 +-
.../google/src/provide_credential/vm_metadata.rs | 14 +-
services/google/src/sign_request.rs | 16 +-
services/huaweicloud-obs/Cargo.toml | 3 +-
services/huaweicloud-obs/src/sign_request.rs | 36 ++--
services/oracle/Cargo.toml | 3 +-
services/oracle/src/credential.rs | 5 +-
services/oracle/src/provide_credential/config.rs | 6 +-
.../oracle/src/provide_credential/config_file.rs | 6 +-
services/oracle/src/provide_credential/env.rs | 6 +-
services/oracle/src/sign_request.rs | 15 +-
services/tencent-cos/Cargo.toml | 3 +-
services/tencent-cos/src/credential.rs | 5 +-
.../assume_role_with_web_identity.rs | 6 +-
services/tencent-cos/src/sign_request.rs | 15 +-
services/tencent-cos/tests/credential_chain.rs | 4 +-
50 files changed, 379 insertions(+), 308 deletions(-)
diff --git a/Cargo.toml b/Cargo.toml
index f8f218d..df08d4f 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -27,17 +27,17 @@ rust-version = "1.85.0"
[workspace.dependencies]
# Workspace dependencies
-reqsign-aliyun-oss = { version = "1.1.0", path = "services/aliyun-oss" }
-reqsign-aws-v4 = { version = "1.1.0", path = "services/aws-v4" }
-reqsign-azure-storage = { version = "1.1.0", path = "services/azure-storage" }
-reqsign-command-execute-tokio = { version = "1.1.0", path =
"context/command-execute-tokio" }
-reqsign-core = { version = "1.1.0", path = "core" }
-reqsign-file-read-tokio = { version = "1.1.0", path =
"context/file-read-tokio" }
-reqsign-google = { version = "1.1.0", path = "services/google" }
-reqsign-http-send-reqwest = { version = "1.1.0", path =
"context/http-send-reqwest" }
-reqsign-huaweicloud-obs = { version = "1.1.0", path =
"services/huaweicloud-obs" }
-reqsign-oracle = { version = "1.1.0", path = "services/oracle" }
-reqsign-tencent-cos = { version = "1.1.0", path = "services/tencent-cos" }
+reqsign-aliyun-oss = { version = "2.0.0", path = "services/aliyun-oss" }
+reqsign-aws-v4 = { version = "2.0.0", path = "services/aws-v4" }
+reqsign-azure-storage = { version = "2.0.0", path = "services/azure-storage" }
+reqsign-command-execute-tokio = { version = "2.0.0", path =
"context/command-execute-tokio" }
+reqsign-core = { version = "2.0.0", path = "core" }
+reqsign-file-read-tokio = { version = "2.0.0", path =
"context/file-read-tokio" }
+reqsign-google = { version = "2.0.0", path = "services/google" }
+reqsign-http-send-reqwest = { version = "2.0.0", path =
"context/http-send-reqwest" }
+reqsign-huaweicloud-obs = { version = "2.0.0", path =
"services/huaweicloud-obs" }
+reqsign-oracle = { version = "2.0.0", path = "services/oracle" }
+reqsign-tencent-cos = { version = "2.0.0", path = "services/tencent-cos" }
# Crates.io dependencies
anyhow = "1"
diff --git a/context/command-execute-tokio/Cargo.toml
b/context/command-execute-tokio/Cargo.toml
index c4981dc..44cca44 100644
--- a/context/command-execute-tokio/Cargo.toml
+++ b/context/command-execute-tokio/Cargo.toml
@@ -17,7 +17,7 @@
[package]
name = "reqsign-command-execute-tokio"
-version = "1.1.0"
+version = "2.0.0"
categories = ["asynchronous"]
description = "Tokio-based command execution implementation for reqsign"
diff --git a/context/file-read-tokio/Cargo.toml
b/context/file-read-tokio/Cargo.toml
index 417e6a0..b8599c4 100644
--- a/context/file-read-tokio/Cargo.toml
+++ b/context/file-read-tokio/Cargo.toml
@@ -17,7 +17,7 @@
[package]
name = "reqsign-file-read-tokio"
-version = "1.1.0"
+version = "2.0.0"
categories = ["asynchronous"]
description = "Tokio-based file reader implementation for reqsign"
diff --git a/context/http-send-reqwest/Cargo.toml
b/context/http-send-reqwest/Cargo.toml
index 9b361b5..f215dd6 100644
--- a/context/http-send-reqwest/Cargo.toml
+++ b/context/http-send-reqwest/Cargo.toml
@@ -17,7 +17,7 @@
[package]
name = "reqsign-http-send-reqwest"
-version = "1.1.0"
+version = "2.0.0"
categories = ["asynchronous"]
description = "Reqwest-based HTTP client implementation for reqsign."
diff --git a/core/Cargo.toml b/core/Cargo.toml
index 117e7e0..8f7c127 100644
--- a/core/Cargo.toml
+++ b/core/Cargo.toml
@@ -17,7 +17,7 @@
[package]
name = "reqsign-core"
-version = "1.1.0"
+version = "2.0.0"
categories = ["command-line-utilities", "web-programming"]
description = "Signing API requests without effort."
diff --git a/core/src/time.rs b/core/src/time.rs
index d2fd5f6..d538aa5 100644
--- a/core/src/time.rs
+++ b/core/src/time.rs
@@ -18,66 +18,196 @@
//! Time related utils.
use crate::Error;
+use std::fmt;
+use std::ops::{Add, AddAssign, Sub, SubAssign};
+use std::str::FromStr;
+use std::time::{Duration, SystemTime};
-/// DateTime is the alias for `jiff::Timestamp`.
-pub type Timestamp = jiff::Timestamp;
+/// An instant in time represented as the number of nanoseconds since the Unix
epoch.
+#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
+pub struct Timestamp(jiff::Timestamp);
-/// Create datetime of now.
-pub fn now() -> Timestamp {
- Timestamp::now()
+impl FromStr for Timestamp {
+ type Err = Error;
+
+ /// Parse a timestamp by the default [`DateTimeParser`].
+ ///
+ /// All of them are valid time:
+ ///
+ /// - `2022-03-13T07:20:04Z`
+ /// - `2022-03-01T08:12:34+00:00`
+ /// - `2022-03-01T08:12:34.00+00:00`
+ /// - `2022-07-08T02:14:07+02:00[Europe/Paris]`
+ ///
+ /// [`DateTimeParser`]: jiff::fmt::temporal::DateTimeParser
+ fn from_str(s: &str) -> Result<Self, Self::Err> {
+ match s.parse() {
+ Ok(t) => Ok(Timestamp(t)),
+ Err(err) => Err(
+ Error::unexpected(format!("parse '{s}' into timestamp
failed")).with_source(err),
+ ),
+ }
+ }
}
-/// Format time into date: `20220301`
-pub fn format_date(t: Timestamp) -> String {
- t.strftime("%Y%m%d").to_string()
+impl fmt::Display for Timestamp {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "{}", self.0)
+ }
}
-/// Format time into ISO8601: `20220313T072004Z`
-pub fn format_iso8601(t: Timestamp) -> String {
- t.strftime("%Y%m%dT%H%M%SZ").to_string()
+impl Timestamp {
+ /// Create the timestamp of now.
+ pub fn now() -> Self {
+ Self(jiff::Timestamp::now())
+ }
+
+ /// Format the timestamp into date: `20220301`
+ pub fn format_date(self) -> String {
+ self.0.strftime("%Y%m%d").to_string()
+ }
+
+ /// Format the timestamp into ISO8601: `20220313T072004Z`
+ pub fn format_iso8601(self) -> String {
+ self.0.strftime("%Y%m%dT%H%M%SZ").to_string()
+ }
+
+ /// Format the timestamp into http date: `Sun, 06 Nov 1994 08:49:37 GMT`
+ ///
+ /// ## Note
+ ///
+ /// HTTP date is slightly different from RFC2822.
+ ///
+ /// - Timezone is fixed to GMT.
+ /// - Day must be 2 digit.
+ pub fn format_http_date(self) -> String {
+ self.0.strftime("%a, %d %b %Y %T GMT").to_string()
+ }
+
+ /// Format the timestamp into RFC3339 in Zulu: `2022-03-13T07:20:04Z`
+ pub fn format_rfc3339_zulu(self) -> String {
+ self.0.strftime("%FT%TZ").to_string()
+ }
+
+ /// Returns this timestamp as a number of seconds since the Unix epoch.
+ ///
+ /// This only returns the number of whole seconds. That is, if there are
+ /// any fractional seconds in this timestamp, then they are truncated.
+ pub fn as_second(self) -> i64 {
+ self.0.as_second()
+ }
+
+ /// Returns the fractional second component of this timestamp in units of
+ /// nanoseconds.
+ ///
+ /// It is guaranteed that this will never return a value that is greater
+ /// than 1 second (or less than -1 second).
+ pub fn subsec_nanosecond(self) -> i32 {
+ self.0.subsec_nanosecond()
+ }
+
+ /// Convert to `SystemTime`.
+ pub fn as_system_time(self) -> SystemTime {
+ SystemTime::from(self.0)
+ }
+
+ /// Creates a new instant in time from the number of milliseconds elapsed
+ /// since the Unix epoch.
+ ///
+ /// When `millisecond` is negative, it corresponds to an instant in time
+ /// before the Unix epoch. A smaller number corresponds to an instant in
+ /// time further into the past.
+ pub fn from_millisecond(millis: i64) -> crate::Result<Self> {
+ match jiff::Timestamp::from_millisecond(millis) {
+ Ok(t) => Ok(Timestamp(t)),
+ Err(err) => Err(Error::unexpected(format!(
+ "convert '{millis}' milliseconds into timestamp failed"
+ ))
+ .with_source(err)),
+ }
+ }
+
+ /// Creates a new instant in time from the number of seconds elapsed since
+ /// the Unix epoch.
+ ///
+ /// When `second` is negative, it corresponds to an instant in time before
+ /// the Unix epoch. A smaller number corresponds to an instant in time
+ /// further into the past.
+ pub fn from_second(second: i64) -> crate::Result<Self> {
+ match jiff::Timestamp::from_second(second) {
+ Ok(t) => Ok(Timestamp(t)),
+ Err(err) => Err(Error::unexpected(format!(
+ "convert '{second}' seconds into timestamp failed"
+ ))
+ .with_source(err)),
+ }
+ }
+
+ /// Parse a timestamp from RFC2822.
+ ///
+ /// All of them are valid time:
+ ///
+ /// - `Sat, 13 Jul 2024 15:09:59 -0400`
+ /// - `Mon, 15 Aug 2022 16:50:12 GMT`
+ pub fn parse_rfc2822(s: &str) -> crate::Result<Timestamp> {
+ match jiff::fmt::rfc2822::parse(s) {
+ Ok(zoned) => Ok(Timestamp(zoned.timestamp())),
+ Err(err) => {
+ Err(Error::unexpected(format!("parse '{s}' into rfc2822
failed")).with_source(err))
+ }
+ }
+ }
+
+ /// Parse the string format "2023-10-31 21:59:10.000000".
+ pub fn parse_datetime_utc(s: &str) -> crate::Result<Timestamp> {
+ let dt = s.parse::<jiff::civil::DateTime>().map_err(|err| {
+ Error::unexpected(format!("parse '{s}' into datetime
failed")).with_source(err)
+ })?;
+
+ let ts = jiff::tz::TimeZone::UTC.to_timestamp(dt).map_err(|err| {
+ Error::unexpected(format!("convert '{s}' into timestamp
failed")).with_source(err)
+ })?;
+
+ Ok(Timestamp(ts))
+ }
}
-/// Format time into http date: `Sun, 06 Nov 1994 08:49:37 GMT`
-///
-/// ## Note
-///
-/// HTTP date is slightly different from RFC2822.
-///
-/// - Timezone is fixed to GMT.
-/// - Day must be 2 digit.
-pub fn format_http_date(t: Timestamp) -> String {
- t.strftime("%a, %d %b %Y %T GMT").to_string()
+impl Add<Duration> for Timestamp {
+ type Output = Timestamp;
+
+ fn add(self, rhs: Duration) -> Timestamp {
+ let ts = self
+ .0
+ .checked_add(rhs)
+ .expect("adding unsigned duration to timestamp overflowed");
+
+ Timestamp(ts)
+ }
}
-/// Format time into RFC3339: `2022-03-13T07:20:04Z`
-pub fn format_rfc3339(t: Timestamp) -> String {
- t.strftime("%FT%TZ").to_string()
+impl AddAssign<Duration> for Timestamp {
+ fn add_assign(&mut self, rhs: Duration) {
+ *self = *self + rhs
+ }
}
-/// Parse time from RFC3339.
-///
-/// All of them are valid time:
-///
-/// - `2022-03-13T07:20:04Z`
-/// - `2022-03-01T08:12:34+00:00`
-/// - `2022-03-01T08:12:34.00+00:00`
-pub fn parse_rfc3339(s: &str) -> crate::Result<Timestamp> {
- s.parse().map_err(|err| {
- Error::unexpected(format!("parse '{s}' into rfc3339
failed")).with_source(err)
- })
+impl Sub<Duration> for Timestamp {
+ type Output = Timestamp;
+
+ fn sub(self, rhs: Duration) -> Timestamp {
+ let ts = self
+ .0
+ .checked_sub(rhs)
+ .expect("subtracting unsigned duration from timestamp overflowed");
+
+ Timestamp(ts)
+ }
}
-/// Parse time from RFC2822.
-///
-/// All of them are valid time:
-///
-/// - `Sat, 13 Jul 2024 15:09:59 -0400`
-/// - `Mon, 15 Aug 2022 16:50:12 GMT`
-pub fn parse_rfc2822(s: &str) -> crate::Result<Timestamp> {
- let zoned = jiff::fmt::rfc2822::parse(s).map_err(|err| {
- Error::unexpected(format!("parse '{s}' into rfc2822
failed")).with_source(err)
- })?;
- Ok(zoned.timestamp())
+impl SubAssign<Duration> for Timestamp {
+ fn sub_assign(&mut self, rhs: Duration) {
+ *self = *self - rhs
+ }
}
#[cfg(test)]
@@ -85,31 +215,31 @@ mod tests {
use super::*;
fn test_time() -> Timestamp {
- "2022-03-01T08:12:34Z".parse().unwrap()
+ Timestamp("2022-03-01T08:12:34Z".parse().unwrap())
}
#[test]
fn test_format_date() {
let t = test_time();
- assert_eq!("20220301", format_date(t))
+ assert_eq!("20220301", t.format_date())
}
#[test]
fn test_format_ios8601() {
let t = test_time();
- assert_eq!("20220301T081234Z", format_iso8601(t))
+ assert_eq!("20220301T081234Z", t.format_iso8601())
}
#[test]
fn test_format_http_date() {
let t = test_time();
- assert_eq!("Tue, 01 Mar 2022 08:12:34 GMT", format_http_date(t))
+ assert_eq!("Tue, 01 Mar 2022 08:12:34 GMT", t.format_http_date())
}
#[test]
fn test_format_rfc3339() {
let t = test_time();
- assert_eq!("2022-03-01T08:12:34Z", format_rfc3339(t))
+ assert_eq!("2022-03-01T08:12:34Z", t.format_rfc3339_zulu())
}
#[test]
@@ -121,7 +251,7 @@ mod tests {
"2022-03-01T08:12:34+00:00",
"2022-03-01T08:12:34.00+00:00",
] {
- assert_eq!(t, parse_rfc3339(v).expect("must be valid time"));
+ assert_eq!(t, v.parse().expect("must be valid time"));
}
}
}
diff --git a/reqsign/Cargo.toml b/reqsign/Cargo.toml
index 34c1fba..0816666 100644
--- a/reqsign/Cargo.toml
+++ b/reqsign/Cargo.toml
@@ -17,7 +17,7 @@
[package]
name = "reqsign"
-version = "0.17.1"
+version = "0.18.0"
categories = ["authentication", "web-programming::http-client"]
description = "Signing HTTP requests for AWS, Azure, Google, Huawei, Aliyun,
Tencent and Oracle services"
diff --git a/services/aliyun-oss/Cargo.toml b/services/aliyun-oss/Cargo.toml
index fbbc124..09e5b20 100644
--- a/services/aliyun-oss/Cargo.toml
+++ b/services/aliyun-oss/Cargo.toml
@@ -17,7 +17,7 @@
[package]
name = "reqsign-aliyun-oss"
-version = "1.1.0"
+version = "2.0.0"
description = "Aliyun OSS signing implementation for reqsign."
@@ -30,7 +30,6 @@ rust-version.workspace = true
anyhow = { workspace = true }
async-trait = { workspace = true }
http = { workspace = true }
-jiff = { workspace = true }
log = { workspace = true }
percent-encoding = { workspace = true }
reqsign-core = { workspace = true }
diff --git a/services/aliyun-oss/src/credential.rs
b/services/aliyun-oss/src/credential.rs
index 2c66229..495ce51 100644
--- a/services/aliyun-oss/src/credential.rs
+++ b/services/aliyun-oss/src/credential.rs
@@ -16,9 +16,10 @@
// under the License.
use reqsign_core::SigningCredential;
-use reqsign_core::time::{Timestamp, now};
+use reqsign_core::time::Timestamp;
use reqsign_core::utils::Redact;
use std::fmt::{Debug, Formatter};
+use std::time::Duration;
/// Credential that holds the access_key and secret_key.
#[derive(Default, Clone)]
@@ -54,7 +55,7 @@ impl SigningCredential for Credential {
// Take 120s as buffer to avoid edge cases.
if let Some(valid) = self
.expires_in
- .map(|v| v > now() + jiff::SignedDuration::from_mins(2))
+ .map(|v| v > Timestamp::now() + Duration::from_secs(120))
{
return valid;
}
diff --git
a/services/aliyun-oss/src/provide_credential/assume_role_with_oidc.rs
b/services/aliyun-oss/src/provide_credential/assume_role_with_oidc.rs
index e928d6d..cedb3a3 100644
--- a/services/aliyun-oss/src/provide_credential/assume_role_with_oidc.rs
+++ b/services/aliyun-oss/src/provide_credential/assume_role_with_oidc.rs
@@ -18,7 +18,7 @@
use crate::{Credential, constants::*};
use async_trait::async_trait;
use reqsign_core::Result;
-use reqsign_core::time::{format_rfc3339, now, parse_rfc3339};
+use reqsign_core::time::Timestamp;
use reqsign_core::{Context, ProvideCredential};
use serde::Deserialize;
@@ -87,7 +87,7 @@ impl ProvideCredential for
AssumeRoleWithOidcCredentialProvider {
provider_arn,
role_arn,
role_session_name,
- format_rfc3339(now()),
+ Timestamp::now().format_rfc3339_zulu(),
token
);
@@ -119,7 +119,7 @@ impl ProvideCredential for
AssumeRoleWithOidcCredentialProvider {
access_key_id: resp_cred.access_key_id,
access_key_secret: resp_cred.access_key_secret,
security_token: Some(resp_cred.security_token),
- expires_in: Some(parse_rfc3339(&resp_cred.expiration)?),
+ expires_in: Some(resp_cred.expiration.parse()?),
};
Ok(Some(cred))
diff --git a/services/aliyun-oss/src/sign_request.rs
b/services/aliyun-oss/src/sign_request.rs
index e159439..cdc4802 100644
--- a/services/aliyun-oss/src/sign_request.rs
+++ b/services/aliyun-oss/src/sign_request.rs
@@ -22,7 +22,7 @@ use http::header::{AUTHORIZATION, CONTENT_TYPE, DATE};
use percent_encoding::utf8_percent_encode;
use reqsign_core::Result;
use reqsign_core::hash::base64_hmac_sha1;
-use reqsign_core::time::{Timestamp, format_http_date, now};
+use reqsign_core::time::Timestamp;
use reqsign_core::{Context, SignRequest};
use std::collections::HashSet;
use std::fmt::Write;
@@ -60,7 +60,7 @@ impl RequestSigner {
}
fn get_time(&self) -> Timestamp {
- self.time.unwrap_or_else(now)
+ self.time.unwrap_or_else(Timestamp::now)
}
}
@@ -105,7 +105,7 @@ impl RequestSigner {
// Add date header
req.headers
- .insert(DATE, format_http_date(signing_time).parse()?);
+ .insert(DATE, Timestamp::format_http_date(signing_time).parse()?);
// Add security token if present
if let Some(token) = &cred.security_token {
@@ -128,10 +128,7 @@ impl RequestSigner {
signing_time: Timestamp,
expires: Duration,
) -> Result<()> {
- let expiration_time = signing_time
- + jiff::SignedDuration::try_from(expires).map_err(|e| {
- reqsign_core::Error::request_invalid(format!("Invalid
expiration duration: {e}"))
- })?;
+ let expiration_time = signing_time + expires;
let string_to_sign = self.build_string_to_sign(req, cred,
signing_time, Some(expires))?;
let signature =
base64_hmac_sha1(cred.access_key_secret.as_bytes(),
string_to_sign.as_bytes());
@@ -228,16 +225,11 @@ impl RequestSigner {
// Date or Expires
match expires {
Some(expires_duration) => {
- let expiration_time = signing_time
- +
jiff::SignedDuration::try_from(expires_duration).map_err(|e| {
- reqsign_core::Error::request_invalid(format!(
- "Invalid expiration duration: {e}"
- ))
- })?;
+ let expiration_time = signing_time + expires_duration;
writeln!(&mut s, "{}", expiration_time.as_second())?;
}
None => {
- writeln!(&mut s, "{}", format_http_date(signing_time))?;
+ writeln!(&mut s, "{}", signing_time.format_http_date())?;
}
}
diff --git a/services/aws-v4/Cargo.toml b/services/aws-v4/Cargo.toml
index 84b1af9..e576e33 100644
--- a/services/aws-v4/Cargo.toml
+++ b/services/aws-v4/Cargo.toml
@@ -17,7 +17,7 @@
[package]
name = "reqsign-aws-v4"
-version = "1.1.0"
+version = "2.0.0"
description = "AWS SigV4 signing implementation for reqsign."
@@ -36,7 +36,6 @@ async-trait = { workspace = true }
bytes = "1.7.2"
form_urlencoded = { workspace = true }
http = { workspace = true }
-jiff = { workspace = true }
log = { workspace = true }
percent-encoding = { workspace = true }
quick-xml = { workspace = true }
diff --git a/services/aws-v4/src/credential.rs
b/services/aws-v4/src/credential.rs
index edb3806..b2468ea 100644
--- a/services/aws-v4/src/credential.rs
+++ b/services/aws-v4/src/credential.rs
@@ -16,9 +16,10 @@
// under the License.
use reqsign_core::SigningCredential;
-use reqsign_core::time::{Timestamp, now};
+use reqsign_core::time::Timestamp;
use reqsign_core::utils::Redact;
use std::fmt::{Debug, Formatter};
+use std::time::Duration;
/// Credential that holds the access_key and secret_key.
#[derive(Default, Clone)]
@@ -54,7 +55,7 @@ impl SigningCredential for Credential {
// Take 120s as buffer to avoid edge cases.
if let Some(valid) = self
.expires_in
- .map(|v| v > now() + jiff::SignedDuration::from_mins(2))
+ .map(|v| v > Timestamp::now() + Duration::from_secs(120))
{
return valid;
}
diff --git a/services/aws-v4/src/provide_credential/assume_role.rs
b/services/aws-v4/src/provide_credential/assume_role.rs
index a738a9b..6b6a616 100644
--- a/services/aws-v4/src/provide_credential/assume_role.rs
+++ b/services/aws-v4/src/provide_credential/assume_role.rs
@@ -22,7 +22,6 @@ use crate::provide_credential::utils::{parse_sts_error,
sts_endpoint};
use async_trait::async_trait;
use bytes::Bytes;
use quick_xml::de;
-use reqsign_core::time::parse_rfc3339;
use reqsign_core::{Context, Error, ProvideCredential, Result, Signer};
use serde::Deserialize;
use std::fmt::Write;
@@ -238,7 +237,7 @@ impl ProvideCredential for AssumeRoleCredentialProvider {
access_key_id: resp_cred.access_key_id,
secret_access_key: resp_cred.secret_access_key,
session_token: Some(resp_cred.session_token),
- expires_in: Some(parse_rfc3339(&resp_cred.expiration).map_err(|e| {
+ expires_in: Some(resp_cred.expiration.parse().map_err(|e| {
Error::unexpected("failed to parse AssumeRole credential
expiration")
.with_source(e)
.with_context(format!("expiration_value: {}",
resp_cred.expiration))
diff --git
a/services/aws-v4/src/provide_credential/assume_role_with_web_identity.rs
b/services/aws-v4/src/provide_credential/assume_role_with_web_identity.rs
index 87c9933..196892b 100644
--- a/services/aws-v4/src/provide_credential/assume_role_with_web_identity.rs
+++ b/services/aws-v4/src/provide_credential/assume_role_with_web_identity.rs
@@ -20,7 +20,6 @@ use crate::provide_credential::utils::{parse_sts_error,
sts_endpoint};
use async_trait::async_trait;
use bytes::Bytes;
use quick_xml::de;
-use reqsign_core::time::parse_rfc3339;
use reqsign_core::{Context, Error, ProvideCredential, Result, utils::Redact};
use serde::Deserialize;
use std::fmt::{Debug, Formatter};
@@ -211,7 +210,7 @@ impl ProvideCredential for
AssumeRoleWithWebIdentityCredentialProvider {
access_key_id: resp_cred.access_key_id,
secret_access_key: resp_cred.secret_access_key,
session_token: Some(resp_cred.session_token),
- expires_in: Some(parse_rfc3339(&resp_cred.expiration).map_err(|e| {
+ expires_in: Some(resp_cred.expiration.parse().map_err(|e| {
Error::unexpected("failed to parse web identity credential
expiration")
.with_source(e)
.with_context(format!("expiration_value: {}",
resp_cred.expiration))
diff --git a/services/aws-v4/src/provide_credential/imds.rs
b/services/aws-v4/src/provide_credential/imds.rs
index 01eedc9..1ec8bd2 100644
--- a/services/aws-v4/src/provide_credential/imds.rs
+++ b/services/aws-v4/src/provide_credential/imds.rs
@@ -21,10 +21,11 @@ use async_trait::async_trait;
use bytes::Bytes;
use http::Method;
use http::header::CONTENT_LENGTH;
-use reqsign_core::time::{Timestamp, now, parse_rfc3339};
+use reqsign_core::time::Timestamp;
use reqsign_core::{Context, Error, ProvideCredential, Result};
use serde::Deserialize;
use std::sync::{Arc, Mutex};
+use std::time::Duration;
#[derive(Debug, Clone)]
pub struct IMDSv2CredentialProvider {
@@ -68,7 +69,7 @@ impl IMDSv2CredentialProvider {
async fn load_ec2_metadata_token(&self, ctx: &Context) -> Result<String> {
{
let (token, expires_in) = self.token.lock().expect("lock
poisoned").clone();
- if expires_in > now() {
+ if expires_in > Timestamp::now() {
return Ok(token);
}
}
@@ -105,8 +106,7 @@ impl IMDSv2CredentialProvider {
}
let ec2_token = resp.into_body();
// Set expires_in to 10 minutes to enforce re-read.
- let expires_in =
- now() + jiff::SignedDuration::from_secs(21600) -
jiff::SignedDuration::from_secs(600);
+ let expires_in = Timestamp::now() + Duration::from_secs(21600) -
Duration::from_secs(600);
{
*self.token.lock().expect("lock poisoned") = (ec2_token.clone(),
expires_in);
@@ -244,7 +244,7 @@ impl ProvideCredential for IMDSv2CredentialProvider {
access_key_id: resp.access_key_id,
secret_access_key: resp.secret_access_key,
session_token: Some(resp.token),
- expires_in: Some(parse_rfc3339(&resp.expiration).map_err(|e| {
+ expires_in: Some(resp.expiration.parse().map_err(|e| {
Error::unexpected("failed to parse IMDS credential expiration
time")
.with_source(e)
.with_context(format!("expiration_value: {}",
resp.expiration))
diff --git a/services/aws-v4/src/provide_credential/process.rs
b/services/aws-v4/src/provide_credential/process.rs
index 8782199..d3383d1 100644
--- a/services/aws-v4/src/provide_credential/process.rs
+++ b/services/aws-v4/src/provide_credential/process.rs
@@ -19,7 +19,6 @@ use crate::Credential;
use async_trait::async_trait;
use ini::Ini;
use log::debug;
-use reqsign_core::time::Timestamp;
use reqsign_core::{Context, Error, ProvideCredential, Result};
use serde::Deserialize;
@@ -210,16 +209,9 @@ impl ProvideCredential for ProcessCredentialProvider {
};
let output = self.execute_process(ctx, &command).await?;
-
- let expires_in =
- if let Some(exp_str) = &output.expiration {
- Some(exp_str.parse::<Timestamp>().map_err(|e| {
- Error::unexpected(format!("failed to parse expiration
time: {e}"))
- })?)
- } else {
- None
- };
-
+ let expires_in = output
+ .expiration
+ .and_then(|expires_in| expires_in.parse().ok());
Ok(Some(Credential {
access_key_id: output.access_key_id,
secret_access_key: output.secret_access_key,
diff --git a/services/aws-v4/src/provide_credential/s3_express_session.rs
b/services/aws-v4/src/provide_credential/s3_express_session.rs
index c1c5e79..31706f2 100644
--- a/services/aws-v4/src/provide_credential/s3_express_session.rs
+++ b/services/aws-v4/src/provide_credential/s3_express_session.rs
@@ -20,7 +20,6 @@ use async_trait::async_trait;
use bytes::Bytes;
use http::{Method, Request, header};
use log::debug;
-use reqsign_core::time::parse_rfc3339;
use reqsign_core::{Context, Error, ProvideCredential, Result, SignRequest};
use serde::Deserialize;
@@ -160,10 +159,13 @@ impl S3ExpressSessionProvider {
})?;
// Parse expiration time from ISO8601 format
- let expiration =
-
parse_rfc3339(&create_session_resp.credentials.expiration).map_err(|e| {
+ let expiration = create_session_resp
+ .credentials
+ .expiration
+ .parse()
+ .map_err(|e| {
Error::unexpected(format!(
- "Failed to parse expiration time '{}': {e}",
+ "failed to parse expiration time '{}': {e}",
create_session_resp.credentials.expiration
))
})?;
diff --git a/services/aws-v4/src/provide_credential/sso.rs
b/services/aws-v4/src/provide_credential/sso.rs
index 04f9ece..3237f2c 100644
--- a/services/aws-v4/src/provide_credential/sso.rs
+++ b/services/aws-v4/src/provide_credential/sso.rs
@@ -20,7 +20,7 @@ use async_trait::async_trait;
use http::{Method, Request, StatusCode};
use ini::Ini;
use log::{debug, warn};
-use reqsign_core::time::{Timestamp, now};
+use reqsign_core::time::Timestamp;
use reqsign_core::{Context, Error, ProvideCredential, Result};
use serde::Deserialize;
@@ -218,11 +218,8 @@ impl SSOCredentialProvider {
})?;
// Check if token is expired
- let expires_at =
token.expires_at.parse::<Timestamp>().map_err(|e| {
- Error::unexpected(format!("failed to parse expiration
time: {e}"))
- })?;
-
- if expires_at <= now() {
+ let expires_at = token.expires_at.parse::<Timestamp>()?;
+ if expires_at <= Timestamp::now() {
warn!("SSO token is expired");
return Ok(None);
}
diff --git a/services/aws-v4/src/sign_request.rs
b/services/aws-v4/src/sign_request.rs
index 8b9e734..10c583f 100644
--- a/services/aws-v4/src/sign_request.rs
+++ b/services/aws-v4/src/sign_request.rs
@@ -26,7 +26,7 @@ use http::{HeaderValue, header};
use log::debug;
use percent_encoding::{percent_decode_str, utf8_percent_encode};
use reqsign_core::hash::{hex_hmac_sha256, hex_sha256, hmac_sha256};
-use reqsign_core::time::{Timestamp, format_date, format_iso8601, now};
+use reqsign_core::time::Timestamp;
use reqsign_core::{Context, Result, SignRequest, SigningRequest};
use std::fmt::Write;
use std::time::Duration;
@@ -77,7 +77,7 @@ impl SignRequest for RequestSigner {
credential: Option<&Self::Credential>,
expires_in: Option<Duration>,
) -> Result<()> {
- let now = self.time.unwrap_or_else(now);
+ let now = self.time.unwrap_or_else(Timestamp::now);
let mut signed_req = SigningRequest::build(req)?;
let Some(cred) = credential else {
@@ -102,7 +102,7 @@ impl SignRequest for RequestSigner {
// Scope: "20220313/<region>/<service>/aws4_request"
let scope = format!(
"{}/{}/{}/aws4_request",
- format_date(now),
+ now.format_date(),
self.region,
self.service
);
@@ -119,7 +119,7 @@ impl SignRequest for RequestSigner {
writeln!(f, "AWS4-HMAC-SHA256").map_err(|e| {
reqsign_core::Error::unexpected(format!("failed to write
algorithm: {e}"))
})?;
- writeln!(f, "{}", format_iso8601(now)).map_err(|e| {
+ writeln!(f, "{}", now.format_iso8601()).map_err(|e| {
reqsign_core::Error::unexpected(format!("failed to write
timestamp: {e}"))
})?;
writeln!(f, "{}", &scope).map_err(|e| {
@@ -255,7 +255,7 @@ fn canonicalize_header(
if expires_in.is_none() {
// Insert DATE header if not present.
if ctx.headers.get(X_AMZ_DATE).is_none() {
- let date_header =
HeaderValue::try_from(format_iso8601(now)).map_err(|e| {
+ let date_header =
HeaderValue::try_from(now.format_iso8601()).map_err(|e| {
reqsign_core::Error::unexpected(format!("failed to create date
header: {e}"))
})?;
ctx.headers.insert(X_AMZ_DATE, date_header);
@@ -310,12 +310,12 @@ fn canonicalize_query(
format!(
"{}/{}/{}/{}/aws4_request",
cred.access_key_id,
- format_date(now),
+ now.format_date(),
region,
service
),
));
- ctx.query.push(("X-Amz-Date".into(), format_iso8601(now)));
+ ctx.query.push(("X-Amz-Date".into(), now.format_iso8601()));
ctx.query
.push(("X-Amz-Expires".into(), expire.as_secs().to_string()));
ctx.query.push((
@@ -355,20 +355,17 @@ fn generate_signing_key(secret: &str, time: Timestamp,
region: &str, service: &s
// Sign secret
let secret = format!("AWS4{secret}");
// Sign date
- let sign_date = hmac_sha256(secret.as_bytes(),
format_date(time).as_bytes());
+ let sign_date = hmac_sha256(secret.as_bytes(),
time.format_date().as_bytes());
// Sign region
let sign_region = hmac_sha256(sign_date.as_slice(), region.as_bytes());
// Sign service
let sign_service = hmac_sha256(sign_region.as_slice(), service.as_bytes());
// Sign request
-
hmac_sha256(sign_service.as_slice(), "aws4_request".as_bytes())
}
#[cfg(test)]
mod tests {
- use std::time::SystemTime;
-
use super::*;
use crate::provide_credential::StaticCredentialProvider;
use anyhow::Result;
@@ -487,7 +484,7 @@ mod tests {
.expect("url must be valid");
req.headers_mut().insert(
- http::header::CONTENT_LENGTH,
+ header::CONTENT_LENGTH,
HeaderValue::from_str(&content.len().to_string()).expect("must be
valid"),
);
@@ -599,7 +596,7 @@ mod tests {
req.uri().path(),
req.uri().query(),
);
- let now = now();
+ let now = Timestamp::now();
let mut ss = SigningSettings::default();
ss.percent_encoding_mode = PercentEncodingMode::Double;
@@ -616,7 +613,7 @@ mod tests {
.identity(&id)
.region("test")
.name("s3")
- .time(SystemTime::from(now))
+ .time(now.as_system_time())
.settings(ss)
.build()
.expect("signing params must be valid");
@@ -674,13 +671,13 @@ mod tests {
req.uri().path(),
req.uri().query(),
);
- let now = now();
+ let now = Timestamp::now();
let mut ss = SigningSettings::default();
ss.percent_encoding_mode = PercentEncodingMode::Double;
ss.payload_checksum_kind = PayloadChecksumKind::XAmzSha256;
ss.signature_location = SignatureLocation::QueryParams;
- ss.expires_in = Some(std::time::Duration::from_secs(3600));
+ ss.expires_in = Some(Duration::from_secs(3600));
let id = Credentials::new(
"access_key_id",
"secret_access_key",
@@ -693,7 +690,7 @@ mod tests {
.identity(&id)
.region("test")
.name("s3")
- .time(SystemTime::from(now))
+ .time(now.as_system_time())
.settings(ss)
.build()
.expect("signing params must be valid");
@@ -756,7 +753,7 @@ mod tests {
req.uri().path(),
req.uri().query(),
);
- let now = now();
+ let now = Timestamp::now();
let mut ss = SigningSettings::default();
ss.percent_encoding_mode = PercentEncodingMode::Double;
@@ -773,7 +770,7 @@ mod tests {
.identity(&id)
.region("test")
.name("s3")
- .time(SystemTime::from(now))
+ .time(now.as_system_time())
.settings(ss)
.build()
.expect("signing params must be valid");
@@ -834,13 +831,13 @@ mod tests {
req.uri().path(),
req.uri().query(),
);
- let now = now();
+ let now = Timestamp::now();
let mut ss = SigningSettings::default();
ss.percent_encoding_mode = PercentEncodingMode::Double;
ss.payload_checksum_kind = PayloadChecksumKind::XAmzSha256;
ss.signature_location = SignatureLocation::QueryParams;
- ss.expires_in = Some(std::time::Duration::from_secs(3600));
+ ss.expires_in = Some(Duration::from_secs(3600));
let id = Credentials::new(
"access_key_id",
"secret_access_key",
@@ -854,7 +851,7 @@ mod tests {
.region("test")
// .security_token("security_token")
.name("s3")
- .time(SystemTime::from(now))
+ .time(now.as_system_time())
.settings(ss)
.build()
.expect("signing params must be valid");
diff --git a/services/azure-storage/Cargo.toml
b/services/azure-storage/Cargo.toml
index 210807e..edde2b3 100644
--- a/services/azure-storage/Cargo.toml
+++ b/services/azure-storage/Cargo.toml
@@ -17,7 +17,7 @@
[package]
name = "reqsign-azure-storage"
-version = "1.1.0"
+version = "2.0.0"
description = "Azure Storage signing implementation for reqsign."
@@ -33,7 +33,6 @@ base64 = { workspace = true }
bytes = { workspace = true }
form_urlencoded = { workspace = true }
http = { workspace = true }
-jiff = { workspace = true }
log = { workspace = true }
percent-encoding = { workspace = true }
reqsign-core = { workspace = true }
diff --git a/services/azure-storage/src/account_sas.rs
b/services/azure-storage/src/account_sas.rs
index e7c79fc..916c336 100644
--- a/services/azure-storage/src/account_sas.rs
+++ b/services/azure-storage/src/account_sas.rs
@@ -18,7 +18,6 @@
use reqsign_core::Result;
use reqsign_core::hash;
-use reqsign_core::time;
use reqsign_core::time::Timestamp;
/// The default parameters that make up a SAS token
@@ -68,8 +67,8 @@ impl AccountSharedAccessSignature {
self.resource_type,
self.start
.as_ref()
- .map_or("".to_string(), |v|
urlencoded(time::format_rfc3339(*v))),
- time::format_rfc3339(self.expiry),
+ .map_or("".to_string(), |v|
urlencoded(v.format_rfc3339_zulu())),
+ self.expiry.format_rfc3339_zulu(),
self.ip.clone().unwrap_or_default(),
self.protocol
.as_ref()
@@ -93,13 +92,13 @@ impl AccountSharedAccessSignature {
("srt".to_string(), self.resource_type.to_string()),
(
"se".to_string(),
- urlencoded(time::format_rfc3339(self.expiry)),
+ urlencoded(self.expiry.format_rfc3339_zulu()),
),
("sp".to_string(), self.permissions.to_string()),
];
if let Some(start) = &self.start {
- elements.push(("st".to_string(),
urlencoded(time::format_rfc3339(*start))))
+ elements.push(("st".to_string(),
urlencoded(start.format_rfc3339_zulu())))
}
if let Some(ip) = &self.ip {
elements.push(("sip".to_string(), ip.to_string()))
@@ -121,9 +120,9 @@ fn urlencoded(s: String) -> String {
#[cfg(test)]
mod tests {
- use std::str::FromStr;
-
use super::*;
+ use std::str::FromStr;
+ use std::time::Duration;
fn test_time() -> Timestamp {
Timestamp::from_str("2022-03-01T08:12:34Z").unwrap()
@@ -132,7 +131,7 @@ mod tests {
#[test]
fn test_can_generate_sas_token() {
let key = hash::base64_encode("key".as_bytes());
- let expiry = test_time() + jiff::SignedDuration::from_mins(5);
+ let expiry = test_time() + Duration::from_secs(300);
let sign = AccountSharedAccessSignature::new("account".to_string(),
key, expiry);
let token_content = sign.token().expect("token decode failed");
let token = token_content
diff --git a/services/azure-storage/src/credential.rs
b/services/azure-storage/src/credential.rs
index faaa4c4..ae64b13 100644
--- a/services/azure-storage/src/credential.rs
+++ b/services/azure-storage/src/credential.rs
@@ -16,9 +16,10 @@
// under the License.
use reqsign_core::SigningCredential;
-use reqsign_core::time::{Timestamp, now};
+use reqsign_core::time::Timestamp;
use reqsign_core::utils::Redact;
use std::fmt::{Debug, Formatter};
+use std::time::Duration;
/// Credential enum for different Azure Storage authentication methods.
#[derive(Clone)]
@@ -82,7 +83,7 @@ impl SigningCredential for Credential {
}
// Check expiration for bearer tokens (take 20s as buffer to
avoid edge cases)
if let Some(expires) = expires_in {
- *expires > now() + jiff::SignedDuration::from_secs(20)
+ *expires > Timestamp::now() + Duration::from_secs(20)
} else {
true
}
diff --git a/services/azure-storage/src/provide_credential/azure_cli.rs
b/services/azure-storage/src/provide_credential/azure_cli.rs
index 69f112a..abe7d84 100644
--- a/services/azure-storage/src/provide_credential/azure_cli.rs
+++ b/services/azure-storage/src/provide_credential/azure_cli.rs
@@ -96,13 +96,9 @@ impl ProvideCredential for AzureCliCredentialProvider {
// Calculate expiration time
let expires_on = if let Some(timestamp) = token.expires_on_timestamp {
- Some(Timestamp::from_second(timestamp).unwrap())
+ Timestamp::from_second(timestamp).ok()
} else if let Some(expires_str) = token.expires_on {
- // Parse the string format "2023-10-31 21:59:10.000000"
- expires_str
- .parse::<jiff::civil::DateTime>()
- .and_then(|dt| jiff::tz::TimeZone::UTC.to_timestamp(dt))
- .ok()
+ Timestamp::parse_datetime_utc(&expires_str).ok()
} else {
None
};
diff --git a/services/azure-storage/src/provide_credential/azure_pipelines.rs
b/services/azure-storage/src/provide_credential/azure_pipelines.rs
index a1849d0..fef7912 100644
--- a/services/azure-storage/src/provide_credential/azure_pipelines.rs
+++ b/services/azure-storage/src/provide_credential/azure_pipelines.rs
@@ -15,13 +15,13 @@
// specific language governing permissions and limitations
// under the License.
-use std::collections::HashMap;
-
use crate::credential::Credential;
use async_trait::async_trait;
-use reqsign_core::time::now;
+use reqsign_core::time::Timestamp;
use reqsign_core::{Context, ProvideCredential};
use serde::Deserialize;
+use std::collections::HashMap;
+use std::time::Duration;
/// AzurePipelinesCredentialProvider provides credentials using Azure
Pipelines workload identity
///
@@ -233,12 +233,12 @@ impl ProvideCredential for
AzurePipelinesCredentialProvider {
.await?;
// Calculate expiration time
- let expires_in =
std::time::Duration::from_secs(token_response.expires_in);
- let expires_on = now().checked_add(expires_in).ok();
+ let expires_in = Duration::from_secs(token_response.expires_in);
+ let expires_on = Timestamp::now() + expires_in;
Ok(Some(Credential::with_bearer_token(
&token_response.access_token,
- expires_on,
+ Some(expires_on),
)))
}
}
diff --git
a/services/azure-storage/src/provide_credential/client_certificate.rs
b/services/azure-storage/src/provide_credential/client_certificate.rs
index 97bff76..3bbb4f1 100644
--- a/services/azure-storage/src/provide_credential/client_certificate.rs
+++ b/services/azure-storage/src/provide_credential/client_certificate.rs
@@ -23,7 +23,7 @@ use async_trait::async_trait;
use base64::Engine;
use base64::engine::general_purpose::URL_SAFE_NO_PAD;
use jsonwebtoken::{Algorithm, EncodingKey, Header};
-use reqsign_core::time::now;
+use reqsign_core::time::Timestamp;
use reqsign_core::{Context, ProvideCredential};
use rsa::RsaPrivateKey;
use rsa::pkcs8::DecodePrivateKey;
@@ -315,12 +315,11 @@ impl ProvideCredential for
ClientCertificateCredentialProvider {
.await?;
// Calculate expiration time
- let expires_in = Duration::from_secs(token_response.expires_in);
- let expires_on = now().checked_add(expires_in).ok();
+ let expires_on = Timestamp::now() +
Duration::from_secs(token_response.expires_in);
Ok(Some(Credential::with_bearer_token(
&token_response.access_token,
- expires_on,
+ Some(expires_on),
)))
}
}
diff --git a/services/azure-storage/src/provide_credential/client_secret.rs
b/services/azure-storage/src/provide_credential/client_secret.rs
index bde45cd..b46922d 100644
--- a/services/azure-storage/src/provide_credential/client_secret.rs
+++ b/services/azure-storage/src/provide_credential/client_secret.rs
@@ -17,7 +17,9 @@
use crate::Credential;
use async_trait::async_trait;
+use reqsign_core::time::Timestamp;
use reqsign_core::{Context, ProvideCredential, Result};
+use std::time::Duration;
/// Load credential from Azure Client Secret.
///
@@ -90,9 +92,7 @@ impl ProvideCredential for ClientSecretCredentialProvider {
match token {
Some(token_response) => {
- let expires_on = reqsign_core::time::now()
- +
jiff::SignedDuration::from_secs(token_response.expires_in as i64);
-
+ let expires_on = Timestamp::now() +
Duration::from_secs(token_response.expires_in);
Ok(Some(Credential::with_bearer_token(
&token_response.access_token,
Some(expires_on),
diff --git a/services/azure-storage/src/provide_credential/imds.rs
b/services/azure-storage/src/provide_credential/imds.rs
index 963b34f..5c24959 100644
--- a/services/azure-storage/src/provide_credential/imds.rs
+++ b/services/azure-storage/src/provide_credential/imds.rs
@@ -19,6 +19,7 @@ use crate::Credential;
use async_trait::async_trait;
use reqsign_core::time::Timestamp;
use reqsign_core::{Context, ProvideCredential, Result};
+use std::time::Duration;
/// Load credential from Azure Instance Metadata Service (IMDS).
///
@@ -52,7 +53,7 @@ impl ProvideCredential for ImdsCredentialProvider {
let token = get_access_token("https://storage.azure.com/", ctx).await?;
let expires_on = if token.expires_on.is_empty() {
- reqsign_core::time::now() + jiff::SignedDuration::from_mins(10)
+ Timestamp::now() + Duration::from_secs(600)
} else {
// Azure IMDS returns expires_on as Unix timestamp (seconds since
epoch)
let timestamp = token.expires_on.parse::<i64>().map_err(|e| {
diff --git a/services/azure-storage/src/provide_credential/workload_identity.rs
b/services/azure-storage/src/provide_credential/workload_identity.rs
index 500186a..eeea220 100644
--- a/services/azure-storage/src/provide_credential/workload_identity.rs
+++ b/services/azure-storage/src/provide_credential/workload_identity.rs
@@ -17,7 +17,9 @@
use crate::Credential;
use async_trait::async_trait;
+use reqsign_core::time::Timestamp;
use reqsign_core::{Context, ProvideCredential, Result};
+use std::time::Duration;
/// Load credential from Azure Workload Identity.
///
@@ -85,13 +87,11 @@ impl ProvideCredential for
WorkloadIdentityCredentialProvider {
match token {
Some(token_response) => {
let expires_on = match token_response.expires_on {
- Some(expires_on) => {
-
reqsign_core::time::parse_rfc3339(&expires_on).map_err(|e| {
- reqsign_core::Error::unexpected("failed to parse
expires_on time")
- .with_source(e)
- })?
- }
- None => reqsign_core::time::now() +
jiff::SignedDuration::from_mins(10),
+ Some(expires_on) => expires_on.parse().map_err(|e| {
+ reqsign_core::Error::unexpected("failed to parse
expires_on time")
+ .with_source(e)
+ })?,
+ None => Timestamp::now() + Duration::from_secs(600),
};
Ok(Some(Credential::with_bearer_token(
diff --git a/services/azure-storage/src/sign_request.rs
b/services/azure-storage/src/sign_request.rs
index aceb460..98563f0 100644
--- a/services/azure-storage/src/sign_request.rs
+++ b/services/azure-storage/src/sign_request.rs
@@ -23,7 +23,7 @@ use http::{HeaderValue, header};
use log::debug;
use percent_encoding::percent_encode;
use reqsign_core::hash::{base64_decode, base64_hmac_sha256};
-use reqsign_core::time::{Timestamp, format_http_date, now};
+use reqsign_core::time::Timestamp;
use reqsign_core::{Context, Result, SignRequest, SigningMethod,
SigningRequest};
use std::fmt::Write;
use std::time::Duration;
@@ -103,7 +103,7 @@ impl SignRequest for RequestSigner {
SigningMethod::Header => {
ctx.headers.insert(
X_MS_DATE,
- format_http_date(now()).parse().map_err(|e| {
+
Timestamp::now().format_http_date().parse().map_err(|e| {
reqsign_core::Error::unexpected("failed to
parse date header")
.with_source(e)
})?,
@@ -133,11 +133,7 @@ impl SignRequest for RequestSigner {
let signer =
crate::account_sas::AccountSharedAccessSignature::new(
account_name.clone(),
account_key.clone(),
- now()
- +
jiff::SignedDuration::try_from(d).map_err(|e| {
- reqsign_core::Error::unexpected("failed to
convert duration")
- .with_source(e)
- })?,
+ Timestamp::now() + d,
);
let signer_token = signer.token().map_err(|e| {
reqsign_core::Error::unexpected("failed to
generate account SAS token")
@@ -148,7 +144,7 @@ impl SignRequest for RequestSigner {
});
}
SigningMethod::Header => {
- let now_time = self.time.unwrap_or_else(now);
+ let now_time =
self.time.unwrap_or_else(Timestamp::now);
let string_to_sign = string_to_sign(&mut ctx,
account_name, now_time)?;
let decode_content =
base64_decode(account_key).map_err(|e| {
reqsign_core::Error::unexpected("failed to decode
account key")
@@ -377,7 +373,7 @@ fn string_to_sign(
fn canonicalize_header(ctx: &mut SigningRequest, now_time: Timestamp) ->
Result<String> {
ctx.headers.insert(
X_MS_DATE,
- format_http_date(now_time).parse().map_err(|e| {
+ now_time.format_http_date().parse().map_err(|e| {
reqsign_core::Error::unexpected("failed to parse x-ms-date
header").with_source(e)
})?,
);
@@ -462,7 +458,7 @@ mod tests {
.with_env(OsEnv);
let cred = Credential::with_bearer_token(
"token",
- Some(now() + jiff::SignedDuration::from_hours(1)),
+ Some(Timestamp::now() + Duration::from_secs(3600)),
);
let builder = RequestSigner::new();
diff --git a/services/google/Cargo.toml b/services/google/Cargo.toml
index 44e8a45..339d1fd 100644
--- a/services/google/Cargo.toml
+++ b/services/google/Cargo.toml
@@ -17,7 +17,7 @@
[package]
name = "reqsign-google"
-version = "1.1.0"
+version = "2.0.0"
description = "Goole Cloud Platform signing implementation for reqsign."
@@ -29,7 +29,6 @@ rust-version.workspace = true
[dependencies]
async-trait = { workspace = true }
http = { workspace = true }
-jiff = { workspace = true }
jsonwebtoken = "9.2"
log = { workspace = true }
percent-encoding = { workspace = true }
diff --git a/services/google/src/credential.rs
b/services/google/src/credential.rs
index 700ead0..81291ca 100644
--- a/services/google/src/credential.rs
+++ b/services/google/src/credential.rs
@@ -15,10 +15,9 @@
// specific language governing permissions and limitations
// under the License.
-use reqsign_core::{
- Result, SigningCredential as KeyTrait, time::Timestamp, time::now,
utils::Redact,
-};
+use reqsign_core::{Result, SigningCredential as KeyTrait, time::Timestamp,
utils::Redact};
use std::fmt::{self, Debug};
+use std::time::Duration;
/// ServiceAccount holds the client email and private key for service account
authentication.
#[derive(Clone, serde::Deserialize)]
@@ -204,8 +203,8 @@ impl KeyTrait for Token {
match self.expires_at {
Some(expires_at) => {
// Consider token invalid if it expires within 2 minutes
- let buffer = jiff::SignedDuration::from_mins(2);
- now() < expires_at - buffer
+ let buffer = Duration::from_secs(120);
+ Timestamp::now() < expires_at - buffer
}
None => true, // No expiration means always valid
}
@@ -337,15 +336,15 @@ mod tests {
assert!(token.is_valid());
// Token with future expiration
- token.expires_at = Some(now() + jiff::SignedDuration::from_hours(1));
+ token.expires_at = Some(Timestamp::now() + Duration::from_secs(3600));
assert!(token.is_valid());
// Token that expires within 2 minutes
- token.expires_at = Some(now() + jiff::SignedDuration::from_secs(30));
+ token.expires_at = Some(Timestamp::now() + Duration::from_secs(30));
assert!(!token.is_valid());
// Expired token
- token.expires_at = Some(now() - jiff::SignedDuration::from_hours(1));
+ token.expires_at = Some(Timestamp::now() - Duration::from_secs(3600));
assert!(!token.is_valid());
// Empty access token
@@ -417,7 +416,7 @@ mod tests {
// Valid token only
let cred = Credential::with_token(Token {
access_token: "test".to_string(),
- expires_at: Some(now() + jiff::SignedDuration::from_hours(1)),
+ expires_at: Some(Timestamp::now() + Duration::from_secs(3600)),
});
assert!(cred.is_valid());
assert!(!cred.has_service_account());
@@ -439,7 +438,7 @@ mod tests {
});
cred.token = Some(Token {
access_token: "test".to_string(),
- expires_at: Some(now() + jiff::SignedDuration::from_hours(1)),
+ expires_at: Some(Timestamp::now() + Duration::from_secs(3600)),
});
assert!(cred.is_valid());
assert!(cred.has_service_account());
@@ -452,7 +451,7 @@ mod tests {
});
cred.token = Some(Token {
access_token: "test".to_string(),
- expires_at: Some(now() - jiff::SignedDuration::from_hours(1)),
+ expires_at: Some(Timestamp::now() - Duration::from_secs(3600)),
});
assert!(cred.is_valid()); // Still valid because of service account
assert!(!cred.has_valid_token());
diff --git a/services/google/src/provide_credential/authorized_user.rs
b/services/google/src/provide_credential/authorized_user.rs
index f805175..c37e15c 100644
--- a/services/google/src/provide_credential/authorized_user.rs
+++ b/services/google/src/provide_credential/authorized_user.rs
@@ -18,10 +18,11 @@
use http::header::CONTENT_TYPE;
use log::{debug, error};
use serde::{Deserialize, Serialize};
-
-use reqsign_core::{Context, ProvideCredential, Result, time::now};
+use std::time::Duration;
use crate::credential::{Credential, OAuth2Credentials, Token};
+use reqsign_core::time::Timestamp;
+use reqsign_core::{Context, ProvideCredential, Result};
/// OAuth2 refresh token request.
#[derive(Serialize)]
@@ -96,13 +97,11 @@ impl ProvideCredential for AuthorizedUserCredentialProvider
{
let expires_at = token_resp
.expires_in
- .map(|expires_in| now() +
jiff::SignedDuration::from_secs(expires_in as i64));
+ .map(|expires_in| Timestamp::now() +
Duration::from_secs(expires_in));
- let token = Token {
+ Ok(Some(Credential::with_token(Token {
access_token: token_resp.access_token,
expires_at,
- };
-
- Ok(Some(Credential::with_token(token)))
+ })))
}
}
diff --git a/services/google/src/provide_credential/external_account.rs
b/services/google/src/provide_credential/external_account.rs
index a4dba76..c28cca7 100644
--- a/services/google/src/provide_credential/external_account.rs
+++ b/services/google/src/provide_credential/external_account.rs
@@ -22,8 +22,8 @@ use log::{debug, error};
use serde::{Deserialize, Serialize};
use crate::credential::{Credential, ExternalAccount, Token, external_account};
-use reqsign_core::time::parse_rfc3339;
-use reqsign_core::{Context, ProvideCredential, Result, time::now};
+use reqsign_core::time::Timestamp;
+use reqsign_core::{Context, ProvideCredential, Result};
/// The maximum impersonated token lifetime allowed, 1 hour.
const MAX_LIFETIME: Duration = Duration::from_secs(3600);
@@ -178,7 +178,7 @@ impl ExternalAccountCredentialProvider {
let expires_at = token_resp
.expires_in
- .map(|expires_in| now() +
jiff::SignedDuration::from_secs(expires_in as i64));
+ .map(|expires_in| Timestamp::now() +
Duration::from_secs(expires_in));
Ok(Token {
access_token: token_resp.access_token,
@@ -247,11 +247,9 @@ impl ExternalAccountCredentialProvider {
})?;
// Parse expire time from RFC3339 format
- let expires_at = parse_rfc3339(&token_resp.expire_time).ok();
-
Ok(Some(Token {
access_token: token_resp.access_token,
- expires_at,
+ expires_at: token_resp.expire_time.parse().ok(),
}))
}
}
diff --git
a/services/google/src/provide_credential/impersonated_service_account.rs
b/services/google/src/provide_credential/impersonated_service_account.rs
index 6035a6f..5d57c09 100644
--- a/services/google/src/provide_credential/impersonated_service_account.rs
+++ b/services/google/src/provide_credential/impersonated_service_account.rs
@@ -22,8 +22,8 @@ use log::{debug, error};
use serde::{Deserialize, Serialize};
use crate::credential::{Credential, ImpersonatedServiceAccount, Token};
-use reqsign_core::time::parse_rfc3339;
-use reqsign_core::{Context, ProvideCredential, Result, time::now};
+use reqsign_core::time::Timestamp;
+use reqsign_core::{Context, ProvideCredential, Result};
/// The maximum impersonated token lifetime allowed, 1 hour.
const MAX_LIFETIME: Duration = Duration::from_secs(3600);
@@ -137,7 +137,7 @@ impl ImpersonatedServiceAccountCredentialProvider {
let expires_at = token_resp
.expires_in
- .map(|expires_in| now() +
jiff::SignedDuration::from_secs(expires_in as i64));
+ .map(|expires_in| Timestamp::now() +
Duration::from_secs(expires_in));
Ok(Token {
access_token: token_resp.access_token,
@@ -200,11 +200,9 @@ impl ImpersonatedServiceAccountCredentialProvider {
})?;
// Parse expire time from RFC3339 format
- let expires_at = parse_rfc3339(&token_resp.expire_time).ok();
-
Ok(Token {
access_token: token_resp.access_token,
- expires_at,
+ expires_at: token_resp.expire_time.parse().ok(),
})
}
}
diff --git a/services/google/src/provide_credential/vm_metadata.rs
b/services/google/src/provide_credential/vm_metadata.rs
index abf8839..ece9c62 100644
--- a/services/google/src/provide_credential/vm_metadata.rs
+++ b/services/google/src/provide_credential/vm_metadata.rs
@@ -17,10 +17,11 @@
use log::debug;
use serde::Deserialize;
-
-use reqsign_core::{Context, ProvideCredential, Result, time::now};
+use std::time::Duration;
use crate::credential::{Credential, Token};
+use reqsign_core::time::Timestamp;
+use reqsign_core::{Context, ProvideCredential, Result};
/// VM metadata token response.
#[derive(Deserialize)]
@@ -106,13 +107,10 @@ impl ProvideCredential for VmMetadataCredentialProvider {
.with_source(e)
})?;
- let expires_at = now() +
jiff::SignedDuration::from_secs(token_resp.expires_in as i64);
-
- let token = Token {
+ let expires_at = Timestamp::now() +
Duration::from_secs(token_resp.expires_in);
+ Ok(Some(Credential::with_token(Token {
access_token: token_resp.access_token,
expires_at: Some(expires_at),
- };
-
- Ok(Some(Credential::with_token(token)))
+ })))
}
}
diff --git a/services/google/src/sign_request.rs
b/services/google/src/sign_request.rs
index e7aa3f7..4577133 100644
--- a/services/google/src/sign_request.rs
+++ b/services/google/src/sign_request.rs
@@ -47,7 +47,7 @@ struct Claims {
impl Claims {
fn new(client_email: &str, scope: &str) -> Self {
- let current = now().as_second() as u64;
+ let current = Timestamp::now().as_second() as u64;
Claims {
iss: client_email.to_string(),
@@ -157,7 +157,7 @@ impl RequestSigner {
let expires_at = token_resp
.expires_in
- .map(|expires_in| now() +
jiff::SignedDuration::from_secs(expires_in as i64));
+ .map(|expires_in| Timestamp::now() +
Duration::from_secs(expires_in));
Ok(Token {
access_token: token_resp.access_token,
@@ -193,7 +193,7 @@ impl RequestSigner {
expires_in: Duration,
) -> Result<SigningRequest> {
let mut req = SigningRequest::build(parts)?;
- let now = now();
+ let now = Timestamp::now();
// Canonicalize headers
canonicalize_header(&mut req)?;
@@ -215,7 +215,7 @@ impl RequestSigner {
// Build scope
let scope = format!(
"{}/{}/{}/goog4_request",
- format_date(now),
+ now.format_date(),
self.region,
self.service
);
@@ -226,7 +226,7 @@ impl RequestSigner {
let mut f = String::new();
f.push_str("GOOG4-RSA-SHA256");
f.push('\n');
- f.push_str(&format_iso8601(now));
+ f.push_str(&now.format_iso8601());
f.push('\n');
f.push_str(&scope);
f.push('\n');
@@ -282,7 +282,7 @@ impl SignRequest for RequestSigner {
if token.is_valid() {
self.build_token_auth(req, token)?
} else if let Some(sa) = &cred.service_account {
- // Token expired but we have SA, exchange for new token
+ // Token expired, but we have SA, exchange for new
token
debug!("token expired, exchanging service account for
new token");
let new_token = self.exchange_token(ctx, sa).await?;
self.build_token_auth(req, &new_token)?
@@ -385,12 +385,12 @@ fn canonicalize_query(
format!(
"{}/{}/{}/{}/goog4_request",
&cred.client_email,
- format_date(now),
+ now.format_date(),
region,
service
),
));
- req.query.push(("X-Goog-Date".into(), format_iso8601(now)));
+ req.query.push(("X-Goog-Date".into(), now.format_iso8601()));
req.query
.push(("X-Goog-Expires".into(), expire.as_secs().to_string()));
req.query.push((
diff --git a/services/huaweicloud-obs/Cargo.toml
b/services/huaweicloud-obs/Cargo.toml
index eb6c8f7..7337512 100644
--- a/services/huaweicloud-obs/Cargo.toml
+++ b/services/huaweicloud-obs/Cargo.toml
@@ -17,7 +17,7 @@
[package]
name = "reqsign-huaweicloud-obs"
-version = "1.1.0"
+version = "2.0.0"
description = "Huawei Cloud OBS signing implementation for reqsign."
@@ -30,7 +30,6 @@ rust-version.workspace = true
anyhow = { workspace = true }
async-trait = { workspace = true }
http = { workspace = true }
-jiff = { workspace = true }
log = { workspace = true }
percent-encoding = { workspace = true }
reqsign-core = { workspace = true }
diff --git a/services/huaweicloud-obs/src/sign_request.rs
b/services/huaweicloud-obs/src/sign_request.rs
index f1beb57..3725511 100644
--- a/services/huaweicloud-obs/src/sign_request.rs
+++ b/services/huaweicloud-obs/src/sign_request.rs
@@ -33,8 +33,6 @@ use super::constants::*;
use super::credential::Credential;
use reqsign_core::hash::base64_hmac_sha1;
use reqsign_core::time::Timestamp;
-use reqsign_core::time::format_http_date;
-use reqsign_core::time::now;
use reqsign_core::{SignRequest, SigningMethod, SigningRequest};
/// RequestSigner that implement Huawei Cloud Object Storage Service
Authorization.
@@ -81,7 +79,7 @@ impl SignRequest for RequestSigner {
) -> Result<()> {
let k = credential
.ok_or_else(|| reqsign_core::Error::credential_invalid("missing
credential"))?;
- let now = self.time.unwrap_or_else(now);
+ let now = self.time.unwrap_or_else(Timestamp::now);
let method = if let Some(expires_in) = expires_in {
SigningMethod::Query(expires_in)
@@ -96,7 +94,7 @@ impl SignRequest for RequestSigner {
match method {
SigningMethod::Header => {
- ctx.headers.insert(DATE, format_http_date(now).parse()?);
+ ctx.headers.insert(DATE, now.format_http_date().parse()?);
ctx.headers.insert(AUTHORIZATION, {
let mut value: HeaderValue =
format!("OBS {}:{}", k.access_key_id,
signature).parse()?;
@@ -106,14 +104,9 @@ impl SignRequest for RequestSigner {
});
}
SigningMethod::Query(expire) => {
- ctx.headers.insert(DATE, format_http_date(now).parse()?);
+ ctx.headers.insert(DATE, now.format_http_date().parse()?);
ctx.query_push("AccessKeyId", &k.access_key_id);
- ctx.query_push(
- "Expires",
- (now + jiff::SignedDuration::try_from(expire).unwrap())
- .as_second()
- .to_string(),
- );
+ ctx.query_push("Expires", (now +
expire).as_second().to_string());
ctx.query_push(
"Signature",
utf8_percent_encode(&signature,
percent_encoding::NON_ALPHANUMERIC).to_string(),
@@ -163,14 +156,10 @@ fn string_to_sign(
s.write_str("\n")?;
match method {
SigningMethod::Header => {
- writeln!(&mut s, "{}", format_http_date(now))?;
+ writeln!(&mut s, "{}", now.format_http_date())?;
}
SigningMethod::Query(expires) => {
- writeln!(
- &mut s,
- "{}",
- (now +
jiff::SignedDuration::try_from(expires).unwrap()).as_second()
- )?;
+ writeln!(&mut s, "{}", (now + expires).as_second())?;
}
}
@@ -306,7 +295,6 @@ mod tests {
use http::Uri;
use http::header::HeaderName;
use reqsign_core::Result;
- use reqsign_core::time::parse_rfc2822;
use reqsign_core::{Context, OsEnv, Signer};
use reqsign_file_read_tokio::TokioFileRead;
use reqsign_http_send_reqwest::ReqwestHttpSend;
@@ -317,8 +305,8 @@ mod tests {
#[tokio::test]
async fn test_sign() -> Result<()> {
let loader = StaticCredentialProvider::new("access_key", "123456");
- let builder =
- RequestSigner::new("bucket").with_time(parse_rfc2822("Mon, 15 Aug
2022 16:50:12 GMT")?);
+ let builder = RequestSigner::new("bucket")
+ .with_time(Timestamp::parse_rfc2822("Mon, 15 Aug 2022 16:50:12
GMT")?);
let ctx = Context::new()
.with_file_read(TokioFileRead)
@@ -356,8 +344,8 @@ mod tests {
#[tokio::test]
async fn test_sign_with_subresource() -> Result<()> {
let loader = StaticCredentialProvider::new("access_key", "123456");
- let builder =
- RequestSigner::new("bucket").with_time(parse_rfc2822("Mon, 15 Aug
2022 16:50:12 GMT")?);
+ let builder = RequestSigner::new("bucket")
+ .with_time(Timestamp::parse_rfc2822("Mon, 15 Aug 2022 16:50:12
GMT")?);
let ctx = Context::new()
.with_file_read(TokioFileRead)
@@ -397,8 +385,8 @@ mod tests {
#[tokio::test]
async fn test_sign_list_objects() -> Result<()> {
let loader = StaticCredentialProvider::new("access_key", "123456");
- let builder =
- RequestSigner::new("bucket").with_time(parse_rfc2822("Mon, 15 Aug
2022 16:50:12 GMT")?);
+ let builder = RequestSigner::new("bucket")
+ .with_time(Timestamp::parse_rfc2822("Mon, 15 Aug 2022 16:50:12
GMT")?);
let ctx = Context::new()
.with_file_read(TokioFileRead)
diff --git a/services/oracle/Cargo.toml b/services/oracle/Cargo.toml
index 1e258f6..3a86cc7 100644
--- a/services/oracle/Cargo.toml
+++ b/services/oracle/Cargo.toml
@@ -17,7 +17,7 @@
[package]
name = "reqsign-oracle"
-version = "1.1.0"
+version = "2.0.0"
description = "Oracle Cloud signing implementation for reqsign."
@@ -31,7 +31,6 @@ anyhow = { workspace = true }
async-trait = { workspace = true }
base64 = { workspace = true }
http = { workspace = true }
-jiff = { workspace = true }
log = { workspace = true }
reqsign-core = { workspace = true }
rsa = { workspace = true }
diff --git a/services/oracle/src/credential.rs
b/services/oracle/src/credential.rs
index a43052a..d1420f6 100644
--- a/services/oracle/src/credential.rs
+++ b/services/oracle/src/credential.rs
@@ -16,9 +16,10 @@
// under the License.
use reqsign_core::SigningCredential;
-use reqsign_core::time::{Timestamp, now};
+use reqsign_core::time::Timestamp;
use reqsign_core::utils::Redact;
use std::fmt::{Debug, Formatter};
+use std::time::Duration;
/// Credential that holds the API private key information.
#[derive(Default, Clone)]
@@ -59,7 +60,7 @@ impl SigningCredential for Credential {
// Take 120s as buffer to avoid edge cases.
if let Some(valid) = self
.expires_in
- .map(|v| v > now() + jiff::SignedDuration::from_mins(2))
+ .map(|v| v > Timestamp::now() + Duration::from_secs(120))
{
return valid;
}
diff --git a/services/oracle/src/provide_credential/config.rs
b/services/oracle/src/provide_credential/config.rs
index 71d8c5f..a801102 100644
--- a/services/oracle/src/provide_credential/config.rs
+++ b/services/oracle/src/provide_credential/config.rs
@@ -20,8 +20,10 @@
use crate::{Config, Credential};
use async_trait::async_trait;
use log::debug;
+use reqsign_core::time::Timestamp;
use reqsign_core::{Context, ProvideCredential, Result};
use std::sync::Arc;
+use std::time::Duration;
/// Static configuration based loader.
#[derive(Debug)]
@@ -62,9 +64,7 @@ impl ProvideCredential for ConfigCredentialProvider {
key_file: key_file.clone(),
fingerprint: fingerprint.clone(),
// Set expires_in to 10 minutes to enforce re-read
- expires_in: Some(
- reqsign_core::time::now() +
jiff::SignedDuration::from_mins(10),
- ),
+ expires_in: Some(Timestamp::now() +
Duration::from_secs(600)),
}))
}
_ => {
diff --git a/services/oracle/src/provide_credential/config_file.rs
b/services/oracle/src/provide_credential/config_file.rs
index a222b5f..af9e903 100644
--- a/services/oracle/src/provide_credential/config_file.rs
+++ b/services/oracle/src/provide_credential/config_file.rs
@@ -21,7 +21,9 @@ use crate::constants::{
};
use async_trait::async_trait;
use log::debug;
+use reqsign_core::time::Timestamp;
use reqsign_core::{Context, ProvideCredential, Result};
+use std::time::Duration;
/// ConfigFileCredentialProvider loads credentials from Oracle config file
(~/.oci/config).
///
@@ -108,9 +110,7 @@ impl ProvideCredential for ConfigFileCredentialProvider {
user: user.to_string(),
key_file: expanded_key_file,
fingerprint: fingerprint.to_string(),
- expires_in: Some(
- reqsign_core::time::now() +
jiff::SignedDuration::from_mins(10),
- ),
+ expires_in: Some(Timestamp::now() +
Duration::from_secs(600)),
}))
}
_ => {
diff --git a/services/oracle/src/provide_credential/env.rs
b/services/oracle/src/provide_credential/env.rs
index 9f3c41a..8fb093c 100644
--- a/services/oracle/src/provide_credential/env.rs
+++ b/services/oracle/src/provide_credential/env.rs
@@ -17,7 +17,9 @@
use crate::{Credential, constants::*};
use async_trait::async_trait;
+use reqsign_core::time::Timestamp;
use reqsign_core::{Context, ProvideCredential, Result};
+use std::time::Duration;
/// EnvCredentialProvider loads Oracle Cloud credentials from environment
variables.
///
@@ -64,9 +66,7 @@ impl ProvideCredential for EnvCredentialProvider {
tenancy: tenancy.clone(),
key_file: expanded_key_file,
fingerprint: fingerprint.clone(),
- expires_in: Some(
- reqsign_core::time::now() +
jiff::SignedDuration::from_mins(10),
- ),
+ expires_in: Some(Timestamp::now() +
Duration::from_secs(600)),
}))
}
_ => Ok(None),
diff --git a/services/oracle/src/sign_request.rs
b/services/oracle/src/sign_request.rs
index 06ea20c..b7e6115 100644
--- a/services/oracle/src/sign_request.rs
+++ b/services/oracle/src/sign_request.rs
@@ -18,14 +18,11 @@
use crate::Credential;
use async_trait::async_trait;
use base64::{Engine as _, engine::general_purpose};
+use http::header::{AUTHORIZATION, DATE};
use http::request::Parts;
-use http::{
- HeaderValue,
- header::{AUTHORIZATION, DATE},
-};
use log::debug;
use reqsign_core::Result;
-use reqsign_core::time::{format_http_date, now};
+use reqsign_core::time::Timestamp;
use reqsign_core::{Context, SignRequest, SigningRequest};
use rsa::pkcs1v15::SigningKey;
use rsa::sha2::Sha256;
@@ -68,13 +65,13 @@ impl SignRequest for RequestSigner {
return Ok(());
};
- let now = now();
+ let now = Timestamp::now();
let mut signing_req = SigningRequest::build(req)?;
// Construct string to sign
let string_to_sign = {
let mut f = String::new();
- writeln!(f, "date: {}", format_http_date(now))?;
+ writeln!(f, "date: {}", now.format_http_date())?;
writeln!(
f,
"(request-target): {} {}",
@@ -103,7 +100,7 @@ impl SignRequest for RequestSigner {
// Set headers
signing_req
.headers
- .insert(DATE, HeaderValue::from_str(&format_http_date(now))?);
+ .insert(DATE, now.format_http_date().parse()?);
// Build authorization header
let mut auth_value = String::new();
@@ -119,7 +116,7 @@ impl SignRequest for RequestSigner {
signing_req
.headers
- .insert(AUTHORIZATION, HeaderValue::from_str(&auth_value)?);
+ .insert(AUTHORIZATION, auth_value.parse()?);
signing_req.apply(req)
}
diff --git a/services/tencent-cos/Cargo.toml b/services/tencent-cos/Cargo.toml
index e1418ea..5805609 100644
--- a/services/tencent-cos/Cargo.toml
+++ b/services/tencent-cos/Cargo.toml
@@ -17,7 +17,7 @@
[package]
name = "reqsign-tencent-cos"
-version = "1.1.0"
+version = "2.0.0"
description = "Tencent Cloud COS signing implementation for reqsign."
@@ -30,7 +30,6 @@ rust-version.workspace = true
anyhow = { workspace = true }
async-trait = { workspace = true }
http = { workspace = true }
-jiff = { workspace = true }
log = { workspace = true }
percent-encoding = { workspace = true }
reqsign-core = { workspace = true }
diff --git a/services/tencent-cos/src/credential.rs
b/services/tencent-cos/src/credential.rs
index 1c04713..98ac83a 100644
--- a/services/tencent-cos/src/credential.rs
+++ b/services/tencent-cos/src/credential.rs
@@ -16,9 +16,10 @@
// under the License.
use reqsign_core::SigningCredential;
-use reqsign_core::time::{Timestamp, now};
+use reqsign_core::time::Timestamp;
use reqsign_core::utils::Redact;
use std::fmt::{Debug, Formatter};
+use std::time::Duration;
/// Credential for Tencent COS.
#[derive(Default, Clone)]
@@ -52,7 +53,7 @@ impl SigningCredential for Credential {
// Take 120s as buffer to avoid edge cases.
if let Some(valid) = self
.expires_in
- .map(|v| v > now() + jiff::SignedDuration::from_mins(2))
+ .map(|v| v > Timestamp::now() + Duration::from_secs(120))
{
return valid;
}
diff --git
a/services/tencent-cos/src/provide_credential/assume_role_with_web_identity.rs
b/services/tencent-cos/src/provide_credential/assume_role_with_web_identity.rs
index 96cb55e..4805135 100644
---
a/services/tencent-cos/src/provide_credential/assume_role_with_web_identity.rs
+++
b/services/tencent-cos/src/provide_credential/assume_role_with_web_identity.rs
@@ -21,7 +21,7 @@ use async_trait::async_trait;
use http::header::{AUTHORIZATION, CONTENT_LENGTH, CONTENT_TYPE};
use log::debug;
use reqsign_core::Result;
-use reqsign_core::time::{now, parse_rfc3339};
+use reqsign_core::time::Timestamp;
use reqsign_core::{Context, ProvideCredential};
use serde::{Deserialize, Serialize};
@@ -110,7 +110,7 @@ impl ProvideCredential for
AssumeRoleWithWebIdentityCredentialProvider {
.header(CONTENT_LENGTH, bs.len())
.header("X-TC-Action", "AssumeRoleWithWebIdentity")
.header("X-TC-Region", ®ion)
- .header("X-TC-Timestamp", now().as_second())
+ .header("X-TC-Timestamp", Timestamp::now().as_second())
.header("X-TC-Version", "2018-08-13")
.body(bs.into())?;
@@ -140,7 +140,7 @@ impl ProvideCredential for
AssumeRoleWithWebIdentityCredentialProvider {
secret_id: resp_cred.tmp_secret_id,
secret_key: resp_cred.tmp_secret_key,
security_token: Some(resp_cred.token),
- expires_in: Some(parse_rfc3339(&resp_expiration)?),
+ expires_in: Some(resp_expiration.parse()?),
};
Ok(Some(cred))
diff --git a/services/tencent-cos/src/sign_request.rs
b/services/tencent-cos/src/sign_request.rs
index f81249d..bae88d7 100644
--- a/services/tencent-cos/src/sign_request.rs
+++ b/services/tencent-cos/src/sign_request.rs
@@ -23,7 +23,7 @@ use http::request::Parts;
use log::debug;
use percent_encoding::{percent_decode_str, utf8_percent_encode};
use reqsign_core::hash::{hex_hmac_sha1, hex_sha1};
-use reqsign_core::time::{Timestamp, format_http_date, now};
+use reqsign_core::time::Timestamp;
use reqsign_core::{Context, Result, SignRequest, SigningRequest};
use std::time::Duration;
@@ -69,7 +69,7 @@ impl SignRequest for RequestSigner {
return Ok(());
};
- let now = self.time.unwrap_or_else(now);
+ let now = self.time.unwrap_or_else(Timestamp::now);
let mut signing_req = SigningRequest::build(req)?;
if let Some(expires) = expires_in {
@@ -78,7 +78,7 @@ impl SignRequest for RequestSigner {
signing_req
.headers
- .insert(DATE, format_http_date(now).parse()?);
+ .insert(DATE, now.format_http_date().parse()?);
signing_req.query_append(&signature);
if let Some(token) = &cred.security_token {
@@ -93,7 +93,7 @@ impl SignRequest for RequestSigner {
signing_req
.headers
- .insert(DATE, format_http_date(now).parse()?);
+ .insert(DATE, now.format_http_date().parse()?);
signing_req.headers.insert(AUTHORIZATION, {
let mut value: http::HeaderValue = signature.parse()?;
value.set_sensitive(true);
@@ -119,12 +119,7 @@ fn build_signature(
now: Timestamp,
expires: Duration,
) -> String {
- let key_time = format!(
- "{};{}",
- now.as_second(),
- (now + jiff::SignedDuration::try_from(expires).unwrap()).as_second()
- );
-
+ let key_time = format!("{};{}", now.as_second(), (now +
expires).as_second());
let sign_key = hex_hmac_sha1(cred.secret_key.as_bytes(),
key_time.as_bytes());
let mut params = ctx
diff --git a/services/tencent-cos/tests/credential_chain.rs
b/services/tencent-cos/tests/credential_chain.rs
index 6645714..9fdcd3c 100644
--- a/services/tencent-cos/tests/credential_chain.rs
+++ b/services/tencent-cos/tests/credential_chain.rs
@@ -19,11 +19,13 @@
use async_trait::async_trait;
use reqsign_core::ProvideCredentialChain;
+use reqsign_core::time::Timestamp;
use reqsign_core::{Context, OsEnv, ProvideCredential, Result};
use reqsign_file_read_tokio::TokioFileRead;
use reqsign_http_send_reqwest::ReqwestHttpSend;
use reqsign_tencent_cos::{Credential, EnvCredentialProvider};
use std::sync::Arc;
+use std::time::Duration;
/// Mock provider that tracks how many times it was called
#[derive(Debug)]
@@ -199,7 +201,7 @@ impl ProvideCredential for SecurityTokenProvider {
secret_id: "temp_id".to_string(),
secret_key: "temp_key".to_string(),
security_token: Some("security_token".to_string()),
- expires_in: Some(reqsign_core::time::now() +
jiff::SignedDuration::from_hours(1)),
+ expires_in: Some(Timestamp::now() + Duration::from_secs(3600)),
}))
}
}