Skip to content

Commit 3ed7ca1

Browse files
authored
Merge pull request #818 from basedosdados/feat/data_api
feat: change credits with hashed API key
2 parents 7e5ab5f + 021d080 commit 3ed7ca1

File tree

2 files changed

+64
-17
lines changed

2 files changed

+64
-17
lines changed

backend/apps/data_api/admin.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ class KeyInline(admin.TabularInline):
2020
readonly_fields = (
2121
"id",
2222
"name",
23+
"hash",
2324
"prefix",
2425
"is_active",
2526
"expires_at",
@@ -115,6 +116,7 @@ def pricing_actions(self, obj):
115116
class KeyAdmin(admin.ModelAdmin):
116117
list_display = (
117118
"name",
119+
"hash",
118120
"account",
119121
"prefix",
120122
"balance",
@@ -124,13 +126,14 @@ class KeyAdmin(admin.ModelAdmin):
124126
)
125127
list_filter = ("is_active",)
126128
search_fields = ("name", "prefix", "account__email", "account__full_name")
127-
readonly_fields = ("id", "prefix", "hash", "balance", "created_at", "updated_at")
129+
readonly_fields = ("id", "hash", "prefix", "balance", "created_at", "updated_at")
128130
fieldsets = (
129131
(
130132
None,
131133
{
132134
"fields": (
133135
"name",
136+
"hash",
134137
"account",
135138
"prefix",
136139
"balance",

backend/apps/data_api/views.py

Lines changed: 60 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -105,13 +105,30 @@ def get(self, request):
105105

106106
@method_decorator(csrf_exempt, name="dispatch")
107107
class DataAPICreditAddView(View):
108-
# TODO: remove GET method when in production
108+
def _get_hashed_key(self, key=None, hashed_key=None):
109+
if not key and not hashed_key:
110+
return None, "Either key or hashed_key must be provided"
111+
112+
if key and hashed_key:
113+
# If both are provided, validate they match
114+
computed_hash = sha256(key.encode()).hexdigest()
115+
if computed_hash != hashed_key:
116+
return None, "Provided key and hashed_key do not match"
117+
return hashed_key, None
118+
119+
if hashed_key:
120+
return hashed_key, None
121+
122+
# If only key is provided, hash it
123+
return sha256(key.encode()).hexdigest(), None
124+
109125
def get(self, request):
110126
key = request.GET.get("key")
127+
hashed_key = request.GET.get("hashed_key")
111128
amount = request.GET.get("amount")
112129
currency = request.GET.get("currency")
113130

114-
if not all([key, amount, currency]):
131+
if not all([amount, currency]):
115132
return JsonResponse(
116133
{"error": "Missing required parameters", "success": False}, status=400
117134
)
@@ -127,8 +144,10 @@ def get(self, request):
127144
except ValueError:
128145
return JsonResponse({"error": "Invalid amount format", "success": False}, status=400)
129146

130-
# Hash the API key
131-
hashed_key = sha256(key.encode()).hexdigest()
147+
# Get and validate hashed key
148+
hashed_key, error = self._get_hashed_key(key, hashed_key)
149+
if error:
150+
return JsonResponse({"error": error, "success": False}, status=400)
132151

133152
try:
134153
amount = Decimal(str(amount))
@@ -162,14 +181,17 @@ def post(self, request):
162181
metadata = payment_intent.metadata
163182

164183
key = metadata.get("key")
184+
hashed_key = metadata.get("hashed_key")
165185
amount = float(payment_intent.amount) / 100 # Convert from cents to BRL
166186
currency = payment_intent.currency.upper()
167187

168-
if not key:
169-
raise ValueError("API key not found in payment metadata")
188+
if not key and not hashed_key:
189+
raise ValueError("Neither key nor hashed_key found in payment metadata")
170190

171-
# Hash the API key
172-
hashed_key = sha256(key.encode()).hexdigest()
191+
# Get and validate hashed key
192+
hashed_key, error = self._get_hashed_key(key, hashed_key)
193+
if error:
194+
raise ValueError(error)
173195

174196
try:
175197
amount = Decimal(str(amount))
@@ -196,13 +218,30 @@ def post(self, request):
196218

197219
@method_decorator(csrf_exempt, name="dispatch")
198220
class DataAPICreditDeductView(View):
199-
# TODO: remove GET method when in production
221+
def _get_hashed_key(self, key=None, hashed_key=None):
222+
if not key and not hashed_key:
223+
return None, "Either key or hashed_key must be provided"
224+
225+
if key and hashed_key:
226+
# If both are provided, validate they match
227+
computed_hash = sha256(key.encode()).hexdigest()
228+
if computed_hash != hashed_key:
229+
return None, "Provided key and hashed_key do not match"
230+
return hashed_key, None
231+
232+
if hashed_key:
233+
return hashed_key, None
234+
235+
# If only key is provided, hash it
236+
return sha256(key.encode()).hexdigest(), None
237+
200238
def get(self, request):
201239
key = request.GET.get("key")
240+
hashed_key = request.GET.get("hashed_key")
202241
amount = request.GET.get("amount")
203242
currency = request.GET.get("currency")
204243

205-
if not all([key, amount, currency]):
244+
if not all([amount, currency]):
206245
return JsonResponse(
207246
{"error": "Missing required parameters", "success": False}, status=400
208247
)
@@ -218,8 +257,10 @@ def get(self, request):
218257
except ValueError:
219258
return JsonResponse({"error": "Invalid amount format", "success": False}, status=400)
220259

221-
# Hash the API key
222-
hashed_key = sha256(key.encode()).hexdigest()
260+
# Get and validate hashed key
261+
hashed_key, error = self._get_hashed_key(key, hashed_key)
262+
if error:
263+
return JsonResponse({"error": error, "success": False}, status=400)
223264

224265
try:
225266
amount = Decimal(str(amount))
@@ -254,14 +295,17 @@ def post(self, request):
254295
metadata = payment_intent.metadata
255296

256297
key = metadata.get("key")
298+
hashed_key = metadata.get("hashed_key")
257299
amount = float(payment_intent.amount) / 100 # Convert from cents to currency units
258300
currency = payment_intent.currency.upper()
259301

260-
if not key:
261-
raise ValueError("API key not found in payment metadata")
302+
if not key and not hashed_key:
303+
raise ValueError("Neither key nor hashed_key found in payment metadata")
262304

263-
# Hash the API key
264-
hashed_key = sha256(key.encode()).hexdigest()
305+
# Get and validate hashed key
306+
hashed_key, error = self._get_hashed_key(key, hashed_key)
307+
if error:
308+
raise ValueError(error)
265309

266310
try:
267311
amount = Decimal(str(amount))

0 commit comments

Comments
 (0)