Skip to content

Commit fe5df2d

Browse files
committed
Implemented auth for uploading to S3
1 parent cdf120c commit fe5df2d

File tree

3 files changed

+155
-5
lines changed

3 files changed

+155
-5
lines changed

lf_toolkit/evaluation/image_upload.py

Lines changed: 56 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import hashlib
2+
13
import requests
24
import uuid
35
import os
@@ -6,6 +8,10 @@
68
from PIL import Image
79
from dotenv import load_dotenv
810

11+
from botocore.auth import SigV4Auth
12+
from botocore.awsrequest import AWSRequest
13+
from botocore.credentials import Credentials
14+
915
load_dotenv()
1016

1117
MIME_TO_FORMAT: Dict[str, List[str]] = {
@@ -63,6 +69,49 @@ def get_s3_bucket_uri() -> str:
6369
return s3_uri
6470

6571

72+
def get_aws_signed_request(full_url, buffer, mime_type):
73+
credentials = Credentials(
74+
access_key=os.environ['AWS_ACCESS_KEY_ID'],
75+
secret_key=os.environ['AWS_SECRET_ACCESS_KEY'],
76+
)
77+
78+
if hasattr(buffer, 'read'):
79+
# It's a file-like object (BytesIO, etc.)
80+
current_pos = buffer.tell() # Save current position
81+
buffer.seek(0) # Go to start
82+
data = buffer.read() # Read all data
83+
buffer.seek(current_pos) # Restore position
84+
else:
85+
# It's already bytes
86+
data = buffer
87+
88+
# Calculate content hash and length
89+
content_hash = hashlib.sha256(data).hexdigest()
90+
content_length = len(data)
91+
92+
# Create the request for signing with required headers
93+
headers = {
94+
'Content-Type': mime_type,
95+
'Content-Length': str(content_length),
96+
'x-amz-content-sha256': content_hash
97+
}
98+
99+
# Create the request for signing
100+
aws_request = AWSRequest(
101+
method='PUT',
102+
url=full_url,
103+
data=buffer,
104+
headers=headers
105+
)
106+
107+
region = os.environ.get('AWS_REGION', 'eu-west-2')
108+
109+
# Sign the request
110+
SigV4Auth(credentials, 's3', region).add_auth(aws_request)
111+
112+
return aws_request
113+
114+
66115
def upload_image(img: Image.Image) -> str:
67116
"""Upload PIL image with comprehensive MIME type validation
68117
@@ -95,10 +144,13 @@ def upload_image(img: Image.Image) -> str:
95144
img.save(buffer, format=img_format)
96145
buffer.seek(0)
97146

98-
response: requests.Response = requests.put(
99-
full_url,
100-
data=buffer,
101-
headers={'Content-Type': mime_type},
147+
aws_request = get_aws_signed_request(full_url, buffer, mime_type).prepare()
148+
149+
response: requests.Response = requests.request(
150+
method=aws_request.method,
151+
url=aws_request.url,
152+
data=aws_request.body,
153+
headers=aws_request.headers,
102154
timeout=30
103155
)
104156

poetry.lock

Lines changed: 98 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ pytest-asyncio = "^1.2.0"
4646
pillow = "^12.1.0"
4747
requests = "^2.32.5"
4848
dotenv = "^0.9.9"
49+
boto3 = "^1.42.36"
4950

5051
[tool.poetry.group.dev.dependencies]
5152
black = "24.8.0"

0 commit comments

Comments
 (0)