13 Commits

8 changed files with 117 additions and 73 deletions

1
.gitignore vendored
View File

@ -12,3 +12,4 @@ data
install.sh install.sh
nohup.out nohup.out
test.py test.py
points.csv

View File

@ -3,7 +3,7 @@
A Microsoft reward automator, designed to work headless on any server. A Microsoft reward automator, designed to work headless on any server.
Using a discord webhook or SQL to log points everyday. Using a discord webhook or SQL to log points everyday.
Using Selenium and geckodriver. Using Selenium and Geckodriver.
## If you're using docker (way easier) ## If you're using docker (way easier)
to use docker, run to use docker, run
@ -12,14 +12,14 @@ sudo docker build .
#copy the build id #copy the build id
sudo docker run -ti --name MsRewards [build id] sudo docker run -ti --name MsRewards [build id]
``` ```
Then, fill the config and start the programm everydays with Then, fill the config and start the program everyday with
``` ```
sudo docker start MsRewards sudo docker start MsRewards
``` ```
## Other configuration ## Other configuration
To use the database, I recommand MySql, Create a database with the name you want and create a table `daily`, like the one from the image : To use the database, I recommend MySql, Create a database with the name you want and create a table `daily`, like the one from the image :
![B96F2F6D-7257-4F12-BFA7-0BEC3FB72993](https://user-images.githubusercontent.com/74496300/172872979-05396b6b-b682-471a-b71b-41602d816504.jpeg) ![B96F2F6D-7257-4F12-BFA7-0BEC3FB72993](https://user-images.githubusercontent.com/74496300/172872979-05396b6b-b682-471a-b71b-41602d816504.jpeg)
You have to use the default world list (`sudo apt install wfrench`). The language is french by default, but you can change it if you want. You have to use the default world list (`sudo apt install wfrench`). The language is french by default, but you can change it if you want.

86
V5.py
View File

@ -15,9 +15,8 @@ def printf(e):
printf2(str(e), _mail) printf2(str(e), _mail)
# TODO # TODO
# handle "panda"'s error: error while logging in preventing some task to be done # handle "panda"'s error: error while logging in preventing some task to be done SadPanda.svg
# check that each card worked (lot of misses lately) -- test that -- don't crash at least # check that each card worked (lot of misses lately) -- test that -- don't crash at least
# Fix l'affichage du compteur de custom_sleep
# create a webdriver # create a webdriver
@ -85,9 +84,8 @@ def log_error(error, ldriver=driver, log=FULL_LOG):
file = File("screenshot.png") file = File("screenshot.png")
embed.set_image(url="attachment://screenshot.png") embed.set_image(url="attachment://screenshot.png")
embed.set_footer(text=_mail) embed.set_footer(text=_mail)
webhookFailure.send(embed=embed, file=file) webhookFailure.send(embed=embed, username="error", file=file, avatar_url = AVATAR_URL)
webhookFailure.send(file=File("page.html")) webhookFailure.send(username="error", file=File("page.html"), avatar_url = AVATAR_URL)
# close the tab currently on and go back to the one first, or the one specified # close the tab currently on and go back to the one first, or the one specified
@ -103,7 +101,7 @@ def play_quiz2(override=10) -> None:
printf("starting play_quiz2") printf("starting play_quiz2")
for j in range(override): for j in range(override):
try: try:
rgpd_popup(driver) # rgpd_popup(driver)
custom_sleep(uniform(3, 5)) custom_sleep(uniform(3, 5))
page_html = driver.page_source page_html = driver.page_source
secret_answer = search('IG:"([^"]+)"', page_html)[1] # variable used to calculate offset secret_answer = search('IG:"([^"]+)"', page_html)[1] # variable used to calculate offset
@ -137,7 +135,7 @@ def play_quiz8():
printf(f"play_quiz8 : start, override : {override}") printf(f"play_quiz8 : start, override : {override}")
try: try:
counter = 0 counter = 0
rgpd_popup(driver) # rgpd_popup(driver)
for _ in range(override): for _ in range(override):
custom_sleep(uniform(3, 5)) custom_sleep(uniform(3, 5))
correct_answers = [] correct_answers = []
@ -184,7 +182,7 @@ def play_quiz4(override=None):
for i in range(override): for i in range(override):
custom_sleep(uniform(3, 5)) custom_sleep(uniform(3, 5))
txt = driver.page_source txt = driver.page_source
rgpd_popup(driver) # rgpd_popup(driver)
answer_option = search('correctAnswer":"([^"]+)', txt)[1] answer_option = search('correctAnswer":"([^"]+)', txt)[1]
answer_option = answer_option.replace("\\u0027", "'") # replace Unicode weird symbols answer_option = answer_option.replace("\\u0027", "'") # replace Unicode weird symbols
try: try:
@ -221,9 +219,10 @@ def all_cards(): # return to the main page and closes all other tabs
if len(driver.window_handles) == 1: if len(driver.window_handles) == 1:
driver.get("https://www.bing.com/rewardsapp/flyout") driver.get("https://www.bing.com/rewardsapp/flyout")
if part2: if part2:
driver.find_element( row_element = driver.find_elements(By.CSS_SELECTOR, f'[class="i-h rw-sh fp_row"]')[1]
By.XPATH, "/html/body/div/div/div[3]/div[2]/div[2]/div[2]/div[1]" expanded = row_element.get_attribute("aria-expanded")
).click() if expanded != "true":
row_element.click()
else: else:
driver.switch_to.window(driver.window_handles[1]) driver.switch_to.window(driver.window_handles[1])
printf(f"fermeture : {driver.current_url}") printf(f"fermeture : {driver.current_url}")
@ -233,10 +232,10 @@ def all_cards(): # return to the main page and closes all other tabs
driver.get("https://www.bing.com/rewardsapp/flyout") driver.get("https://www.bing.com/rewardsapp/flyout")
reset(part2) reset(part2)
def daily_cards(): # cartes de la premiere partie (renouvelées chaque jours). def daily_cards(): # cartes de la premiere partie (renouvelée chaque jour).
try: try:
# make sure that the daily area is expanded # make sure that the daily area is expanded
row_element = driver.find_element(By.XPATH, "/html/body/div/div/div[3]/div[2]/div[1]/div[1]") row_element = driver.find_elements(By.CSS_SELECTOR, f'[class="i-h rw-sh fp_row"]')[0]
expanded = row_element.get_attribute("aria-expanded") expanded = row_element.get_attribute("aria-expanded")
if expanded != "true": if expanded != "true":
row_element.click() row_element.click()
@ -244,9 +243,8 @@ def all_cards(): # return to the main page and closes all other tabs
custom_sleep(uniform(3, 5)) custom_sleep(uniform(3, 5))
try: try:
titre = "Placeholder" titre = "Placeholder"
driver.find_element( elm = driver.find_elements(By.CLASS_NAME, 'promo_cont')
By.XPATH,f"/html/body/div/div/div[3]/div[2]/div[1]/div[2]/div/div[{i+1}]/a", elm[i].click()
).click()
sleep(1) sleep(1)
titre = driver.title titre = driver.title
try_play(titre) try_play(titre)
@ -255,7 +253,7 @@ def all_cards(): # return to the main page and closes all other tabs
printf(f"DailyCard {titre} ok") printf(f"DailyCard {titre} ok")
except Exception as e: except Exception as e:
log_error(f"all_cards card {titre} error ({format_error(e)})") log_error(f"all_cards card {titre} error ({format_error(e)})")
"""
try : # devrait renvoyer vrai si la carte i est faite ou pas, a l'aide su symbole en haut a droite de la carte try : # devrait renvoyer vrai si la carte i est faite ou pas, a l'aide su symbole en haut a droite de la carte
elm = driver.find_element(By.XPATH, f"/html/body/div/div/div[3]/div[2]/div[1]/div[2]/div/div[{i+1}]/a/div/div[2]/div[1]/div[2]/div") elm = driver.find_element(By.XPATH, f"/html/body/div/div/div[3]/div[2]/div[1]/div[2]/div/div[{i+1}]/a/div/div[2]/div[1]/div[2]/div")
if not ("correctCircle" in elm.get_attribute("innerHTML")): if not ("correctCircle" in elm.get_attribute("innerHTML")):
@ -266,23 +264,25 @@ def all_cards(): # return to the main page and closes all other tabs
except Exception as e : except Exception as e :
printf(format_error(e) + "probablement ok - check card") printf(format_error(e) + "probablement ok - check card")
# if it fail, it's probably okay -> when all three card are done, the pannel fold # if it fail, it's probably okay -> when all three card are done, the pannel fold
"""
except Exception as e: except Exception as e:
log_error(e) log_error(e)
def weekly_cards(): def weekly_cards():
# make sure that the weekly area is expanded # make sure that the weekly area is expanded
row_element = driver.find_element(By.XPATH, "/html/body/div/div/div[3]/div[2]/div[2]/div[2]") row_element = driver.find_elements(By.CSS_SELECTOR, f'[class="i-h rw-sh fp_row"]')[1]
expanded = row_element.get_attribute("aria-expanded") expanded = row_element.get_attribute("aria-expanded")
if expanded != "true": if expanded != "true":
row_element.click() row_element.click()
for i in range(20): # Should raise an error whene there is no card left for i in range(20): # Should raise an error whene there is no card left
printf("début de l'une des cartes") printf("début de l'une des cartes")
driver.find_element( elm = driver.find_elements(By.CLASS_NAME, 'promo_cont')
By.XPATH, try :
"/html/body/div/div/div[3]/div[2]/div[2]/div[3]/div/div[1]/a/div/div[2]", elm[0].click()
).click() except Exception as e :
print(f"{e} + {driver.current_url}")
break
driver.switch_to.window(driver.window_handles[len(driver.window_handles) - 1]) driver.switch_to.window(driver.window_handles[len(driver.window_handles) - 1])
sleep(1) sleep(1)
titre = driver.title titre = driver.title
@ -290,13 +290,13 @@ def all_cards(): # return to the main page and closes all other tabs
try_play(titre) try_play(titre)
reset(True) reset(True)
sleep(1) sleep(1)
try: #try:
findall('href="([^<]+)" title=""', driver.page_source)[3] # return error if there is no cards left to do # findall('href="([^<]+)" title=""', driver.page_source)[3] # return error if there is no cards left to do
except: #except:
break # break
def top_cards(): def top_cards():
for _ in range(10): for _ in range(2):
try : try :
driver.find_element(By.XPATH, "/html/body/div/div/div[3]/div[1]/div/div[1]/div[2]").click() driver.find_element(By.XPATH, "/html/body/div/div/div[3]/div[1]/div/div[1]/div[2]").click()
reset() reset()
@ -305,17 +305,20 @@ def all_cards(): # return to the main page and closes all other tabs
break break
try : try :
top_cards() #top_cards()
print("top card not working really well right now. They are currently disabled")
except Exception as e: except Exception as e:
log_error(e) log_error(e)
try: try:
daily_cards() daily_cards()
print("daily card")
except Exception as e: except Exception as e:
log_error(e) log_error(e)
try : try :
weekly_cards() weekly_cards()
print("weekly card")
except Exception as e: except Exception as e:
log_error(e) log_error(e)
@ -363,7 +366,7 @@ def try_play(nom="inconnu"):
if "bt_PollRadio" in driver.page_source: if "bt_PollRadio" in driver.page_source:
try: try:
printf("Poll detected") printf("Poll detected")
rgpd_popup(driver) #rgpd_popup(driver)
do_poll() do_poll()
printf("Poll succeeded") printf("Poll succeeded")
except Exception as e: except Exception as e:
@ -379,12 +382,12 @@ def try_play(nom="inconnu"):
elif search("([0-9]) de ([0-9]) finalisée", driver.page_source): elif search("([0-9]) de ([0-9]) finalisée", driver.page_source):
printf("fidélité") printf("fidélité")
rgpd_popup(driver) #rgpd_popup(driver)
fidelity() fidelity()
else: else:
printf(f"rien à faire sur la page {nom}") printf(f"rien à faire sur la page {nom}")
rgpd_popup(driver) # rgpd_popup(driver)
custom_sleep(uniform(3, 5)) custom_sleep(uniform(3, 5))
@ -463,14 +466,18 @@ def login(ldriver):
printf("Timeout error occurred. \"normal\"....., maybe because of mismatch date ? ") printf("Timeout error occurred. \"normal\"....., maybe because of mismatch date ? ")
log_error("Timeout error occurred. \"normal\"....., maybe because of mismatch date ?", ldriver, True) # TODO check this hypothesis log_error("Timeout error occurred. \"normal\"....., maybe because of mismatch date ?", ldriver, True) # TODO check this hypothesis
else: else:
log_error(e) log_error(e, ldriver)
custom_sleep(20) # TODO : remplacer par un wait_element wait_until_visible(By.CSS_SELECTOR, '[data-bi-id="sh-sharedshell-rewards"]', 20, ldriver)
if ("account.microsoft.com" in ldriver.current_url) : if ("account.microsoft.com" in ldriver.current_url) :
ldriver.get("https://bing.com") ldriver.get("https://bing.com")
custom_sleep(5) custom_sleep(5)
ldriver.refresh() ldriver.refresh()
rgpd_popup(ldriver) rgpd_popup(ldriver) # Ultra important
ldriver.get("https://www.bing.com/rewardsapp/flyout") ldriver.get("https://www.bing.com/rewardsapp/flyout")
#if "SadPanda.svg" in ldriver.page_source :
# log_error('test SadPanda before', ldriver)
# driver.execute_script("location.reload(true);")
# log_error('test SadPanda after', ldriver)
if not('>Tableau de bord' in ldriver.page_source): if not('>Tableau de bord' in ldriver.page_source):
try : try :
ldriver.find_element(By.CSS_SELECTOR, "[h='ID=RewardsFlyout,2.1']").click() ldriver.find_element(By.CSS_SELECTOR, "[h='ID=RewardsFlyout,2.1']").click()
@ -665,7 +672,6 @@ def fidelity():
fidelity_link = fidelity_link_page.content.decode("UTF-8") fidelity_link = fidelity_link_page.content.decode("UTF-8")
if (fidelity_link.split(":")[0] == "https") or (fidelity_link.split(":")[0] == "http") : if (fidelity_link.split(":")[0] == "https") or (fidelity_link.split(":")[0] == "http") :
driver.get(fidelity_link) driver.get(fidelity_link)
wait_until_visible(By.CSS_SELECTOR, 'div[class="pull-left spacer-48-bottom punchcard-row"]', browser=driver) wait_until_visible(By.CSS_SELECTOR, 'div[class="pull-left spacer-48-bottom punchcard-row"]', browser=driver)
try : try :
@ -678,9 +684,10 @@ def fidelity():
answer_number = search("([0-9]) de ([0-9]) finalisé", driver.page_source) answer_number = search("([0-9]) de ([0-9]) finalisé", driver.page_source)
if answer_number is None : if answer_number is None :
answer_number = search("([0-9]) licence\(s\) sur ([0-9]) disponible\(s\)", driver.page_source) answer_number = search("([0-9]) licence\(s\) sur ([0-9]) disponible\(s\)", driver.page_source)
if answer_number is None :
answer_number = search("([0-9])&nbsp;défi\(s\) terminé\(s\) sur ([0-9])", driver.page_source)
if answer_number is None : if answer_number is None :
answer_number = [0,0,0] answer_number = [0,0,0]
for _ in range(int(answer_number[2]) - int(answer_number[1])): for _ in range(int(answer_number[2]) - int(answer_number[1])):
driver.refresh() driver.refresh()
custom_sleep(2) custom_sleep(2)
@ -842,7 +849,7 @@ def daily_routine(custom = False):
def dev(): def dev():
pass log_error("test")
def CustomStart(Credentials): def CustomStart(Credentials):
@ -925,6 +932,9 @@ elif UNBAN:
elif POINTS_FILE != "": elif POINTS_FILE != "":
save_points_from_file(POINTS_FILE) save_points_from_file(POINTS_FILE)
else: else:
if UPDATE_VERSION != "None":
if DISCORD_ENABLED_ERROR:
webhookFailure.send(f"Updated to {UPDATE_VERSION}")
for cred in Credentials: for cred in Credentials:
_mail = cred[0] _mail = cred[0]
_password = cred[1] _password = cred[1]

View File

@ -10,9 +10,16 @@ parser.add_argument(
help="Choose a file", help="Choose a file",
type=argparse.FileType('r') type=argparse.FileType('r')
) )
parser.add_argument(
"-m",
"--manual",
help="add point manually do database",
dest="manual",
action="store_true"
)
args = parser.parse_args() args = parser.parse_args()
MANUAL = args.manual
config_path = "./user_data/config.cfg" config_path = "./user_data/config.cfg"
config = configparser.ConfigParser() config = configparser.ConfigParser()
@ -47,7 +54,7 @@ def ban_account(name: str, pts = 0):
def update_pts(name: str, pts = 0): def update_pts(name: str, pts = 0):
pass pass
if not MANUAL :
print("ajouter un compte : 1\nban un compte : 2") print("ajouter un compte : 1\nban un compte : 2")
i = input() i = input()
if i == "1": if i == "1":
@ -70,3 +77,16 @@ elif i == '2':
mydb.commit() mydb.commit()
mycursor.close() mycursor.close()
mydb.close() mydb.close()
else :
import modules.db as datab
config_path = f"{path.abspath(path.dirname(path.dirname( __file__ )))}/MsRewards/user_data/config.cfg"
print(config_path)
config = configparser.ConfigParser()
config.read(config_path)
sql_usr = config["SQL"]["usr"]
sql_pwd = config["SQL"]["pwd"]
sql_host = config["SQL"]["host"]
sql_database = config["SQL"]["database"]
account_name = input("compte ? ")
points = int(input("points ? "))
datab.add_to_database(account_name, points, sql_host, sql_usr, sql_pwd, sql_database)

