Skip to main content

reqsign_core/
lib.rs

1// Licensed to the Apache Software Foundation (ASF) under one
2// or more contributor license agreements.  See the NOTICE file
3// distributed with this work for additional information
4// regarding copyright ownership.  The ASF licenses this file
5// to you under the Apache License, Version 2.0 (the
6// "License"); you may not use this file except in compliance
7// with the License.  You may obtain a copy of the License at
8//
9//   http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing,
12// software distributed under the License is distributed on an
13// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14// KIND, either express or implied.  See the License for the
15// specific language governing permissions and limitations
16// under the License.
17
18//! Core components for signing API requests.
19//!
20//! This crate provides the foundational types and traits for the reqsign ecosystem.
21//! It defines the core abstractions that enable flexible and extensible request signing.
22//!
23//! ## Overview
24//!
25//! The crate is built around several key concepts:
26//!
27//! - **Context**: A container that holds implementations for file reading, HTTP sending, and environment access
28//! - **Traits**: Abstract interfaces for credential loading (`ProvideCredential`) and request signing (`SignRequest`)
29//! - **Signer**: The main orchestrator that coordinates credential loading and request signing
30//!
31//! ## Example
32//!
33//! ```no_run
34//! use reqsign_core::{Context, OsEnv, ProvideCredential, Result, SignRequest, Signer, SigningCredential};
35//! use http::request::Parts;
36//! use std::time::Duration;
37//!
38//! // Define your credential type
39//! #[derive(Clone, Debug)]
40//! struct MyCredential {
41//!     key: String,
42//!     secret: String,
43//! }
44//!
45//! impl SigningCredential for MyCredential {
46//!     fn is_valid(&self) -> bool {
47//!         !self.key.is_empty() && !self.secret.is_empty()
48//!     }
49//! }
50//!
51//! // Implement credential loader
52//! #[derive(Debug)]
53//! struct MyLoader;
54//!
55//! impl ProvideCredential for MyLoader {
56//!     type Credential = MyCredential;
57//!
58//!     async fn provide_credential(&self, _: &Context) -> Result<Option<Self::Credential>> {
59//!         Ok(Some(MyCredential {
60//!             key: "my-access-key".to_string(),
61//!             secret: "my-secret-key".to_string(),
62//!         }))
63//!     }
64//! }
65//!
66//! // Implement request builder
67//! #[derive(Debug)]
68//! struct MyBuilder;
69//!
70//! impl SignRequest for MyBuilder {
71//!     type Credential = MyCredential;
72//!
73//!     async fn sign_request(
74//!         &self,
75//!         _ctx: &Context,
76//!         req: &mut Parts,
77//!         _cred: Option<&Self::Credential>,
78//!         _expires_in: Option<Duration>,
79//!     ) -> Result<()> {
80//!         // Add example header
81//!         req.headers.insert("x-custom-auth", "signed".parse()?);
82//!         Ok(())
83//!     }
84//! }
85//!
86//! # async fn example() -> Result<()> {
87//! # use reqsign_core::{FileRead, HttpSend};
88//! # use bytes::Bytes;
89//! #
90//! # // Mock implementations for the example
91//! # #[derive(Debug, Clone)]
92//! # struct MockFileRead;
93//! # impl FileRead for MockFileRead {
94//! #     async fn file_read(&self, _path: &str) -> Result<Vec<u8>> {
95//! #         Ok(vec![])
96//! #     }
97//! # }
98//! #
99//! # #[derive(Debug, Clone)]
100//! # struct MockHttpSend;
101//! # impl HttpSend for MockHttpSend {
102//! #     async fn http_send(&self, _req: http::Request<Bytes>) -> Result<http::Response<Bytes>> {
103//! #         Ok(http::Response::builder().status(200).body(Bytes::new())?)
104//! #     }
105//! # }
106//! #
107//! // Create a context with your implementations
108//! let ctx = Context::new()
109//!     .with_file_read(MockFileRead)
110//!     .with_http_send(MockHttpSend)
111//!     .with_env(OsEnv);
112//!
113//! // Create a signer
114//! let signer = Signer::new(ctx, MyLoader, MyBuilder);
115//!
116//! // Sign your requests
117//! let mut parts = http::Request::builder()
118//!     .method("GET")
119//!     .uri("https://example.com")
120//!     .body(())
121//!     .unwrap()
122//!     .into_parts()
123//!     .0;
124//!
125//! signer.sign(&mut parts, None).await?;
126//! # Ok(())
127//! # }
128//! ```
129//!
130//! ## Traits
131//!
132//! This crate defines several important traits:
133//!
134//! - [`FileRead`]: For asynchronous file reading
135//! - [`HttpSend`]: For sending HTTP requests
136//! - [`Env`]: For environment variable access
137//! - [`ProvideCredential`]: For loading credentials from various sources
138//! - [`SignRequest`]: For building service-specific signing requests
139//! - [`SigningCredential`]: For validating credentials
140//!
141//! ## Utilities
142//!
143//! The crate also provides utility modules:
144//!
145//! - [`hash`]: Cryptographic hashing utilities
146//! - [`time`]: Time manipulation utilities
147//! - [`utils`]: General utilities including data redaction
148
149// Make sure all our public APIs have docs.
150#![warn(missing_docs)]
151
152/// Error types for reqsign operations
153pub mod error;
154mod futures_util;
155pub mod hash;
156pub mod time;
157pub mod utils;
158
159pub use error::{Error, ErrorKind, Result};
160pub use futures_util::BoxedFuture;
161pub use futures_util::MaybeSend;
162
163mod context;
164pub use context::CommandExecute;
165pub use context::CommandExecuteDyn;
166pub use context::CommandOutput;
167pub use context::Context;
168pub use context::Env;
169pub use context::FileRead;
170pub use context::FileReadDyn;
171pub use context::HttpSend;
172pub use context::HttpSendDyn;
173pub use context::NoopCommandExecute;
174pub use context::NoopEnv;
175pub use context::NoopFileRead;
176pub use context::NoopHttpSend;
177pub use context::OsEnv;
178pub use context::StaticEnv;
179
180mod api;
181pub use api::ProvideCredential;
182pub use api::ProvideCredentialChain;
183pub use api::ProvideCredentialDyn;
184pub use api::SignRequest;
185pub use api::SignRequestDyn;
186pub use api::SigningCredential;
187mod request;
188pub use request::{SigningMethod, SigningRequest};
189mod signer;
190pub use signer::Signer;