logicguy1 / Discord-Nitro-Generator-and-Checker

Generate discord nitro codes and check them
MIT License
616 stars 987 forks source link

This Script Won't Work Due to Cloudflare Rate Limiting (Working Code Included) #146

Open MatchaOnMuffins opened 2 years ago

MatchaOnMuffins commented 2 years ago

Describe the bug Discord protects its services with the Cloudflare network, which imposes strict API rate limiting. The original Gift Code validity checker quickChecker (which relies on spamming the API) will get blocked after roughly 5 requests. The Discord Gift Code API rate limit is roughly 5 requests per minute. This is a fundamental issue (aside from the minuscule chance of getting a valid code by brute-forcing).

Desktop:

Smartphone:

Additional context

Rate limits exist across Discord's APIs to prevent spam, abuse, and service overload. Limits are applied to individual bots and users both on a per-route basis and globally. Individuals are determined using a request's authentication—for example, a bot token for a bot. -- Discord API Documentation

Exceeding A Rate Limit In the case that a rate limit is exceeded, the API will return a HTTP 429 response code with a JSON body. Your application should rely on the Retry-After header or retry_after field to determine when to retry the request. -- Discord API Documentation

Working Code

The following is an improved version of the original code, where rate limits are handled by default and the possibility of generating legit Nitro Gift Codes actually exist. However, the chances of getting a valid Nitro Gift Code using any brute-forcing method is roughly $3.12 \times 10^ {-30}$ (if around 10000 Nitro Gift Codes are in circulation at any given moment), so the possibility of obtaining Nitro this way is possibly 28 orders of magnitudes smaller than simply asking a parental figure to purchase it for you and 21 orders of magnitudes smaller than winning the world's biggest lottery.

import asyncio
import string
import time
import httpx
import numpy

__config__ = {
    "Use_WebHook": True,
    # Set the WebHook URL if Use_WebHook is True
    "WebHook_URL": "",
}

if __config__["Use_WebHook"]:
    if __config__["WebHook_URL"] == "":
        print("[!] Please set WebHook URL in __config__")
        """
        Or
        __config__["Use_WebHook"] = False
        """

        raise Exception("WebHook URL is empty")
    else:
        print("WebHook URL: " + __config__["WebHook_URL"])

USE_WEBHOOK = False
# check if user is connected to internet
github_url = "https://github.com"
try:
    response = httpx.get(github_url)  # Get the response from the url
    print("Internet check")
    time.sleep(.4)
except ConnectionError:
    # Tell the user
    input("You are not connected to internet, check your connection and try again.\nPress enter to exit")
    exit()  # Exit program

