Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Howto do a order and automatic payment #215

Open
NightFalcon650 opened this issue Feb 13, 2023 · 35 comments
Open

Howto do a order and automatic payment #215

NightFalcon650 opened this issue Feb 13, 2023 · 35 comments

Comments

@NightFalcon650
Copy link

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?

@Jurrie
Copy link
Contributor

Jurrie commented Feb 16, 2023

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.

@solve-fx
Copy link

Is this how you were able to find the endpoints and create your pull request @Jurrie?

@Jurrie
Copy link
Contributor

Jurrie commented Mar 20, 2023

Yes it is. It's not all that hard actually:

  1. Install Android Studio.
  2. Create an Android Virtual Device (make sure to select an image with Google Play, otherwise the TGTG app will not run).
  3. Install the TGTG app (download it via something like APK Pure and use adb install <APK>).
  4. Root the AVD using the instructions here.
  5. Use mitmproxy or something similar to sniff the traffic (install the mitmproxy CA certificate to the system trust store first).

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.

@SamyMP
Copy link

SamyMP commented Apr 12, 2023

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.

@Vivalemuc
Copy link

@Jurrie

Can you share sample of the payment request bro ? Even if it's not perfect, just to see the work :)

@matteonu
Copy link

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).

@Vivalemuc
Copy link

@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 ?

@brandonbondig
Copy link
Contributor

@matteonu

Thanks for the solution, it worked perfectly!

@Vivalemuc
Copy link

@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..

@brandonbondig
Copy link
Contributor

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)

@Vivalemuc
Copy link

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 ?

@Vivalemuc
Copy link

@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 :)

@matteonu
Copy link

@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.

@Vivalemuc
Copy link

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 !

@Landwirt909
Copy link

@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']}")

@Crankle437
Copy link

@Landwirt909 I've the same issue. I've tried it with cards from Revolut (temp and virtual cards).

@Nyantad
Copy link

Nyantad commented Oct 6, 2023

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!

@SwannG
Copy link

SwannG commented Oct 15, 2023

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'}

@liulock
Copy link

liulock commented Nov 27, 2023

tgtg updated the payment encryption, no wonder @matteonu 's method stop working.

@extern94
Copy link

is there a way to manually pay for the created order?

@hovak101
Copy link

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

@extern94
Copy link

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

@Vivalemuc
Copy link

@extern94

Can you share your code snippet pls ? I only want paypal payment to buy order myself !
Thanks

@hovak101
Copy link

@extern94 got ya. That's a great solution! I'll have to look into it.

@sebastianpc
Copy link

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

@mehov
Copy link

mehov commented Feb 28, 2024

Hi everyone

Can you please point to how can the payments be implemented using Paypal?

The Adyen method doesn't work for me either.

@floriegl
Copy link
Contributor

floriegl commented May 7, 2024

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

@floriegl
Copy link
Contributor

floriegl commented May 8, 2024

Also see: Der-Henning/tgtg#171

@Shusaku1
Copy link

Shusaku1 commented Jan 3, 2025

Yes it is. It's not all that hard actually:

  1. Install Android Studio.
  2. Create an Android Virtual Device (make sure to select an image with Google Play, otherwise the TGTG app will not run).
  3. Install the TGTG app (download it via something like APK Pure and use adb install <APK>).
  4. Root the AVD using the instructions here.
  5. Use mitmproxy or something similar to sniff the traffic (install the mitmproxy CA certificate to the system trust store first).

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, thank you for the detailed steps written out.
Though I have implemented all of the above, with mitmproxy CA certificate, TGTG still seems to not let me do any action with extra security of certificate pinning or something. Has any of you encountered this situation, or have any idea how I could overcome this situation?

@floriegl
Copy link
Contributor

floriegl commented Jan 3, 2025

Hi, thank you for the detailed steps written out. Though I have implemented all of the above, with mitmproxy CA certificate, TGTG still seems to not let me do any action with extra security of certificate pinning or something. Has any of you encountered this situation, or have any idea how I could overcome this situation?

@Shusaku1 Der-Henning/tgtg#171 (comment) (apk-mitm also removes certificate pinning)

@Shusaku1
Copy link

Shusaku1 commented Jan 5, 2025

Hi, thank you for the detailed steps written out. Though I have implemented all of the above, with mitmproxy CA certificate, TGTG still seems to not let me do any action with extra security of certificate pinning or something. Has any of you encountered this situation, or have any idea how I could overcome this situation?

@Shusaku1 Der-Henning/tgtg#171 (comment) (apk-mitm also removes certificate pinning)

Thank you @floriegl!
Thanks for sharing your method. I’ve been trying a similar setup, but ran into some issues. I would really appreciate it if you or anybody could provide some advice. Here’s the of steps I took:

Installed a Google Pixel 2 emulator (API 31) and rooted it with Magisk. Added the MITMProxy CA certificate to the emulator.
Set up MITMProxy and was able to intercept traffic from various websites (e.g., Wikipedia) over HTTP and HTTPS. However, none of TGTG's traffic appeared, and the app showed an error: “Something went wrong, try again later.” This led me to suspect SSL pinning.
Following the method you mentioned, I used adb to pull the APK from the emulator to my host machine for patching.
On the host machine, I used apk-mitm (latest version) along with Apktool to patch the APK for bypassing SSL pinning. During the process, I encountered errors related to styles.xml and enums. To bypass these errors, I used a flag like --ignore-resources (or a similar workaround) to compile the APK successfully.
Reinstalled the patched APK on the emulator, but the app didn’t open anymore, which I suspect was due to the workaround potentially breaking functionality.
I’m wondering if I missed a step when using apk-mitm, especially for handling SSL pinning or hostname verification. Did you encounter issues like the styles.xml or enums error during the patching process? If so, how did you resolve them without affecting the app’s functionality?

@floriegl
Copy link
Contributor

floriegl commented Jan 5, 2025

I used apk-mitm (latest version) along with Apktool to patch the APK for bypassing SSL pinning.

@Shusaku1 did you use the latest version of Apktool (v2.10.0) too? apk-mitm often doesn't use the current version per default (check usage on how to specify the correct version)

@Shusaku1
Copy link

Shusaku1 commented Jan 5, 2025

@floriegl Yes, I have used the latest version of Apktool(v2.10.0).....

I pulled the base.apk and split APKs (split_config.en.apk, split_config.x86_64.apk, etc.) to my host machine. I then used apk-mitm with apktool to patch the base.apk for bypassing SSL pinning. Is this the correct step that you went through as well?

@floriegl
Copy link
Contributor

floriegl commented Jan 5, 2025

I did my reverse engineering before they changed to split APKs only. I also used an unrooted Nox emulator (apk-mitm adds the mitm-proxy certificate to the apk). Maybe just patching the full xapk (see niklashigi/apk-mitm#175 (comment)) and then installing it with Split APKs Installer works?

@Shusaku1
Copy link

Shusaku1 commented Jan 5, 2025

Thank you for the advice @floriegl . I finally managed to bypass Certificate Pinning as well and now can see TGTG on mitmproxy.
I managed to make it work with Magisk modules of MagiskTrustUserCerts, without apkTools.
For reference, if anybody needs. https://github.com/NVISOsecurity/MagiskTrustUserCerts

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests