33
33
)
34
34
from aws_database_encryption_sdk .smithygenerated .aws_cryptography_dbencryptionsdk_dynamodb .models import (
35
35
DynamoDbTablesEncryptionConfig ,
36
+ DynamoDbTableEncryptionConfig ,
36
37
)
38
+ from aws_database_encryption_sdk .smithygenerated .aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor .config import (
39
+ DynamoDbItemEncryptorConfig ,
40
+ )
41
+ from aws_database_encryption_sdk .encryptor .item import ItemEncryptor
37
42
43
+ class EncryptedPaginator :
44
+ def __init__ (
45
+ self ,
46
+ paginator : Paginator ,
47
+ item_encryptors : dict [str , ItemEncryptor ]
48
+ ):
49
+ self ._paginator = paginator
50
+ self ._item_encryptors = item_encryptors
51
+
52
+ def paginate (self , ** kwargs ):
53
+ """Create an iterator that will paginate through responses from the underlying paginator,
54
+ transparently decrypting any returned items.
55
+ """
56
+ table_name = kwargs ["TableName" ]
57
+
58
+ try :
59
+ item_encryptor = self ._item_encryptors [table_name ]
60
+ except KeyError :
61
+ raise KeyError (f"No encryption configuration found for table { table_name } " )
62
+
63
+ for page in self ._paginator .paginate (** kwargs ):
64
+ encrypted_items = page ["Items" ]
65
+ decrypted_items = []
66
+ for item in encrypted_items :
67
+ decrypted_items .append (item_encryptor .decrypt_dynamodb_item (item ))
68
+ page ["Items" ] = decrypted_items
69
+ yield page
38
70
39
71
class EncryptedClient :
40
72
"""
@@ -319,4 +351,42 @@ def __getattr__(self, name):
319
351
elif hasattr (self ._client , name ):
320
352
return getattr (self ._client , name )
321
353
else :
322
- raise AttributeError (f"'{ self .__class__ .__name__ } ' object has no attribute '{ name } '" )
354
+ raise AttributeError (f"'{ self .__class__ .__name__ } ' object has no attribute '{ name } '" )
355
+
356
+ def _table_encryption_config_to_item_encryptor_config (
357
+ table_encryption_config : DynamoDbTableEncryptionConfig
358
+ ) -> DynamoDbItemEncryptorConfig :
359
+ return DynamoDbItemEncryptorConfig (
360
+ logical_table_name = table_encryption_config .logical_table_name ,
361
+ partition_key_name = table_encryption_config .partition_key_name ,
362
+ attribute_actions_on_encrypt = table_encryption_config .attribute_actions_on_encrypt ,
363
+ sort_key_name = table_encryption_config .sort_key_name ,
364
+ allowed_unsigned_attributes = table_encryption_config .allowed_unsigned_attributes ,
365
+ allowed_unsigned_attribute_prefix = table_encryption_config .allowed_unsigned_attribute_prefix ,
366
+ algorithm_suite_id = table_encryption_config .algorithm_suite_id ,
367
+ keyring = table_encryption_config .keyring ,
368
+ cmm = table_encryption_config .cmm ,
369
+ legacy_override = table_encryption_config .legacy_override ,
370
+ plaintext_override = table_encryption_config .plaintext_override ,
371
+ )
372
+
373
+ def get_paginator (self , operation_name : str ) -> EncryptedPaginator :
374
+ """Get a paginator from the underlying client. If the paginator requested is for
375
+ "scan" or "query", the paginator returned will transparently decrypt the returned items.
376
+
377
+ :param str operation_name: Name of operation for which to get paginator
378
+ :returns: Paginator for name
379
+ :rtype: :class:`botocore.paginate.Paginator` or :class:`EncryptedPaginator`
380
+ """
381
+ paginator = self ._client .get_paginator (operation_name )
382
+
383
+ item_encryptors = {}
384
+ for table_name , table_config in self ._encryption_config .items ():
385
+ item_encryptors [table_name ] = self ._table_encryption_config_to_item_encryptor_config (table_config )
386
+
387
+ if operation_name in ("scan" , "query" ):
388
+ return EncryptedPaginator (
389
+ paginator = paginator , item_encryptor_by_table = item_encryptors , client = self ._client
390
+ )
391
+
392
+ return paginator
0 commit comments