pub struct Client { /* private fields */ }
Implementations§
Source§impl Client
impl Client
Sourcepub fn put_item_input_transform(&self) -> PutItemInputTransformFluentBuilder
pub fn put_item_input_transform(&self) -> PutItemInputTransformFluentBuilder
Constructs a fluent builder for the PutItemInputTransform
operation.
- The fluent builder is configurable:
- On success, responds with
PutItemInputTransformOutput
with field(s): - On failure, responds with
SdkError<PutItemInputTransformError>
Source§impl Client
impl Client
Sourcepub fn put_item_output_transform(&self) -> PutItemOutputTransformFluentBuilder
pub fn put_item_output_transform(&self) -> PutItemOutputTransformFluentBuilder
Constructs a fluent builder for the PutItemOutputTransform
operation.
- The fluent builder is configurable:
original_input(impl Into<Option<aws_sdk_dynamodb::operation::put_item::PutItemInput>>)
/set_original_input(Option<aws_sdk_dynamodb::operation::put_item::PutItemInput>)
: (undocumented)sdk_output(impl Into<Option<aws_sdk_dynamodb::operation::put_item::PutItemOutput>>)
/set_sdk_output(Option<aws_sdk_dynamodb::operation::put_item::PutItemOutput>)
: (undocumented)
- On success, responds with
PutItemOutputTransformOutput
with field(s): - On failure, responds with
SdkError<PutItemOutputTransformError>
Source§impl Client
impl Client
Sourcepub fn get_item_input_transform(&self) -> GetItemInputTransformFluentBuilder
pub fn get_item_input_transform(&self) -> GetItemInputTransformFluentBuilder
Constructs a fluent builder for the GetItemInputTransform
operation.
- The fluent builder is configurable:
- On success, responds with
GetItemInputTransformOutput
with field(s): - On failure, responds with
SdkError<GetItemInputTransformError>
Source§impl Client
impl Client
Sourcepub fn get_item_output_transform(&self) -> GetItemOutputTransformFluentBuilder
pub fn get_item_output_transform(&self) -> GetItemOutputTransformFluentBuilder
Constructs a fluent builder for the GetItemOutputTransform
operation.
- The fluent builder is configurable:
original_input(impl Into<Option<aws_sdk_dynamodb::operation::get_item::GetItemInput>>)
/set_original_input(Option<aws_sdk_dynamodb::operation::get_item::GetItemInput>)
: (undocumented)sdk_output(impl Into<Option<aws_sdk_dynamodb::operation::get_item::GetItemOutput>>)
/set_sdk_output(Option<aws_sdk_dynamodb::operation::get_item::GetItemOutput>)
: (undocumented)
- On success, responds with
GetItemOutputTransformOutput
with field(s): - On failure, responds with
SdkError<GetItemOutputTransformError>
Source§impl Client
impl Client
Sourcepub fn batch_write_item_input_transform(
&self,
) -> BatchWriteItemInputTransformFluentBuilder
pub fn batch_write_item_input_transform( &self, ) -> BatchWriteItemInputTransformFluentBuilder
Constructs a fluent builder for the BatchWriteItemInputTransform
operation.
- The fluent builder is configurable:
- On success, responds with
BatchWriteItemInputTransformOutput
with field(s): - On failure, responds with
SdkError<BatchWriteItemInputTransformError>
Source§impl Client
impl Client
Sourcepub fn batch_write_item_output_transform(
&self,
) -> BatchWriteItemOutputTransformFluentBuilder
pub fn batch_write_item_output_transform( &self, ) -> BatchWriteItemOutputTransformFluentBuilder
Constructs a fluent builder for the BatchWriteItemOutputTransform
operation.
- The fluent builder is configurable:
original_input(impl Into<Option<aws_sdk_dynamodb::operation::batch_write_item::BatchWriteItemInput>>)
/set_original_input(Option<aws_sdk_dynamodb::operation::batch_write_item::BatchWriteItemInput>)
: (undocumented)sdk_output(impl Into<Option<aws_sdk_dynamodb::operation::batch_write_item::BatchWriteItemOutput>>)
/set_sdk_output(Option<aws_sdk_dynamodb::operation::batch_write_item::BatchWriteItemOutput>)
: (undocumented)
- On success, responds with
BatchWriteItemOutputTransformOutput
with field(s): - On failure, responds with
SdkError<BatchWriteItemOutputTransformError>
Source§impl Client
impl Client
Sourcepub fn batch_get_item_input_transform(
&self,
) -> BatchGetItemInputTransformFluentBuilder
pub fn batch_get_item_input_transform( &self, ) -> BatchGetItemInputTransformFluentBuilder
Constructs a fluent builder for the BatchGetItemInputTransform
operation.
- The fluent builder is configurable:
- On success, responds with
BatchGetItemInputTransformOutput
with field(s): - On failure, responds with
SdkError<BatchGetItemInputTransformError>
Source§impl Client
impl Client
Sourcepub fn batch_get_item_output_transform(
&self,
) -> BatchGetItemOutputTransformFluentBuilder
pub fn batch_get_item_output_transform( &self, ) -> BatchGetItemOutputTransformFluentBuilder
Constructs a fluent builder for the BatchGetItemOutputTransform
operation.
- The fluent builder is configurable:
original_input(impl Into<Option<aws_sdk_dynamodb::operation::batch_get_item::BatchGetItemInput>>)
/set_original_input(Option<aws_sdk_dynamodb::operation::batch_get_item::BatchGetItemInput>)
: (undocumented)sdk_output(impl Into<Option<aws_sdk_dynamodb::operation::batch_get_item::BatchGetItemOutput>>)
/set_sdk_output(Option<aws_sdk_dynamodb::operation::batch_get_item::BatchGetItemOutput>)
: (undocumented)
- On success, responds with
BatchGetItemOutputTransformOutput
with field(s): - On failure, responds with
SdkError<BatchGetItemOutputTransformError>
Source§impl Client
impl Client
Sourcepub fn scan_input_transform(&self) -> ScanInputTransformFluentBuilder
pub fn scan_input_transform(&self) -> ScanInputTransformFluentBuilder
Constructs a fluent builder for the ScanInputTransform
operation.
- The fluent builder is configurable:
- On success, responds with
ScanInputTransformOutput
with field(s): - On failure, responds with
SdkError<ScanInputTransformError>
Source§impl Client
impl Client
Sourcepub fn scan_output_transform(&self) -> ScanOutputTransformFluentBuilder
pub fn scan_output_transform(&self) -> ScanOutputTransformFluentBuilder
Constructs a fluent builder for the ScanOutputTransform
operation.
- The fluent builder is configurable:
original_input(impl Into<Option<aws_sdk_dynamodb::operation::scan::ScanInput>>)
/set_original_input(Option<aws_sdk_dynamodb::operation::scan::ScanInput>)
: (undocumented)sdk_output(impl Into<Option<aws_sdk_dynamodb::operation::scan::ScanOutput>>)
/set_sdk_output(Option<aws_sdk_dynamodb::operation::scan::ScanOutput>)
: (undocumented)
- On success, responds with
ScanOutputTransformOutput
with field(s): - On failure, responds with
SdkError<ScanOutputTransformError>
Source§impl Client
impl Client
Sourcepub fn query_input_transform(&self) -> QueryInputTransformFluentBuilder
pub fn query_input_transform(&self) -> QueryInputTransformFluentBuilder
Constructs a fluent builder for the QueryInputTransform
operation.
- The fluent builder is configurable:
- On success, responds with
QueryInputTransformOutput
with field(s): - On failure, responds with
SdkError<QueryInputTransformError>
Source§impl Client
impl Client
Sourcepub fn query_output_transform(&self) -> QueryOutputTransformFluentBuilder
pub fn query_output_transform(&self) -> QueryOutputTransformFluentBuilder
Constructs a fluent builder for the QueryOutputTransform
operation.
- The fluent builder is configurable:
original_input(impl Into<Option<aws_sdk_dynamodb::operation::query::QueryInput>>)
/set_original_input(Option<aws_sdk_dynamodb::operation::query::QueryInput>)
: (undocumented)sdk_output(impl Into<Option<aws_sdk_dynamodb::operation::query::QueryOutput>>)
/set_sdk_output(Option<aws_sdk_dynamodb::operation::query::QueryOutput>)
: (undocumented)
- On success, responds with
QueryOutputTransformOutput
with field(s): - On failure, responds with
SdkError<QueryOutputTransformError>
Source§impl Client
impl Client
Sourcepub fn transact_write_items_input_transform(
&self,
) -> TransactWriteItemsInputTransformFluentBuilder
pub fn transact_write_items_input_transform( &self, ) -> TransactWriteItemsInputTransformFluentBuilder
Constructs a fluent builder for the TransactWriteItemsInputTransform
operation.
- The fluent builder is configurable:
- On success, responds with
TransactWriteItemsInputTransformOutput
with field(s): - On failure, responds with
SdkError<TransactWriteItemsInputTransformError>
Source§impl Client
impl Client
Sourcepub fn transact_write_items_output_transform(
&self,
) -> TransactWriteItemsOutputTransformFluentBuilder
pub fn transact_write_items_output_transform( &self, ) -> TransactWriteItemsOutputTransformFluentBuilder
Constructs a fluent builder for the TransactWriteItemsOutputTransform
operation.
- The fluent builder is configurable:
original_input(impl Into<Option<aws_sdk_dynamodb::operation::transact_write_items::TransactWriteItemsInput>>)
/set_original_input(Option<aws_sdk_dynamodb::operation::transact_write_items::TransactWriteItemsInput>)
: (undocumented)sdk_output(impl Into<Option<aws_sdk_dynamodb::operation::transact_write_items::TransactWriteItemsOutput>>)
/set_sdk_output(Option<aws_sdk_dynamodb::operation::transact_write_items::TransactWriteItemsOutput>)
: (undocumented)
- On success, responds with
TransactWriteItemsOutputTransformOutput
with field(s): - On failure, responds with
SdkError<TransactWriteItemsOutputTransformError>
Source§impl Client
impl Client
Sourcepub fn update_item_input_transform(
&self,
) -> UpdateItemInputTransformFluentBuilder
pub fn update_item_input_transform( &self, ) -> UpdateItemInputTransformFluentBuilder
Constructs a fluent builder for the UpdateItemInputTransform
operation.
- The fluent builder is configurable:
- On success, responds with
UpdateItemInputTransformOutput
with field(s): - On failure, responds with
SdkError<UpdateItemInputTransformError>
Source§impl Client
impl Client
Sourcepub fn update_item_output_transform(
&self,
) -> UpdateItemOutputTransformFluentBuilder
pub fn update_item_output_transform( &self, ) -> UpdateItemOutputTransformFluentBuilder
Constructs a fluent builder for the UpdateItemOutputTransform
operation.
- The fluent builder is configurable:
original_input(impl Into<Option<aws_sdk_dynamodb::operation::update_item::UpdateItemInput>>)
/set_original_input(Option<aws_sdk_dynamodb::operation::update_item::UpdateItemInput>)
: (undocumented)sdk_output(impl Into<Option<aws_sdk_dynamodb::operation::update_item::UpdateItemOutput>>)
/set_sdk_output(Option<aws_sdk_dynamodb::operation::update_item::UpdateItemOutput>)
: (undocumented)
- On success, responds with
UpdateItemOutputTransformOutput
with field(s): - On failure, responds with
SdkError<UpdateItemOutputTransformError>
Source§impl Client
impl Client
Sourcepub fn delete_item_input_transform(
&self,
) -> DeleteItemInputTransformFluentBuilder
pub fn delete_item_input_transform( &self, ) -> DeleteItemInputTransformFluentBuilder
Constructs a fluent builder for the DeleteItemInputTransform
operation.
- The fluent builder is configurable:
- On success, responds with
DeleteItemInputTransformOutput
with field(s): - On failure, responds with
SdkError<DeleteItemInputTransformError>
Source§impl Client
impl Client
Sourcepub fn delete_item_output_transform(
&self,
) -> DeleteItemOutputTransformFluentBuilder
pub fn delete_item_output_transform( &self, ) -> DeleteItemOutputTransformFluentBuilder
Constructs a fluent builder for the DeleteItemOutputTransform
operation.
- The fluent builder is configurable:
original_input(impl Into<Option<aws_sdk_dynamodb::operation::delete_item::DeleteItemInput>>)
/set_original_input(Option<aws_sdk_dynamodb::operation::delete_item::DeleteItemInput>)
: (undocumented)sdk_output(impl Into<Option<aws_sdk_dynamodb::operation::delete_item::DeleteItemOutput>>)
/set_sdk_output(Option<aws_sdk_dynamodb::operation::delete_item::DeleteItemOutput>)
: (undocumented)
- On success, responds with
DeleteItemOutputTransformOutput
with field(s): - On failure, responds with
SdkError<DeleteItemOutputTransformError>
Source§impl Client
impl Client
Sourcepub fn transact_get_items_input_transform(
&self,
) -> TransactGetItemsInputTransformFluentBuilder
pub fn transact_get_items_input_transform( &self, ) -> TransactGetItemsInputTransformFluentBuilder
Constructs a fluent builder for the TransactGetItemsInputTransform
operation.
- The fluent builder is configurable:
- On success, responds with
TransactGetItemsInputTransformOutput
with field(s): - On failure, responds with
SdkError<TransactGetItemsInputTransformError>
Source§impl Client
impl Client
Sourcepub fn transact_get_items_output_transform(
&self,
) -> TransactGetItemsOutputTransformFluentBuilder
pub fn transact_get_items_output_transform( &self, ) -> TransactGetItemsOutputTransformFluentBuilder
Constructs a fluent builder for the TransactGetItemsOutputTransform
operation.
- The fluent builder is configurable:
original_input(impl Into<Option<aws_sdk_dynamodb::operation::transact_get_items::TransactGetItemsInput>>)
/set_original_input(Option<aws_sdk_dynamodb::operation::transact_get_items::TransactGetItemsInput>)
: (undocumented)sdk_output(impl Into<Option<aws_sdk_dynamodb::operation::transact_get_items::TransactGetItemsOutput>>)
/set_sdk_output(Option<aws_sdk_dynamodb::operation::transact_get_items::TransactGetItemsOutput>)
: (undocumented)
- On success, responds with
TransactGetItemsOutputTransformOutput
with field(s): - On failure, responds with
SdkError<TransactGetItemsOutputTransformError>
Source§impl Client
impl Client
Sourcepub fn execute_statement_input_transform(
&self,
) -> ExecuteStatementInputTransformFluentBuilder
pub fn execute_statement_input_transform( &self, ) -> ExecuteStatementInputTransformFluentBuilder
Constructs a fluent builder for the ExecuteStatementInputTransform
operation.
- The fluent builder is configurable:
- On success, responds with
ExecuteStatementInputTransformOutput
with field(s): - On failure, responds with
SdkError<ExecuteStatementInputTransformError>
Source§impl Client
impl Client
Sourcepub fn execute_statement_output_transform(
&self,
) -> ExecuteStatementOutputTransformFluentBuilder
pub fn execute_statement_output_transform( &self, ) -> ExecuteStatementOutputTransformFluentBuilder
Constructs a fluent builder for the ExecuteStatementOutputTransform
operation.
- The fluent builder is configurable:
original_input(impl Into<Option<aws_sdk_dynamodb::operation::execute_statement::ExecuteStatementInput>>)
/set_original_input(Option<aws_sdk_dynamodb::operation::execute_statement::ExecuteStatementInput>)
: (undocumented)sdk_output(impl Into<Option<aws_sdk_dynamodb::operation::execute_statement::ExecuteStatementOutput>>)
/set_sdk_output(Option<aws_sdk_dynamodb::operation::execute_statement::ExecuteStatementOutput>)
: (undocumented)
- On success, responds with
ExecuteStatementOutputTransformOutput
with field(s): - On failure, responds with
SdkError<ExecuteStatementOutputTransformError>
Source§impl Client
impl Client
Sourcepub fn batch_execute_statement_input_transform(
&self,
) -> BatchExecuteStatementInputTransformFluentBuilder
pub fn batch_execute_statement_input_transform( &self, ) -> BatchExecuteStatementInputTransformFluentBuilder
Constructs a fluent builder for the BatchExecuteStatementInputTransform
operation.
- The fluent builder is configurable:
- On success, responds with
BatchExecuteStatementInputTransformOutput
with field(s): - On failure, responds with
SdkError<BatchExecuteStatementInputTransformError>
Source§impl Client
impl Client
Sourcepub fn batch_execute_statement_output_transform(
&self,
) -> BatchExecuteStatementOutputTransformFluentBuilder
pub fn batch_execute_statement_output_transform( &self, ) -> BatchExecuteStatementOutputTransformFluentBuilder
Constructs a fluent builder for the BatchExecuteStatementOutputTransform
operation.
- The fluent builder is configurable:
original_input(impl Into<Option<aws_sdk_dynamodb::operation::batch_execute_statement::BatchExecuteStatementInput>>)
/set_original_input(Option<aws_sdk_dynamodb::operation::batch_execute_statement::BatchExecuteStatementInput>)
: (undocumented)sdk_output(impl Into<Option<aws_sdk_dynamodb::operation::batch_execute_statement::BatchExecuteStatementOutput>>)
/set_sdk_output(Option<aws_sdk_dynamodb::operation::batch_execute_statement::BatchExecuteStatementOutput>)
: (undocumented)
- On success, responds with
BatchExecuteStatementOutputTransformOutput
with field(s): - On failure, responds with
SdkError<BatchExecuteStatementOutputTransformError>
Source§impl Client
impl Client
Sourcepub fn execute_transaction_input_transform(
&self,
) -> ExecuteTransactionInputTransformFluentBuilder
pub fn execute_transaction_input_transform( &self, ) -> ExecuteTransactionInputTransformFluentBuilder
Constructs a fluent builder for the ExecuteTransactionInputTransform
operation.
- The fluent builder is configurable:
- On success, responds with
ExecuteTransactionInputTransformOutput
with field(s): - On failure, responds with
SdkError<ExecuteTransactionInputTransformError>
Source§impl Client
impl Client
Sourcepub fn execute_transaction_output_transform(
&self,
) -> ExecuteTransactionOutputTransformFluentBuilder
pub fn execute_transaction_output_transform( &self, ) -> ExecuteTransactionOutputTransformFluentBuilder
Constructs a fluent builder for the ExecuteTransactionOutputTransform
operation.
- The fluent builder is configurable:
original_input(impl Into<Option<aws_sdk_dynamodb::operation::execute_transaction::ExecuteTransactionInput>>)
/set_original_input(Option<aws_sdk_dynamodb::operation::execute_transaction::ExecuteTransactionInput>)
: (undocumented)sdk_output(impl Into<Option<aws_sdk_dynamodb::operation::execute_transaction::ExecuteTransactionOutput>>)
/set_sdk_output(Option<aws_sdk_dynamodb::operation::execute_transaction::ExecuteTransactionOutput>)
: (undocumented)
- On success, responds with
ExecuteTransactionOutputTransformOutput
with field(s): - On failure, responds with
SdkError<ExecuteTransactionOutputTransformError>
Source§impl Client
impl Client
Sourcepub fn resolve_attributes(&self) -> ResolveAttributesFluentBuilder
pub fn resolve_attributes(&self) -> ResolveAttributesFluentBuilder
Constructs a fluent builder for the ResolveAttributes
operation.
- The fluent builder is configurable:
item(impl Into<Option<::std::collections::HashMap<::std::string::String, aws_sdk_dynamodb::types::AttributeValue>>>)
/set_item(Option<::std::collections::HashMap<::std::string::String, aws_sdk_dynamodb::types::AttributeValue>>)
: (undocumented)table_name(impl Into<Option<::std::string::String>>)
/set_table_name(Option<::std::string::String>)
: (undocumented)version(impl Into<Option<::std::primitive::i32>>)
/set_version(Option<::std::primitive::i32>)
: (undocumented)
- On success, responds with
ResolveAttributesOutput
with field(s): - On failure, responds with
SdkError<ResolveAttributesError>
Examples found in repository?
60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328
pub async fn put_and_query_with_beacon(branch_key_id: &str) -> Result<(), crate::BoxError> {
let ddb_table_name = test_utils::UNIT_INSPECTION_TEST_DDB_TABLE_NAME;
let branch_key_wrapping_kms_key_arn = test_utils::TEST_BRANCH_KEY_WRAPPING_KMS_KEY_ARN;
let branch_key_ddb_table_name = test_utils::TEST_BRANCH_KEYSTORE_DDB_TABLE_NAME;
// 1. Create Beacons.
// These are the same beacons as in the "BasicSearchableEncryptionExample" in this directory.
// See that file to see details on beacon construction and parameters.
// While we will not directly query against these beacons,
// you must create standard beacons on encrypted fields
// that we wish to use in compound beacons.
let last4_beacon = StandardBeacon::builder()
.name("inspector_id_last4")
.length(10)
.build()?;
let unit_beacon = StandardBeacon::builder().name("unit").length(30).build()?;
let standard_beacon_list = vec![last4_beacon, unit_beacon];
// 2. Define encrypted parts.
// Encrypted parts define the beacons that can be used to construct a compound beacon,
// and how the compound beacon prefixes those beacon values.
// A encrypted part must receive:
// - name: Name of a standard beacon
// - prefix: Any string. This is plaintext that prefixes the beaconized value in the compound beacon.
// Prefixes must be unique across the configuration, and must not be a prefix of another prefix;
// i.e. for all configured prefixes, the first N characters of a prefix must not equal another prefix.
// In practice, it is suggested to have a short value distinguishable from other parts served on the prefix.
// For this example, we will choose "L-" as the prefix for "Last 4 digits of inspector ID".
// With this prefix and the standard beacon's bit length definition (10), the beaconized
// version of the inspector ID's last 4 digits will appear as
// `L-000` to `L-3ff` inside a compound beacon.
// For this example, we will choose "U-" as the prefix for "unit".
// With this prefix and the standard beacon's bit length definition (30), a unit beacon will appear
// as `U-00000000` to `U-3fffffff` inside a compound beacon.
let encrypted_parts_list = vec![
EncryptedPart::builder()
.name("inspector_id_last4")
.prefix("L-")
.build()?,
EncryptedPart::builder().name("unit").prefix("U-").build()?,
];
// 3. Define compound beacon.
// A compound beacon allows one to serve multiple beacons or attributes from a single index.
// A compound beacon must receive:
// - name: The name of the beacon. Compound beacon values will be written to `aws_ddb_e_[name]`.
// - split: A character separating parts in a compound beacon
// A compound beacon may also receive:
// - encrypted: A list of encrypted parts. This is effectively a list of beacons. We provide the list
// that we created above.
// - constructors: A list of constructors. This is an ordered list of possible ways to create a beacon.
// We have not defined any constructors here; see the complex example for how to do this.
// The client will provide a default constructor, which will write a compound beacon as:
// all signed parts in the order they are added to the signed list;
// all encrypted parts in order they are added to the encrypted list; all parts required.
// In this example, we expect compound beacons to be written as
// `L-XXX.U-YYYYYYYY`, since our encrypted list looks like
// [last4EncryptedPart, unitEncryptedPart].
// - signed: A list of signed parts, i.e. plaintext attributes. This would be provided if we
// wanted to use plaintext values as part of constructing our compound beacon. We do not
// provide this here; see the Complex example for an example.
let compound_beacon_list = vec![CompoundBeacon::builder()
.name("last4UnitCompound")
.split(".")
.encrypted(encrypted_parts_list)
.build()?];
// 4. Configure the Keystore
// These are the same constructions as in the Basic example, which describes these in more detail.
let sdk_config = aws_config::load_defaults(aws_config::BehaviorVersion::latest()).await;
let key_store_config = KeyStoreConfig::builder()
.kms_client(aws_sdk_kms::Client::new(&sdk_config))
.ddb_client(aws_sdk_dynamodb::Client::new(&sdk_config))
.ddb_table_name(branch_key_ddb_table_name)
.logical_key_store_name(branch_key_ddb_table_name)
.kms_configuration(KmsConfiguration::KmsKeyArn(
branch_key_wrapping_kms_key_arn.to_string(),
))
.build()?;
let key_store = keystore_client::Client::from_conf(key_store_config)?;
// 5. Create BeaconVersion.
// This is similar to the Basic example, except we have also provided a compoundBeaconList.
// We must also continue to provide all of the standard beacons that compose a compound beacon list.
let beacon_version = BeaconVersion::builder()
.standard_beacons(standard_beacon_list)
.compound_beacons(compound_beacon_list)
.version(1) // MUST be 1
.key_store(key_store.clone())
.key_source(BeaconKeySource::Single(
SingleKeyStore::builder()
// `keyId` references a beacon key.
// For every branch key we create in the keystore,
// we also create a beacon key.
// This beacon key is not the same as the branch key,
// but is created with the same ID as the branch key.
.key_id(branch_key_id)
.cache_ttl(6000)
.build()?,
))
.build()?;
let beacon_versions = vec![beacon_version];
// 6. Create a Hierarchical Keyring
// This is the same configuration as in the Basic example.
let mpl_config = MaterialProvidersConfig::builder().build()?;
let mpl = mpl_client::Client::from_conf(mpl_config)?;
let kms_keyring = mpl
.create_aws_kms_hierarchical_keyring()
.branch_key_id(branch_key_id)
.key_store(key_store)
.ttl_seconds(6000)
.send()
.await?;
// 7. Configure which attributes are encrypted and/or signed when writing new items.
let attribute_actions_on_encrypt = HashMap::from([
("work_id".to_string(), CryptoAction::SignOnly), // Our partition attribute must be SIGN_ONLY
("inspection_date".to_string(), CryptoAction::SignOnly), // Our sort attribute must be SIGN_ONLY
(
"inspector_id_last4".to_string(),
CryptoAction::EncryptAndSign,
), // Beaconized attributes must be encrypted
("unit".to_string(), CryptoAction::EncryptAndSign), // Beaconized attributes must be encrypted
]);
// We do not need to define a crypto action on last4UnitCompound.
// We only need to define crypto actions on attributes that we pass to PutItem.
// 8. Create the DynamoDb Encryption configuration for the table we will be writing to.
// The beaconVersions are added to the search configuration.
let table_config = DynamoDbTableEncryptionConfig::builder()
.logical_table_name(ddb_table_name)
.partition_key_name("work_id")
.sort_key_name("inspection_date")
.attribute_actions_on_encrypt(attribute_actions_on_encrypt)
.keyring(kms_keyring)
.search(
SearchConfig::builder()
.write_version(1) // MUST be 1
.versions(beacon_versions)
.build()?,
)
.build()?;
// 9. Create config
let encryption_config = DynamoDbTablesEncryptionConfig::builder()
.table_encryption_configs(HashMap::from([(ddb_table_name.to_string(), table_config)]))
.build()?;
// 10. Create an item with both attributes used in the compound beacon.
let item = HashMap::from([
(
"work_id".to_string(),
AttributeValue::S("9ce39272-8068-4efd-a211-cd162ad65d4c".to_string()),
),
(
"inspection_date".to_string(),
AttributeValue::S("2023-06-13".to_string()),
),
(
"inspector_id_last4".to_string(),
AttributeValue::S("5678".to_string()),
),
(
"unit".to_string(),
AttributeValue::S("011899988199".to_string()),
),
]);
// 11. If developing or debugging, verify config by checking compound beacon values directly
let trans = transform_client::Client::from_conf(encryption_config.clone())?;
let resolve_output = trans
.resolve_attributes()
.table_name(ddb_table_name)
.item(item.clone())
.version(1)
.send()
.await?;
// Verify that there are no virtual fields
assert_eq!(resolve_output.virtual_fields.unwrap().len(), 0);
// Verify that CompoundBeacons has the expected value
let compound_beacons = resolve_output.compound_beacons.unwrap();
assert_eq!(compound_beacons.len(), 1);
assert_eq!(
compound_beacons["last4UnitCompound"],
"L-5678.U-011899988199"
);
// Note : the compound beacon actually stored in the table is not "L-5678.U-011899988199"
// but rather something like "L-abc.U-123", as both parts are EncryptedParts
// and therefore the text is replaced by the associated beacon
// 12. 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(encryption_config))
.build();
let ddb = aws_sdk_dynamodb::Client::from_conf(dynamo_config);
// 13. Write the item to the table
ddb.put_item()
.table_name(ddb_table_name)
.set_item(Some(item.clone()))
.send()
.await?;
// 14. Query for the item we just put.
let expression_attribute_values = HashMap::from([
// This query expression takes a few factors into consideration:
// - The configured prefix for the last 4 digits of an inspector ID is "L-";
// the prefix for the unit is "U-"
// - The configured split character, separating component parts, is "."
// - The default constructor adds encrypted parts in the order they are in the encrypted list, which
// configures `last4` to come before `unit``
// NOTE: We did not need to create a compound beacon for this query. This query could have also been
// done by querying on the partition and sort key, as was done in the Basic example.
// This is intended to be a simple example to demonstrate how one might set up a compound beacon.
// For examples where compound beacons are required, see the Complex example.
// The most basic extension to this example that would require a compound beacon would add a third
// part to the compound beacon, then query against three parts.
(
":value".to_string(),
AttributeValue::S("L-5678.U-011899988199".to_string()),
),
]);
// GSIs are sometimes a little bit delayed, so we retry if the query comes up empty.
for _i in 0..10 {
let query_response = ddb
.query()
.table_name(ddb_table_name)
.index_name(GSI_NAME)
.key_condition_expression("last4UnitCompound = :value")
.set_expression_attribute_values(Some(expression_attribute_values.clone()))
.send()
.await?;
// if no results, sleep and try again
if query_response.items.is_none() || query_response.items.as_ref().unwrap().is_empty() {
std::thread::sleep(std::time::Duration::from_millis(20));
continue;
}
let attribute_values = query_response.items.unwrap();
// Validate only 1 item was returned: the item we just put
assert_eq!(attribute_values.len(), 1);
let returned_item = &attribute_values[0];
// Validate the item has the expected attributes
assert_eq!(
returned_item["inspector_id_last4"],
AttributeValue::S("5678".to_string())
);
assert_eq!(
returned_item["unit"],
AttributeValue::S("011899988199".to_string())
);
break;
}
println!("compound_beacon_searchable_encryption successful.");
Ok(())
}
More examples
119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437
pub async fn put_and_query_with_beacon(branch_key_id: &str) -> Result<(), crate::BoxError> {
let ddb_table_name = test_utils::SIMPLE_BEACON_TEST_DDB_TABLE_NAME;
let branch_key_wrapping_kms_key_arn = test_utils::TEST_BRANCH_KEY_WRAPPING_KMS_KEY_ARN;
let branch_key_ddb_table_name = test_utils::TEST_BRANCH_KEYSTORE_DDB_TABLE_NAME;
// 1. Construct a length-1 prefix virtual transform.
// `hasTestResult` is a binary attribute, containing either `true` or `false`.
// As an example to demonstrate virtual transforms, we will truncate the value
// of `hasTestResult` in the virtual field to the length-1 prefix of the binary value, i.e.:
// - "true" -> "t"
// - "false -> "f"
// This is not necessary. This is done as a demonstration of virtual transforms.
// Virtual transform operations treat all attributes as strings
// (i.e. the boolean value `true` is interpreted as a string "true"),
// so its length-1 prefix is just "t".
let length1_prefix_virtual_transform_list = vec![VirtualTransform::Prefix(
GetPrefix::builder().length(1).build()?,
)];
// 2. Construct the VirtualParts required for the VirtualField
let has_test_result_part = VirtualPart::builder()
.loc("hasTestResult")
.trans(length1_prefix_virtual_transform_list)
.build()?;
let state_part = VirtualPart::builder().loc("state").build()?;
// Note that we do not apply any transform to the `state` attribute,
// and the virtual field will read in the attribute as-is.
// 3. Construct the VirtualField from the VirtualParts
// Note that the order that virtual parts are added to the virtualPartList
// dictates the order in which they are concatenated to build the virtual field.
// You must add virtual parts in the same order on write as you do on read.
let virtual_part_list = vec![state_part, has_test_result_part];
let state_and_has_test_result_field = VirtualField::builder()
.name("stateAndHasTestResult")
.parts(virtual_part_list)
.build()?;
let virtual_field_list = vec![state_and_has_test_result_field];
// 4. Configure our beacon.
// The virtual field is assumed to hold a US 2-letter state abbreviation
// (56 possible values = 50 states + 6 territories) concatenated with a binary attribute
// (2 possible values: true/false hasTestResult field), we expect a population size of
// 56 * 2 = 112 possible values.
// We will also assume that these values are reasonably well-distributed across
// customer IDs. In practice, this will not be true. We would expect
// more populous states to appear more frequently in the database.
// A more complex analysis would show that a stricter upper bound
// is necessary to account for this by hiding information from the
// underlying distribution.
//
// This link provides guidance for choosing a beacon length:
// https://docs.aws.amazon.com/database-encryption-sdk/latest/devguide/choosing-beacon-length.html
// We follow the guidance in the link above to determine reasonable bounds for beacon length:
// - min: log(sqrt(112))/log(2) ~= 3.4, round down to 3
// - max: log((112/2))/log(2) ~= 5.8, round up to 6
// You will somehow need to round results to a nearby integer.
// We choose to round to the nearest integer; you might consider a different rounding approach.
// Rounding up will return fewer expected "false positives" in queries,
// leading to fewer decrypt calls and better performance,
// but it is easier to identify which beacon values encode distinct plaintexts.
// Rounding down will return more expected "false positives" in queries,
// leading to more decrypt calls and worse performance,
// but it is harder to identify which beacon values encode distinct plaintexts.
// We can choose a beacon length between 3 and 6:
// - Closer to 3, we expect more "false positives" to be returned,
// making it harder to identify which beacon values encode distinct plaintexts,
// but leading to more decrypt calls and worse performance
// - Closer to 6, we expect fewer "false positives" returned in queries,
// leading to fewer decrypt calls and better performance,
// but it is easier to identify which beacon values encode distinct plaintexts.
// As an example, we will choose 5.
// Values stored in aws_dbe_b_stateAndHasTestResult will be 5 bits long (0x00 - 0x1f)
// There will be 2^5 = 32 possible HMAC values.
// With a well-distributed dataset (112 values), for a particular beacon we expect
// (112/32) = 3.5 combinations of abbreviation + true/false attribute
// sharing that beacon value.
let standard_beacon_list = vec![StandardBeacon::builder()
.name("stateAndHasTestResult")
.length(5)
.build()?];
// 5. Configure Keystore.
// This example expects that you have already set up a KeyStore with a single branch key.
// See the "CreateKeyStoreTableExample" and "CreateKeyStoreKeyExample" files for how to do this.
// After you create a branch key, you should persist its ID for use in this example.
let sdk_config = aws_config::load_defaults(aws_config::BehaviorVersion::latest()).await;
let key_store_config = KeyStoreConfig::builder()
.kms_client(aws_sdk_kms::Client::new(&sdk_config))
.ddb_client(aws_sdk_dynamodb::Client::new(&sdk_config))
.ddb_table_name(branch_key_ddb_table_name)
.logical_key_store_name(branch_key_ddb_table_name)
.kms_configuration(KmsConfiguration::KmsKeyArn(
branch_key_wrapping_kms_key_arn.to_string(),
))
.build()?;
let key_store = keystore_client::Client::from_conf(key_store_config)?;
// 6. Create BeaconVersion.
// The BeaconVersion inside the list holds the list of beacons on the table.
// The BeaconVersion also stores information about the keystore.
// BeaconVersion must be provided:
// - keyStore: The keystore configured in the previous step.
// - keySource: A configuration for the key source.
// For simple use cases, we can configure a 'singleKeySource' which
// statically configures a single beaconKey. That is the approach this example takes.
// For use cases where you want to use different beacon keys depending on the data
// (for example if your table holds data for multiple tenants, and you want to use
// a different beacon key per tenant), look into configuring a MultiKeyStore:
// https://docs.aws.amazon.com/database-encryption-sdk/latest/devguide/searchable-encryption-multitenant.html
// We also provide our standard beacon list and virtual fields here.
let beacon_version = BeaconVersion::builder()
.standard_beacons(standard_beacon_list)
.virtual_fields(virtual_field_list)
.version(1) // MUST be 1
.key_store(key_store.clone())
.key_source(BeaconKeySource::Single(
SingleKeyStore::builder()
// `keyId` references a beacon key.
// For every branch key we create in the keystore,
// we also create a beacon key.
// This beacon key is not the same as the branch key,
// but is created with the same ID as the branch key.
.key_id(branch_key_id)
.cache_ttl(6000)
.build()?,
))
.build()?;
let beacon_versions = vec![beacon_version];
// 7. Create a Hierarchical Keyring
// This is a KMS keyring that utilizes the keystore table.
// This config defines how items are encrypted and decrypted.
// NOTE: You should configure this to use the same keystore as your search config.
let mpl_config = MaterialProvidersConfig::builder().build()?;
let mpl = mpl_client::Client::from_conf(mpl_config)?;
let kms_keyring = mpl
.create_aws_kms_hierarchical_keyring()
.branch_key_id(branch_key_id)
.key_store(key_store)
.ttl_seconds(6000)
.send()
.await?;
// 8. Configure which attributes are encrypted and/or signed when writing new items.
// For each attribute that may exist on the items we plan to write to our DynamoDbTable,
// we must explicitly configure how they should be treated during item encryption:
// - ENCRYPT_AND_SIGN: The attribute is encrypted and included in the signature
// - SIGN_ONLY: The attribute not encrypted, but is still included in the signature
// - DO_NOTHING: The attribute is not encrypted and not included in the signature
// Any attributes that will be used in beacons must be configured as ENCRYPT_AND_SIGN.
let attribute_actions_on_encrypt = HashMap::from([
("customer_id".to_string(), CryptoAction::SignOnly), // Our partition attribute must be SIGN_ONLY
("create_time".to_string(), CryptoAction::SignOnly), // Our sort attribute must be SIGN_ONLY
("state".to_string(), CryptoAction::EncryptAndSign), // Beaconized attributes must be encrypted
("hasTestResult".to_string(), CryptoAction::EncryptAndSign), // Beaconized attributes must be encrypted
]);
// 9. Create the DynamoDb Encryption configuration for the table we will be writing to.
// The beaconVersions are added to the search configuration.
let table_config = DynamoDbTableEncryptionConfig::builder()
.logical_table_name(ddb_table_name)
.partition_key_name("customer_id")
.sort_key_name("create_time")
.attribute_actions_on_encrypt(attribute_actions_on_encrypt)
.keyring(kms_keyring)
.search(
SearchConfig::builder()
.write_version(1) // MUST be 1
.versions(beacon_versions)
.build()?,
)
.build()?;
// 10. Create config
let encryption_config = DynamoDbTablesEncryptionConfig::builder()
.table_encryption_configs(HashMap::from([(ddb_table_name.to_string(), table_config)]))
.build()?;
// 11. Create test items
// Create item with hasTestResult=true
let item_with_has_test_result = HashMap::from([
(
"customer_id".to_string(),
AttributeValue::S("ABC-123".to_string()),
),
(
"create_time".to_string(),
AttributeValue::N("1681495205".to_string()),
),
("state".to_string(), AttributeValue::S("CA".to_string())),
("hasTestResult".to_string(), AttributeValue::Bool(true)),
]);
// Create item with hasTestResult=false
let item_with_no_has_test_result = HashMap::from([
(
"customer_id".to_string(),
AttributeValue::S("DEF-456".to_string()),
),
(
"create_time".to_string(),
AttributeValue::N("1681495205".to_string()),
),
("state".to_string(), AttributeValue::S("CA".to_string())),
("hasTestResult".to_string(), AttributeValue::Bool(false)),
]);
// 12. If developing or debugging, verify config by checking virtual field values directly
let trans = transform_client::Client::from_conf(encryption_config.clone())?;
let resolve_output = trans
.resolve_attributes()
.table_name(ddb_table_name)
.item(item_with_has_test_result.clone())
.version(1)
.send()
.await?;
// CompoundBeacons is empty because we have no Compound Beacons configured
assert_eq!(resolve_output.compound_beacons.unwrap().len(), 0);
// Verify that VirtualFields has the expected value
let virtual_fields = resolve_output.virtual_fields.unwrap();
assert_eq!(virtual_fields.len(), 1);
assert_eq!(virtual_fields["stateAndHasTestResult"], "CAt");
// 13. 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(encryption_config))
.build();
let ddb = aws_sdk_dynamodb::Client::from_conf(dynamo_config);
// 14. Put two items into our table using the above client.
// The two items will differ only in their `customer_id` attribute (primary key)
// and their `hasTestResult` attribute.
// We will query against these items to demonstrate how to use our setup above
// to query against our `stateAndHasTestResult` beacon.
// Before the item gets sent to DynamoDb, it will be encrypted
// client-side, according to our configuration.
// Since our configuration includes a beacon on a virtual field named
// `stateAndHasTestResult`, the client will add an attribute
// to the item with name `aws_dbe_b_stateAndHasTestResult`.
// Its value will be an HMAC truncated to as many bits as the
// beacon's `length` parameter; i.e. 5.
ddb.put_item()
.table_name(ddb_table_name)
.set_item(Some(item_with_has_test_result.clone()))
.send()
.await?;
ddb.put_item()
.table_name(ddb_table_name)
.set_item(Some(item_with_no_has_test_result.clone()))
.send()
.await?;
// 15. Query by stateAndHasTestResult attribute.
// Note that we are constructing the query as if we were querying on plaintext values.
// However, the DDB encryption client will detect that this attribute name has a beacon configured.
// The client will add the beaconized attribute name and attribute value to the query,
// and transform the query to use the beaconized name and value.
// Internally, the client will query for and receive all items with a matching HMAC value in the beacon field.
// This may include a number of "false positives" with different ciphertext, but the same truncated HMAC.
// e.g. if truncate(HMAC("CAt"), 5) == truncate(HMAC("DCf"), 5), the query will return both items.
// The client will decrypt all returned items to determine which ones have the expected attribute values,
// and only surface items with the correct plaintext to the user.
// This procedure is internal to the client and is abstracted away from the user;
// e.g. the user will only see "CAt" and never "DCf", though the actual query returned both.
let expression_attribute_values = HashMap::from([
// We are querying for the item with `state`="CA" and `hasTestResult`=`true`.
// Since we added virtual parts as `state` then `hasTestResult`,
// we must write our query expression in the same order.
// We constructed our virtual field as `state`+`hasTestResult`,
// so we add the two parts in that order.
// Since we also created a virtual transform that truncated `hasTestResult`
// to its length-1 prefix, i.e. "true" -> "t",
// we write that field as its length-1 prefix in the query.
(
":stateAndHasTestResult".to_string(),
AttributeValue::S("CAt".to_string()),
),
]);
// GSIs are sometimes a little bit delayed, so we retry if the query comes up empty.
for _i in 0..10 {
let query_response = ddb
.query()
.table_name(ddb_table_name)
.index_name(GSI_NAME)
.key_condition_expression("stateAndHasTestResult = :stateAndHasTestResult")
.set_expression_attribute_values(Some(expression_attribute_values.clone()))
.send()
.await?;
// if no results, sleep and try again
if query_response.items.is_none() || query_response.items.as_ref().unwrap().is_empty() {
std::thread::sleep(std::time::Duration::from_millis(20));
continue;
}
let attribute_values = query_response.items.unwrap();
// Validate only 1 item was returned: the item we just put
assert_eq!(attribute_values.len(), 1);
let returned_item = &attribute_values[0];
// Validate the item has the expected attributes
assert_eq!(returned_item["state"], AttributeValue::S("CA".to_string()));
assert_eq!(returned_item["hasTestResult"], AttributeValue::Bool(true));
break;
}
println!("virtual_beacon_searchable_encryption successful.");
Ok(())
}
Source§impl Client
impl Client
Sourcepub fn from_conf(conf: DynamoDbTablesEncryptionConfig) -> Result<Self, Error>
pub fn from_conf(conf: DynamoDbTablesEncryptionConfig) -> Result<Self, Error>
Creates a new client from the service Config
.
Examples found in repository?
60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328
pub async fn put_and_query_with_beacon(branch_key_id: &str) -> Result<(), crate::BoxError> {
let ddb_table_name = test_utils::UNIT_INSPECTION_TEST_DDB_TABLE_NAME;
let branch_key_wrapping_kms_key_arn = test_utils::TEST_BRANCH_KEY_WRAPPING_KMS_KEY_ARN;
let branch_key_ddb_table_name = test_utils::TEST_BRANCH_KEYSTORE_DDB_TABLE_NAME;
// 1. Create Beacons.
// These are the same beacons as in the "BasicSearchableEncryptionExample" in this directory.
// See that file to see details on beacon construction and parameters.
// While we will not directly query against these beacons,
// you must create standard beacons on encrypted fields
// that we wish to use in compound beacons.
let last4_beacon = StandardBeacon::builder()
.name("inspector_id_last4")
.length(10)
.build()?;
let unit_beacon = StandardBeacon::builder().name("unit").length(30).build()?;
let standard_beacon_list = vec![last4_beacon, unit_beacon];
// 2. Define encrypted parts.
// Encrypted parts define the beacons that can be used to construct a compound beacon,
// and how the compound beacon prefixes those beacon values.
// A encrypted part must receive:
// - name: Name of a standard beacon
// - prefix: Any string. This is plaintext that prefixes the beaconized value in the compound beacon.
// Prefixes must be unique across the configuration, and must not be a prefix of another prefix;
// i.e. for all configured prefixes, the first N characters of a prefix must not equal another prefix.
// In practice, it is suggested to have a short value distinguishable from other parts served on the prefix.
// For this example, we will choose "L-" as the prefix for "Last 4 digits of inspector ID".
// With this prefix and the standard beacon's bit length definition (10), the beaconized
// version of the inspector ID's last 4 digits will appear as
// `L-000` to `L-3ff` inside a compound beacon.
// For this example, we will choose "U-" as the prefix for "unit".
// With this prefix and the standard beacon's bit length definition (30), a unit beacon will appear
// as `U-00000000` to `U-3fffffff` inside a compound beacon.
let encrypted_parts_list = vec![
EncryptedPart::builder()
.name("inspector_id_last4")
.prefix("L-")
.build()?,
EncryptedPart::builder().name("unit").prefix("U-").build()?,
];
// 3. Define compound beacon.
// A compound beacon allows one to serve multiple beacons or attributes from a single index.
// A compound beacon must receive:
// - name: The name of the beacon. Compound beacon values will be written to `aws_ddb_e_[name]`.
// - split: A character separating parts in a compound beacon
// A compound beacon may also receive:
// - encrypted: A list of encrypted parts. This is effectively a list of beacons. We provide the list
// that we created above.
// - constructors: A list of constructors. This is an ordered list of possible ways to create a beacon.
// We have not defined any constructors here; see the complex example for how to do this.
// The client will provide a default constructor, which will write a compound beacon as:
// all signed parts in the order they are added to the signed list;
// all encrypted parts in order they are added to the encrypted list; all parts required.
// In this example, we expect compound beacons to be written as
// `L-XXX.U-YYYYYYYY`, since our encrypted list looks like
// [last4EncryptedPart, unitEncryptedPart].
// - signed: A list of signed parts, i.e. plaintext attributes. This would be provided if we
// wanted to use plaintext values as part of constructing our compound beacon. We do not
// provide this here; see the Complex example for an example.
let compound_beacon_list = vec![CompoundBeacon::builder()
.name("last4UnitCompound")
.split(".")
.encrypted(encrypted_parts_list)
.build()?];
// 4. Configure the Keystore
// These are the same constructions as in the Basic example, which describes these in more detail.
let sdk_config = aws_config::load_defaults(aws_config::BehaviorVersion::latest()).await;
let key_store_config = KeyStoreConfig::builder()
.kms_client(aws_sdk_kms::Client::new(&sdk_config))
.ddb_client(aws_sdk_dynamodb::Client::new(&sdk_config))
.ddb_table_name(branch_key_ddb_table_name)
.logical_key_store_name(branch_key_ddb_table_name)
.kms_configuration(KmsConfiguration::KmsKeyArn(
branch_key_wrapping_kms_key_arn.to_string(),
))
.build()?;
let key_store = keystore_client::Client::from_conf(key_store_config)?;
// 5. Create BeaconVersion.
// This is similar to the Basic example, except we have also provided a compoundBeaconList.
// We must also continue to provide all of the standard beacons that compose a compound beacon list.
let beacon_version = BeaconVersion::builder()
.standard_beacons(standard_beacon_list)
.compound_beacons(compound_beacon_list)
.version(1) // MUST be 1
.key_store(key_store.clone())
.key_source(BeaconKeySource::Single(
SingleKeyStore::builder()
// `keyId` references a beacon key.
// For every branch key we create in the keystore,
// we also create a beacon key.
// This beacon key is not the same as the branch key,
// but is created with the same ID as the branch key.
.key_id(branch_key_id)
.cache_ttl(6000)
.build()?,
))
.build()?;
let beacon_versions = vec![beacon_version];
// 6. Create a Hierarchical Keyring
// This is the same configuration as in the Basic example.
let mpl_config = MaterialProvidersConfig::builder().build()?;
let mpl = mpl_client::Client::from_conf(mpl_config)?;
let kms_keyring = mpl
.create_aws_kms_hierarchical_keyring()
.branch_key_id(branch_key_id)
.key_store(key_store)
.ttl_seconds(6000)
.send()
.await?;
// 7. Configure which attributes are encrypted and/or signed when writing new items.
let attribute_actions_on_encrypt = HashMap::from([
("work_id".to_string(), CryptoAction::SignOnly), // Our partition attribute must be SIGN_ONLY
("inspection_date".to_string(), CryptoAction::SignOnly), // Our sort attribute must be SIGN_ONLY
(
"inspector_id_last4".to_string(),
CryptoAction::EncryptAndSign,
), // Beaconized attributes must be encrypted
("unit".to_string(), CryptoAction::EncryptAndSign), // Beaconized attributes must be encrypted
]);
// We do not need to define a crypto action on last4UnitCompound.
// We only need to define crypto actions on attributes that we pass to PutItem.
// 8. Create the DynamoDb Encryption configuration for the table we will be writing to.
// The beaconVersions are added to the search configuration.
let table_config = DynamoDbTableEncryptionConfig::builder()
.logical_table_name(ddb_table_name)
.partition_key_name("work_id")
.sort_key_name("inspection_date")
.attribute_actions_on_encrypt(attribute_actions_on_encrypt)
.keyring(kms_keyring)
.search(
SearchConfig::builder()
.write_version(1) // MUST be 1
.versions(beacon_versions)
.build()?,
)
.build()?;
// 9. Create config
let encryption_config = DynamoDbTablesEncryptionConfig::builder()
.table_encryption_configs(HashMap::from([(ddb_table_name.to_string(), table_config)]))
.build()?;
// 10. Create an item with both attributes used in the compound beacon.
let item = HashMap::from([
(
"work_id".to_string(),
AttributeValue::S("9ce39272-8068-4efd-a211-cd162ad65d4c".to_string()),
),
(
"inspection_date".to_string(),
AttributeValue::S("2023-06-13".to_string()),
),
(
"inspector_id_last4".to_string(),
AttributeValue::S("5678".to_string()),
),
(
"unit".to_string(),
AttributeValue::S("011899988199".to_string()),
),
]);
// 11. If developing or debugging, verify config by checking compound beacon values directly
let trans = transform_client::Client::from_conf(encryption_config.clone())?;
let resolve_output = trans
.resolve_attributes()
.table_name(ddb_table_name)
.item(item.clone())
.version(1)
.send()
.await?;
// Verify that there are no virtual fields
assert_eq!(resolve_output.virtual_fields.unwrap().len(), 0);
// Verify that CompoundBeacons has the expected value
let compound_beacons = resolve_output.compound_beacons.unwrap();
assert_eq!(compound_beacons.len(), 1);
assert_eq!(
compound_beacons["last4UnitCompound"],
"L-5678.U-011899988199"
);
// Note : the compound beacon actually stored in the table is not "L-5678.U-011899988199"
// but rather something like "L-abc.U-123", as both parts are EncryptedParts
// and therefore the text is replaced by the associated beacon
// 12. 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(encryption_config))
.build();
let ddb = aws_sdk_dynamodb::Client::from_conf(dynamo_config);
// 13. Write the item to the table
ddb.put_item()
.table_name(ddb_table_name)
.set_item(Some(item.clone()))
.send()
.await?;
// 14. Query for the item we just put.
let expression_attribute_values = HashMap::from([
// This query expression takes a few factors into consideration:
// - The configured prefix for the last 4 digits of an inspector ID is "L-";
// the prefix for the unit is "U-"
// - The configured split character, separating component parts, is "."
// - The default constructor adds encrypted parts in the order they are in the encrypted list, which
// configures `last4` to come before `unit``
// NOTE: We did not need to create a compound beacon for this query. This query could have also been
// done by querying on the partition and sort key, as was done in the Basic example.
// This is intended to be a simple example to demonstrate how one might set up a compound beacon.
// For examples where compound beacons are required, see the Complex example.
// The most basic extension to this example that would require a compound beacon would add a third
// part to the compound beacon, then query against three parts.
(
":value".to_string(),
AttributeValue::S("L-5678.U-011899988199".to_string()),
),
]);
// GSIs are sometimes a little bit delayed, so we retry if the query comes up empty.
for _i in 0..10 {
let query_response = ddb
.query()
.table_name(ddb_table_name)
.index_name(GSI_NAME)
.key_condition_expression("last4UnitCompound = :value")
.set_expression_attribute_values(Some(expression_attribute_values.clone()))
.send()
.await?;
// if no results, sleep and try again
if query_response.items.is_none() || query_response.items.as_ref().unwrap().is_empty() {
std::thread::sleep(std::time::Duration::from_millis(20));
continue;
}
let attribute_values = query_response.items.unwrap();
// Validate only 1 item was returned: the item we just put
assert_eq!(attribute_values.len(), 1);
let returned_item = &attribute_values[0];
// Validate the item has the expected attributes
assert_eq!(
returned_item["inspector_id_last4"],
AttributeValue::S("5678".to_string())
);
assert_eq!(
returned_item["unit"],
AttributeValue::S("011899988199".to_string())
);
break;
}
println!("compound_beacon_searchable_encryption successful.");
Ok(())
}
More examples
119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437
pub async fn put_and_query_with_beacon(branch_key_id: &str) -> Result<(), crate::BoxError> {
let ddb_table_name = test_utils::SIMPLE_BEACON_TEST_DDB_TABLE_NAME;
let branch_key_wrapping_kms_key_arn = test_utils::TEST_BRANCH_KEY_WRAPPING_KMS_KEY_ARN;
let branch_key_ddb_table_name = test_utils::TEST_BRANCH_KEYSTORE_DDB_TABLE_NAME;
// 1. Construct a length-1 prefix virtual transform.
// `hasTestResult` is a binary attribute, containing either `true` or `false`.
// As an example to demonstrate virtual transforms, we will truncate the value
// of `hasTestResult` in the virtual field to the length-1 prefix of the binary value, i.e.:
// - "true" -> "t"
// - "false -> "f"
// This is not necessary. This is done as a demonstration of virtual transforms.
// Virtual transform operations treat all attributes as strings
// (i.e. the boolean value `true` is interpreted as a string "true"),
// so its length-1 prefix is just "t".
let length1_prefix_virtual_transform_list = vec![VirtualTransform::Prefix(
GetPrefix::builder().length(1).build()?,
)];
// 2. Construct the VirtualParts required for the VirtualField
let has_test_result_part = VirtualPart::builder()
.loc("hasTestResult")
.trans(length1_prefix_virtual_transform_list)
.build()?;
let state_part = VirtualPart::builder().loc("state").build()?;
// Note that we do not apply any transform to the `state` attribute,
// and the virtual field will read in the attribute as-is.
// 3. Construct the VirtualField from the VirtualParts
// Note that the order that virtual parts are added to the virtualPartList
// dictates the order in which they are concatenated to build the virtual field.
// You must add virtual parts in the same order on write as you do on read.
let virtual_part_list = vec![state_part, has_test_result_part];
let state_and_has_test_result_field = VirtualField::builder()
.name("stateAndHasTestResult")
.parts(virtual_part_list)
.build()?;
let virtual_field_list = vec![state_and_has_test_result_field];
// 4. Configure our beacon.
// The virtual field is assumed to hold a US 2-letter state abbreviation
// (56 possible values = 50 states + 6 territories) concatenated with a binary attribute
// (2 possible values: true/false hasTestResult field), we expect a population size of
// 56 * 2 = 112 possible values.
// We will also assume that these values are reasonably well-distributed across
// customer IDs. In practice, this will not be true. We would expect
// more populous states to appear more frequently in the database.
// A more complex analysis would show that a stricter upper bound
// is necessary to account for this by hiding information from the
// underlying distribution.
//
// This link provides guidance for choosing a beacon length:
// https://docs.aws.amazon.com/database-encryption-sdk/latest/devguide/choosing-beacon-length.html
// We follow the guidance in the link above to determine reasonable bounds for beacon length:
// - min: log(sqrt(112))/log(2) ~= 3.4, round down to 3
// - max: log((112/2))/log(2) ~= 5.8, round up to 6
// You will somehow need to round results to a nearby integer.
// We choose to round to the nearest integer; you might consider a different rounding approach.
// Rounding up will return fewer expected "false positives" in queries,
// leading to fewer decrypt calls and better performance,
// but it is easier to identify which beacon values encode distinct plaintexts.
// Rounding down will return more expected "false positives" in queries,
// leading to more decrypt calls and worse performance,
// but it is harder to identify which beacon values encode distinct plaintexts.
// We can choose a beacon length between 3 and 6:
// - Closer to 3, we expect more "false positives" to be returned,
// making it harder to identify which beacon values encode distinct plaintexts,
// but leading to more decrypt calls and worse performance
// - Closer to 6, we expect fewer "false positives" returned in queries,
// leading to fewer decrypt calls and better performance,
// but it is easier to identify which beacon values encode distinct plaintexts.
// As an example, we will choose 5.
// Values stored in aws_dbe_b_stateAndHasTestResult will be 5 bits long (0x00 - 0x1f)
// There will be 2^5 = 32 possible HMAC values.
// With a well-distributed dataset (112 values), for a particular beacon we expect
// (112/32) = 3.5 combinations of abbreviation + true/false attribute
// sharing that beacon value.
let standard_beacon_list = vec![StandardBeacon::builder()
.name("stateAndHasTestResult")
.length(5)
.build()?];
// 5. Configure Keystore.
// This example expects that you have already set up a KeyStore with a single branch key.
// See the "CreateKeyStoreTableExample" and "CreateKeyStoreKeyExample" files for how to do this.
// After you create a branch key, you should persist its ID for use in this example.
let sdk_config = aws_config::load_defaults(aws_config::BehaviorVersion::latest()).await;
let key_store_config = KeyStoreConfig::builder()
.kms_client(aws_sdk_kms::Client::new(&sdk_config))
.ddb_client(aws_sdk_dynamodb::Client::new(&sdk_config))
.ddb_table_name(branch_key_ddb_table_name)
.logical_key_store_name(branch_key_ddb_table_name)
.kms_configuration(KmsConfiguration::KmsKeyArn(
branch_key_wrapping_kms_key_arn.to_string(),
))
.build()?;
let key_store = keystore_client::Client::from_conf(key_store_config)?;
// 6. Create BeaconVersion.
// The BeaconVersion inside the list holds the list of beacons on the table.
// The BeaconVersion also stores information about the keystore.
// BeaconVersion must be provided:
// - keyStore: The keystore configured in the previous step.
// - keySource: A configuration for the key source.
// For simple use cases, we can configure a 'singleKeySource' which
// statically configures a single beaconKey. That is the approach this example takes.
// For use cases where you want to use different beacon keys depending on the data
// (for example if your table holds data for multiple tenants, and you want to use
// a different beacon key per tenant), look into configuring a MultiKeyStore:
// https://docs.aws.amazon.com/database-encryption-sdk/latest/devguide/searchable-encryption-multitenant.html
// We also provide our standard beacon list and virtual fields here.
let beacon_version = BeaconVersion::builder()
.standard_beacons(standard_beacon_list)
.virtual_fields(virtual_field_list)
.version(1) // MUST be 1
.key_store(key_store.clone())
.key_source(BeaconKeySource::Single(
SingleKeyStore::builder()
// `keyId` references a beacon key.
// For every branch key we create in the keystore,
// we also create a beacon key.
// This beacon key is not the same as the branch key,
// but is created with the same ID as the branch key.
.key_id(branch_key_id)
.cache_ttl(6000)
.build()?,
))
.build()?;
let beacon_versions = vec![beacon_version];
// 7. Create a Hierarchical Keyring
// This is a KMS keyring that utilizes the keystore table.
// This config defines how items are encrypted and decrypted.
// NOTE: You should configure this to use the same keystore as your search config.
let mpl_config = MaterialProvidersConfig::builder().build()?;
let mpl = mpl_client::Client::from_conf(mpl_config)?;
let kms_keyring = mpl
.create_aws_kms_hierarchical_keyring()
.branch_key_id(branch_key_id)
.key_store(key_store)
.ttl_seconds(6000)
.send()
.await?;
// 8. Configure which attributes are encrypted and/or signed when writing new items.
// For each attribute that may exist on the items we plan to write to our DynamoDbTable,
// we must explicitly configure how they should be treated during item encryption:
// - ENCRYPT_AND_SIGN: The attribute is encrypted and included in the signature
// - SIGN_ONLY: The attribute not encrypted, but is still included in the signature
// - DO_NOTHING: The attribute is not encrypted and not included in the signature
// Any attributes that will be used in beacons must be configured as ENCRYPT_AND_SIGN.
let attribute_actions_on_encrypt = HashMap::from([
("customer_id".to_string(), CryptoAction::SignOnly), // Our partition attribute must be SIGN_ONLY
("create_time".to_string(), CryptoAction::SignOnly), // Our sort attribute must be SIGN_ONLY
("state".to_string(), CryptoAction::EncryptAndSign), // Beaconized attributes must be encrypted
("hasTestResult".to_string(), CryptoAction::EncryptAndSign), // Beaconized attributes must be encrypted
]);
// 9. Create the DynamoDb Encryption configuration for the table we will be writing to.
// The beaconVersions are added to the search configuration.
let table_config = DynamoDbTableEncryptionConfig::builder()
.logical_table_name(ddb_table_name)
.partition_key_name("customer_id")
.sort_key_name("create_time")
.attribute_actions_on_encrypt(attribute_actions_on_encrypt)
.keyring(kms_keyring)
.search(
SearchConfig::builder()
.write_version(1) // MUST be 1
.versions(beacon_versions)
.build()?,
)
.build()?;
// 10. Create config
let encryption_config = DynamoDbTablesEncryptionConfig::builder()
.table_encryption_configs(HashMap::from([(ddb_table_name.to_string(), table_config)]))
.build()?;
// 11. Create test items
// Create item with hasTestResult=true
let item_with_has_test_result = HashMap::from([
(
"customer_id".to_string(),
AttributeValue::S("ABC-123".to_string()),
),
(
"create_time".to_string(),
AttributeValue::N("1681495205".to_string()),
),
("state".to_string(), AttributeValue::S("CA".to_string())),
("hasTestResult".to_string(), AttributeValue::Bool(true)),
]);
// Create item with hasTestResult=false
let item_with_no_has_test_result = HashMap::from([
(
"customer_id".to_string(),
AttributeValue::S("DEF-456".to_string()),
),
(
"create_time".to_string(),
AttributeValue::N("1681495205".to_string()),
),
("state".to_string(), AttributeValue::S("CA".to_string())),
("hasTestResult".to_string(), AttributeValue::Bool(false)),
]);
// 12. If developing or debugging, verify config by checking virtual field values directly
let trans = transform_client::Client::from_conf(encryption_config.clone())?;
let resolve_output = trans
.resolve_attributes()
.table_name(ddb_table_name)
.item(item_with_has_test_result.clone())
.version(1)
.send()
.await?;
// CompoundBeacons is empty because we have no Compound Beacons configured
assert_eq!(resolve_output.compound_beacons.unwrap().len(), 0);
// Verify that VirtualFields has the expected value
let virtual_fields = resolve_output.virtual_fields.unwrap();
assert_eq!(virtual_fields.len(), 1);
assert_eq!(virtual_fields["stateAndHasTestResult"], "CAt");
// 13. 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(encryption_config))
.build();
let ddb = aws_sdk_dynamodb::Client::from_conf(dynamo_config);
// 14. Put two items into our table using the above client.
// The two items will differ only in their `customer_id` attribute (primary key)
// and their `hasTestResult` attribute.
// We will query against these items to demonstrate how to use our setup above
// to query against our `stateAndHasTestResult` beacon.
// Before the item gets sent to DynamoDb, it will be encrypted
// client-side, according to our configuration.
// Since our configuration includes a beacon on a virtual field named
// `stateAndHasTestResult`, the client will add an attribute
// to the item with name `aws_dbe_b_stateAndHasTestResult`.
// Its value will be an HMAC truncated to as many bits as the
// beacon's `length` parameter; i.e. 5.
ddb.put_item()
.table_name(ddb_table_name)
.set_item(Some(item_with_has_test_result.clone()))
.send()
.await?;
ddb.put_item()
.table_name(ddb_table_name)
.set_item(Some(item_with_no_has_test_result.clone()))
.send()
.await?;
// 15. Query by stateAndHasTestResult attribute.
// Note that we are constructing the query as if we were querying on plaintext values.
// However, the DDB encryption client will detect that this attribute name has a beacon configured.
// The client will add the beaconized attribute name and attribute value to the query,
// and transform the query to use the beaconized name and value.
// Internally, the client will query for and receive all items with a matching HMAC value in the beacon field.
// This may include a number of "false positives" with different ciphertext, but the same truncated HMAC.
// e.g. if truncate(HMAC("CAt"), 5) == truncate(HMAC("DCf"), 5), the query will return both items.
// The client will decrypt all returned items to determine which ones have the expected attribute values,
// and only surface items with the correct plaintext to the user.
// This procedure is internal to the client and is abstracted away from the user;
// e.g. the user will only see "CAt" and never "DCf", though the actual query returned both.
let expression_attribute_values = HashMap::from([
// We are querying for the item with `state`="CA" and `hasTestResult`=`true`.
// Since we added virtual parts as `state` then `hasTestResult`,
// we must write our query expression in the same order.
// We constructed our virtual field as `state`+`hasTestResult`,
// so we add the two parts in that order.
// Since we also created a virtual transform that truncated `hasTestResult`
// to its length-1 prefix, i.e. "true" -> "t",
// we write that field as its length-1 prefix in the query.
(
":stateAndHasTestResult".to_string(),
AttributeValue::S("CAt".to_string()),
),
]);
// GSIs are sometimes a little bit delayed, so we retry if the query comes up empty.
for _i in 0..10 {
let query_response = ddb
.query()
.table_name(ddb_table_name)
.index_name(GSI_NAME)
.key_condition_expression("stateAndHasTestResult = :stateAndHasTestResult")
.set_expression_attribute_values(Some(expression_attribute_values.clone()))
.send()
.await?;
// if no results, sleep and try again
if query_response.items.is_none() || query_response.items.as_ref().unwrap().is_empty() {
std::thread::sleep(std::time::Duration::from_millis(20));
continue;
}
let attribute_values = query_response.items.unwrap();
// Validate only 1 item was returned: the item we just put
assert_eq!(attribute_values.len(), 1);
let returned_item = &attribute_values[0];
// Validate the item has the expected attributes
assert_eq!(returned_item["state"], AttributeValue::S("CA".to_string()));
assert_eq!(returned_item["hasTestResult"], AttributeValue::Bool(true));
break;
}
println!("virtual_beacon_searchable_encryption successful.");
Ok(())
}
Trait Implementations§
impl StructuralPartialEq for Client
Auto Trait Implementations§
impl Freeze for Client
impl !RefUnwindSafe for Client
impl !Send for Client
impl !Sync for Client
impl Unpin for Client
impl !UnwindSafe for Client
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
Source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self
into a Left
variant of Either<Self, Self>
if into_left
is true
.
Converts self
into a Right
variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self
into a Left
variant of Either<Self, Self>
if into_left(&self)
returns true
.
Converts self
into a Right
variant of Either<Self, Self>
otherwise. Read more