# s3v4: A crate for signing S3 requests and pre-signing URLs [reference](https://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-query-string-auth.html) 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 ```rust 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 ```rust 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 ```rust 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 ```rust 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. ```rust 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::() .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 = 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 ```shell cargo run --example presign -- \ ["YYYY-MM-DDTHH:MM:SSZ" (timestamp)] ``` To send the request just use `curl` with * `-I` for `HEAD` requests * --file-upload for `PUT` requests * nothing for `GET` requests