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;