class NitroGen:  # Initialise the class
    def __init__(self):  # The initialisation function
        self.fileName = "Nitro_Codes.txt"  # Set the file name the codes are stored in

    async def main(self):  # The main function contains the most important code
        num = 0  # Set the number to 0
        num_str = input(f"Enter amount of Nitro Codes you want to generate: ")
        # Ask the user how many codes they want to generate
        try:
            num = int(num_str)  # Try to convert the string to an integer
        except ValueError:  # If the user enters a string instead of an integer
            input("Specified input wasn't a number.\nPress enter to exit")
            exit()  # Exit program

        valid = []  # Keep track of valid codes
        invalid = 0  # Keep track of how many invalid codes was detected
        chars = []
        chars[:0] = string.ascii_letters + string.digits

        # generate codes faster than using random.choice
        c = numpy.random.choice(chars, size=[num, 19])  # Currently, Discord Nitro Codes are 19 characters long
        for s in c:  # Loop over the amount of codes to check
            code = ''.join(x for x in s)
            url = f"https://discord.gift/{code}"
            try:
                result = await NitroGen.quickChecker(code)  # Check the codes
                if result:  # If the code was valid
                    # Add that code to the list of found codes
                    valid.append(url)
                    # write the code to self.fileName
                    with open(self.fileName, "a") as f:
                        f.write(f"{url}\n")
                    if __config__["Use_WebHook"]:
                        await NitroGen.webhook(url)
                else:  # If the code was not valid
                    invalid += 1  # Increase the invalid counter by one
                # sleep for a bit to prevent hitting the rate limit
                # Discord gift codes are limited to 5 requests per minute
                time.sleep(12)
            except KeyboardInterrupt:
                # If the user interrupted the program
                print("\nInterrupted by user")
                break  # Break the loop
            except Exception as e:
                print(e)
                print(f" Error | {url} ")  # Tell the user an error occurred

        print(f"""
Results:
Valid: {len(valid)}
Invalid: {invalid}
Valid Codes: {', '.join(valid)}
""")  # Give a report of the results of the check

        # Tell the user the program finished
        input("\nThe end! Press Enter to close the program.")

    @staticmethod
    def slowType(text: str, speed: float, newLine=True):
        for i in text:  # Loop over the message
            # Print the one character, flush is used to force python to print the char
            print(i, end="", flush=True)
            time.sleep(speed)  # Sleep a little before the next one
        if newLine:  # Check if the newLine argument is set to True
            print()  # Print a final newline to make it act more like a normal print statement

    @staticmethod
    async def quickChecker(nitro: str):  # Used to check a single code at a time
        try:
            # Generate the request url
            url = f"https://discordapp.com/api/v9/entitlements/gift-codes/{nitro}?with_application=false&with_subscription_plan=true"
            response_api = httpx.get(url)  # Get the response from discord

            if response_api.status_code == 200:  # If the response went through
                # Notify the user the code was valid
                print("200 response | Valid Code")
                print(f"{nitro}")
                return True  # Tell the main function the code was found

            # If the request was rate limited
            elif response_api.status_code == 429:
                print(f"{response_api.status_code} response| Rate Limited")
                delay = int(response_api.headers.get("Retry-After"))
                print(f"Waiting for {delay} seconds")
                await asyncio.sleep(delay)
                return await NitroGen.quickChecker(nitro)
            elif response_api.status_code == 404:
                # print(f"{response_api.status_code} response | Invalid Code")
                print(f"{404} response | Invalid Code")
                return False
            else:
                # Tell the user it tested a code, and it was invalid
                print(url)
                print(f"{response_api.status_code} response | Invalid Code")
                print(response_api.headers)
                # log invalid code
                with open("invalid_codes.txt", "a") as f:
                    f.write(f"{nitro}\n")

                return False  # Tell the main function there was not a code found
        except KeyboardInterrupt:
            # If the user interrupted the program
            print("\nInterrupted by user")
            return False  # Tell the main function there was not a code found
        except Exception as e:
            print(e)

    @staticmethod
    async def webhook(url: str):
        # sends a post request to the webhook url
        webhook_content = {
            "username": "NitroGen",
            "embeds": [
                {
                    "title": "Nitro Code Found",
                    "fields": [{
                        "name": "Nitro Code",
                        "value": f"{url}",
                    }],
                    "color": 0xFFC0CB,  # Color of the embed (Pink)
                }
            ],
        }
        webhook_url = __config__["WebHook_URL"]
        httpx.post(webhook_url, json=webhook_content)

if __name__ == '__main__':
    Gen = NitroGen()  # Create the nitro generator object
    asyncio.run(Gen.main())  # Run the main code

Other Issues

The URL provided to quickChecker in main is an address instead of a Gift Code, which will result in a response status code of 404 not found regardless of the Gift Code. changing url to code in line 120 will fix this. This issue is fixed in the code above. https://github.com/logicguy1/Discord-Nitro-Generator-and-Checker/blob/63d7070234bb2af94ba3caa1db615b1ad83b548e/main.py#L118-L120

scaandal commented 1 year ago

@MatchaOnMuffins bro, can you write a code where the nitro check will be without a webhook? And so that the logs are also displayed

MatchaOnMuffins commented 1 year ago

@MatchaOnMuffins bro, can you write a code where the nitro check will be without a webhook? And so that the logs are also displayed Just set "Use_WebHook" to False

Yu-Vitaqua-fer-Chronos commented 1 year ago

Is there any way to make it faster? Doubt it since ratelimiting but, would be nice

Yu-Vitaqua-fer-Chronos commented 1 year ago

One solution could be proxy servers, perhaps?

MatchaOnMuffins commented 1 year ago

Yes, proxy servers would work, but it would still take forever to generate a working code

logicguy1 commented 1 year ago

You need private proxies for that, might as well just buy nitro

MatchaOnMuffins commented 1 year ago

You need private proxies for that, might as well just buy nitro

exactly