Skip to content
This repository has been archived by the owner on Apr 2, 2023. It is now read-only.

Commit

Permalink
Merge branch 'add-submit-entry' into main
Browse files Browse the repository at this point in the history
Matthew17-21 committed May 1, 2021

Unverified

This commit is not signed, but one or more authors requires that any commit attributed to them is signed.
2 parents a973de1 + 1f0d6d4 commit 39f31f6
Showing 10 changed files with 786 additions and 45 deletions.
44 changes: 36 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
@@ -26,13 +26,26 @@ $ python3 main.py
| keys | dict | dict containing keys to solving sites | - |
| generate_random | bool | Should the program generate random password. | `true` or `false` |
| choices | array | Array of password choices | - |

| user_agents| array | Array of user-agents for mobile & desktop | - |

### /newegg/*
- Contains the core software code.

# Creating Accounts
- If you want to create accounts via mobile, change line 93 in `main.py` from `desktop.Create_Account(self, email)` to `mobile.Create_Account(self, email)`
* And vice versa
- MAKE SURE YOU STORE YOUR SESSIONS SOMEWHERE (Don't delete the `.log` file)

# Submitting Entries
- In order to submit entries, you must make sure:
* The program will pull accounts/sessions from the filename that was used to create accounts (`output_filename` in the settings.json file).
* Your .log file is in the main directory (alongside with `main.py`)
* Accounts/Sessions are still in the .log file
* The program will automatically enter on the same platform as the account was created (Desktop or App)
* MAKE SURE YOU KEEP YOUR SESSIONS (Don't delete the `.log` file)

# Recommendations
1. **MAKE SURE YOU STORE YOUR SESSIONS SOMEWHERE**
1. **MAKE SURE YOU STORE YOUR SESSIONS SOMEWHERE (Don't delete the `.log` file)**
2. Althought not completely necessary, but you should add/delete/randomify events for accertify.
3. Make sure iOS app version is up to date
4. Handle exceptions better
@@ -47,12 +60,23 @@ $ python3 main.py
* I recommend using anticaptcha for V3, but Capmonster & 2Captcha is also available.
- Only tested on Python 3.7
* *Should* work on other versions, but I can't promise anything.
- This is intended for devs, so try not to change too much code as it might break something.
- This is intended for devs. If you aren't familiar with python, try not to change too much code as it might break something.
- This isn't a reflection of how I actually write code so pls don't judge too hard :joy:
* I've been writing in Go lately, hence the structure of the whole thing.
- If you want to create accounts via mobile, change line 79 in `main.py` from `desktop.Create_Account(self, email)` to `mobile.Create_Account(self, email)`
* And vice versa
- There are lots of ways to make this better, cleaner and better on memory. If I find till I'll update this repo.
- There are lots of ways to make this better, cleaner and better on memory. If I find time, I'll update this repo.


# Maintenance
- This bot is fully functional with success. I won't be working on it much. I'll only work on it when:
* They make some massive change
* Have *loads* of free time and can complete the [to do list](https://github.com/Matthew17-21/Newegg-Shuffle#to-do)
- Pull requests are always welcome
- If any issues were to arise, [open an issue](https://github.com/Matthew17-21/Newegg-Shuffle/issues/new)
* Please incude:
* Python version
* Error
* How to replicate
- You may also contact me on discord - `Matthew#6937` with any questions or concerns

# FAQ
1. Does this work out of the box?
@@ -68,8 +92,12 @@ $ python3 main.py

# Success
![Genning](https://i.imgur.com/lvrTp36.png)
![Running](https://i.imgur.com/r8gPUIq.png)
![Success](https://i.imgur.com/8csUoqR.png)

# TO DO
1. [] Clean up code
2. [] Update documentation
1. [] Clean up & document code
2. [] Release GUI version
3. [] Maybe a folder for logs?
4. [] Release in Go
5. [] Inherit, don't pass.
9 changes: 9 additions & 0 deletions data/settings.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"ios_app_version": "6.23.0",
"output_filename": "Successfully created accounts.log",
"captcha": {
"version": "v3",
@@ -17,6 +18,14 @@
"Also,IfYouHaventNoticed,!!1!",
"ThereNeedsToBeANumberAndSpecialChar!12!"
]
},
"user_agents": {
"mobile":[
"Mozilla/5.0 (iPhone; CPU iPhone OS 14_4_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0.3 Mobile/15E148 Safari/604.1"
],
"desktop":[
"Mozilla/5.0 (Macintosh; Intel Mac OS X 11_2_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.114 Safari/537.36"
]
}

}
155 changes: 136 additions & 19 deletions main.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import sys
try:
import os
import platform
import logging
import json
import threading
@@ -10,21 +12,21 @@
colorama.init()
init(autoreset=True)
from captchatools import captcha_harvesters
from newegg.create_account import desktop, mobile, static_data
from newegg.create_account import static_data
import time
except ModuleNotFoundError:
print("Make sure you ran pip3 install -r requirements.txt")
time.sleep(999)
sys.exit(0)


with open("./data/settings.json") as settingsFile:
settings = json.load(settingsFile)
logging.basicConfig(filename=settings["output_filename"], level=logging.INFO)

class Newegg:
def __init__(self):
self.screenlock = Semaphore(value=1)

# Load config
settings = self.load_settings()
self.settings = settings
if settings["captcha"]["captcha_solver"] == 1 or str( settings["captcha"]["captcha_solver"]).lower() == "capmonster":
api_key = settings["captcha"]["keys"]["capmonster"]
@@ -33,9 +35,9 @@ def __init__(self):
elif settings["captcha"]["captcha_solver"] == 3 or str( settings["captcha"]["captcha_solver"]).lower() == "2captcha":
api_key = settings["captcha"]["keys"]["2captcha"]

if settings["captcha"]["version"] == "v3":
if settings["captcha"]["version"].lower() == "v3":
sitekey = static_data.v3_sitekey
elif settings["captcha"]["version"] == "v3":
elif settings["captcha"]["version"].lower() == "v2":
sitekey = static_data.v2_sitekey


@@ -47,33 +49,148 @@ def __init__(self):
min_score=0.7, action="Register", captcha_type=settings["captcha"]["version"]
)

# Start the bot.
# Start the bot when initialized.
self.main()

def main(self):
num_tasks = eval(input(Fore.BLUE + "Enter amount of tasks at a time: " + Fore.WHITE + " "))
'''
Main method.
This method will be called (automatically) when the bot starts.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
'''

# Get user input for what they want to do
print()
print(Fore.CYAN + '1' ,Fore.MAGENTA + "=", Fore.YELLOW + "Create Accounts")
print(Fore.CYAN + '2' ,Fore.MAGENTA + "=", Fore.YELLOW + "Submit Entries")
choice = eval(input("{}".format(Fore.MAGENTA + "Enter your choice: " + Fore.CYAN)))
if choice == 1:
self.create_accounts()
elif choice == 2:
self.submit_entries()

def load_settings(self):
# Some users said their program couldn't find the files
# So this is a quick fix to that.
original_path = os.getcwd()
os.chdir("./data/")
self.PATH_EMAILS = os.getcwd() + "\\emails.txt"
self.PATH_PROXIES = os.getcwd() + "\\proxies.txt"
if platform.system() == "Linux" or platform.system() == "Darwin":
self.PATH_EMAILS = self.PATH_EMAILS.replace("\\", "/")
self.PATH_PROXIES = self.PATH_PROXIES.replace("\\", "/")


# Open settings file
settings_file_path = os.getcwd() + "/settings.json"
os.chdir(original_path)
with open(settings_file_path) as settingsFile:
try:
return json.load(settingsFile)
except json.JSONDecodeError:
print(Fore.RED + "There is an error in your settings.json file." +
"Make sure the commas are correct and there aren't any extra commas!")
time.sleep(999)
sys.exit(0)

def create_accounts(self):
'''
This method will be called when the user wants to create Newegg Accounts.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
It will pull emails from the /data/emails.txt folder and use those
to create the accounts
'''
from newegg.create_account import desktop, app, static_data

# Prompt for how many tasks
num_tasks = eval(input(Fore.BLUE + "\nEnter amount of tasks at a time: " + Fore.WHITE + " "))
self.sema = threading.Semaphore(value=num_tasks)
threads = []

with open("./data/emails.txt") as email_file:
# Start to create create accounts
with open(self.PATH_EMAILS) as email_file:
for line in email_file.readlines():
email = line.split(':')[0].strip("\n")
self.sema.acquire()
thread = threading.Thread(target=self.create,args=(email,))
thread = threading.Thread(target=desktop.Create_Account,args=(self,email))
threads.append(thread)
thread.start()

def create(self,email):
task = desktop.Create_Account(self, email)
data = task.start()
def submit_entries(self):
'''
This method will be called when the user wants to enter the Newegg raffle.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
It'll pull sessions from the file that the user used to create accounts
'''
from newegg.submit_raffle import raffles, app, desktop
path_to_created_accounts = os.getcwd() + "\\{}".format(self.settings["output_filename"]) if \
platform.system == "Windows" else os.getcwd() + "/{}".format(self.settings["output_filename"])

# Because Newegg still has V2 captcha enabled for submitting entries,
# we'll use that over V3. If for whatever reason you want to use V3,
# you would have to change this line of code.
self.captcha_solver.sitekey = "6Lcv-WUUAAAAAA9hyir8HPKZ44OvDLg1oZqnq_9d"
self.captcha_solver.captcha_type = "v2"

# Scrape & display raffle items
print()
print(Fore.YELLOW + "Getting items in raffle...")
items = raffles.get_items()
index = 0
for item in items:
print(Fore.GREEN + str(index) ,Fore.MAGENTA + "=", Fore.CYAN + "{} (${})".format( item["name"], item["price"]))
index +=1

# Log Data
logging.info("{}:{}".format(
email,
json.dumps(data)
))
self.sema.release()

# Get user choice(s) for the items they want to enter for
self.PRODUCTS_TO_ENTER = [] # This will be the array used to submit entries
choices = input(Fore.MAGENTA + "Enter the numbers of all the products you'd like to enter for, seperated by a space. (Example: 1 5 7 9 ): " + Fore.GREEN)
for choice in choices.split():
try:
self.PRODUCTS_TO_ENTER.append({"ItemNumber": items[eval(choice)]["id"]})
except Exception:
print(Fore.RED + f"There was an error with item: #{choice}. Skipping that item.")


# Show how many accounts have been made / are about to enter the raffle
print()
try:
with open(path_to_created_accounts) as email_file:
print( Fore.BLUE + "Amount of accounts loaded: {} ({})".format(
Fore.CYAN + str(len(email_file.readlines())),
self.settings["output_filename"])
)
except (FileExistsError, FileNotFoundError):
print(Fore.RED + "Could not find the file with sessions. Check repo fore help.")
time.sleep(100)
return


# Prompt how many tasks
num_tasks = eval(input(Fore.BLUE + "Enter amount of tasks at a time: " + Fore.WHITE + " "))
self.sema = threading.Semaphore(value=num_tasks)
threads = []


# Enter raffle
with open(path_to_created_accounts) as email_file: # Get the emails from the file the user named
for line in email_file.readlines():
if "error" not in line:
self.sema.acquire()
email = line.split(':')[2].strip("\n")
sessionData = json.loads(":".join(line.split(":")[3:]))

# If the acct was created via desktop, it will enter via that way
# If the acct was created via app, it will enter via that way
if sessionData["desktop"] == {}: # If there are no desktop cookies, means it was created via APP
task = threading.Thread(target=app.SubmitRaffle,args=(self,email, sessionData))
else:
task = threading.Thread(target=desktop.SubmitRaffle,args=(self,email, sessionData))
threads.append(task)
task.start()


Newegg()
34 changes: 29 additions & 5 deletions newegg/create_account/mobile.py → newegg/create_account/app.py
Original file line number Diff line number Diff line change
@@ -19,21 +19,25 @@
from Crypto.Cipher import PKCS1_v1_5 as Cipher_pksc1_v1_5
from Crypto.PublicKey import RSA
from . import static_data, Accertify

from threading import Thread
POSTURL_ticketID = "https://secure.m.newegg.com//Application/UnifiedLogin/Landingpage"



class Create_Account:
def __init__(self, NeweggParent:object, email):
# I don't like how I'm passing these in. I'm going to change this soon.
logging.basicConfig(filename=NeweggParent.settings["output_filename"], level=logging.INFO)
self.screenlock = NeweggParent.screenlock
self.captcha_solver = NeweggParent.captcha_solver
self.sema = NeweggParent.sema
self.PATH_PROXIES = NeweggParent.PATH_PROXIES


# Define basic info
self.current_task = email
self.email = email
self.logging_data = {}

if NeweggParent.settings["password"]["generate_random"]:
self.password = self.randompassword()
else:
@@ -47,14 +51,32 @@ def __init__(self, NeweggParent:object, email):
self.HEADERS_createAccount = static_data.HEADERS_createAccount
self.HEADERS_afterCreate = static_data.HEADERS_afterCreate

# Update Headers
user_agent = random.choice(NeweggParent.settings["user_agents"]["mobile"])
self.HEADERS_getTicketID["User-Agent"] = user_agent
self.HEADERS_getFormKeys["User-Agent"] = user_agent
self.HEADERS_createAccount["User-Agent"] = user_agent
self.HEADERS_afterCreate["User-Agent"] = user_agent

self.start()

def start(self):
self.getProxy()
self.get_ticket_id()
if self.create_account():
self.get_cookies()
return self.logging_data

logging.info("{}:{}".format(
self.email,
json.dumps(self.logging_data)
))
self.sema.release()
return

def get_ticket_id(self):
'''
The get_ticket_id methods returns an ID that is used in POST URL's to create account
'''
while True:
try:
# Get Cookies
@@ -65,7 +87,6 @@ def get_ticket_id(self):
self.session.get(GETURL_getCookies, headers=self.HEADERS_getCookies)



# Get Ticket ID
payload = "Payload=%7B%22enableGustCheckout%22%3Afalse%2C%22regionCode%22%3A%22USA%22%2C%22LastLoginName%22%3A%22%22%2C%22themeStyle%22%3A0%2C%22userState%22%3A%22%7B%5C%22APPType%5C%22%3A%5C%22ios%5C%22%2C%5C%22path%5C%22%3A%5C%22SignUp%5C%22%7D%22%7D"
resp = self.session.post(POSTURL_ticketID, headers=self.HEADERS_getTicketID, data=payload, allow_redirects=False)
@@ -94,6 +115,9 @@ def get_ticket_id(self):
continue

def create_account(self):
'''
The create_account is called when all the info is gather and creates accounts.
'''
POSTURL_createAccount = f"https://secure.newegg.com/identity/api/SignUp?ticket={self.ticketID}"
GETURL_tokenData = f"https://secure.newegg.com/identity/api/InitSignUp?ticket={self.ticketID}"
self.HEADERS_createAccount["Referer"] = self.ticketURL
@@ -189,7 +213,7 @@ def create_account(self):

def getProxy(self):
# Load proxy from file
with open("./data/proxies.txt", "r") as file:
with open(self.PATH_PROXIES, "r") as file:
proxies = file.readlines()
if len(proxies) > 0:
line = proxies[random.randint(0, len(proxies) - 1)].strip("\n").split(":")
31 changes: 24 additions & 7 deletions newegg/create_account/desktop.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import os
import requests
from requests import exceptions as requestsExceptions
import sys
@@ -23,13 +24,17 @@

class Create_Account:
def __init__(self, NeweggParent:object, email):
# I don't like how I'm passing these in. I'm going to change this soon.
logging.basicConfig(filename=NeweggParent.settings["output_filename"], level=logging.INFO)
self.screenlock = NeweggParent.screenlock
self.captcha_solver = NeweggParent.captcha_solver
self.sema = NeweggParent.sema
self.PATH_PROXIES = NeweggParent.PATH_PROXIES

# Define basic info
self.current_task = email
self.email = email
self.logging_data = {}

if NeweggParent.settings["password"]["generate_random"]:
self.password = self.randompassword()
else:
@@ -39,17 +44,31 @@ def __init__(self, NeweggParent:object, email):
self.HEADERS_getPages = static_data.HEADERS_getPages.copy()
self.HEADERS_createAccountPOST = static_data.HEADERS_createAccountPOST.copy()

# Update Headers
user_agent = random.choice(NeweggParent.settings["user_agents"]["desktop"])
self.HEADERS_getPages["user-agent"] = user_agent
self.HEADERS_createAccountPOST["user-agent"] = user_agent

self.start()



def start(self):
self.getProxy()
self.get_ticket_id()
if self.create_account():
self.get_cookies()
return self.logging_data

logging.info("{}:{}".format(
self.email,
json.dumps(self.logging_data)
))
self.sema.release()
return

def get_ticket_id(self):
'''
This method will get the token for the POST URL
The get_ticket_id methods returns an ID that is used in POST URL's to create account
'''
self.screenlock.acquire()
print(Fore.CYAN + '{}'.format(datetime.datetime.now()),Fore.MAGENTA + "{}".format(self.current_task), Fore.YELLOW + "Getting Ticket ID...")
@@ -84,7 +103,7 @@ def get_ticket_id(self):

def create_account(self):
'''
This method will create the account
The create_account is called once all the info is gather and creates accounts.
'''
POSTURL_createAccount = f"https://secure.newegg.com/identity/api/SignUp?ticket={self.tkToken}"
GETURL_tokenData = f"https://secure.newegg.com/identity/api/InitSignUp?ticket={self.tkToken}"
@@ -146,8 +165,6 @@ def create_account(self):
self.screenlock.release()
self.session.cookies.clear()
self.get_ticket_id()


elif "CustomerAddLoginNameDuplicate" in response.text:
self.screenlock.acquire()
print(Fore.CYAN + '{}'.format(datetime.datetime.now()),Fore.MAGENTA + "{}".format(self.current_task), Fore.CYAN + "Email already had an account. Stopping.")
@@ -228,7 +245,7 @@ def get_cookies(self):

def getProxy(self):
# Load proxy from file
with open("./data/proxies.txt", "r") as file:
with open(self.PATH_PROXIES) as file:
proxies = file.readlines()
if len(proxies) > 0:
line = proxies[random.randint(0, len(proxies) - 1)].strip("\n").split(":")
12 changes: 6 additions & 6 deletions newegg/create_account/static_data.py
Original file line number Diff line number Diff line change
@@ -31,7 +31,7 @@
"sec-fetch-site": "none",
"sec-fetch-user": "?1",
"upgrade-insecure-requests": "1",
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 11_2_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.114 Safari/537.36"
"user-agent": ""
}
global HEADERS_createAccountPOST
HEADERS_createAccountPOST = {
@@ -46,7 +46,7 @@
"sec-fetch-dest": "empty",
"sec-fetch-mode": "cors",
"sec-fetch-site": "same-origin",
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 11_2_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.114 Safari/537.36",
"user-agent": "",
"x-ua-pki": "ne200508|ne200509"
}

@@ -73,7 +73,7 @@
"Upgrade-Insecure-Requests": "1",
"Origin": "null",
"Content-Type": "application/x-www-form-urlencoded",
"User-Agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 14_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0.3 Mobile/15E148 Safari/604.1",
"User-Agent": "",
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9",
"X-Requested-With": "com.newegg.app",
"Sec-Fetch-Site": "cross-site",
@@ -87,7 +87,7 @@
HEADERS_getFormKeys = {
"Host": "secure.newegg.com",
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
"User-Agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 14_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0.3 Mobile/15E148 Safari/604.1",
"User-Agent": "",
"Accept-Language": "en-us",
"Accept-Encoding": "gzip, deflate",
"Connection": "keep-alive"
@@ -102,7 +102,7 @@
"Accept-Language": "en-us",
"Content-Type": "application/json",
"Origin": "https://secure.newegg.com",
"User-Agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 14_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0.3 Mobile/15E148 Safari/604.1",
"User-Agent": "",
"Connection": "keep-alive",
"Referer": ""
}
@@ -112,7 +112,7 @@
"Host": "secure.m.newegg.com",
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
"Connection": "keep-alive",
"User-Agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 14_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0.3 Mobile/15E148 Safari/604.1",
"User-Agent": "",
"Accept-Language": "en-us",
"Referer": "",
"Accept-Encoding": "gzip, deflate"
247 changes: 247 additions & 0 deletions newegg/submit_raffle/app.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,247 @@
import datetime
import logging
import json
import urllib.parse
import random
import requests
from requests import exceptions as requestsExceptions
import sys
import colorama
from colorama import Fore
from colorama import init
colorama.init()
init(autoreset=True)
from . import raffle_data

# Get the current date and use that as the log file name
log_file_name = "{} entries.log".format(datetime.datetime.now().strftime("%m-%d-%Y"))
logging.basicConfig(filename=log_file_name, level=logging.INFO)

DO_NOT_ENCODE_KEYS =[
"LoginToken",
"CustomerNumber",
"LoginName",
"EncryptLoginName"
]

class SubmitRaffle:
def __init__(self, NeweggParent:object, email, sessionJSON):
self.screenlock = NeweggParent.screenlock
self.PRODUCTS_TO_ENTER = NeweggParent.PRODUCTS_TO_ENTER
self.captcha_solver = NeweggParent.captcha_solver
self.captcha_solver.captcha_url = raffle_data.App.RAFFLE_URL


# Define task specific data
self.email = email
self.current_task = email
self.logging_data = sessionJSON
self.session = requests.Session()
self.HEADERS_general = raffle_data.App.HEADERS_general.copy()
self.HEADERS_submit = raffle_data.App.HEADERS_submitEntry.copy()

# Update User Agents
user_agent = random.choice(NeweggParent.settings["user_agents"]["mobile"])
self.HEADERS_general["User-Agent"] = user_agent
self.HEADERS_submit["User-Agent"] = user_agent

# Create the mobile cookie
cookiesJSON = self.logging_data["app"]["cookies"]
for cookie in cookiesJSON:
self.session.cookies.set(cookie, cookiesJSON[cookie])
appData = self.logging_data["app"]
NV_NeweggApp={
"LoginToken":appData["login_token"],
"CustomerNumber":appData["misc"]["CustomerLoginInfo"]["EncryptCustomerNumber"],
"LoginName":appData["misc"]["CustomerLoginInfo"]["LoginName"],
"EncryptLoginName":appData["misc"]["CustomerLoginInfo"]["EncryptLoginName"],
"ContactWith":appData["misc"]["CustomerLoginInfo"]["ContactWith"],
"IsCANB2BCustomer":False,
"IsEggXpert":False,
"UserAgent":"Newegg iPhone App / {}".format(NeweggParent.settings["ios_app_version"])
}

cookiesTemp = []
for cookie in NV_NeweggApp:
# URL encode the key & value
# DO NOT ENCODE IF COOKIE_KEY = LoginToken, CustomerNumber, LoginName, EncryptLoginName,
keyEncoded = self.encode('"{}"'.format(cookie))
if cookie in DO_NOT_ENCODE_KEYS:
valueEncoded = "%22{}%22".format(NV_NeweggApp[cookie])
else:
if NV_NeweggApp[cookie] == False:
valueEncoded = self.encode('false')
else:
valueEncoded = self.encode('"{}"'.format(NV_NeweggApp[cookie]))
temp = '{}:{}'.format(keyEncoded, valueEncoded)
cookiesTemp.append(temp)

string = ""
string += self.encode('{')
temp = ",".join(cookiesTemp)
string += temp
string += self.encode('}')
NCTC = cookiesJSON["NVTC"]
self.HEADERS_submit["Cookie"] = f"NV%5FNeweggApp={string}; NVTC={NCTC};"

# Start the bot
self.start()


def start(self):
self.getProxy()
self.get_lottery_id()
self.submit_entries()

logging.info("{}:{}".format(
self.email,
json.dumps(self.logging_data)
))
return

def get_lottery_id(self):
while True:
try:
self.screenlock.acquire()
print(Fore.CYAN + '{}'.format(datetime.datetime.now()),Fore.MAGENTA + "{}".format(self.current_task), Fore.YELLOW + "Getting Lottery ID...")
self.screenlock.release()

# Get Lottery ID
response = self.session.get(raffle_data.App.RAFFLE_URL, headers=self.HEADERS_general)
HTML_Splitted = json.loads(response.text.split("window.__initialState__ = ")[1].split("</script>")[0])
self.lotteryID = HTML_Splitted["lotteryData"]["LotteryID"]
self.screenlock.acquire()
print(Fore.CYAN + '{}'.format(datetime.datetime.now()),Fore.MAGENTA + "{}".format(self.current_task), Fore.YELLOW + "Lottery ID: {}".format(self.lotteryID))
self.screenlock.release()
return

except requestsExceptions.ConnectTimeout:
self.screenlock.acquire()
print(Fore.CYAN + '{}'.format(datetime.datetime.now()),Fore.MAGENTA + "{}".format(self.current_task), Fore.MAGENTA + "Connection timedout.")
self.screenlock.release()
continue
except requestsExceptions.ProxyError:
self.screenlock.acquire()
print(Fore.CYAN + '{}'.format(datetime.datetime.now()),Fore.MAGENTA + "{}".format(self.current_task), Fore.MAGENTA + "Proxy error.")
self.screenlock.release()
self.getProxy()
continue

except Exception as e:
print(e)
self.screenlock.acquire()
print(Fore.CYAN + '{}'.format(datetime.datetime.now()),Fore.MAGENTA + "{}".format(self.current_task), Fore.RED + 'Error on line {}'.format(sys.exc_info()[-1].tb_lineno), Fore.RED + "{}".format(type(e).__name__), Fore.RED + "{}".format( e))
self.screenlock.release()
continue

def submit_entries(self):
while True:
try:
# Solve Captcha
self.screenlock.acquire()
print(Fore.CYAN + '{}'.format(datetime.datetime.now()),Fore.MAGENTA + "{}".format(self.current_task), Fore.YELLOW + "Waiting on Captcha...")
self.screenlock.release()
captcha_answer = self.captcha_solver.get_token()



# Submit Entry
self.screenlock.acquire()
print(Fore.CYAN + '{}'.format(datetime.datetime.now()),Fore.MAGENTA + "{}".format(self.current_task), Fore.YELLOW + "Submitting entry...")
self.screenlock.release()
payload = self.getPayload(self.lotteryID, "v2", captcha_answer, self.PRODUCTS_TO_ENTER)
submit = self.session.post(raffle_data.POSTURL_submitEntry, headers=self.HEADERS_submit, json=payload)

# Parse Response
response = json.loads(submit.text)
if response["Result"] == "Success":
self.screenlock.acquire()
print(Fore.CYAN + '{}'.format(datetime.datetime.now()),Fore.MAGENTA + "{}".format(self.current_task), Fore.GREEN + f"Successfully entered raffle!")
self.screenlock.release()

self.logging_data["app"]["cookies"] = json.dumps(self.session.cookies.get_dict())
return
elif response["Result"] == "ReChaptCha Invalid":
self.screenlock.acquire()
print(Fore.CYAN + '{}'.format(datetime.datetime.now()),Fore.MAGENTA + "{}".format(self.current_task), Fore.MAGENTA + "Invalid captcha token.")
self.screenlock.release()
elif response["Result"] == "UnAccess" or response["Result"] == "UnSuccess":
self.screenlock.acquire()
print(Fore.CYAN + '{}'.format(datetime.datetime.now()),Fore.MAGENTA + "{}".format(self.current_task), Fore.CYAN + "UnAccess. Stopping.")
self.screenlock.release()

self.logging_data["error"] = True
self.logging_data["error_msg"] = "UnAccess"
self.logging_data["app"]["cookies"] = json.dumps(self.session.cookies.get_dict())
return
elif response["Code"] == "111":
self.screenlock.acquire()
print(Fore.CYAN + '{}'.format(datetime.datetime.now()),Fore.MAGENTA + "{}".format(self.current_task), Fore.CYAN + "Proxy banned. Switiching.")
self.screenlock.release()
self.getProxy()
else:
self.screenlock.acquire()
print(Fore.CYAN + '{}'.format(datetime.datetime.now()),Fore.MAGENTA + "{}".format(self.current_task), Fore.CYAN + "Unknown response while entering. Check text file")
self.screenlock.release()
with open("Failed to enter - {}.json".format(self.email),'w') as outfile:
print(json.dumps(response, indent=2), file=outfile)

self.logging_data["error"] = True
self.logging_data["error_msg"] = "Unknown error"
self.logging_data["app"]["cookies"] = json.dumps(self.session.cookies.get_dict())
return


except requestsExceptions.ConnectTimeout:
self.screenlock.acquire()
print(Fore.CYAN + '{}'.format(datetime.datetime.now()),Fore.MAGENTA + "{}".format(self.current_task), Fore.MAGENTA + "Connection timedout.")
self.screenlock.release()
continue
except requestsExceptions.ProxyError:
self.screenlock.acquire()
print(Fore.CYAN + '{}'.format(datetime.datetime.now()),Fore.MAGENTA + "{}".format(self.current_task), Fore.MAGENTA + "Proxy error.")
self.screenlock.release()
self.getProxy()
continue

except Exception as e:
self.screenlock.acquire()
print(Fore.CYAN + '{}'.format(datetime.datetime.now()),Fore.MAGENTA + "{}".format(self.current_task), Fore.RED + 'Error on line {}'.format(sys.exc_info()[-1].tb_lineno), Fore.RED + "{}".format(type(e).__name__), Fore.RED + "{}".format( e))
self.screenlock.release()
self.getProxy()
continue

def getProxy(self):
# Load proxy from file
with open(self.PATH_PROXIES, "r") as file:
proxies = file.readlines()
if len(proxies) > 0:
line = proxies[random.randint(0, len(proxies) - 1)].strip("\n").split(":")
if len(line) == 2: #if proxy length is ==2, its an IP Auth proxy
line = proxies[random.randint(0, len(proxies) - 1)].strip("\n")
proxy= {
'http':line,
'https':line,
}

else:#if proxy length is anything else, its an USER:PASS
proxy = {'http': 'http://' + line[2] + ":" + line[3] + "@" + line[0] + ":" + line[1] + "/",
'https': 'https://' + line[2] + ":" + line[3] + "@" + line[0] + ":" + line[1] + "/"}
self.session.proxies.update(proxy)
return

@staticmethod
def encode(string):
return urllib.parse.quote(string)

@staticmethod
def getPayload(lotteryID, captchaType, captchaToken, PRODUCTS_TO_ENTER):
return {
"LoginToken":"",
"LotteryID":lotteryID,
"LotteryInfos":PRODUCTS_TO_ENTER,
"version":captchaType,
"token":captchaToken,
# This URL is typically static. Feel free to change it to another Shuffle URL
"url":"https://www.newegg.com/product-shuffle?template=1&cm_sp=Promo_Banner-_-mobile_promo_shuffle-_-%252f%252fc1.neweggimages.com%252fnewegg%252ftool%252fshuffle_promo_banner.jpg&icid=612023"
}
198 changes: 198 additions & 0 deletions newegg/submit_raffle/desktop.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,198 @@
import datetime
import logging
import json
import urllib.parse
import random
import requests
from requests import exceptions as requestsExceptions
import sys
import colorama
from colorama import Fore
from colorama import init
colorama.init()
init(autoreset=True)
from . import raffle_data

# Get the current date and use that as the log file name
log_file_name = "{} entries.log".format(datetime.datetime.now().strftime("%m-%d-%Y"))
logging.basicConfig(filename=log_file_name, level=logging.INFO)



class SubmitRaffle:
def __init__(self, NeweggParent:object, email, sessionJSON):
self.screenlock = NeweggParent.screenlock
self.PRODUCTS_TO_ENTER = NeweggParent.PRODUCTS_TO_ENTER
self.captcha_solver = NeweggParent.captcha_solver
self.captcha_solver.captcha_url = raffle_data.Desktop.RAFFLE_URL
self.PATH_PROXIES = NeweggParent.PATH_PROXIES


# Define task specific data
self.email = email
self.current_task = email
self.logging_data = sessionJSON
self.HEADERS_general = raffle_data.Desktop.HEADERS_general.copy()
self.HEADERS_submit = raffle_data.Desktop.HEADERS_submitEntry.copy()

# Update Cookies
self.session = requests.Session()
cookiesJSON = self.logging_data["desktop"]["cookies"]
for cookie in cookiesJSON:
self.session.cookies.set(cookie, cookiesJSON[cookie])

# Update User Agents
user_agent = random.choice(NeweggParent.settings["user_agents"]["mobile"])
self.HEADERS_general['user-agent'] = user_agent
self.HEADERS_submit['user-agent'] = user_agent

# Start the task
self.start()

def start(self):
self.getProxy()
self.get_lottery_id()
self.submit_entries()
logging.info("{}:{}".format(
self.email,
json.dumps(self.logging_data)
))
return

def get_lottery_id(self):
while True:
try:
self.screenlock.acquire()
print(Fore.CYAN + '{}'.format(datetime.datetime.now()),Fore.MAGENTA + "{}".format(self.current_task), Fore.YELLOW + "Getting Lottery ID...")
self.screenlock.release()

# Get Lottery ID
response = self.session.get(raffle_data.Desktop.RAFFLE_URL, headers=self.HEADERS_general)
HTML_Splitted = json.loads(response.text.split("window.__initialState__ = ")[1].split("</script>")[0])
self.lotteryID = HTML_Splitted["lotteryData"]["LotteryID"]
self.screenlock.acquire()
print(Fore.CYAN + '{}'.format(datetime.datetime.now()),Fore.MAGENTA + "{}".format(self.current_task), Fore.YELLOW + "Lottery ID: {}".format(self.lotteryID))
self.screenlock.release()
return

except requestsExceptions.ConnectTimeout:
self.screenlock.acquire()
print(Fore.CYAN + '{}'.format(datetime.datetime.now()),Fore.MAGENTA + "{}".format(self.current_task), Fore.MAGENTA + "Connection timedout.")
self.screenlock.release()
continue
except requestsExceptions.ProxyError:
self.screenlock.acquire()
print(Fore.CYAN + '{}'.format(datetime.datetime.now()),Fore.MAGENTA + "{}".format(self.current_task), Fore.MAGENTA + "Proxy error.")
self.screenlock.release()
self.getProxy()
continue

except Exception as e:
self.screenlock.acquire()
print(Fore.CYAN + '{}'.format(datetime.datetime.now()),Fore.MAGENTA + "{}".format(self.current_task), Fore.RED + 'Error on line {}'.format(sys.exc_info()[-1].tb_lineno), Fore.RED + "{}".format(type(e).__name__), Fore.RED + "{}".format( e))
self.screenlock.release()
continue

def submit_entries(self):
while True:
try:
# Solve Captcha
self.screenlock.acquire()
print(Fore.CYAN + '{}'.format(datetime.datetime.now()),Fore.MAGENTA + "{}".format(self.current_task), Fore.YELLOW + "Waiting on Captcha...")
self.screenlock.release()
captcha_answer = self.captcha_solver.get_token()


# Submit Entry
self.screenlock.acquire()
print(Fore.CYAN + '{}'.format(datetime.datetime.now()),Fore.MAGENTA + "{}".format(self.current_task), Fore.YELLOW + "Submitting entry...")
self.screenlock.release()
payload = self.getPayload(self.lotteryID, "v2", captcha_answer, self.PRODUCTS_TO_ENTER)
submit = self.session.post(raffle_data.POSTURL_submitEntry, headers=self.HEADERS_submit, json=payload)

# Parse Response
response = json.loads(submit.text)
if response["Result"] == "Success":
self.screenlock.acquire()
print(Fore.CYAN + '{}'.format(datetime.datetime.now()),Fore.MAGENTA + "{}".format(self.current_task), Fore.GREEN + f"Successfully entered raffle!")
self.screenlock.release()

self.logging_data["desktop"]["cookies"] = json.dumps(self.session.cookies.get_dict())
return

elif response["Result"] == "ReChaptCha Invalid":
self.screenlock.acquire()
print(Fore.CYAN + '{}'.format(datetime.datetime.now()),Fore.MAGENTA + "{}".format(self.current_task), Fore.MAGENTA + "Invalid captcha token.")
self.screenlock.release()


elif response["Result"] == "UnAccess" or response["Result"] == "UnSuccess":
self.screenlock.acquire()
print(Fore.CYAN + '{}'.format(datetime.datetime.now()),Fore.MAGENTA + "{}".format(self.current_task), Fore.CYAN + "UnAccess. Stopping.")
self.screenlock.release()

self.logging_data["error"] = True
self.logging_data["error_msg"] = "UnAccess"
self.logging_data["desktop"]["cookies"] = json.dumps(self.session.cookies.get_dict())
return
else:
self.screenlock.acquire()
print(Fore.CYAN + '{}'.format(datetime.datetime.now()),Fore.MAGENTA + "{}".format(self.current_task), Fore.CYAN + "Unknown response while entering. Check text file")
self.screenlock.release()
with open("Failed to enter - {}.json".format(self.email),'w') as outfile:
print(json.dumps(response, indent=2), file=outfile)

self.logging_data["error"] = True
self.logging_data["error_msg"] = "Unknown error"
self.logging_data["desktop"]["cookies"] = json.dumps(self.session.cookies.get_dict())
return


except requestsExceptions.ConnectTimeout:
self.screenlock.acquire()
print(Fore.CYAN + '{}'.format(datetime.datetime.now()),Fore.MAGENTA + "{}".format(self.current_task), Fore.MAGENTA + "Connection timedout.")
self.screenlock.release()
continue
except requestsExceptions.ProxyError:
self.screenlock.acquire()
print(Fore.CYAN + '{}'.format(datetime.datetime.now()),Fore.MAGENTA + "{}".format(self.current_task), Fore.MAGENTA + "Proxy error.")
self.screenlock.release()
self.getProxy()
continue

except Exception as e:
self.screenlock.acquire()
print(Fore.CYAN + '{}'.format(datetime.datetime.now()),Fore.MAGENTA + "{}".format(self.current_task), Fore.RED + 'Error on line {}'.format(sys.exc_info()[-1].tb_lineno), Fore.RED + "{}".format(type(e).__name__), Fore.RED + "{}".format( e))
self.screenlock.release()
self.getProxy()
continue

def getProxy(self):
# Load proxy from file
with open(self.PATH_PROXIES, "r") as file:
proxies = file.readlines()
if len(proxies) > 0:
line = proxies[random.randint(0, len(proxies) - 1)].strip("\n").split(":")
if len(line) == 2: #if proxy length is ==2, its an IP Auth proxy
line = proxies[random.randint(0, len(proxies) - 1)].strip("\n")
proxy= {
'http':line,
'https':line,
}

else:#if proxy length is anything else, its an USER:PASS
proxy = {'http': 'http://' + line[2] + ":" + line[3] + "@" + line[0] + ":" + line[1] + "/",
'https': 'https://' + line[2] + ":" + line[3] + "@" + line[0] + ":" + line[1] + "/"}
self.session.proxies.update(proxy)
return

@staticmethod
def getPayload(lotteryID, captchaType, captchaToken, PRODUCTS_TO_ENTER):
return {
"LoginToken":"",
"LotteryID":lotteryID,
"LotteryInfos": PRODUCTS_TO_ENTER,
"version":captchaType,
"token":captchaToken,
"url":"https://www.newegg.com/product-shuffle"
}
67 changes: 67 additions & 0 deletions newegg/submit_raffle/raffle_data.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# Use this file as a config

global POSTURL_submitEntry
POSTURL_submitEntry = "https://www.newegg.com/events/api/GoogleRecaptCha"

class App:
'''
The attributes in this object is everything needed for App
'''
RAFFLE_URL = "https://www.newegg.com/product-shuffle?template=1&cm_sp=Promo_Banner-_-mobile_promo_shuffle-_-%252f%252fc1.neweggimages.com%252fnewegg%252ftool%252fshuffle_promo_banner.jpg&icid=612023"
HEADERS_general = {
"Host": "www.newegg.com",
"Content-Type": "application/json",
"Origin": "https://www.newegg.com",
"Accept-Encoding": "gzip, deflate",
"Connection": "keep-alive",
"Accept": "application/json, text/plain, */*",
"User-Agent": "",
"Accept-Language": "en-us"
}
HEADERS_submitEntry = {
"Host": "www.newegg.com",
"Content-Type": "application/json",
"Origin": "https://www.newegg.com",
"Accept-Encoding": "gzip, deflate",
"Cookie" : "", # Certain cookie will distinguish it from the desktop
"Connection": "keep-alive",
"Accept": "application/json, text/plain, */*",
"User-Agent": "",
"Referer": RAFFLE_URL,
"Accept-Language": "en-us"
}


class Desktop:
'''
The attributes in this object is everything needed for Desktop entries
'''
RAFFLE_URL = "https://www.newegg.com/product-shuffle"
HEADERS_general = {
"accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9",
"accept-encoding": "gzip, deflate",
"accept-language": "en-US,en;q=0.9",
"sec-ch-ua": '"Google Chrome";v="89", "Chromium";v="89", ";Not A Brand";v="99"',
"sec-ch-ua-mobile": "?0",
"sec-fetch-dest": "document",
"sec-fetch-mode": "navigate",
"sec-fetch-site": "none",
"sec-fetch-user": "?1",
"upgrade-insecure-requests": "1",
"user-agent": ""
}

HEADERS_submitEntry = {
"accept": "application/json, text/plain, */*",
"accept-encoding": "gzip, deflate",
"accept-language": "en-US,en;q=0.9",
"content-type": "application/json",
"origin": "https://www.newegg.com",
'referer': "https://www.newegg.com/product-shuffle",
"sec-ch-ua": '"Google Chrome";v="89", "Chromium";v="89", ";Not A Brand";v="99"',
"sec-ch-ua-mobile": '?0',
"sec-fetch-dest": "empty",
"sec-fetch-mode": "cors",
"sec-fetch-site": "same-origin",
'user-agent': ""
}
34 changes: 34 additions & 0 deletions newegg/submit_raffle/raffles.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import re
import json
import requests



def get_items():
temp = []
while True:
try:
s = requests.Session()
res = s.get("https://www.newegg.com/product-shuffle")
raffle_products = json.loads(re.findall(r"{.+[:,].+}", res.text)[1].split("</script>")[0])
for products in raffle_products["lotteryData"]["LotteryItems"]:
for raffle_item in products["ChildItem"]:
# Get the item(s) in the combo
combo_items = [] # Products that you can select to enter the raffle for
for item in raffle_item["ComboItems"]:
combo_items.append(item["Title"])
items_name = " & ".join(combo_items)

# Get the ID of the combo/item to enter the raffle & price
item_id= raffle_item["ItemNumber"] # This is used to enter the raffle
combo_price = raffle_item["FinalPrice"]


temp.append({
"name": items_name,
"id": item_id,
"price": combo_price
})
return temp
except Exception:
print("[ERROR GETTING RAFFLES]")

0 comments on commit 39f31f6

Please sign in to comment.