2 releases
0.3.5 | Jun 17, 2023 |
---|---|
0.3.4 | Jun 5, 2022 |
#572 in Authentication
291 downloads per month
Used in upload-to-s3
24KB
324 lines
s3v4: A crate for signing S3 requests and pre-signing URLs
This crate provides a signature
function that can be used to sign a request to an S3 endpoint
and a pre_signed_url
function for generating a presigned URL.
Both functions return an Error
generated by the error_chain
crate which can be
converted to a String
or accessed through the description
method or display_chain
and backtrace
methods in case a full backtrace is needed.
Examples showing how to upload and download data with signed headers or pre-signed
URLs are provided in the ./examples
folder.
Examples
Signing a request
let signature: s3v4::Signature = s3v4::signature(
url,
method,
&access,
&secret,
®ion,
&"s3",
"UNSIGNED-PAYLOAD", //payload hash, or "UNSIGNED-PAYLOAD"
).map_err(|err| format!("Signature error: {}", err.display_chain()))?;
Using the signature data to make a request
Hyper
let req = Request::builder()
.method(Method::PUT)
.header("x-amz-content-sha256", "UNSIGNED-PAYLOAD")
.header("x-amz-date", &signature.date_time)
.header("authorization", &signature.auth_header)
Ureq
let agent = AgentBuilder::new().build();
let response = agent
.put(&uri)
.set("x-amz-content-sha256", "UNSIGNED-PAYLOAD")
.set("x-amz-date", &signature.date_time)
.set("authorization", &signature.auth_header)
Generting a pre-signed URL
let pre_signed_url = s3v4::pre_signed_url(
&access,
&secret,
expiration,
&url,
&method,
&payload_hash,
®ion,
&date_time,
&service,
)
.map_err(|err| format!("{:?}", err))?;
The following code can be used as is to generate a presigned URL.
use url;
fn main() -> Result<(), String> {
let url =
url::Url::parse(&std::env::args().nth(1).expect("missing url")).expect("malformed URL");
let access = std::env::args().nth(2).expect("missing access");
let secret = std::env::args().nth(3).expect("missing secret");
let method = std::env::args().nth(4).expect("missing method");
let expiration = std::env::args()
.nth(5)
.expect("missing expiration (seconds)")
.parse::<u64>()
.expect("wrong expiration format");
let region = std::env::args().nth(6).expect("missing region");
let service = std::env::args().nth(7).expect("missing service");
let date_time: chrono::DateTime<chrono::Utc> = match std::env::args().nth(8) {
Some(d) => chrono::DateTime::parse_from_rfc3339(&d)
.expect("Invalid date format (should be \"YYYY-MM-DDTHH:MM:SSZ)\"")
.into(),
None => chrono::Utc::now(),
};
let payload_hash = "UNSIGNED-PAYLOAD";
let pre_signed_url = s3v4::pre_signed_url(
&access,
&secret,
expiration,
&url,
&method,
&payload_hash,
®ion,
&date_time,
&service,
)
.map_err(|err| format!("{:?}", err))?;
println!("{}", pre_signed_url);
Ok(())
}
Run with
cargo run --example presign -- <endpoint URL> <access> <secret> <method> \
<expiration in seconds> <region> ["YYYY-MM-DDTHH:MM:SSZ" (timestamp)]
To send the request just use curl
with
-I
forHEAD
requests- --file-upload for
PUT
requests - nothing for
GET
requests
Dependencies
~5–11MB
~134K SLoC