forked from Deuxfleurs/garage
Alex
5768bf3622
**Specification:** View spec at [this URL](https://git.deuxfleurs.fr/Deuxfleurs/garage/src/branch/k2v/doc/drafts/k2v-spec.md) - [x] Specify the structure of K2V triples - [x] Specify the DVVS format used for causality detection - [x] Specify the K2V index (just a counter of number of values per partition key) - [x] Specify single-item endpoints: ReadItem, InsertItem, DeleteItem - [x] Specify index endpoint: ReadIndex - [x] Specify multi-item endpoints: InsertBatch, ReadBatch, DeleteBatch - [x] Move to JSON objects instead of tuples - [x] Specify endpoints for polling for updates on single values (PollItem) **Implementation:** - [x] Table for K2V items, causal contexts - [x] Indexing mechanism and table for K2V index - [x] Make API handlers a bit more generic - [x] K2V API endpoint - [x] K2V API router - [x] ReadItem - [x] InsertItem - [x] DeleteItem - [x] PollItem - [x] ReadIndex - [x] InsertBatch - [x] ReadBatch - [x] DeleteBatch **Testing:** - [x] Just a simple Python script that does some requests to check visually that things are going right (does not contain parsing of results or assertions on returned values) - [x] Actual tests: - [x] Adapt testing framework - [x] Simple test with InsertItem + ReadItem - [x] Test with several Insert/Read/DeleteItem + ReadIndex - [x] Test all combinations of return formats for ReadItem - [x] Test with ReadBatch, InsertBatch, DeleteBatch - [x] Test with PollItem - [x] Test error codes - [ ] Fix most broken stuff - [x] test PollItem broken randomly - [x] when invalid causality tokens are given, errors should be 4xx not 5xx **Improvements:** - [x] Descending range queries - [x] Specify - [x] Implement - [x] Add test - [x] Batch updates to index counter - [x] Put K2V behind `k2v` feature flag Co-authored-by: Alex Auvolat <alex@adnab.me> Reviewed-on: Deuxfleurs/garage#293 Co-authored-by: Alex <alex@adnab.me> Co-committed-by: Alex <alex@adnab.me>
53 lines
1.5 KiB
Rust
53 lines
1.5 KiB
Rust
use chrono::{DateTime, Utc};
|
|
use hmac::{Hmac, Mac, NewMac};
|
|
use sha2::Sha256;
|
|
|
|
use garage_util::data::{sha256sum, Hash};
|
|
|
|
use crate::error::*;
|
|
|
|
pub mod payload;
|
|
pub mod streaming;
|
|
|
|
pub const SHORT_DATE: &str = "%Y%m%d";
|
|
pub const LONG_DATETIME: &str = "%Y%m%dT%H%M%SZ";
|
|
|
|
type HmacSha256 = Hmac<Sha256>;
|
|
|
|
pub fn verify_signed_content(expected_sha256: Hash, body: &[u8]) -> Result<(), Error> {
|
|
if expected_sha256 != sha256sum(body) {
|
|
return Err(Error::BadRequest(
|
|
"Request content hash does not match signed hash".to_string(),
|
|
));
|
|
}
|
|
Ok(())
|
|
}
|
|
|
|
pub fn signing_hmac(
|
|
datetime: &DateTime<Utc>,
|
|
secret_key: &str,
|
|
region: &str,
|
|
service: &str,
|
|
) -> Result<HmacSha256, crypto_mac::InvalidKeyLength> {
|
|
let secret = String::from("AWS4") + secret_key;
|
|
let mut date_hmac = HmacSha256::new_varkey(secret.as_bytes())?;
|
|
date_hmac.update(datetime.format(SHORT_DATE).to_string().as_bytes());
|
|
let mut region_hmac = HmacSha256::new_varkey(&date_hmac.finalize().into_bytes())?;
|
|
region_hmac.update(region.as_bytes());
|
|
let mut service_hmac = HmacSha256::new_varkey(®ion_hmac.finalize().into_bytes())?;
|
|
service_hmac.update(service.as_bytes());
|
|
let mut signing_hmac = HmacSha256::new_varkey(&service_hmac.finalize().into_bytes())?;
|
|
signing_hmac.update(b"aws4_request");
|
|
let hmac = HmacSha256::new_varkey(&signing_hmac.finalize().into_bytes())?;
|
|
Ok(hmac)
|
|
}
|
|
|
|
pub fn compute_scope(datetime: &DateTime<Utc>, region: &str, service: &str) -> String {
|
|
format!(
|
|
"{}/{}/{}/aws4_request",
|
|
datetime.format(SHORT_DATE),
|
|
region,
|
|
service
|
|
)
|
|
}
|