13
main.py
View File

@ -154,29 +154,32 @@ def proxy() :
edit_config_txt("port",port) edit_config_txt("port",port)
def check_update(): def check_update(args):
try : try :
latest = requests.get("https://api.github.com/repos/piair338/MsRewards/releases").json()[0]["tag_name"] latest = requests.get("https://api.github.com/repos/piair338/MsRewards/releases").json()[0]["tag_name"]
latest = parse_version(latest) latest = parse_version(latest)
except Exception as e : except Exception as e :
print(e) print(e)
return () return (args)
f = open("./version", 'r') f = open("./version", 'r')
txt = f.readlines()[0].replace("\n","") txt = f.readlines()[0].replace("\n","")
f.close() f.close()
cur = parse_version(txt) cur = parse_version(txt)
if not (cur < latest) : if not (cur < latest) :
print("Already up to date.") print("Already up to date.")
return(args)
else : else :
print(f"updating to {latest}") print(f"updating to {latest}")
os.system("git reset --hard")
os.system("git pull") os.system("git pull")
print("updated") os.system("python3 -m pip install -r requirements.txt > update.result")
print(f"updated to {latest}")
return(args + f" --version {latest}")
LogPath = config["PATH"]["logpath"] LogPath = config["PATH"]["logpath"]
if LogPath == "/your/path/to/loginandpass.csv" : if LogPath == "/your/path/to/loginandpass.csv" :
setup() setup()
else : else :
args = " ".join(sys.argv[1::]) args = " ".join(sys.argv[1::])
check_update() args = check_update(args)
os.system("python3 V5.py " + args) os.system("python3 V5.py " + args)

