Open NightFalcon650 opened 1 year ago
For now, these functions are not implemented. You can figure them out yourself. Easiest way (though not all that easy) is to sniff the traffic of the TGTG app running on an Android emulator. You could use mitmproxy to sniff that traffic. You'll need an Android emulator (an AVD) with Google Play, and you'll need to insert the mitmproxy CA certificate as trusted system certificate. Not easy, and you're probably on your own, but it's definitely doable.
Is this how you were able to find the endpoints and create your pull request @Jurrie?
Yes it is. It's not all that hard actually:
adb install <APK>
).I wrote some documentation on how to do this for mitmproxy. My PR was merged, but no new release was done yet. So the documentation is not live. But it's on GitHub: check here. Using the latest release of mitmproxy (v9.0.1 currently) works just fine.
Hi @Jurrie,
Thank you for the detailed tutorial. I am also interested in implementing such a method to automate payment. However, unfortunatly, I can not run Android Studio or even a simple emulator on my computer since I do not have enough memory, my computer becomes very laggy when I try to use virtualization.
Do you think it would be possible for you to share the code you implemented, even if it's not perfect and needs clean up (I can do that if you want) ? Of course, if there are any sensitive information (like card numbers hard coded), you can replace it with placeholders.
@Jurrie
Can you share sample of the payment request bro ? Even if it's not perfect, just to see the work :)
I made a fork that supports payments with credit cards (https://github.com/matteonu/tgtg-python). It should work for cards where no ThreeDS2 authorization is needed. For ThreeDS2 authorization support you need to be able to handle Adyen actions I think (https://docs.adyen.com/online-payments/3d-secure/native-3ds2/web-component?tab=create-new-component_2#3ds2-component).
@matteonu Thanks for sharing :)
Is it possible to take the card on the account or not ? Because i made a bot for my friend, and i dont want to store the credit card information :) Or maybe using paypal accoun ?
@matteonu
Thanks for the solution, it worked perfectly!
@brandonbondig
Did you succeed to pay order with store card in TGTG pref ? I succeed to get the store card with v1/payments endpoint, i get the card identifier, but i dont succeed to pay order with this card. It will be so useful to avoid put the card each time etc..
I haven't been successful in paying with the card stored on the TGTG app. By using @matteonu's method from the py-adyen-encrypt library on GitHub, I was able to successfully use my credit/debit card to pay for the reserved ID with TGTG's payment endpoint.
def pay_order(self, order_id, card_data: dict[str, str]):
self.login()
headers = {
"User-Agent": USER_AGENTS[2],
"Host": "checkoutshopper-live.adyen.com",
"Connection": "Keep-Alive",
}
url = urljoin(BASE_URL_ADYEN, ADYEN_KEY_ENDPOINT)
response = requests.request("GET", url, headers=headers, data={})
ADYEN_KEY = response.json()["publicKey"]
enc = encryptor(ADYEN_KEY)
enc.adyen_version = "_0_1_1"
card = enc.encrypt_card(
card=card_data["card"],
cvv=card_data["cvv"],
month=card_data["month"],
year=card_data["year"],
)
inner_payload = {
"type": "scheme",
"encryptedCardNumber": card["card"],
"encryptedExpiryMonth": card["month"],
"encryptedExpiryYear": card["year"],
"encryptedSecurityCode": card["cvv"],
"threeDS2SdkVersion": "2.2.10",
}
inner_payload_str = json.dumps(inner_payload).replace("/", "\/")
payload = {
"authorization": {
"authorization_payload": {
"payload": inner_payload_str,
"payment_type": "CREDITCARD",
"save_payment_method": False,
"type": "adyenAuthorizationPayload",
},
"payment_provider": "ADYEN",
"return_url": "adyencheckout://com.app.tgtg.itemview",
}
}
payload_str = json.dumps(payload)
response = self.session.post(
url=self._get_url(PAY_ORDER_ENDPOINT.format(order_id)),
headers=self._headers,
data=payload_str,
proxies=self.proxies,
timeout=self.timeout,
)
if response.status_code == HTTPStatus.OK:
return response.json()
else:
raise TgtgAPIError(response.status_code, response.content)
yeah :( But i use it with many friends, and i dont want store the credit card on my server obviously :)
@matteonu I just need the payload when user click on "Pay" on the App with store card, did you have it ? Or maybe @Jurrie ?
@Override // an.a public final Object invokeSuspend(Object obj) { Object obj2; c cVar; a aVar = a.COROUTINE_SUSPENDED; int i8 = this.f18862i; PaymentViewModel paymentViewModel = this.f18863j; PaymentMethods paymentMethods = this.f18864k; if (i8 == 0) { n0.F(obj); c cVar2 = paymentViewModel.f9077c; c3 c3Var = paymentViewModel.f9076b; String cardIdentifier = paymentMethods.getCardIdentifier(); this.f18861h = cVar2; this.f18862i = 1; e eVar = c3Var.f13481a; eVar.getClass(); g0 a5 = g0.a(1, "SELECT secret FROM biodata WHERE id = ?"); if (cardIdentifier == null) { a5.z(1); } else { a5.q(1, cardIdentifier); } obj2 = n.s(eVar.f15733a, new CancellationSignal(), new j4.e(eVar, 4, a5), this); if (obj2 == aVar) { return aVar; } cVar = cVar2; } else if (i8 == 1) { cVar = this.f18861h; try { n0.F(obj); obj2 = obj; } catch (Exception unused) { paymentViewModel.j(paymentMethods); return Unit.f19672a; } } else { throw new IllegalStateException("call to 'resume' before 'invoke' with coroutine"); } String str = (String) obj2; KeyPair keyPair = this.f18865l; Intrinsics.c(keyPair); PrivateKey privateKey = keyPair.getPrivate(); Intrinsics.c(privateKey); cVar.getClass(); Intrinsics.checkNotNullParameter(str, "data"); Cipher cipher = cVar.f12264a; cipher.init(2, privateKey); byte[] doFinal = cipher.doFinal(Base64.decode(str, 0)); Intrinsics.checkNotNullExpressionValue(doFinal, "decodedData"); String str2 = new String(doFinal, b.f19720b); PaymentType paymentType = paymentMethods.getPaymentType(); Intrinsics.c(paymentType); PaymentViewModel.k(this.f18863j, new AuthorizationPayload(str2, (String) null, false, paymentType.name(), "adyenAuthorizationPayload", new AdyenCustomPayload(this.f18866m, paymentMethods.getCardIdentifier()).toJson(), (String) null, (String) null, (String) null, (String) null, 966, (DefaultConstructorMarker) null), this.f18864k, this.f18867n, this.f18868o, this.f18869p); return Unit.f19672a; }
I need to understand the str2 string, to pass at biometricssecret to use the store card :)
@Vivalemuc Honestly, I think this is a lost cause. Also in the end you probably get your friends credit card info again but this time via TooGoodToGo. What you could try is to send your friends the private key, they encrypt their credit card info, send it to you and you then make the payment with the encrypted info. This could be automated of course.
i cant do this in automatic process, because the user need to input the data in my program, so it's not secure..
If i get the Card ID store in TGTG app, and use it to pay order it will be totaly secure for me, and for users too !
@brandonbondig I don't know why but for me the Payment always fails. Maybe I forgot something but this is what I have done:
order = client.create_order(item_id, 1) order_id = order['id'] time.sleep(1) payment = client.pay_order(order_id, card_data) payment_id = payment['payment_id'] time.sleep(1) print(f"Payment status: {client.get_payment_status(payment_id)['state']}")
@Landwirt909 I've the same issue. I've tried it with cards from Revolut (temp and virtual cards).
Hi I'm back on this thread but it was to know if there had been improvements on this automatic payment system or if someone else had done something else!
Same issue on my side with 3 different cards.
On pay_order -> {'payment_id': '12345', 'order_id': '54321', 'payment_provider': 'ADYEN', 'state': 'AUTHORIZATION_INITIATED', 'user_id': '1111'}
On get_payment_status -> {'payment_id': '12345', 'order_id': '54321', 'payment_provider': 'ADYEN', 'state': 'FAILED', 'user_id': '1111'}
tgtg updated the payment encryption, no wonder @matteonu 's method stop working.
is there a way to manually pay for the created order?
I think this is a lost cause. The issue we have is figuring out the AES key, which we would need in order to encrypt the payload in order for Adyen to process our order. However, this is impossible to know without having access to the client code, which we do not. We only know the public RSA key, which is used for encrypting the AES key. But that doesn't help with actually encrypting and sending over the payload. Please let me know if I've misunderstood something, I'm a novice when it comes to encryption :) Shouldn't we close this issue now? @ahivert
i managed payment by using paypal and a telegram bot to send the payment link on my phone So if this semi automatic version is an option, it is easily implemented following the guide from @Jurrie
@extern94
Can you share your code snippet pls ? I only want paypal payment to buy order myself ! Thanks
@extern94 got ya. That's a great solution! I'll have to look into it.
Hello @hovak101
It seems the AES key is randomly generated.
The following code should be the code behind it: https://gist.github.com/sebastianpc/16ab6a81f1273f8839dffb65e6ddad86
Hi everyone
Can you please point to how can the payments be implemented using Paypal?
The Adyen method doesn't work for me either.
Before create order (maybe even possible after the order is created): POST https://apptoogoodtogo.com/api/paymentMethod/v1/item/<item_id>
with {"supported_types":[{"provider":"ADYEN","payment_types":["CREDITCARD","SOFORT","IDEAL","PAYPAL","BCMCMOBILE","BCMCCARD","VIPPS","TWINT","MBWAY","SWISH","BLIK","GOOGLEPAY"]},{"provider":"VOUCHER","payment_types":["VOUCHER","FAKE_DOOR"]},{"provider":"BRAINTREE","payment_types":["VENMO"]},{"provider":"CHARITY","payment_types":["CHARITY"]},{"provider":"SATISPAY","payment_types":["SATISPAY"]}]}
and make sure that the response json has a payment_methods_state = "SUCCESS" and payment_methods[].payment_type = "PAYPAL"
Create order and make sure order is reserved with POST https://apptoogoodtogo.com/api/order/v7/<order.id>/status
(response should have the JSON property "state" = "RESERVED"
POST https://apptoogoodtogo.com/api/order/v7/<orrder.id>/pay
with {"authorization":{"authorization_payload":{"save_payment_method":false,"payment_type":"<payment_methods[]payment_type - should be 'PAYPAL'>","type":"adyenAuthorizationPayload","payload":<payment_methods[].adyen_api_payload>},"payment_provider":"<payment_methods[]-payment_provider - should be 'ADYEN'>","return_url":"adyencheckout://com.app.tgtg.itemview"}}
(where payment_methods[].payment_type = "PAYPAL"; the payload is a JSON string with escape characters e.g., "{\"configuration\":{\"merchantId\":\"<retracted>\",\"intent\":\"authorize\"},\"name\":\"PayPal\",\"type\":\"paypal\"}"
); save payment_id from the response json
POST https://apptoogoodtogo.com/api/payment/v3/<payment_id >
- the response json has a payload property looking like this: "{\"method\":\"GET\",\"paymentMethodType\":\"paypal\",\"resendInterval\":0,\"resendMaxAttempts\":0,\"type\":\"redirect\",\"url\":\"https://live.adyen.com/hpp/checkout.shtml?u=redirectPayPal&p=<some_magic_payment_string>\"}",
This live.adyen.com
link should work for finishing the payment
I love a Pythonscript to order tgtg boxes, but does anyone have a working pythonscript so you can order and automatically pay for exampe through iDeal?