Skip to content

Commit

Permalink
chore:Rust release 0.2.0 (#1526)
Browse files Browse the repository at this point in the history
* chore:Rust release 0.2.0
  • Loading branch information
ajewellamz authored Dec 19, 2024
1 parent a4ca2f9 commit e10fed9
Show file tree
Hide file tree
Showing 168 changed files with 21,630 additions and 4,855 deletions.
2 changes: 1 addition & 1 deletion DynamoDbEncryption/runtimes/rust/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "aws-db-esdk"
version = "0.1.1"
version = "0.2.0"
edition = "2021"
rust-version = "1.81.0"
keywords = ["cryptography", "security", "dynamodb", "encryption", "client-side"]
Expand Down
2 changes: 1 addition & 1 deletion DynamoDbEncryption/runtimes/rust/start_release.sh
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ perl -pe "s/^version = .*$/version = \"$1\"/" < Cargo.toml > new_Cargo.toml
mv new_Cargo.toml Cargo.toml

# Remove all files and directories in src except for specified files
find src -depth 1 | egrep -v '(intercept.rs|lib.rs|software_externs.rs)' | xargs rm -rf
find src -depth 1 | egrep -v '(intercept.rs|lib.rs|software_externs.rs|README)' | xargs rm -rf

# Change to the parent directory and run make polymorph and transpile commands
cd ../..
Expand Down
21 changes: 11 additions & 10 deletions releases/rust/db_esdk/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
[package]
name = "aws-db-esdk"
version = "0.1.1"
version = "0.2.0"
edition = "2021"
rust-version = "1.80.0"
rust-version = "1.81.0"
keywords = ["cryptography", "security", "dynamodb", "encryption", "client-side"]
license = "ISC AND (Apache-2.0 OR ISC)"
description = "aws-db-esdk is a library for implementing client side encryption with DynamoDB."
Expand All @@ -16,18 +16,19 @@ readme = "README.md"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
aws-config = "1.5.10"
aws-lc-rs = "1.11.1"
aws-lc-sys = "0.23.1"
aws-sdk-dynamodb = "1.54.0"
aws-sdk-kms = "1.50.0"
aws-config = "1.5.11"
aws-lc-rs = "1.12.0"
aws-lc-sys = "0.24.0"
aws-sdk-dynamodb = "1.56.0"
aws-sdk-kms = "1.52.0"
aws-smithy-runtime-api = {version = "1.7.3", features = ["client"] }
aws-smithy-types = "1.2.9"
chrono = "0.4.38"
aws-smithy-types = "1.2.10"
chrono = "0.4.39"
cpu-time = "1.0.0"
dafny-runtime = "0.1.1"
dashmap = "6.1.0"
pem = "3.0.4"
tokio = {version = "1.41.1", features = ["full"] }
tokio = {version = "1.42.0", features = ["full"] }
uuid = { version = "1.11.0", features = ["v4"] }

[[example]]
Expand Down
68 changes: 17 additions & 51 deletions releases/rust/db_esdk/README.md
Original file line number Diff line number Diff line change
@@ -1,64 +1,30 @@
# AWS Database Encryption SDK for DynamoDB

AWS Database Encryption SDK for DynamoDB
[![build status](https://github.com/aws/aws-database-encryption-sdk-dynamodb/actions/workflows/daily_ci.yml/badge.svg?branch=main)](https://github.com/aws/aws-database-encryption-sdk-dynamodb/actions/workflows/daily_ci.yml)
[![crates.io](https://img.shields.io/crates/v/aws-db-esdk.svg)](https://crates.io/crates/aws-db-esdk)
[![docs](https://docs.rs/aws-db-esdk/badge.svg)](https://docs.rs/aws-db-esdk)
[![rustc](https://img.shields.io/badge/rust-1.81%2B-orange.svg)](https://img.shields.io/badge/rust-1.81%2B-orange.svg)

## Using the AWS Database Encryption SDK for DynamoDB for Rust
This is the official [AWS Database Encryption SDK (DB-ESDK) for DynamoDB in Rust](https://crates.io/crates/aws-db-esdk).

The AWS Database Encryption SDK for DynamoDB is available on [Crates.io](https://www.crates.io/).
## [CHANGELOG](https://github.com/aws/aws-database-encryption-sdk-dynamodb/blob/main/CHANGELOG.md)

## Building the AWS Database Encryption SDK for DynamoDB
## Overview

To build, the AWS Database Encryption SDK for DynamoDB requires the most up to date version of [Dafny](https://github.com/dafny-lang/dafny) on your PATH.
The AWS Database Encryption SDK (DB-ESDK) for DynamoDB is a client-side encryption
library that allows you to perform attribute-level encryption, enabling you to encrypt specific
attribute values within items before storing them in your DynamoDB table. All encryption and
decryption are performed within your application. This lets you protect sensitive data in-transit
and at-rest, as data cannot be exposed unless decrypted by your application.

You will also need to ensure that you fetch all submodules using either `git clone --recursive ...` when cloning the repository or `git submodule update --init` on an existing clone.
For more details about the design and architecture of the DB-ESDK for DynamoDB,
see the [AWS Database Encryption SDK Developer Guide](https://docs.aws.amazon.com/database-encryption-sdk/latest/devguide/).

To setup your project to use the AWS Database Encryption SDK for DynamoDB in Rust, run:
## Examples for AWS Database Encryption SDK in Rust

```
cd DynamoDbEncryption
# Polymorph smithy to Rust
make polymorph_rust
# Transpile Dafny to Rust
make transpile_rust
# Build Project
cd runtimes/rust
cargo build
```
Please look at the Examples on how to use the AWS Database Encryption SDK in Rust [here](https://github.com/aws/aws-database-encryption-sdk-dynamodb/tree/main/DynamoDbEncryption/runtimes/rust/examples).

### (Optional) Set up the AWS Database Encryption SDK for DynamoDB to work with AWS KMS

If you set up the AWS Database Encryption SDK for DynamoDB to use the AWS KMS Keyring,
the AWS Database Encryption SDK for DynamoDB will make calls to AWS KMS on your behalf,
using the appropriate AWS SDK.

However, you must first set up AWS credentials for use with the AWS SDK.

## Testing the AWS Database Encryption SDK for DynamoDB for Rust

### Configure AWS credentials

To run the test suite you must first set up AWS credentials for use with the AWS SDK.
This is required in order to run the integration tests, which use a KMS Keyring against a publicly accessible KMS CMK.

### Run the tests

Run the test suite with:

```
cd AwsEncryptionSDK
make test_rust
```

Run tests on examples, to ensure they are up to date:

```
cd AwsEncryptionSDK/runtimes/rust/
cargo test --examples
```

Please look at the Examples on how to use the Encryption SDK in Rust [here](examples).

Please note that tests and test vectors require internet access and valid AWS credentials, since calls to KMS are made as part of the test workflow.
Please note that some examples MAY require internet access and valid AWS credentials, since calls to KMS are made.

## License

Expand Down
12 changes: 6 additions & 6 deletions releases/rust/db_esdk/examples/basic_get_put_example.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@ use crate::test_utils;
use aws_sdk_dynamodb::types::AttributeValue;
use std::collections::HashMap;

use aws_db_esdk::aws_cryptography_dbEncryptionSdk_structuredEncryption::types::CryptoAction;
use aws_db_esdk::aws_cryptography_materialProviders::client;
use aws_db_esdk::aws_cryptography_materialProviders::types::material_providers_config::MaterialProvidersConfig;
use aws_db_esdk::CryptoAction;
use aws_db_esdk::material_providers::client;
use aws_db_esdk::material_providers::types::material_providers_config::MaterialProvidersConfig;

use aws_db_esdk::aws_cryptography_dbEncryptionSdk_dynamoDb::types::DynamoDbTableEncryptionConfig;
use aws_db_esdk::aws_cryptography_materialProviders::types::DbeAlgorithmSuiteId;
use aws_db_esdk::dynamodb::types::DynamoDbTableEncryptionConfig;
use aws_db_esdk::material_providers::types::DbeAlgorithmSuiteId;
use aws_db_esdk::intercept::DbEsdkInterceptor;
use aws_db_esdk::types::dynamo_db_tables_encryption_config::DynamoDbTablesEncryptionConfig;

Expand Down Expand Up @@ -116,7 +116,7 @@ pub async fn put_item_get_item() -> Result<(), crate::BoxError> {
// 5. Create a new AWS SDK DynamoDb client using the TableEncryptionConfigs
let sdk_config = aws_config::load_defaults(aws_config::BehaviorVersion::latest()).await;
let dynamo_config = aws_sdk_dynamodb::config::Builder::from(&sdk_config)
.interceptor(DbEsdkInterceptor::new(table_configs))
.interceptor(DbEsdkInterceptor::new(table_configs)?)
.build();
let ddb = aws_sdk_dynamodb::Client::from_conf(dynamo_config);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@

use super::regional_role_client_supplier::RegionalRoleClientSupplier;
use crate::test_utils;
use aws_db_esdk::aws_cryptography_dbEncryptionSdk_dynamoDb::types::DynamoDbTableEncryptionConfig;
use aws_db_esdk::aws_cryptography_dbEncryptionSdk_structuredEncryption::types::CryptoAction;
use aws_db_esdk::aws_cryptography_materialProviders::client as mpl_client;
use aws_db_esdk::aws_cryptography_materialProviders::types::material_providers_config::MaterialProvidersConfig;
use aws_db_esdk::aws_cryptography_materialProviders::types::DiscoveryFilter;
use aws_db_esdk::dynamodb::types::DynamoDbTableEncryptionConfig;
use aws_db_esdk::CryptoAction;
use aws_db_esdk::material_providers::client as mpl_client;
use aws_db_esdk::material_providers::types::material_providers_config::MaterialProvidersConfig;
use aws_db_esdk::material_providers::types::DiscoveryFilter;
use aws_db_esdk::intercept::DbEsdkInterceptor;
use aws_db_esdk::DynamoDbTablesEncryptionConfig;
use aws_sdk_dynamodb::types::AttributeValue;
Expand Down Expand Up @@ -123,7 +123,7 @@ pub async fn put_item_get_item() -> Result<(), crate::BoxError> {
// 5. Create a new AWS SDK DynamoDb client using the DynamoDb Config above
let sdk_config = aws_config::load_defaults(aws_config::BehaviorVersion::latest()).await;
let dynamo_config = aws_sdk_dynamodb::config::Builder::from(&sdk_config)
.interceptor(DbEsdkInterceptor::new(table_configs))
.interceptor(DbEsdkInterceptor::new(table_configs)?)
.build();
let ddb = aws_sdk_dynamodb::Client::from_conf(dynamo_config);

Expand Down Expand Up @@ -215,7 +215,7 @@ pub async fn put_item_get_item() -> Result<(), crate::BoxError> {
.build()?;

let only_replica_dynamo_config = aws_sdk_dynamodb::config::Builder::from(&sdk_config)
.interceptor(DbEsdkInterceptor::new(only_replica_table_configs))
.interceptor(DbEsdkInterceptor::new(only_replica_table_configs)?)
.build();
let only_replica_ddb = aws_sdk_dynamodb::Client::from_conf(only_replica_dynamo_config);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
// SPDX-License-Identifier: Apache-2.0

use aws_config::Region;
use aws_db_esdk::aws_cryptography_materialProviders::operation::get_client::GetClientInput;
use aws_db_esdk::aws_cryptography_materialProviders::types::error::Error;
use aws_db_esdk::aws_cryptography_materialProviders::types::ClientSupplier;
use aws_db_esdk::deps::com_amazonaws_kms::client::Client as kms_client;
use aws_db_esdk::material_providers::operation::get_client::GetClientInput;
use aws_db_esdk::material_providers::types::error::Error;
use aws_db_esdk::material_providers::types::ClientSupplier;
use aws_db_esdk::com_amazonaws_kms::client::Client as kms_client;

/*
Example class demonstrating an implementation of a custom client supplier.
Expand Down Expand Up @@ -44,7 +44,7 @@ impl ClientSupplier for RegionalRoleClientSupplier {
.build();

let inner_client = aws_sdk_kms::Client::from_conf(kms_config);
Ok(aws_db_esdk::deps::com_amazonaws_kms::client::Client {
Ok(kms_client {
inner: inner_client,
})
}
Expand Down
6 changes: 3 additions & 3 deletions releases/rust/db_esdk/examples/create_keystore_key.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
// SPDX-License-Identifier: Apache-2.0

use crate::test_utils;
use aws_db_esdk::aws_cryptography_keyStore::client as keystore_client;
use aws_db_esdk::aws_cryptography_keyStore::types::key_store_config::KeyStoreConfig;
use aws_db_esdk::aws_cryptography_keyStore::types::KmsConfiguration;
use aws_db_esdk::key_store::client as keystore_client;
use aws_db_esdk::key_store::types::key_store_config::KeyStoreConfig;
use aws_db_esdk::key_store::types::KmsConfiguration;

/*
The Hierarchical Keyring Example and Searchable Encryption Examples
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
// SPDX-License-Identifier: Apache-2.0

use crate::test_utils;
use aws_db_esdk::aws_cryptography_dbEncryptionSdk_dynamoDb::client as dbesdk_client;
use aws_db_esdk::aws_cryptography_dbEncryptionSdk_dynamoDb::types::dynamo_db_encryption_config::DynamoDbEncryptionConfig;
use aws_db_esdk::aws_cryptography_dbEncryptionSdk_dynamoDb::types::GetEncryptedDataKeyDescriptionUnion;
use aws_db_esdk::dynamodb::client as dbesdk_client;
use aws_db_esdk::dynamodb::types::dynamo_db_encryption_config::DynamoDbEncryptionConfig;
use aws_db_esdk::dynamodb::types::GetEncryptedDataKeyDescriptionUnion;
use aws_sdk_dynamodb::types::AttributeValue;
use std::collections::HashMap;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@ use crate::test_utils;
use aws_sdk_dynamodb::types::AttributeValue;
use std::collections::HashMap;

use aws_db_esdk::aws_cryptography_dbEncryptionSdk_structuredEncryption::types::CryptoAction;
use aws_db_esdk::aws_cryptography_materialProviders::client as mpl_client;
use aws_db_esdk::aws_cryptography_materialProviders::types::material_providers_config::MaterialProvidersConfig;
use aws_db_esdk::CryptoAction;
use aws_db_esdk::material_providers::client as mpl_client;
use aws_db_esdk::material_providers::types::material_providers_config::MaterialProvidersConfig;

use aws_db_esdk::aws_cryptography_dbEncryptionSdk_dynamoDb_itemEncryptor::types::dynamo_db_item_encryptor_config::DynamoDbItemEncryptorConfig;
use aws_db_esdk::aws_cryptography_dbEncryptionSdk_dynamoDb_itemEncryptor::client as enc_client;
use aws_db_esdk::aws_cryptography_materialProviders::types::DbeAlgorithmSuiteId;
use aws_db_esdk::item_encryptor::types::dynamo_db_item_encryptor_config::DynamoDbItemEncryptorConfig;
use aws_db_esdk::item_encryptor::client as enc_client;
use aws_db_esdk::material_providers::types::DbeAlgorithmSuiteId;

/*
This example sets up a DynamoDb Item Encryptor and uses
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

use aws_db_esdk::aws_cryptography_dbEncryptionSdk_dynamoDb::operation::get_branch_key_id_from_ddb_key::GetBranchKeyIdFromDdbKeyInput;
use aws_db_esdk::aws_cryptography_dbEncryptionSdk_dynamoDb::operation::get_branch_key_id_from_ddb_key::GetBranchKeyIdFromDdbKeyOutput;
use aws_db_esdk::aws_cryptography_dbEncryptionSdk_dynamoDb::types::error::Error;
use aws_db_esdk::aws_cryptography_dbEncryptionSdk_dynamoDb::types::DynamoDbKeyBranchKeyIdSupplier;
use aws_db_esdk::dynamodb::operation::get_branch_key_id_from_ddb_key::GetBranchKeyIdFromDdbKeyInput;
use aws_db_esdk::dynamodb::operation::get_branch_key_id_from_ddb_key::GetBranchKeyIdFromDdbKeyOutput;
use aws_db_esdk::dynamodb::types::error::Error;
use aws_db_esdk::dynamodb::types::DynamoDbKeyBranchKeyIdSupplier;

// Used in the 'HierarchicalKeyringExample'.
// In that example, we have a table where we distinguish multiple tenants
Expand Down
20 changes: 10 additions & 10 deletions releases/rust/db_esdk/examples/keyring/hierarchical_keyring.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@

use super::branch_key_id_supplier::ExampleBranchKeyIdSupplier;
use crate::test_utils;
use aws_db_esdk::aws_cryptography_dbEncryptionSdk_dynamoDb::client as dbesdk_client;
use aws_db_esdk::aws_cryptography_dbEncryptionSdk_dynamoDb::types::dynamo_db_encryption_config::DynamoDbEncryptionConfig;
use aws_db_esdk::aws_cryptography_keyStore::client as keystore_client;
use aws_db_esdk::aws_cryptography_keyStore::types::key_store_config::KeyStoreConfig;
use aws_db_esdk::aws_cryptography_keyStore::types::KmsConfiguration;
use aws_db_esdk::aws_cryptography_materialProviders::client as mpl_client;
use aws_db_esdk::aws_cryptography_materialProviders::types::material_providers_config::MaterialProvidersConfig;
use aws_db_esdk::aws_cryptography_dbEncryptionSdk_dynamoDb::types::DynamoDbTableEncryptionConfig;
use aws_db_esdk::aws_cryptography_dbEncryptionSdk_structuredEncryption::types::CryptoAction;
use aws_db_esdk::dynamodb::client as dbesdk_client;
use aws_db_esdk::dynamodb::types::dynamo_db_encryption_config::DynamoDbEncryptionConfig;
use aws_db_esdk::key_store::client as keystore_client;
use aws_db_esdk::key_store::types::key_store_config::KeyStoreConfig;
use aws_db_esdk::key_store::types::KmsConfiguration;
use aws_db_esdk::material_providers::client as mpl_client;
use aws_db_esdk::material_providers::types::material_providers_config::MaterialProvidersConfig;
use aws_db_esdk::dynamodb::types::DynamoDbTableEncryptionConfig;
use aws_db_esdk::CryptoAction;
use aws_db_esdk::intercept::DbEsdkInterceptor;
use aws_db_esdk::DynamoDbTablesEncryptionConfig;
use aws_sdk_dynamodb::types::AttributeValue;
Expand Down Expand Up @@ -181,7 +181,7 @@ pub async fn put_item_get_item(
// 7. Create a new AWS SDK DynamoDb client using the DynamoDb Encryption Interceptor above
let sdk_config = aws_config::load_defaults(aws_config::BehaviorVersion::latest()).await;
let dynamo_config = aws_sdk_dynamodb::config::Builder::from(&sdk_config)
.interceptor(DbEsdkInterceptor::new(table_configs))
.interceptor(DbEsdkInterceptor::new(table_configs)?)
.build();
let ddb = aws_sdk_dynamodb::Client::from_conf(dynamo_config);

Expand Down
14 changes: 7 additions & 7 deletions releases/rust/db_esdk/examples/keyring/kms_rsa_keyring.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@
// SPDX-License-Identifier: Apache-2.0

use crate::test_utils;
use aws_db_esdk::aws_cryptography_dbEncryptionSdk_dynamoDb::types::DynamoDbTableEncryptionConfig;
use aws_db_esdk::aws_cryptography_dbEncryptionSdk_structuredEncryption::types::CryptoAction;
use aws_db_esdk::aws_cryptography_materialProviders::client as mpl_client;
use aws_db_esdk::aws_cryptography_materialProviders::types::material_providers_config::MaterialProvidersConfig;
use aws_db_esdk::aws_cryptography_materialProviders::types::DbeAlgorithmSuiteId;
use aws_db_esdk::dynamodb::types::DynamoDbTableEncryptionConfig;
use aws_db_esdk::CryptoAction;
use aws_db_esdk::material_providers::client as mpl_client;
use aws_db_esdk::material_providers::types::material_providers_config::MaterialProvidersConfig;
use aws_db_esdk::material_providers::types::DbeAlgorithmSuiteId;
use aws_db_esdk::intercept::DbEsdkInterceptor;
use aws_db_esdk::DynamoDbTablesEncryptionConfig;
use aws_sdk_dynamodb::types::AttributeValue;
Expand All @@ -15,7 +15,7 @@ use std::fs::File;
use std::io::Read;
use std::io::Write;
use std::path::Path;

/*
This example sets up DynamoDb Encryption for the AWS SDK client
using the KMS RSA Keyring. This keyring uses a KMS RSA key pair to
Expand Down Expand Up @@ -151,7 +151,7 @@ pub async fn put_item_get_item() -> Result<(), crate::BoxError> {

// 6. Create a new AWS SDK DynamoDb client using the DynamoDb Encryption Interceptor above
let dynamo_config = aws_sdk_dynamodb::config::Builder::from(&sdk_config)
.interceptor(DbEsdkInterceptor::new(table_configs))
.interceptor(DbEsdkInterceptor::new(table_configs)?)
.build();
let ddb = aws_sdk_dynamodb::Client::from_conf(dynamo_config);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@
// SPDX-License-Identifier: Apache-2.0

use crate::test_utils;
use aws_db_esdk::aws_cryptography_dbEncryptionSdk_dynamoDb::types::DynamoDbTableEncryptionConfig;
use aws_db_esdk::aws_cryptography_dbEncryptionSdk_structuredEncryption::types::CryptoAction;
use aws_db_esdk::aws_cryptography_materialProviders::client as mpl_client;
use aws_db_esdk::aws_cryptography_materialProviders::types::material_providers_config::MaterialProvidersConfig;
use aws_db_esdk::aws_cryptography_materialProviders::types::DiscoveryFilter;
use aws_db_esdk::dynamodb::types::DynamoDbTableEncryptionConfig;
use aws_db_esdk::CryptoAction;
use aws_db_esdk::material_providers::client as mpl_client;
use aws_db_esdk::material_providers::types::material_providers_config::MaterialProvidersConfig;
use aws_db_esdk::material_providers::types::DiscoveryFilter;
use aws_db_esdk::intercept::DbEsdkInterceptor;
use aws_db_esdk::DynamoDbTablesEncryptionConfig;
use aws_sdk_dynamodb::types::AttributeValue;
Expand Down Expand Up @@ -115,7 +115,7 @@ pub async fn put_item_get_item() -> Result<(), crate::BoxError> {
// 5. Create a new AWS SDK DynamoDb client using the config above
let sdk_config = aws_config::load_defaults(aws_config::BehaviorVersion::latest()).await;
let dynamo_config = aws_sdk_dynamodb::config::Builder::from(&sdk_config)
.interceptor(DbEsdkInterceptor::new(table_configs))
.interceptor(DbEsdkInterceptor::new(table_configs)?)
.build();
let ddb = aws_sdk_dynamodb::Client::from_conf(dynamo_config);

Expand Down Expand Up @@ -182,7 +182,7 @@ pub async fn put_item_get_item() -> Result<(), crate::BoxError> {
.build()?;

let dynamo_config_for_decrypt = aws_sdk_dynamodb::config::Builder::from(&sdk_config)
.interceptor(DbEsdkInterceptor::new(table_configs_for_decrypt))
.interceptor(DbEsdkInterceptor::new(table_configs_for_decrypt)?)
.build();
let ddb_for_decrypt = aws_sdk_dynamodb::Client::from_conf(dynamo_config_for_decrypt);

Expand Down
Loading

0 comments on commit e10fed9

Please sign in to comment.