bucketwarden-server 0.1.0

BucketWarden storage server runtime.
Documentation
use super::*;

impl BucketWarden {
    pub fn create_multipart_upload(
        &mut self,
        principal: &str,
        request: CreateMultipartUploadRequest,
        lock: ObjectLock,
    ) -> Result<CreateMultipartUploadResult, RuntimeError> {
        if !validate_object_key(&request.key) {
            return Err(RuntimeError::InvalidObjectKey(request.key));
        }
        let resource = object_resource(&request.bucket, &request.key);
        self.authorize(principal, S3Action::CreateMultipartUpload, &resource)?;
        self.require_bucket(&request.bucket)?;
        let upload_id = self.next_upload_id();
        self.multipart_uploads.insert(
            upload_id.clone(),
            MultipartUploadState {
                bucket: request.bucket.clone(),
                key: request.key.clone(),
                metadata: request.metadata,
                lock,
                initiated_epoch_seconds: self.clock_epoch_seconds,
                parts: BTreeMap::new(),
            },
        );
        self.audit_allowed(
            principal,
            S3Action::CreateMultipartUpload,
            &resource,
            Some(upload_id.clone()),
        );
        Ok(CreateMultipartUploadResult {
            bucket: request.bucket,
            key: request.key,
            upload_id,
        })
    }

    pub fn upload_part(
        &mut self,
        principal: &str,
        request: UploadPartRequest,
    ) -> Result<UploadPartResult, RuntimeError> {
        validate_part_number(request.part_number)?;
        let resource = object_resource(&request.bucket, &request.key);
        self.authorize(principal, S3Action::UploadPart, &resource)?;
        let upload = self.multipart_upload(&request.upload_id, &request.bucket, &request.key)?;
        let etag = multipart_etag(&request.body);
        let checksum_sha256 = sha256_hex(&request.body);
        upload.parts.insert(
            request.part_number,
            MultipartPartState {
                etag: etag.clone(),
                body: request.body,
                checksum_sha256,
            },
        );
        self.audit_allowed(
            principal,
            S3Action::UploadPart,
            &resource,
            Some(format!("{}:{}", request.upload_id, request.part_number)),
        );
        Ok(UploadPartResult {
            bucket: request.bucket,
            key: request.key,
            upload_id: request.upload_id,
            part_number: request.part_number,
            etag,
        })
    }

    pub fn upload_part_copy(
        &mut self,
        principal: &str,
        source_bucket: &str,
        source_key: &str,
        source_version_id: Option<&str>,
        mut request: UploadPartRequest,
        source_range: Option<&str>,
    ) -> Result<UploadPartResult, RuntimeError> {
        validate_part_number(request.part_number)?;
        let source_resource = object_resource(source_bucket, source_key);
        let destination_resource = object_resource(&request.bucket, &request.key);
        self.authorize(principal, S3Action::GetObject, &source_resource)?;
        self.authorize(principal, S3Action::UploadPartCopy, &destination_resource)?;
        let mut body = {
            let source = if let Some(version_id) = source_version_id {
                self.version_by_id(source_bucket, source_key, version_id)?
            } else {
                self.current_version(source_bucket, source_key)?
            };
            if source.delete_marker {
                return Err(RuntimeError::NoSuchKey(object_resource(
                    source_bucket,
                    source_key,
                )));
            }
            let source_ciphertext = source.ciphertext.clone();
            let source_integrity = source.integrity.clone();
            let body = match self.kms.decrypt(&source_ciphertext) {
                Ok(body) => body,
                Err(error) => {
                    self.audit_kms_failure(
                        principal,
                        "kms:Decrypt",
                        &source_resource,
                        &source_ciphertext.key_id,
                        &error.to_string(),
                    );
                    return Err(RuntimeError::Kms(error));
                }
            };
            self.verify_integrity_record(&source_integrity, &body)?;
            body
        };
        if let Some(source_range) = source_range {
            let range = parse_copy_source_range(source_range, body.len())?;
            body = body[range.start..=range.end].to_vec();
        }
        request.body = body;
        let upload = self.multipart_upload(&request.upload_id, &request.bucket, &request.key)?;
        let etag = multipart_etag(&request.body);
        let checksum_sha256 = sha256_hex(&request.body);
        upload.parts.insert(
            request.part_number,
            MultipartPartState {
                etag: etag.clone(),
                body: request.body,
                checksum_sha256,
            },
        );
        self.audit_allowed(
            principal,
            S3Action::UploadPartCopy,
            &destination_resource,
            Some(format!(
                "{}:{}:{}",
                source_resource, request.upload_id, request.part_number
            )),
        );
        Ok(UploadPartResult {
            bucket: request.bucket,
            key: request.key,
            upload_id: request.upload_id,
            part_number: request.part_number,
            etag,
        })
    }
}