Junaidb commited on
Commit
1aff627
·
verified ·
1 Parent(s): f5ffd32

Create components/middleware.py

Browse files
Files changed (1) hide show
  1. components/middleware.py +340 -0
components/middleware.py ADDED
@@ -0,0 +1,340 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import Request
2
+ from fastapi.responses import JSONResponse
3
+ from starlette.middleware.base import BaseHTTPMiddleware
4
+ from nacl.signing import VerifyKey
5
+ from nacl.exceptions import BadSignatureError
6
+ import hashlib
7
+ import secrets
8
+ import base58
9
+ import requests
10
+ import json
11
+ import httpx
12
+ from geopy.geocoders import Nominatim
13
+ from geopy.exc import GeocoderServiceError
14
+ geolocator = Nominatim(user_agent="velocity")
15
+
16
+
17
+
18
+
19
+ def GEOCODER(coords):
20
+ try:
21
+ lat = coords.get("latitude")
22
+ lon = coords.get("longitude")
23
+
24
+ if lat is None or lon is None:
25
+ return {
26
+ "status": "error",
27
+ "message": "Missing latitude or longitude.",
28
+ "data": None
29
+ }
30
+
31
+ location = geolocator.reverse(f"{lat}, {lon}", exactly_one=True)
32
+
33
+ if location and "address" in location.raw:
34
+ country_name = location.raw["address"].get("country")
35
+ country_code = location.raw["address"].get("country_code")
36
+
37
+ return {
38
+ "status": "success",
39
+ "message": "Location resolved successfully.",
40
+ "data": {
41
+ "country": country_name,
42
+ "code": country_code.upper() if country_code else None
43
+ }
44
+ }
45
+
46
+ return {
47
+ "status": "not_found",
48
+ "message": "Location could not be resolved.",
49
+ "data": None
50
+ }
51
+
52
+ except GeocoderServiceError as e:
53
+ return {
54
+ "status": "error",
55
+ "message": f"Geocoding service error: {str(e)}",
56
+ "data": None
57
+ }
58
+
59
+ except Exception as e:
60
+ return {
61
+ "status": "error",
62
+ "message": f"Unexpected error: {str(e)}",
63
+ "data": None
64
+ }
65
+
66
+
67
+
68
+
69
+ def SignatureVerification(X_401_Addr,X_401_Nonce,X_401_Sign,challange):
70
+
71
+
72
+ if X_401_Addr and X_401_Nonce and X_401_Sign:
73
+
74
+ try:
75
+
76
+ signature_bytes = base58.b58decode(X_401_Sign)
77
+ verify_key = VerifyKey(base58.b58decode(X_401_Addr))
78
+ payload_bytes = challange.encode("utf-8")
79
+
80
+ verify_key.verify(payload_bytes, signature_bytes)
81
+ return True
82
+
83
+ except BadSignatureError:
84
+
85
+ return False
86
+
87
+
88
+
89
+ def SecretNonceGenerator():
90
+ random_bytes = secrets.token_bytes(32)
91
+ return hashlib.sha256(random_bytes).hexdigest()
92
+
93
+
94
+
95
+
96
+
97
+
98
+
99
+
100
+
101
+
102
+
103
+ def TokenCheck(walletPublicKey,required_mint,mint_amount):
104
+
105
+ url = f"https://mainnet.helius-rpc.com/?api-key=4e833ada-d32c-48c5-b020-c11b2253f25b"
106
+ payload = {
107
+ "jsonrpc": "2.0",
108
+ "id": "1",
109
+ "method": "getTokenAccountsByOwner",
110
+ "params": [
111
+ walletPublicKey,
112
+ {"mint":required_mint},
113
+ {"encoding": "jsonParsed"}
114
+ ]
115
+ }
116
+
117
+ headers = {"Content-Type": "application/json"}
118
+
119
+ try:
120
+
121
+ response = requests.post(url, json=payload, headers=headers)
122
+ response.raise_for_status()
123
+ data = response.json()
124
+
125
+ except requests.exceptions.RequestException as e:
126
+
127
+ return {"status": False, "message": f"API Request Failed: {e}"}
128
+
129
+
130
+ token_accounts = data.get("result", {}).get("value")
131
+
132
+ if not token_accounts:
133
+
134
+ return False
135
+
136
+ try:
137
+
138
+ account_info = token_accounts[0]["account"]["data"]["parsed"]["info"]
139
+ token_amount = account_info["tokenAmount"]
140
+ ui_amount = float(token_amount.get("uiAmount"))
141
+
142
+ except (TypeError, KeyError, IndexError):
143
+
144
+ return {"status": False, "message": "Could not parse token account data"}
145
+
146
+ if ui_amount >= mint_amount:
147
+
148
+ print(ui_amount)
149
+ return True
150
+
151
+ else:
152
+ print(ui_amount)
153
+ return False
154
+
155
+
156
+
157
+
158
+
159
+
160
+
161
+
162
+
163
+ class x401Kit(BaseHTTPMiddleware):
164
+
165
+
166
+ def __init__(self, app,protected_paths:list):
167
+ super().__init__(app)
168
+ self.protected_paths = protected_paths
169
+
170
+
171
+
172
+
173
+ async def dispatch(self, request: Request, call_next):
174
+
175
+
176
+
177
+ if request.method == "OPTIONS":
178
+ return await call_next(request)
179
+
180
+ if not any(request.url.path.startswith(p) for p in self.protected_paths):
181
+ return await call_next(request)
182
+
183
+
184
+
185
+ NONCE=SecretNonceGenerator()
186
+
187
+ X_401_Nonce=request.headers.get("X-401-Nonce")
188
+ X_401_Sign=request.headers.get("X-401-Signature")
189
+ X_401_Addr=request.headers.get("X-401-Addr")
190
+ lat=request.headers.get("X-Lat")
191
+ long=request.headers.get("X-Long")
192
+
193
+
194
+ required_mint = request.headers.get("required_mint")
195
+ mint_amount=request.headers.get("mint_amount")
196
+ helius_api_key = request.headers.get("helius_api_key")
197
+ secret_domain = request.headers.get("secret_domain")
198
+ geo_code=request.headers.get("geo_code")
199
+ geo_code_locs=[request.headers.get("geo_code_locs")]
200
+ secret_domain=request.headers.get("secret_domain")
201
+
202
+
203
+
204
+ coords={
205
+
206
+ "latitude":lat,
207
+ "longitude":long
208
+
209
+ }
210
+
211
+
212
+
213
+
214
+ REQUIRED_SERVICE=None
215
+
216
+
217
+
218
+
219
+ if not X_401_Addr and not X_401_Nonce and not X_401_Sign :
220
+
221
+ payload401={
222
+
223
+ "X-401-Status":"Authrequired",
224
+ "x-401-Mechanism":"SOLANA",
225
+ "X-401-Nonce":NONCE,
226
+ "Access-Control-Allow-Origin": "*",
227
+ "Access-Control-Allow-Credentials": "true",
228
+ "Access-Control-Expose-Headers": "x-401-Nonce, x-401-Mechanism, x-401-Status"
229
+ }
230
+
231
+ return JSONResponse(content={
232
+
233
+
234
+ "message":"401 Auth Required",
235
+ "information":"Non persistant stateless auth"
236
+
237
+ },headers=payload401,status_code=401)
238
+
239
+
240
+
241
+ challange=f"CHALLENGE::{X_401_Nonce}::{request.url.path}::{secret_domain}"
242
+
243
+ signverify=SignatureVerification(X_401_Addr,X_401_Nonce,X_401_Sign,challange)
244
+ tokenverify=TokenCheck(X_401_Addr,required_mint,mint_amount)
245
+ print(tokenverify)
246
+
247
+ if signverify == True and tokenverify == True:
248
+
249
+
250
+ if geo_code==True:
251
+
252
+ country=GEOCODER(coords)
253
+ print(country)
254
+
255
+ if country["data"] is None:
256
+ return JSONResponse(
257
+
258
+ content={"status": "error", "message": f"Auth error"},
259
+ headers= {
260
+ "Access-Control-Allow-Origin": "*",
261
+ "Access-Control-Allow-Credentials": "true"
262
+ },
263
+ status_code=500
264
+ )
265
+
266
+
267
+ if country["data"]["code"] in geo_code_locs:
268
+
269
+ return JSONResponse(
270
+ content={"status": "locdeny", "message":f"access denied for {country['data']['country']}"},
271
+ headers= {
272
+ "Access-Control-Allow-Origin": "*",
273
+ "Access-Control-Allow-Credentials": "true"
274
+ },
275
+ status_code=401
276
+ )
277
+
278
+
279
+ response = await call_next(request)
280
+
281
+
282
+ if response.headers.get("content-type") == "application/json":
283
+
284
+ body_bytes = b""
285
+ async for chunk in response.body_iterator:
286
+ body_bytes += chunk
287
+
288
+ try:
289
+ data = json.loads(body_bytes.decode())
290
+ except json.JSONDecodeError:
291
+ return response
292
+
293
+
294
+ data["address"] = X_401_Addr
295
+
296
+ response_headers = dict(response.headers)
297
+ response_headers.pop("content-length", None)
298
+ print(data)
299
+
300
+ return JSONResponse(
301
+ content=data,
302
+ status_code=response.status_code,
303
+ headers=response_headers
304
+ )
305
+
306
+
307
+ return response
308
+
309
+
310
+ elif tokenverify==False:
311
+ return JSONResponse(
312
+ content={"status": "error", "message": "Missing required token"},
313
+ status_code=500,
314
+ headers={
315
+ "Access-Control-Allow-Origin": "*",
316
+ "Access-Control-Allow-Credentials": "true"
317
+ }
318
+
319
+ )
320
+
321
+ elif signverify==False:
322
+ print("failed")
323
+ return JSONResponse(
324
+ content={"status": "error", "message": "bad signature"},
325
+ status_code=500,
326
+ headers={
327
+ "Access-Control-Allow-Origin": "*",
328
+ "Access-Control-Allow-Credentials": "true"
329
+ })
330
+
331
+
332
+
333
+ else:
334
+ return JSONResponse(
335
+ content={"status": "error", "message": "Authentication failed"},
336
+ status_code=500,
337
+ headers={
338
+ "Access-Control-Allow-Origin": "*",
339
+ "Access-Control-Allow-Credentials": "true"
340
+ })