View File

@ -81,6 +81,12 @@ parser.add_argument(
default="None" default="None"
) )
parser.add_argument(
"--version",
help="display a message on discord to tell that the bot have been updated",
dest="update_version",
default="None"
)
args = parser.parse_args() args = parser.parse_args()
CUSTOM_START = args.override CUSTOM_START = args.override
@ -93,7 +99,7 @@ if CUSTOM_START :
VNC_ENABLED = args.vnc != "None" VNC_ENABLED = args.vnc != "None"
VNC_PORT = args.vnc VNC_PORT = args.vnc
POINTS_FILE = args.points_file POINTS_FILE = args.points_file
UPDATE_VERSION = args.update_version
# global variables used later in the code # global variables used later in the code
LINUX_HOST = platform == "linux" # if the computer running this program is Linux, it allow more things LINUX_HOST = platform == "linux" # if the computer running this program is Linux, it allow more things
START_TIME = time() START_TIME = time()
@ -125,6 +131,10 @@ DISCORD_SUCCESS_LINK = config["DISCORD"]["successlink"]
DISCORD_ERROR_LINK = config["DISCORD"]["errorlink"] DISCORD_ERROR_LINK = config["DISCORD"]["errorlink"]
DISCORD_ENABLED_ERROR = config["DISCORD"]["DiscordErrorEnabled"] == "True" DISCORD_ENABLED_ERROR = config["DISCORD"]["DiscordErrorEnabled"] == "True"
DISCORD_ENABLED_SUCCESS = config["DISCORD"]["DiscordSuccessEnabled"]== "True" DISCORD_ENABLED_SUCCESS = config["DISCORD"]["DiscordSuccessEnabled"]== "True"
try :
AVATAR_URL = config["OTHER"]["avatar"]== "True"
except :
AVATAR_URL = "https://cdn.discordapp.com/icons/793934298977009674/d8055bccef6eca4855c349e808d0d788.webp"
if DISCORD_ENABLED_ERROR: if DISCORD_ENABLED_ERROR:
webhookFailure = Webhook.from_url(DISCORD_ERROR_LINK, adapter=RequestsWebhookAdapter()) webhookFailure = Webhook.from_url(DISCORD_ERROR_LINK, adapter=RequestsWebhookAdapter())

View File

@ -31,5 +31,5 @@ usr = root
pwd = password pwd = password
[OTHER] [OTHER]
avatar = https://cdn.discordapp.com/icons/793934298977009674/d8055bccef6eca4855c349e808d0d788.webp
ipv6 = False ipv6 = False

View File

@ -1 +1 @@
v5.2.0 v5.5.2