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 async_trait::async_trait;
36//! use http::request::Parts;
37//! use std::time::Duration;
38//!
39//! // Define your credential type
40//! #[derive(Clone, Debug)]
41//! struct MyCredential {
42//!     key: String,
43//!     secret: String,
44//! }
45//!
46//! impl SigningCredential for MyCredential {
47//!     fn is_valid(&self) -> bool {
48//!         !self.key.is_empty() && !self.secret.is_empty()
49//!     }
50//! }
51//!
52//! // Implement credential loader
53//! #[derive(Debug)]
54//! struct MyLoader;
55//!
56//! #[async_trait]
57//! impl ProvideCredential for MyLoader {
58//!     type Credential = MyCredential;
59//!
60//!     async fn provide_credential(&self, _: &Context) -> Result<Option<Self::Credential>> {
61//!         Ok(Some(MyCredential {
62//!             key: "my-access-key".to_string(),
63//!             secret: "my-secret-key".to_string(),
64//!         }))
65//!     }
66//! }
67//!
68//! // Implement request builder
69//! #[derive(Debug)]
70//! struct MyBuilder;
71//!
72//! #[async_trait]
73//! impl SignRequest for MyBuilder {
74//!     type Credential = MyCredential;
75//!
76//!     async fn sign_request(
77//!         &self,
78//!         _ctx: &Context,
79//!         req: &mut Parts,
80//!         _cred: Option<&Self::Credential>,
81//!         _expires_in: Option<Duration>,
82//!     ) -> Result<()> {
83//!         // Add example header
84//!         req.headers.insert("x-custom-auth", "signed".parse()?);
85//!         Ok(())
86//!     }
87//! }
88//!
89//! # async fn example() -> Result<()> {
90//! # use reqsign_core::{FileRead, HttpSend};
91//! # use async_trait::async_trait;
92//! # use bytes::Bytes;
93//! #
94//! # // Mock implementations for the example
95//! # #[derive(Debug, Clone)]
96//! # struct MockFileRead;
97//! # #[async_trait]
98//! # impl FileRead for MockFileRead {
99//! #     async fn file_read(&self, _path: &str) -> Result<Vec<u8>> {
100//! #         Ok(vec![])
101//! #     }
102//! # }
103//! #
104//! # #[derive(Debug, Clone)]
105//! # struct MockHttpSend;
106//! # #[async_trait]
107//! # impl HttpSend for MockHttpSend {
108//! #     async fn http_send(&self, _req: http::Request<Bytes>) -> Result<http::Response<Bytes>> {
109//! #         Ok(http::Response::builder().status(200).body(Bytes::new())?)
110//! #     }
111//! # }
112//! #
113//! // Create a context with your implementations
114//! let ctx = Context::new()
115//!     .with_file_read(MockFileRead)
116//!     .with_http_send(MockHttpSend)
117//!     .with_env(OsEnv);
118//!
119//! // Create a signer
120//! let signer = Signer::new(ctx, MyLoader, MyBuilder);
121//!
122//! // Sign your requests
123//! let mut parts = http::Request::builder()
124//!     .method("GET")
125//!     .uri("https://example.com")
126//!     .body(())
127//!     .unwrap()
128//!     .into_parts()
129//!     .0;
130//!
131//! signer.sign(&mut parts, None).await?;
132//! # Ok(())
133//! # }
134//! ```
135//!
136//! ## Traits
137//!
138//! This crate defines several important traits:
139//!
140//! - [`FileRead`]: For asynchronous file reading
141//! - [`HttpSend`]: For sending HTTP requests
142//! - [`Env`]: For environment variable access
143//! - [`ProvideCredential`]: For loading credentials from various sources
144//! - [`SignRequest`]: For building service-specific signing requests
145//! - [`SigningCredential`]: For validating credentials
146//!
147//! ## Utilities
148//!
149//! The crate also provides utility modules:
150//!
151//! - [`hash`]: Cryptographic hashing utilities
152//! - [`time`]: Time manipulation utilities
153//! - [`utils`]: General utilities including data redaction
154
155// Make sure all our public APIs have docs.
156#![warn(missing_docs)]
157
158/// Error types for reqsign operations
159pub mod error;
160pub mod hash;
161pub mod time;
162pub mod utils;
163
164pub use error::{Error, ErrorKind, Result};
165
166mod context;
167pub use context::CommandExecute;
168pub use context::CommandOutput;
169pub use context::Context;
170pub use context::Env;
171pub use context::FileRead;
172pub use context::HttpSend;
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, ProvideCredentialChain, SignRequest, SigningCredential};
182mod request;
183pub use request::{SigningMethod, SigningRequest};
184mod signer;
185pub use signer::Signer;