Skip to content

Commit a95775f

Browse files
committed
WIP
1 parent c435d4f commit a95775f

File tree

5 files changed

+208
-0
lines changed

5 files changed

+208
-0
lines changed

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ require (
2727
github.com/google/pprof v0.0.0-20240227163752-401108e1b7e7 // indirect
2828
github.com/ianlancetaylor/demangle v0.0.0-20240312041847-bd984b5ce465 // indirect
2929
github.com/jmespath/go-jmespath v0.4.0 // indirect
30+
github.com/klauspost/compress v1.17.7 // indirect
3031
github.com/pmezard/go-difflib v1.0.0 // indirect
3132
github.com/stretchr/objx v0.5.2 // indirect
3233
github.com/stretchr/testify v1.9.0 // indirect

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ github.com/ianlancetaylor/demangle v0.0.0-20240312041847-bd984b5ce465/go.mod h1:
4949
github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
5050
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
5151
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
52+
github.com/klauspost/compress v1.17.7 h1:ehO88t2UGzQK66LMdE8tibEd1ErmzZjNEqWkjLAKQQg=
53+
github.com/klauspost/compress v1.17.7/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
5254
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
5355
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
5456
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=

pkg/encrypted/resource.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package encrypted
2+
3+
import (
4+
"github.com/cloudopsy/dynamodb-encryption-go/pkg/provider"
5+
)
6+
7+
// EncryptedResource provides a high-level interface to work with encrypted DynamoDB resources.
8+
type EncryptedResource struct {
9+
Client *EncryptedClient
10+
MaterialsProvider provider.CryptographicMaterialsProvider
11+
AttributeActions *AttributeActions
12+
}
13+
14+
// NewEncryptedResource creates a new instance of EncryptedResource.
15+
func NewEncryptedResource(client *EncryptedClient, materialsProvider provider.CryptographicMaterialsProvider, attributeActions *AttributeActions) *EncryptedResource {
16+
return &EncryptedResource{
17+
Client: client,
18+
MaterialsProvider: materialsProvider,
19+
AttributeActions: attributeActions,
20+
}
21+
}
22+
23+
// Table returns an EncryptedTable instance for the specified table name.
24+
func (r *EncryptedResource) Table(name string) *EncryptedTable {
25+
return NewEncryptedTable(r.Client)
26+
}

pkg/encrypted/table.go

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
package encrypted
2+
3+
import (
4+
"context"
5+
"fmt"
6+
7+
"github.com/aws/aws-sdk-go-v2/service/dynamodb"
8+
"github.com/aws/aws-sdk-go-v2/service/dynamodb/types"
9+
)
10+
11+
// EncryptedTable provides a high-level interface to encrypted DynamoDB operations.
12+
type EncryptedTable struct {
13+
client *EncryptedClient
14+
}
15+
16+
// NewEncryptedTable creates a new EncryptedTable with the given EncryptedClient.
17+
func NewEncryptedTable(client *EncryptedClient) *EncryptedTable {
18+
return &EncryptedTable{
19+
client: client,
20+
}
21+
}
22+
23+
// PutItem encrypts and stores an item in the DynamoDB table.
24+
func (et *EncryptedTable) PutItem(ctx context.Context, tableName string, item map[string]types.AttributeValue) error {
25+
putItemInput := &dynamodb.PutItemInput{
26+
TableName: &tableName,
27+
Item: item,
28+
}
29+
_, err := et.client.PutItem(ctx, putItemInput)
30+
if err != nil {
31+
return fmt.Errorf("failed to put encrypted item: %w", err)
32+
}
33+
return nil
34+
}
35+
36+
// GetItem retrieves and decrypts an item from the DynamoDB table.
37+
func (et *EncryptedTable) GetItem(ctx context.Context, tableName string, key map[string]types.AttributeValue) (map[string]types.AttributeValue, error) {
38+
getItemInput := &dynamodb.GetItemInput{
39+
TableName: &tableName,
40+
Key: key,
41+
}
42+
result, err := et.client.GetItem(ctx, getItemInput)
43+
if err != nil {
44+
return nil, fmt.Errorf("failed to get and decrypt item: %w", err)
45+
}
46+
return result.Item, nil
47+
}
48+
49+
// Query executes a Query operation on the DynamoDB table and decrypts the returned items.
50+
func (et *EncryptedTable) Query(ctx context.Context, tableName string, input *dynamodb.QueryInput) (*dynamodb.QueryOutput, error) {
51+
// Set the table name for the query input
52+
input.TableName = &tableName
53+
54+
// Execute the query through the EncryptedClient
55+
encryptedOutput, err := et.client.Query(ctx, input)
56+
if err != nil {
57+
return nil, fmt.Errorf("error querying encrypted items: %w", err)
58+
}
59+
60+
// The items are already decrypted by EncryptedClient.Query, return the result directly
61+
return encryptedOutput, nil
62+
}
63+
64+
// Scan executes a Scan operation on the DynamoDB table and decrypts the returned items.
65+
func (et *EncryptedTable) Scan(ctx context.Context, tableName string, input *dynamodb.ScanInput) (*dynamodb.ScanOutput, error) {
66+
// Set the table name for the scan input
67+
input.TableName = &tableName
68+
69+
// Execute the scan through the EncryptedClient
70+
encryptedOutput, err := et.client.Scan(ctx, input)
71+
if err != nil {
72+
return nil, fmt.Errorf("error scanning encrypted items: %w", err)
73+
}
74+
75+
// The items are already decrypted by EncryptedClient. Scan, return the result directly
76+
return encryptedOutput, nil
77+
}

pkg/utils/compression.go

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
package utils
2+
3+
import (
4+
"bytes"
5+
"compress/gzip"
6+
"fmt"
7+
"io"
8+
9+
"github.com/klauspost/compress/zstd"
10+
)
11+
12+
type Compressor interface {
13+
Compress(data []byte) ([]byte, error)
14+
Decompress(data []byte) ([]byte, error)
15+
}
16+
17+
type GzipCompressor struct {
18+
level int
19+
}
20+
21+
func NewGzipCompressor(level int) *GzipCompressor {
22+
return &GzipCompressor{level: level}
23+
}
24+
25+
type ZstdCompressor struct {
26+
level int
27+
}
28+
29+
func NewZstdCompressor(level int) *ZstdCompressor {
30+
return &ZstdCompressor{level: level}
31+
}
32+
33+
func compress(data []byte, fn func(w io.Writer) (io.WriteCloser, error)) ([]byte, error) {
34+
var buf bytes.Buffer
35+
w, err := fn(&buf)
36+
if err != nil {
37+
return nil, fmt.Errorf("failed to create compressor: %v", err)
38+
}
39+
defer w.Close()
40+
41+
_, err = w.Write(data)
42+
if err != nil {
43+
return nil, fmt.Errorf("failed to compress data: %v", err)
44+
}
45+
46+
err = w.Close()
47+
if err != nil {
48+
return nil, fmt.Errorf("failed to close compressor: %v", err)
49+
}
50+
51+
return buf.Bytes(), nil
52+
}
53+
54+
func decompress(data []byte, fn func(r io.Reader) ([]byte, error)) ([]byte, error) {
55+
return fn(bytes.NewReader(data))
56+
}
57+
58+
func (c *GzipCompressor) Compress(data []byte) ([]byte, error) {
59+
return compress(data, func(w io.Writer) (io.WriteCloser, error) {
60+
return gzip.NewWriterLevel(w, c.level)
61+
})
62+
}
63+
64+
func (c *GzipCompressor) Decompress(data []byte) ([]byte, error) {
65+
return decompress(data, func(r io.Reader) ([]byte, error) {
66+
reader, err := gzip.NewReader(r)
67+
if err != nil {
68+
return nil, fmt.Errorf("failed to create gzip reader: %v", err)
69+
}
70+
defer reader.Close()
71+
72+
decompressedData, err := io.ReadAll(reader)
73+
if err != nil {
74+
return nil, fmt.Errorf("failed to decompress data: %v", err)
75+
}
76+
77+
return decompressedData, nil
78+
})
79+
}
80+
81+
func (c *ZstdCompressor) Compress(data []byte) ([]byte, error) {
82+
return compress(data, func(w io.Writer) (io.WriteCloser, error) {
83+
return zstd.NewWriter(w, zstd.WithEncoderLevel(zstd.EncoderLevelFromZstd(c.level)))
84+
})
85+
}
86+
87+
func (c *ZstdCompressor) Decompress(data []byte) ([]byte, error) {
88+
return decompress(data, func(r io.Reader) ([]byte, error) {
89+
decoder, err := zstd.NewReader(r)
90+
if err != nil {
91+
return nil, fmt.Errorf("failed to create zstd reader: %v", err)
92+
}
93+
defer decoder.Close()
94+
95+
decompressedData, err := io.ReadAll(decoder)
96+
if err != nil {
97+
return nil, fmt.Errorf("failed to decompress data: %v", err)
98+
}
99+
100+
return decompressedData, nil
101+
})
102+
}

0 commit comments

Comments
 (0)