Skip to content

Commit 07a079a

Browse files
author
Lucas McDonald
committed
wip
1 parent a9fabd7 commit 07a079a

File tree

19 files changed

+1441
-479
lines changed

19 files changed

+1441
-479
lines changed
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
2+
# SPDX-License-Identifier: Apache-2.0
3+
import abc
4+
from typing import Any, Dict
5+
from abc import abstractmethod
6+
7+
class EncryptedBotoInterface(abc.ABC):
8+
"""Interface for encrypted boto3 interfaces."""
9+
10+
def _copy_sdk_response_to_dbesdk_response(self, sdk_response: Dict[str, Any], dbesdk_response: Dict[str, Any]) -> Dict[str, Any]:
11+
"""Copy any missing fields from the SDK response to the DBESDK response.
12+
13+
Args:
14+
sdk_response: The raw SDK response
15+
dbesdk_response: The current DBESDK response
16+
17+
Returns:
18+
dict: The DBESDK response with any missing fields copied from SDK response
19+
"""
20+
for sdk_response_key, sdk_response_value in sdk_response.items():
21+
if sdk_response_key not in dbesdk_response:
22+
dbesdk_response[sdk_response_key] = sdk_response_value
23+
return dbesdk_response
24+
25+
@property
26+
@abstractmethod
27+
def _boto_client_attr_name(self) -> str:
28+
"""Name of the attribute containing the underlying boto3 client."""
29+
30+
def __getattr__(self, name: str) -> Any:
31+
"""Delegate unknown attributes to the underlying client.
32+
33+
Args:
34+
name: The name of the attribute to get
35+
36+
Returns:
37+
Any: The attribute value from the underlying client
38+
39+
Raises:
40+
AttributeError: If the attribute doesn't exist on the underlying client
41+
"""
42+
client_attr = getattr(self, self._boto_client_attr_name)
43+
if hasattr(client_attr, name):
44+
return getattr(client_attr, name)
45+
raise AttributeError(f"'{self.__class__.__name__}' object has no attribute '{name}'")

DynamoDbEncryption/runtimes/python/src/aws_database_encryption_sdk/encrypted/client.py

Lines changed: 15 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
"""High-level helper class to provide an encrypting wrapper for boto3 DynamoDB clients."""
44
import botocore.client
55
from typing import Optional, Any, Dict, List
6+
from copy import deepcopy
67

78
from aws_database_encryption_sdk.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_transforms.models import (
89
GetItemInputTransformInput,
@@ -22,12 +23,6 @@
2223
QueryInputTransformInput,
2324
QueryOutputTransformInput,
2425
)
25-
from aws_database_encryption_sdk.transform import (
26-
dict_to_ddb,
27-
ddb_to_dict,
28-
list_of_ddb_to_list_of_dict,
29-
list_of_dict_to_list_of_ddb,
30-
)
3126
from aws_database_encryption_sdk.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_transforms.client import (
3227
DynamoDbEncryptionTransforms
3328
)
@@ -37,9 +32,9 @@
3732
from aws_database_encryption_sdk.encrypted.paginator import EncryptedPaginator
3833
from aws_database_encryption_sdk.internal.resource_to_client import ResourceShapeToClientShapeConverter
3934
from aws_database_encryption_sdk.internal.client_to_resource import ClientShapeToResourceShapeConverter
40-
from aws_database_encryption_sdk.internal.utils import _copy_sdk_response_to_dbesdk_response
35+
from aws_database_encryption_sdk.encrypted.boto3_interface import EncryptedBotoInterface
4136

42-
class EncryptedClient:
37+
class EncryptedClient(EncryptedBotoInterface):
4338
"""Wrapper for a boto3 DynamoDB client that transparently encrypts/decrypts items.
4439
4540
This class implements the complete boto3 DynamoDB client API, allowing it to serve as a
@@ -84,8 +79,8 @@ def __init__(
8479
expect_standard_dictionaries (Optional[bool]): Does the underlying boto3 client expect items to be standard Python
8580
dictionaries? This should only be set to True if you are using a client obtained
8681
from a service resource or table resource (ex: `table.meta.client`).
87-
If this is True, the client will expect item-like shapes to be standard Python dictionaries (default: False).
88-
82+
If this is True, EncryptedClient will expect item-like shapes to be
83+
standard Python dictionaries (default: False).
8984
"""
9085
self._client = client
9186
self._encryption_config = encryption_config
@@ -94,7 +89,6 @@ def __init__(
9489
)
9590
self._expect_standard_dictionaries = expect_standard_dictionaries
9691
self._resource_to_client_shape_converter = ResourceShapeToClientShapeConverter()
97-
#
9892
self._client_to_resource_shape_converter = ClientShapeToResourceShapeConverter(delete_table_name=False)
9993

10094
def put_item(self, **kwargs) -> Dict[str, Any]:
@@ -402,10 +396,10 @@ def _client_operation_logic(
402396
dict: The transformed response from DynamoDB
403397
"""
404398
# Transform input from Python dictionary JSON to DynamoDB JSON if required
405-
sdk_input = operation_input.copy()
399+
sdk_input = deepcopy(operation_input)
406400
if self._expect_standard_dictionaries:
407-
if "TableName" in operation_input:
408-
self._resource_to_client_shape_converter.table_name = operation_input["TableName"]
401+
if "TableName" in sdk_input:
402+
self._resource_to_client_shape_converter.table_name = sdk_input["TableName"]
409403
sdk_input = input_item_to_ddb_transform_method(sdk_input)
410404

411405
# Apply encryption transformation to the user-supplied input
@@ -433,26 +427,18 @@ def _client_operation_logic(
433427
).transformed_output
434428

435429
# Copy any missing fields from the SDK output to the response
436-
dbesdk_response = _copy_sdk_response_to_dbesdk_response(sdk_response, dbesdk_response)
430+
dbesdk_response = self._copy_sdk_response_to_dbesdk_response(sdk_response, dbesdk_response)
437431

438432
if self._expect_standard_dictionaries:
439433
dbesdk_response = output_item_to_dict_transform_method(dbesdk_response)
440434

441435
return dbesdk_response
442436

443-
def __getattr__(self, name: str) -> Any:
444-
"""Delegate unknown attributes to the underlying client.
445-
446-
Args:
447-
name: The name of the attribute to get
448-
437+
@property
438+
def _boto_client_attr_name(self) -> str:
439+
"""Name of the attribute containing the underlying boto3 client.
440+
449441
Returns:
450-
Any: The attribute value from the underlying client
451-
452-
Raises:
453-
AttributeError: If the attribute doesn't exist on the underlying client
442+
str: '_client'
454443
"""
455-
if hasattr(self._client, name):
456-
return getattr(self._client, name)
457-
else:
458-
raise AttributeError(f"'{self.__class__.__name__}' object has no attribute '{name}'")
444+
return '_client'

DynamoDbEncryption/runtimes/python/src/aws_database_encryption_sdk/encrypted/interceptor.py

Lines changed: 0 additions & 157 deletions
This file was deleted.

0 commit comments

Comments
 (0)