34 Commits

Author SHA1 Message Date
ed1e91b304 ptite update 2023-04-25 21:56:29 +02:00
710c272659 better logs 2023-04-17 22:28:26 +02:00
6f325c5a6a small fix 2023-04-17 22:00:46 +02:00
3b82419d4d fixed fidelity, but a new version may come sooner or later 2023-04-15 13:10:14 +02:00
9e0514a902 only the number of the config 2023-04-15 11:18:55 +02:00
5c8730dc26 only the number of the config 2023-04-15 11:18:36 +02:00
d11ae4055c euh ué 2023-04-15 11:04:23 +02:00
2dc8cda167 euh ué 2023-04-15 11:03:47 +02:00
fbb2feae31 small but infinite error 2023-04-14 10:31:12 +02:00
8d53a2b30b ok 2023-04-13 22:38:27 +02:00
f8f3ff2382 uéuéué 2023-04-13 22:22:06 +02:00
024b556f5e bruh 2023-04-13 09:11:12 +02:00
b4c9204bf2 oh gosh 2023-04-12 18:25:12 +02:00
f810f0ee3c test 2023-04-12 14:40:32 +02:00
afac7e9539 bump 2023-04-12 13:29:40 +02:00
ae12c18270 not stable either, but something need to change 2023-04-12 13:29:06 +02:00
dfd51bc040 uéuéué faster, more reliable, ... 2023-04-12 00:01:24 +02:00
12a6968ee0 well, SadPanda is still here ;( 2023-04-09 23:41:31 +02:00
8726785dc8 random test 2023-04-08 12:08:26 +02:00
e9f629dee4 sadpanda + typo 2023-04-08 11:51:27 +02:00
c9a838d368 faster overall + better discord error + better login 2023-04-07 23:28:48 +02:00
808916ddd3 testing is everything 2023-04-07 10:04:59 +02:00
c51c463338 the passage to 5.3 wasn't justified ( at least not enough) so i added a new feature 2023-04-07 10:01:47 +02:00
a22d1e6ddb you can manually add points to database 2023-04-07 09:53:11 +02:00
93bb634f7c some fixes here and there 2023-04-06 23:41:11 +02:00
31426a1dfd well, it should be really more robust as it doesn't rely on XPATH everywhere anymore 2023-04-06 23:04:57 +02:00
f862af8699 version control 2023-04-04 21:27:02 +02:00
78e7342acf last update of the night ? 2023-04-04 21:26:40 +02:00
4d8157ba1e better stronger faster 2023-04-04 21:18:09 +02:00
661566aade no clue if that's better 2023-04-04 21:07:12 +02:00
eb2b9dc2d3 you should now start using main : it can finally pass args 2023-04-04 20:59:45 +02:00
3385540350 better way if manually updated 2023-04-04 20:50:56 +02:00
0588180dda should be good for now 2023-04-04 20:46:10 +02:00
9995bc8e25 Auto Updates ? 2023-04-04 20:37:48 +02:00
16 changed files with 565 additions and 644 deletions

2
.gitignore vendored
View File

@ -11,3 +11,5 @@ data
/user_data /user_data
install.sh install.sh
nohup.out nohup.out
test.py
points.csv

View File

@ -4,11 +4,11 @@ ENV DEBIAN_FRONTEND noninteractive
ENV GECKODRIVER_VER v0.31.0 ENV GECKODRIVER_VER v0.31.0
ENV FIREFOX_VER 87.0 ENV FIREFOX_VER 87.0
WORKDIR /app WORKDIR /app
RUN set -x \ RUN set -x \
&& apt update \ && apt update \
&& apt upgrade -y \ && apt upgrade -y \
&& apt install -y \ && apt install -y \
tzdata \
wfrench \ wfrench \
git \ git \
libx11-xcb1 \ libx11-xcb1 \
@ -19,6 +19,7 @@ RUN set -x \
nano \ nano \
tigervnc-standalone-server \ tigervnc-standalone-server \
&& git clone https://github.com/piair338/MsRewards \ && git clone https://github.com/piair338/MsRewards \
&& ln -fs /usr/share/zoneinfo/Europe/Paris /etc/localtime \
&& pip install -r MsRewards/requirements.txt \ && pip install -r MsRewards/requirements.txt \
&& curl -sSLO https://download-installer.cdn.mozilla.net/pub/firefox/releases/91.9.1esr/linux-x86_64/en-US/firefox-91.9.1esr.tar.bz2 \ && curl -sSLO https://download-installer.cdn.mozilla.net/pub/firefox/releases/91.9.1esr/linux-x86_64/en-US/firefox-91.9.1esr.tar.bz2 \
&& tar -jxf firefox-* \ && tar -jxf firefox-* \
@ -31,6 +32,7 @@ RUN set -x \
&& mv geckodriver /usr/bin/ && mv geckodriver /usr/bin/
ENV TZ="Europe/Paris"
WORKDIR /app/MsRewards WORKDIR /app/MsRewards
CMD python main.py CMD python main.py

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,17 +12,17 @@ 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 worldlist (`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.
You can add a link to a website where content is only the link of the monthly fidelity card. You can add a link to a website where content is only the link of the monthly fidelity card.

579
V5.py
View File

@ -1,23 +1,16 @@
#!/usr/bin/python3.10 #!/usr/bin/python3.10
from modules.imports import * from modules.imports import *
from modules.db import add_to_database
from modules.config import * from modules.config import *
from modules.db import add_to_database
from modules.tools import * from modules.tools import *
from modules.error import * from modules.error import *
from modules.driver_tools import * from modules.driver_tools import *
from modules.cards import *
import modules.globals as g
global driver
driver = None
global _mail, _password, _otp, display
# TODO : replace by a better print (with logging, cf https://realpython.com/python-logging/) driver = g.driver
def printf(e): display = g.display
printf2(str(e), _mail)
# TODO
# handle "panda"'s error: error while logging in preventing some task to be done
# 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
@ -33,33 +26,29 @@ def firefox_driver(mobile=False, headless=False):
) )
options = Options() options = Options()
options.set_preference('intl.accept_languages', 'fr-FR, fr') options.set_preference('intl.accept_languages', 'fr-FR, fr')
if proxy_enabled :
setup_proxy(proxy_address,proxy_port, options)
options.set_preference("browser.link.open_newwindow", 3) options.set_preference("browser.link.open_newwindow", 3)
options.set_preference("dom.confirm_repost.testing.always_accept", True) options.set_preference("dom.confirm_repost.testing.always_accept", True)
if FAST :
options.set_preference("permissions.default.image", 2) #disable image loading. You shouldn't use it except if really nessecary
if headless: if headless:
options.add_argument("-headless") options.add_argument("-headless")
if mobile : if mobile :
options.set_preference("general.useragent.override", MOBILE_USER_AGENT) options.set_preference("general.useragent.override", MOBILE_USER_AGENT)
driver = webdriver.Firefox(options=options) driver = webdriver.Firefox(options=options)
driver.set_window_size(1070 + hash(_mail)%20 , 1900 + hash(_password + "salt")%10) # mobile resolution are crazy high now, right ? driver.set_window_size(1070 + hash(g._mail)%20 , 1900 + hash(g._password + "salt")%10) # mobile resolution are crazy high now, right ?
else : else :
options.set_preference("general.useragent.override", PC_USER_AGENT) options.set_preference("general.useragent.override", PC_USER_AGENT)
driver = webdriver.Firefox(options=options) driver = webdriver.Firefox(options=options)
driver.set_window_size(1900 + hash(_mail)%20 , 1070 + hash(_password + "salt")%10) driver.set_window_size(1900 + hash(g._mail)%20 , 1070 + hash(g._password + "salt")%10)
return(driver) return(driver)
def log_error(error, ldriver=driver, log=FULL_LOG): def log_error(error, ldriver=driver, log=g.full_log):
global driver global driver
if ldriver is None: if ldriver is None:
ldriver = driver ldriver = driver
if type(error) != str : if type(error) != str :
error = format_error(error) error = format_error(error)
printf(f"\n\n\033[93m Erreur : {str(error)} \033[0m\n\n") printf(f"\n\n\033[93m Erreur : {str(error)} \033[0m\n\n")
if DISCORD_ENABLED_ERROR: if g.discord_enabled_error:
with open("page.html", "w") as f: with open("page.html", "w") as f:
try : try :
f.write(ldriver.page_source) f.write(ldriver.page_source)
@ -84,10 +73,9 @@ 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=g._mail)
webhookFailure.send(embed=embed, file=file) webhookFailure.send(embed=embed, username="error", file=file, avatar_url = g.avatar_url)
webhookFailure.send(file=File("page.html")) webhookFailure.send(username="error", file=File("page.html"), avatar_url = g.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 +91,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
@ -118,10 +106,12 @@ def play_quiz2(override=10) -> None:
if somme + offset == int(correct_answer_value): if somme + offset == int(correct_answer_value):
answer_elem = driver.find_element(By.ID, "rqAnswerOption0") answer_elem = driver.find_element(By.ID, "rqAnswerOption0")
answer_elem.click() answer_elem.click()
if g.log:
progressBar(j, 10, name="quiz 2") progressBar(j, 10, name="quiz 2")
else: else:
answer_elem = driver.find_element(By.ID, "rqAnswerOption1") answer_elem = driver.find_element(By.ID, "rqAnswerOption1")
answer_elem.click() answer_elem.click()
if g.log:
progressBar(j, 10, name="quiz 2") progressBar(j, 10, name="quiz 2")
except exceptions.ElementNotInteractableException as e: except exceptions.ElementNotInteractableException as e:
@ -130,6 +120,7 @@ def play_quiz2(override=10) -> None:
log_error(e) log_error(e)
break break
printf("play_quiz2 done") printf("play_quiz2 done")
custom_sleep(3)
def play_quiz8(): def play_quiz8():
@ -137,9 +128,9 @@ 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)) sleep(uniform(3, 5))
correct_answers = [] correct_answers = []
for i in range(1,9): for i in range(1,9):
try : try :
@ -152,14 +143,15 @@ def play_quiz8():
for answer_id in correct_answers: for answer_id in correct_answers:
wait_until_visible(By.ID, answer_id, timeout = 20, browser=driver) wait_until_visible(By.ID, answer_id, timeout = 20, browser=driver)
counter += 1 counter += 1
if g.log :
progressBar(counter, 16, name="Quiz 8") progressBar(counter, 16, name="Quiz 8")
try: try:
answer_elem = driver.find_element(By.ID, answer_id) answer_elem = driver.find_element(By.ID, answer_id)
answer_elem.click() answer_elem.click()
custom_sleep(1) sleep(1)
except exceptions.NoSuchElementException : except exceptions.NoSuchElementException :
driver.refresh() driver.refresh()
custom_sleep(10) sleep(10)
answer_elem = driver.find_element(By.ID, answer_id) answer_elem = driver.find_element(By.ID, answer_id)
answer_elem.click() answer_elem.click()
except ElementClickInterceptedException : except ElementClickInterceptedException :
@ -169,6 +161,7 @@ def play_quiz8():
except Exception as e: except Exception as e:
log_error(f"{format_error(e)} \n Good answers : {' '.join(correct_answers)}") log_error(f"{format_error(e)} \n Good answers : {' '.join(correct_answers)}")
printf("play_quiz8 : fin ") printf("play_quiz8 : fin ")
custom_sleep(3)
def play_quiz4(override=None): def play_quiz4(override=None):
@ -184,7 +177,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:
@ -197,6 +190,7 @@ def play_quiz4(override=None):
log_error(e) log_error(e)
raise ValueError(e) raise ValueError(e)
printf("play_quiz4 : end") printf("play_quiz4 : end")
custom_sleep(3)
# do_poll() answer a random thing to poll, on of daily activities # do_poll() answer a random thing to poll, on of daily activities
@ -213,157 +207,135 @@ def do_poll():
log_error(error) log_error(error)
raise ValueError(error) raise ValueError(error)
printf("do_poll : end") printf("do_poll : end")
custom_sleep(3)
# finds all task to do, and launch them def all_cards():
def all_cards(): # return to the main page and closes all other tabs driver.get("https://rewards.bing.com")
def reset(part2=False): wait_until_visible(By.CLASS_NAME, "c-card-content", 10, driver)
if len(driver.window_handles) == 1: liste = driver.find_elements(By.CLASS_NAME, "c-card-content")
driver.get("https://www.bing.com/rewardsapp/flyout") custom_sleep(2)
if part2: if "welcometour" in driver.current_url:
driver.find_element( welcome_tour_NO(driver)
By.XPATH, "/html/body/div/div/div[3]/div[2]/div[2]/div[2]/div[1]" try :
).click() promo()
else: except Exception as e:
printf("no promo card")
if(len(liste) < 10):
log_error("moins de 10 cartes", driver)
if (len(liste) < 20):
if not g.norvege :
g.norvege = True
printf("moins de 20 cartes, disabling fidelity")
g.fidelity_link = "Disabled because norway"
log_error("Verifying if Norway", driver, True)
for i in range(len(liste)):
printf(f"carte {i}")
try :
checked = ("mee-icon-AddMedium" in liste[i].get_attribute("innerHTML"))
except StaleElementReferenceException :
liste = driver.find_elements(By.CLASS_NAME, "c-card-content")
printf(f"staled, {len(liste)}")
checked = ("mee-icon-AddMedium" in liste[i].get_attribute("innerHTML"))
except IndexError:
log_error("IndexError ?", driver)
driver.refresh()
custom_sleep(10)
checked = ("mee-icon-AddMedium" in liste[i].get_attribute("innerHTML"))
if checked:
custom_sleep(3)
driver.execute_script("arguments[0].scrollIntoView();", liste[i])
liste[i].click()
if len(driver.window_handles) > 1 :
driver.switch_to.window(driver.window_handles[1]) driver.switch_to.window(driver.window_handles[1])
printf(f"fermeture : {driver.current_url}") try_play(driver.title)
driver.close() close_tab(driver.window_handles[1])
driver.switch_to.window(driver.window_handles[0]) try :
if driver.current_url != "https://www.bing.com/rewardsapp/flyout": driver.refresh()
driver.get("https://www.bing.com/rewardsapp/flyout") liste = driver.find_elements(By.CLASS_NAME, "c-card-content")
reset(part2) if ("mee-icon-AddMedium" in liste[i].get_attribute("innerHTML")) :
printf(f"carte {i} not okay. Retrying.")
def daily_cards(): # cartes de la premiere partie (renouvelées chaque jours). liste[i].click()
try: log_error(f"Card {i} with issue. WTF ?", driver)
# make sure that the daily area is expanded driver.switch_to.window(driver.window_handles[1])
row_element = driver.find_element(By.XPATH, "/html/body/div/div/div[3]/div[2]/div[1]/div[1]") try_play(driver.title)
expanded = row_element.get_attribute("aria-expanded") close_tab(driver.window_handles[1])
if expanded != "true": except :
row_element.click() pass
for i in range(3): else :
custom_sleep(uniform(3, 5)) try :
try: welcome_tour(liste[i], driver)
titre = "Placeholder"
driver.find_element(
By.XPATH,f"/html/body/div/div/div[3]/div[2]/div[1]/div[2]/div/div[{i+1}]/a",
).click()
sleep(1)
titre = driver.title
try_play(titre)
sleep(1)
reset()
printf(f"DailyCard {titre} ok")
except Exception as e: except Exception as e:
log_error(f"all_cards card {titre} error ({format_error(e)})") printf("no new windows" + format_error(e))
driver.get("https://rewards.bing.com")
custom_sleep(3)
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")
if not ("correctCircle" in elm.get_attribute("innerHTML")):
printf(f"missed card {i}")
try_play(titre)
sleep(3)
reset()
except Exception as e :
printf(format_error(e) + "probablement ok - check card")
# if it fail, it's probably okay -> when all three card are done, the pannel fold
except Exception as e: def promo():
log_error(e) elm = driver.find_element(By.ID, "promo-item")
for i in range(10):
def weekly_cards(): if not elm:
# 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]")
expanded = row_element.get_attribute("aria-expanded")
if expanded != "true":
row_element.click()
for i in range(20): # Should raise an error whene there is no card left
printf("début de l'une des cartes")
driver.find_element(
By.XPATH,
"/html/body/div/div/div[3]/div[2]/div[2]/div[3]/div/div[1]/a/div/div[2]",
).click()
driver.switch_to.window(driver.window_handles[len(driver.window_handles) - 1])
sleep(1)
titre = driver.title
printf(f"carte {titre} en cours")
try_play(titre)
reset(True)
sleep(1)
try:
findall('href="([^<]+)" title=""', driver.page_source)[3] # return error if there is no cards left to do
except:
break break
if i > 8 :
def top_cards(): log_error("chelou, plus de 8 truc", driver)
for _ in range(10): driver.execute_script("arguments[0].click();", elm)
custom_sleep(3)
if len(driver.window_handles) > 1 :
driver.switch_to.window(driver.window_handles[len(driver.window_handles)-1])
try_play(driver.title)
close_tab(driver.window_handles[1])
else :
try : try :
driver.find_element(By.XPATH, "/html/body/div/div/div[3]/div[1]/div/div[1]/div[2]").click() spotify(driver)
reset() except :
except Exception as e: log_error("no new windows", driver)
printf(format_error(e)) driver.get("https://rewards.bing.com")
break custom_sleep(3)
try :
top_cards()
except Exception as e:
log_error(e)
try:
daily_cards()
except Exception as e:
log_error(e)
try :
weekly_cards()
except Exception as e:
log_error(e)
# Find out which type of action to do # Find out which type of action to do
def try_play(nom="inconnu"): def try_play(nom="inconnu"):
rgpd_popup(driver)
printf("try_play en cours")
def play(number): def play(number):
if number == 8 or number == 9: if number == 8 or number == 9:
try: try:
printf(f"\033[96m Quiz 8 detected on {nom} \033[0m") printf(f"\033[96mQuiz 8 detected on `{nom}` \033[0m")
play_quiz8() play_quiz8()
printf(f"\033[92m Quiz 8 succeeded on {nom} \033[0m") printf(f"\033[92mQuiz 8 succeeded on `{nom}` \033[0m")
custom_sleep(uniform(3, 5)) custom_sleep(uniform(3, 5))
except Exception as e: except Exception as e:
printf(f"fail of PlayQuiz 8. Aborted {e} \033[0m") printf(f"fail of PlayQuiz 8. Aborted {e} \033[0m")
elif number == 5 or number == 4: elif number == 5 or number == 4:
try: try:
printf(f"\033[96m Quiz 4 detected on {nom} \033[0m") printf(f"\033[96mQuiz 4 detected on `{nom}` \033[0m")
play_quiz4() play_quiz4()
printf(f"\033[92m Quiz 4 succeeded on {nom} \033[0m") printf(f"\033[92mQuiz 4 succeeded on `{nom}` \033[0m")
custom_sleep(uniform(3, 5)) custom_sleep(uniform(3, 5))
except Exception as e: except Exception as e:
printf(f"fail of PlayQuiz 4. Aborted {e} \033[0m") printf(f"Fail of PlayQuiz 4. Aborted {e} \033[0m")
elif number == 3 or number == 2: elif number == 3 or number == 2:
try: try:
printf(f"\033[96m Quiz 2 detected on {nom}\033[0m") printf(f"\033[96mQuiz 2 detected on `{nom}`\033[0m")
play_quiz2() play_quiz2()
printf(f"\033[92m Quiz 2 succeeded on {nom}\033[0m") printf(f"\033[92mQuiz 2 succeeded on `{nom}`\033[0m")
except Exception as e: except Exception as e:
printf(f"fail of PlayQuiz 2. Aborted {e}") printf(f"fail of PlayQuiz 2. Aborted {e}")
else: else:
log_error("There is an error. rqAnswerOption present in page but no action to do. skipping.") log_error("There is an error. rqAnswerOption present in page but no action to do. skipping.")
try: try:
if wait_until_visible(By.ID, "rqStartQuiz", 5, driver):
custom_sleep(3)
driver.find_element(By.ID, "rqStartQuiz").click() # start the quiz driver.find_element(By.ID, "rqStartQuiz").click() # start the quiz
answer_number = driver.page_source.count("rqAnswerOption") answer_number = driver.page_source.count("rqAnswerOption")
play(answer_number) play(answer_number)
else :
raise (NameError("going to next part"))
except Exception as e: # if there is no start button, an error is thrown except Exception as e: # if there is no start button, an error is thrown
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)
do_poll() do_poll()
printf("Poll succeeded") printf("Poll succeeded")
except Exception as e: except Exception as e:
@ -379,154 +351,98 @@ 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)
fidelity() fidelity()
else: else:
printf(f"rien à faire sur la page {nom}") printf(f"rien à faire sur la page {nom}")
rgpd_popup(driver)
custom_sleep(uniform(3, 5)) custom_sleep(uniform(3, 5))
# login() tries to login to your Microsoft account. # Login with password or with cookies.
# it uses global variable _mail and _password to login # The driver should be in the same state on both case
def login(ldriver): def pwd_login(ldriver):
def pwd_login():
printf("pwd_login : start") printf("pwd_login : start")
ldriver.get("https://login.live.com") ldriver.get("https://login.live.com")
custom_sleep(2)
wait_until_visible(By.ID, "i0116", browser = ldriver) wait_until_visible(By.ID, "i0116", browser = ldriver)
mail_elem = ldriver.find_element(By.ID, "i0116") mail_elem = ldriver.find_element(By.ID, "i0116")
send_keys_wait(mail_elem, _mail) send_keys_wait(mail_elem, g._mail)
mail_elem.send_keys(Keys.ENTER) mail_elem.send_keys(Keys.ENTER)
custom_sleep(2)
wait_until_visible(By.ID, "i0118", browser = ldriver) wait_until_visible(By.ID, "i0118", browser = ldriver)
pwd_elem = ldriver.find_element(By.ID, "i0118") pwd_elem = ldriver.find_element(By.ID, "i0118")
send_keys_wait(pwd_elem, _password) send_keys_wait(pwd_elem, g._password)
pwd_elem.send_keys(Keys.ENTER) pwd_elem.send_keys(Keys.ENTER)
custom_sleep(2) custom_sleep(2)
# 2FA
if "Entrez le code de sécurité" in ldriver.page_source : if "Entrez le code de sécurité" in ldriver.page_source :
try : try :
a2f_elem = ldriver.find_element(By.ID, "idTxtBx_SAOTCC_OTC") a2f_elem = ldriver.find_element(By.ID, "idTxtBx_SAOTCC_OTC")
a2f_elem.send_keys(_otp.now()) a2f_elem.send_keys(g._otp.now())
a2f_elem.send_keys(Keys.ENTER) a2f_elem.send_keys(Keys.ENTER)
except Exception as e : except Exception as e :
log_error(e) log_error(e)
custom_sleep(5)
def cookie_login(ldriver):
printf("cookies_login : start")
ldriver.get("https://login.live.com")
try :
load_cookies(ldriver)
except FileNotFoundError :
printf("No cookies file Found.")
return(False)
try :
ldriver.refresh()
except Exception as e:
printf(format_error(e))
printf("FIX YOUR SITE MS.......")
return(True)
# Accept all cookies question, and check if the account is locked
def login_part_2(ldriver, cookies = False):
custom_sleep(5)
if ('Abuse' in ldriver.current_url) : if ('Abuse' in ldriver.current_url) :
log_error("account suspended")
raise Banned() raise Banned()
save_cookies(driver, _mail) if cookies:
for id in ["KmsiCheckboxField","iLooksGood", "idSIButton9", "iCancel"]: save_cookies(ldriver)
for id in ["KmsiCheckboxField", "id__0", "iLooksGood", "idSIButton9", "iCancel"]:
if get_domain(ldriver) == "account.microsoft.com":
break
try: try:
ldriver.find_element(By.ID, id).click() ldriver.find_element(By.ID, id).click()
restart = True restart = True
except Exception as e: except Exception as e:
pass pass
wait_until_visible(By.CSS_SELECTOR, '[data-bi-id="sh-sharedshell-home"]', 20, ldriver)
try : ldriver.get("https://www.bing.com/?setlang=fr&cc=fr&cc=FR")
body_elem = ldriver.find_element(By.TAG_NAME, "body") # in case of any random popup
body_elem.send_keys(Keys.ENTER)
except :
pass
printf("login completed - going to MsRewards")
custom_sleep(uniform(3,5))
ldriver.get("https://www.bing.com/rewardsapp/flyout")
custom_sleep(uniform(3,5))
for i in [f'[title="Rejoindre maintenant"]', f'[title="Rejoindre"]', f'[title="Join now"]'] :
try:
ldriver.find_element(By.CSS_SELECTOR, i).click() # depend of the language of the page
except:
printf(f"element {i} not found")
rgpd_popup(ldriver) rgpd_popup(ldriver)
custom_sleep(uniform(3,5))
ldriver.get("https://www.bing.com/rewardsapp/flyout")
try:
ldriver.find_element(By.CSS_SELECTOR, '[title="Rejoindre maintenant"]').click() # depend of the language of the page
except:
printf(f"unlock test: fail, probably normal")
printf('on MsRewards')
def cookie_login():
ldriver.get("https://login.live.com")
try :
load_cookies(ldriver, _mail)
except FileNotFoundError :
printf("Creating cookies file")
return(False)
try :
ldriver.refresh()
except WebDriverException as e: # This error occurs at random time. Don't really know why
if "Reached error page: about:neterror?e=netTimeout" in str(e):
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
else:
log_error(e)
custom_sleep(20) # TODO : remplacer par un wait_element
if ("account.microsoft.com" in ldriver.current_url) :
ldriver.get("https://bing.com")
custom_sleep(5)
ldriver.refresh() ldriver.refresh()
rgpd_popup(ldriver) rgpd_popup(ldriver)
ldriver.get("https://www.bing.com/rewardsapp/flyout") #ldriver.get("https://account.microsoft.com/")
if not('>Tableau de bord' in ldriver.page_source): #if wait_until_visible(By.CSS_SELECTOR, '[data-bi-id="sh-sharedshell-home"]', 30, ldriver) :
try : # return(True) #the account logging was successful
ldriver.find_element(By.CSS_SELECTOR, "[h='ID=RewardsFlyout,2.1']").click() #else :
custom_sleep(5) # log_error("Error during login. Trying to refresh")
if "bing.com" in ldriver.current_url : # ldriver.refresh()
rgpd_popup(ldriver) # return(wait_until_visible(By.CSS_SELECTOR, '[data-bi-id="sh-sharedshell-home"]', 30, ldriver))
ldriver.get("https://www.bing.com/rewardsapp/flyout") # useless ?
if ('>Tableau de bord' in ldriver.page_source) :
return(True)
else :
printf("error during the connection. Trying something else")
except Exception as e:
log_error(f"not connected 5 - error {e}", ldriver)
if not('>Tableau de bord' in ldriver.page_source):
try :
ldriver.find_element(By.XPATH, "/html/body/div/div/div/div/div[2]/a").click()
custom_sleep(5)
except Exception as e:
log_error(f"erreur not connected 6{e}", ldriver)
return(False)
if "bing.com" in ldriver.current_url :
rgpd_popup(ldriver)
ldriver.get("https://www.bing.com/rewardsapp/flyout")
if ('>Tableau de bord' in ldriver.page_source) :
return(True)
else :
log_error("not connected 6", ldriver)
return(False)
return(True)
if ('account.live.com' in ldriver.current_url):
log_error("error 1", ldriver, True)
ldriver.refresh()
log_error("error 2", ldriver, True)
ldriver.get("https://bing.com")
ldriver.refresh()
rgpd_popup(ldriver)
log_error("error 3", ldriver, True)
sleep(5)
return(True)
printf("cookies plus valides ?")
return(False)
# login() tries to login to your Microsoft account.
# it uses global variable g._mail and g._password to login
def login(ldriver):
try : try :
if cookie_login(): success_cookies = cookie_login(ldriver)
return (ldriver.current_window_handle) if not success_cookies:
pwd_login() #mobile login in never called. TODO : check if it's bad. pwd_login(ldriver)
return(ldriver.current_window_handle) login_part_2(ldriver, not success_cookies)
ldriver.get("https://rewards.bing.com/")
except Banned: except Banned:
raise Banned() raise Banned()
except Exception as e: except Exception as e:
log_error(e) log_error(e)
ldriver.quit() ldriver.quit()
return(False)
# Makes 30 search as PC Edge # Makes 30 search as PC Edge
@ -552,9 +468,7 @@ def bing_pc_search(override=randint(35, 40)):
sleep(3) sleep(3)
send_keys_wait(driver.find_element(By.ID, "sb_form_q"), word) send_keys_wait(driver.find_element(By.ID, "sb_form_q"), word)
driver.find_element(By.ID, "sb_form_q").send_keys(Keys.ENTER) driver.find_element(By.ID, "sb_form_q").send_keys(Keys.ENTER)
custom_sleep(uniform(3, 7))
custom_sleep(uniform(5, 20))
try: try:
driver.find_element(By.ID, "sb_form_q").clear() driver.find_element(By.ID, "sb_form_q").clear()
except Exception as e: except Exception as e:
@ -566,7 +480,6 @@ def bing_pc_search(override=randint(35, 40)):
log_error(f"clear la barre de recherche - {format_error(e)}") log_error(f"clear la barre de recherche - {format_error(e)}")
# Unban an account, called with -u parameter. You will need a phone number # Unban an account, called with -u parameter. You will need a phone number
def unban() -> None: def unban() -> None:
driver.find_element(By.ID, "StartAction").click() driver.find_element(By.ID, "StartAction").click()
@ -600,23 +513,24 @@ def unban() -> None:
# Sends points to database, discord and whatever service you want # Sends points to database, discord and whatever service you want
def log_points(account="unknown"): def log_points(account="unknown"):
def get_points(): def get_points():
driver.get("https://www.bing.com/rewardsapp/flyout") driver.get("https://rewards.bing.com")
regex1 = '<a href="https://rewards\.bing\.com/" title="((.{1,3}),(.{1,3})) points" target="_blank"' custom_sleep(1)
if "/proofs/" in driver.current_url:
for id in ["KmsiCheckboxField","iLooksGood", "idSIButton9", "iCancel"]:
try: try:
point = search(regex1, driver.page_source)[1].replace(",", "") driver.find_element(By.ID, id).click()
restart = True
except Exception as e: except Exception as e:
elem = driver.find_element(By.CSS_SELECTOR, '[title="Microsoft Rewards"]') pass
elem.click() wait_until_visible(By.CSS_SELECTOR, 'span[mee-element-ready="$ctrl.loadCounterAnimation()"]', browser=driver)
custom_sleep(5)
driver.switch_to.window(driver.window_handles[len(driver.window_handles) - 1])
custom_sleep(uniform(5,7))
try : try :
point = search('availablePoints":([\d]+)', driver.page_source)[1] point = search('availablePoints\":([\d]+)', driver.page_source)[1]
except : except Exception as e:
sleep(5)
log_error(f"Dev error, checking why it doesn't work (waited a bit, is this still white ?) {format_error(e)}", driver, True)
driver.refresh() driver.refresh()
sleep(5) sleep(5)
point = search('availablePoints":([\d]+)', driver.page_source)[1] point = search('availablePoints\":([\d]+)', driver.page_source)[1]
return(point) return(point)
for _ in range (3): for _ in range (3):
@ -634,8 +548,8 @@ def log_points(account="unknown"):
custom_sleep(uniform(3, 20)) custom_sleep(uniform(3, 20))
account_name = account.split("@")[0] account_name = account.split("@")[0]
if DISCORD_ENABLED_SUCCESS: if g.discord_enabled_success:
if DISCORD_EMBED: if g.discord_embed:
embed = Embed( embed = Embed(
title=f"{account_name} actuellement à {str(points)} points", colour=Colour.green() title=f"{account_name} actuellement à {str(points)} points", colour=Colour.green()
) )
@ -644,8 +558,8 @@ def log_points(account="unknown"):
else: else:
webhookSuccess.send(f"{account_name} actuellement à {str(points)} points") webhookSuccess.send(f"{account_name} actuellement à {str(points)} points")
if sql_enabled : if g.sql_enabled :
add_to_database(account_name, points, sql_host, sql_usr, sql_pwd, sql_database) add_to_database(account_name, points, g.sql_host, g.sql_usr, g.sql_pwd, g.sql_database)
def fidelity(): def fidelity():
@ -656,7 +570,7 @@ def fidelity():
except: except:
break break
try : try :
fidelity_link_page = get(FidelityLink) #get the url of fidelity page fidelity_link_page = get(g.fidelity_link) #get the url of fidelity page
except Exception as e : except Exception as e :
printf(e) printf(e)
fidelity_link_page = False fidelity_link_page = False
@ -665,22 +579,23 @@ 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 :
choix = driver.find_element(By.CSS_SELECTOR, 'div[class="pull-left spacer-48-bottom punchcard-row"]') # pull-left spacer-48-bottom punchcard-row? USELESS ? choix = driver.find_element(By.CSS_SELECTOR, 'div[class="pull-left spacer-48-bottom punchcard-row"]') # pull-left spacer-48-bottom punchcard-row? USELESS ?
except : # tentative de fix except : # tentative de fix
driver.refresh() driver.execute_script("location.reload(true);")
wait_until_visible(By.CSS_SELECTOR, 'div[class="pull-left spacer-48-bottom punchcard-row"]', browser=driver)
choix = driver.find_element(By.CSS_SELECTOR, 'div[class="pull-left spacer-48-bottom punchcard-row"]') choix = driver.find_element(By.CSS_SELECTOR, 'div[class="pull-left spacer-48-bottom punchcard-row"]')
answer_number = search("([0-9]) of ([0-9]) completed", driver.page_source) answer_number = search("([0-9]) of ([0-9]) completed", driver.page_source)
if answer_number is None: if answer_number is None:
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)
@ -712,60 +627,6 @@ def fidelity():
log_error(e) log_error(e)
def mobile_login_pwd(error):
try:
# TODO
# seems fine, check if there are no issues NO
mot = choice(Liste_de_mot).replace(" ","+")
mobile_driver.get(f"https://www.bing.com/search?q={mot}")
rgpd_popup(mobile_driver)
printf("start of Mobile login")
try :
mobile_driver.find_element(By.ID, "mHamburger").click()
except Exception as e :
elm = mobile_driver.find_element(By.ID, "mHamburger")
mobile_driver.execute_script("arguments[0].scrollIntoView();", elm)
mobile_driver.find_element(By.ID, "mHamburger").click()
wait_until_visible(By.ID, "hb_s", browser=mobile_driver)
mobile_driver.find_element(By.ID, "hb_s").click()
wait_until_visible(By.ID, "i0116", browser=mobile_driver)
mail_elem = mobile_driver.find_element(By.ID, "i0116")
send_keys_wait(mail_elem, _mail)
mail_elem.send_keys(Keys.ENTER)
wait_until_visible(By.ID, "i0118", browser=mobile_driver)
pwd_elem = mobile_driver.find_element(By.ID, "i0118")
send_keys_wait(pwd_elem, _password)
pwd_elem.send_keys(Keys.ENTER)
custom_sleep(uniform(1, 2))
if "Entrez le code de sécurité" in driver.page_source :
try :
a2f_elem = mobile_driver.find_element(By.ID, "idTxtBx_SAOTCC_OTC")
a2f_elem.send_keys(_otp.now())
a2f_elem.send_keys(Keys.ENTER)
except Exception as e :
log_error(e)
custom_sleep(uniform(1, 2))
for i in ["KmsiCheckboxField", "iLooksGood", "idSIButton9"]:
try:
mobile_driver.find_element(By.ID,i ).click()
except Exception as e:
pass
printf("end of Mobile login")
except Exception as e:
error += 1
if error <= 3:
printf(f"failure on mobile_login. Retrying({error}/3), {e}")
custom_sleep(uniform(5, 10))
mobile_login_pwd(error)
else:
log_error(f"login impossible 3 fois de suite. {e}", mobile_driver)
mobile_driver.quit()
return(True)
def mobile_alert_popup(): def mobile_alert_popup():
try: try:
alert = mobile_driver.switch_to.alert alert = mobile_driver.switch_to.alert
@ -791,7 +652,7 @@ def bing_mobile_search(override=randint(22, 25)):
mot = choice(Liste_de_mot) mot = choice(Liste_de_mot)
send_keys_wait(mobile_driver.find_element(By.ID, "sb_form_q"), mot) send_keys_wait(mobile_driver.find_element(By.ID, "sb_form_q"), mot)
mobile_driver.find_element(By.ID, "sb_form_q").send_keys(Keys.ENTER) mobile_driver.find_element(By.ID, "sb_form_q").send_keys(Keys.ENTER)
custom_sleep(uniform(5, 20)) custom_sleep(uniform(3, 7))
mobile_alert_popup() # check for alert (asking for position or for allowing notifications) mobile_alert_popup() # check for alert (asking for position or for allowing notifications)
mobile_driver.find_element(By.ID, "sb_form_q").clear() mobile_driver.find_element(By.ID, "sb_form_q").clear()
except Exception as e: except Exception as e:
@ -811,7 +672,7 @@ def daily_routine(custom = False):
if not custom: # custom already login if not custom: # custom already login
login(driver) login(driver)
except Banned : except Banned :
log_error("THIS ACCOUNT IS BANNED. FIX THIS ISSUE WITH -U") log_error("This account is locked. Fix that. (-U ?)", driver)
return() return()
try: try:
@ -834,38 +695,35 @@ def daily_routine(custom = False):
except Exception as e: except Exception as e:
log_error(e) log_error(e)
try: try:
log_points(_mail) log_points(g._mail)
except Exception as e: except Exception as e:
log_error(e) log_error(e)
def dev(): def dev():
pass input("dev pause")
def CustomStart(Credentials): def CustomStart():
global START_TIME if not g.islinux :
if not LINUX_HOST :
raise NameError('You need to be on linux to do that, due to the utilisation of a module named enquieries, sorry.') raise NameError('You need to be on linux to do that, due to the utilisation of a module named enquieries, sorry.')
global driver, _mail, _password, p, _otp global driver
system("clear") # clear from previous command to allow a clean choice system("clear") # clear from previous command to allow a clean choice
actions = ["tout", "daily", "pc", "mobile", "log_points","fidelity", "dev"] actions = ["tout", "daily", "pc", "mobile", "log_points","fidelity", "dev"]
Actions = enquiries.choose("quels Actions ?", actions, multi=True) Actions = enquiries.choose("quels Actions ?", actions, multi=True)
liste = select_accounts() liste = select_accounts()
START_TIME = time() # Reset timer to the start of the actions g.start_time = time() # Reset timer to the start of the actions
for cred in liste: for cred in liste:
_mail = cred[0] g._mail = cred[0]
_password = cred[1] g._password = cred[1]
if len(cred) == 3: if len(cred) == 3:
_otp = TOTP(cred[2]) g._otp = TOTP(cred[2])
driver = firefox_driver() driver = firefox_driver()
driver.implicitly_wait(3) driver.implicitly_wait(3)
if login(driver) != "STOP": if login(driver) != "STOP":
if "tout" in Actions: if "tout" in Actions:
daily_routine(True) daily_routine(True)
@ -897,45 +755,44 @@ def CustomStart(Credentials):
break break
if not "tout" in Actions: if not "tout" in Actions:
try: try:
log_points(_mail) log_points(g._mail)
except Exception as e: except Exception as e:
printf(f"CustomStart {e}") printf(f"CustomStart {e}")
driver.close() driver.quit()
if g.vnc_enabled :
if VNC_ENABLED : display = SmartDisplay(backend="xvnc", size=(2160, 2160), rfbport=g.vnc_port, color_depth=24)
display = SmartDisplay(backend="xvnc", size=(2160, 2160), rfbport=VNC_PORT, color_depth=24)
else : else :
display = SmartDisplay(size=(2160, 2160)) display = SmartDisplay(size=(2160, 2160))
display.start() display.start()
if CUSTOM_START: if g.custom_start:
CustomStart(Credentials) CustomStart()
elif UNBAN: elif g.unban:
_mail, _password = select_accounts(False)[0] g._mail, g._password = select_accounts(False)[0]
driver = firefox_driver() driver = firefox_driver()
try : try :
login(driver) login(driver)
except Banned: except Banned:
unban() unban()
driver.quit() driver.quit()
elif POINTS_FILE != "": elif g.points_file != "":
save_points_from_file(POINTS_FILE) save_points_from_file(g.points_file)
else: else:
for cred in Credentials: if g.update_version != "None":
_mail = cred[0] if g.discord_enabled_error:
_password = cred[1] webhookFailure.send(f"Updated to {g.update_version}", username="UPDATE", avatar_url="https://cdn-icons-png.flaticon.com/512/1688/1688988.png")
for cred in g._cred:
g._mail = cred[0]
g._password = cred[1]
if len(cred) == 3: if len(cred) == 3:
_otp = TOTP(cred[2]) g._otp = TOTP(cred[2])
printf("\n\n")
printf(_mail)
custom_sleep(1) custom_sleep(1)
printf("début du driver") printf("Début du driver.")
driver = firefox_driver() driver = firefox_driver()
printf("driver demarré") printf("Driver demarré.")
driver.implicitly_wait(3) driver.implicitly_wait(3)
try: try:
daily_routine() daily_routine()
@ -944,11 +801,11 @@ else:
printf(f"finis. attente de {round(attente/60)}min") printf(f"finis. attente de {round(attente/60)}min")
custom_sleep(attente) custom_sleep(attente)
except KeyboardInterrupt: except KeyboardInterrupt:
printf("canceled. Closing driver and display.") printf("Canceled. Closing driver and display.")
driver.quit() driver.quit()
display.stop() display.stop()
except Exception as e: except Exception as e:
printf(f"error not catched. skipping this account. {e}") printf(f"Error not catched. Skipping this account. {e}")
driver.quit() driver.quit()
display.stop() display.stop()

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,10 +54,10 @@ 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":
if args.file : if args.file :
l =[x.split(",")[0].split("@")[0] for x in args.file.readlines()] l =[x.split(",")[0].split("@")[0] for x in args.file.readlines()]
endroit = input("ou est le bot ? ") endroit = input("ou est le bot ? ")
@ -62,11 +69,24 @@ if i == "1":
endroit = input("ou est le bot ? ") endroit = input("ou est le bot ? ")
proprio = input("qui est le proprio ? ") proprio = input("qui est le proprio ? ")
add_account(name, endroit, proprio) add_account(name, endroit, proprio)
elif i == '2': elif i == '2':
name = input("quel est le compte qui a été ban ? ") name = input("quel est le compte qui a été ban ? ")
pts = input("il avait combien de points ? ") pts = input("il avait combien de points ? ")
ban_account(name, pts) ban_account(name, pts)
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)

44
main.py
View File

@ -1,8 +1,11 @@
#/usr/bin/python3.10 #/usr/bin/python3.10
from packaging.version import parse as parse_version
import configparser import configparser
import os import os
import shutil import shutil
import requests
import sys
config = configparser.ConfigParser() config = configparser.ConfigParser()
@ -16,8 +19,6 @@ except :
config.read(config_path) config.read(config_path)
def confirm(texte, default = False): def confirm(texte, default = False):
if default : if default :
txt = '[Y/n]' txt = '[Y/n]'
@ -41,12 +42,12 @@ text = {"fr" : {
"next" : "voulez vous ajouter un compte ? ", "next" : "voulez vous ajouter un compte ? ",
"finc" : "comptes en cours d'ajout ", "finc" : "comptes en cours d'ajout ",
"ajout" : "comptes ajouté ", "ajout" : "comptes ajouté ",
"fidelity" : "avez vous un lien sur lequel le lien vers la page fidelité du mois est le seul contenu de la page ? ", "fidelity" : "avez vous un lien sur lequel le lien vers la page fidélité du mois est le seul contenu de la page ? ",
"lien" : "entrez le lien ", "lien" : "entrez le lien ",
"discorde" : "voulez vous envoyer les erreurs sur discord ? ", "discorde" : "voulez vous envoyer les erreurs sur discord ? ",
"w1" : "entrez le lien du WebHook pour envoyer les points ", "w1" : "entrez le lien du WebHook pour envoyer les points ",
"w2" : "entrez le lien du WebHook pour envoyer les erreurs ", "w2" : "entrez le lien du WebHook pour envoyer les erreurs ",
"msqle" : "voulez vous untiliser une base de donnée ", "msqle" : "voulez vous utiliser une base de donnée ",
"msqll" : "entrez le lien de la base de donnée ", "msqll" : "entrez le lien de la base de donnée ",
"msqlu" : "entrez l'utilisateur de la base de donnée ", "msqlu" : "entrez l'utilisateur de la base de donnée ",
"msqlp" : "entrez le mot de passe de la base de donnée ", "msqlp" : "entrez le mot de passe de la base de donnée ",
@ -83,8 +84,6 @@ def setup_comptes():
f.write("\n") f.write("\n")
f.close() f.close()
print(t["ajout"]) print(t["ajout"])
#modifie le fichier de configuration
edit_config_txt("logpath",f'{os.getcwd()}/user_data/login.csv') edit_config_txt("logpath",f'{os.getcwd()}/user_data/login.csv')
@ -111,7 +110,7 @@ def setup_settings():
discord() discord()
proxy() proxy()
sql() sql()
amazon()
def general(): def general():
if confirm(t["fidelity"]): if confirm(t["fidelity"]):
@ -144,6 +143,7 @@ def sql() :
pwd = input(t["msqlp"]) pwd = input(t["msqlp"])
edit_config_txt("pwd",pwd) edit_config_txt("pwd",pwd)
def proxy() : def proxy() :
enabled = confirm(t["proxye"], default = False) enabled = confirm(t["proxye"], default = False)
if enabled : if enabled :
@ -153,13 +153,33 @@ def proxy() :
port = input(t["proxyp"]) port = input(t["proxyp"])
edit_config_txt("port",port) edit_config_txt("port",port)
def amazon():
enabled = confirm("claim les recompenses automatiquement sur amazon ?", default = False)
edit_config_txt("claim_amazon",enabled)
def check_update(args):
try :
latest = requests.get("https://api.github.com/repos/piair338/MsRewards/releases").json()[0]["tag_name"]
latest = parse_version(latest)
except Exception as e :
print(e)
return (args)
f = open("./version", 'r')
txt = f.readlines()[0].replace("\n","")
f.close()
cur = parse_version(txt)
if not (cur < latest) :
print("Already up to date.")
return(args)
else :
print(f"updating to {latest}")
os.system("git reset --hard")
os.system("git pull")
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 :
os.system("python3 V5.py") args = " ".join(sys.argv[1::])
args = check_update(args)
os.system("python3 V5.py " + args)

View File

@ -1,69 +0,0 @@
from easyprocess import EasyProcess
from pyvirtualdisplay import Display
from modules.config import *
from selenium import webdriver
from selenium.common import exceptions
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.firefox.options import Options
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import Select
def setup_proxy(ip, port, options, socks=False) :
PROXY = f"{ip}:{port}"
if socks :
options.set_preference('network.proxy.type', 1)
options.set_preference('network.proxy.socks', ip)
options.set_preference('network.proxy.socks_port', int(port))
options.set_preference("browser.link.open_newwindow", 3)
else :
webdriver.DesiredCapabilities.FIREFOX['proxy'] = {
"httpProxy": PROXY,
"sslProxy": PROXY,
"proxyType": "MANUAL",
}
def firefox_driver(mobile=False, Headless=False):
PC_USER_AGENT = (
"Mozilla/5.0 (Windows NT 10.0; Win64; x64)"
"AppleWebKit/537.36 (KHTML, like Gecko)"
"Chrome/110.0.0.0 Safari/537.36 Edg/110.0.1587.56")
MOBILE_USER_AGENT = (
"Mozilla/5.0 (iPhone; CPU iPhone OS 15_5 like Mac OS X)"
"AppleWebKit/605.1.15 (KHTML, like Gecko)"
"CriOS/103.0.5060.63 Mobile/15E148 Safari/604.1"
)
options = Options()
options.set_preference('intl.accept_languages', 'fr-FR, fr')
if proxy_enabled :
setup_proxy(proxy_address,proxy_port, options)
options.set_preference("browser.link.open_newwindow", 3)
if FAST :
options.set_preference("permissions.default.image", 2) #disable image loading. May add this without the fast option soon
if Headless:
options.add_argument("-headless")
if mobile :
options.set_preference("general.useragent.override", MOBILE_USER_AGENT)
else :
options.set_preference("general.useragent.override", PC_USER_AGENT)
driver = webdriver.Firefox(options=options)
driver.set_window_size(1900 + hash(_mail)%20 , 1070 + hash(_password + "salt")%10)
return(driver)
def select_accounts(multiple = True):
system("clear") # clear from previous command to allow a clean choice
emails = [x[0] for x in Credentials] # list of all email adresses
emails_selected = enquiries.choose(f"quel{'s' if multiple else ''} compte{'s' if multiple else ''} ?", emails, multi=multiple)
return([x for x in Credentials if x[0] in emails_selected])
with Display(backend="xvnc", size=(2000, 1000), rfbport=5904) as disp:
_mail, _password = select_accounts(False)[0]
driver = firefox_driver()
print(f"connect via VNC to port 5904. \nID: {_mail}\npwd : {_password}")
i = input('stop ? ')
driver.close()

34
modules/cards.py Normal file
View File

@ -0,0 +1,34 @@
from modules.imports import *
def welcome_tour(elm, driver):
try :
driver.find_element(By.CSS_SELECTOR, '[class="welcome-tour-next-button c-call-to-action c-glyph"]').click()
except :
pass
driver.find_element(By.CSS_SELECTOR, '[class="quiz-link gray-button c-call-to-action c-glyph f-lightweight"]').click()
sleep(5)
driver.find_element(By.CSS_SELECTOR, '[class="c-glyph glyph-cancel"]').click()
elm.click()
driver.find_element(By.CSS_SELECTOR, '[class="quiz-link gray-button c-call-to-action c-glyph f-lightweight"]').click()
sleep(5)
driver.find_element(By.CSS_SELECTOR, '[class="c-glyph glyph-cancel"]').click()
elm.click()
driver.find_element(By.CSS_SELECTOR, '[class="quiz-link gray-button c-call-to-action c-glyph f-lightweight"]').click()
sleep(5)
driver.find_element(By.CSS_SELECTOR, '[class="c-glyph glyph-cancel"]').click()
def welcome_tour_NO(driver):
try :
driver.find_element(By.CSS_SELECTOR, '[class="welcome-tour-next-button c-call-to-action c-glyph"]').click()
except :
pass
driver.find_element(By.CSS_SELECTOR, '[class="c-glyph glyph-cancel"]').click()
sleep(5)
def spotify(driver):
sleep(5)
driver.find_element(By.CSS_SELECTOR, '[data-bi-id="spotify-premium gratuit"]').click()
sleep(5)
close_tab(driver.window_handles[1])

View File

@ -1,18 +1,7 @@
#!/usr/bin/python3.10 #!/usr/bin/python3.10
import configparser from modules.driver_tools import *
from csv import reader from modules.imports import *
from os import sys, system, path import modules.globals as g
from sys import platform
import argparse
from discord import ( # Importing discord.Webhook and discord.RequestsWebhookAdapter
RequestsWebhookAdapter,
Webhook,
Colour,
)
from time import time
from random import shuffle
""" """
Setup for option, like --override or --fulllog Setup for option, like --override or --fulllog
""" """
@ -50,19 +39,12 @@ parser.add_argument(
help="enable full logging in discord", help="enable full logging in discord",
action="store_true", action="store_true",
) )
parser.add_argument(
"-r",
"--risky",
help="make the program faster, probably better risk of ban",
dest="fast",
action="store_true"
)
parser.add_argument( parser.add_argument(
"-c", "-c",
"--config", "--config",
help="Choose a specific config file", help="Choose a specific config file",
type=argparse.FileType('r') default=""
) )
parser.add_argument( parser.add_argument(
@ -81,87 +63,108 @@ 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"
)
parser.add_argument(
"--dev",
help="dev option",
dest="dev",
action="store_true"
)
args = parser.parse_args() args = parser.parse_args()
CUSTOM_START = args.override g.custom_start = args.override
UNBAN = args.unban g.unban = args.unban
LOG = args.log g.log = args.log
FULL_LOG = args.fulllog g.full_log = args.fulllog
FAST = args.fast g.dev = args.dev
if CUSTOM_START :
LOG = True
VNC_ENABLED = args.vnc != "None"
VNC_PORT = args.vnc
POINTS_FILE = args.points_file
if g.custom_start :
g.log = True
g.vnc_enabled = args.vnc != "None"
g.vnc_port = args.vnc
g.points_file = args.points_file
g.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 g.islinux = platform == "linux" # if the computer running this program is Linux, it allow more things
START_TIME = time() g.start_time = time()
if LINUX_HOST:
import enquiries
else:
system("") # enable colors in windows cmd
#reading configuration #reading configuration
config_path = f"{path.abspath(path.dirname(path.dirname( __file__ )))}/user_data/config.cfg"
if args.config :
config_path = path.abspath(args.config.name)
config = configparser.ConfigParser() config = configparser.ConfigParser()
config.read(config_path)
if args.config :
try :
config_path =f"{path.abspath(path.dirname(path.dirname( __file__ )))}/user_data/config{args.config}.cfg"
config.read(config_path)
g.mot_path = config["PATH"]["motpath"]
except :
config_path = path.abspath(args.config)
config.read(config_path)
else :
config_path = f"{path.abspath(path.dirname(path.dirname( __file__ )))}/user_data/config.cfg"
config.read(config_path)
# path configurations # path configurations
MotPath = config["PATH"]["motpath"] g.mot_path = config["PATH"]["motpath"]
CREDENTIALS_PATH = config["PATH"]["logpath"] g.credential_path = config["PATH"]["logpath"]
# discord configuration # discord configuration
DISCORD_SUCCESS_LINK = config["DISCORD"]["successlink"] g.discord_success_link = config["DISCORD"]["successlink"]
DISCORD_ERROR_LINK = config["DISCORD"]["errorlink"] g.discord_error_link = config["DISCORD"]["errorlink"]
DISCORD_ENABLED_ERROR = config["DISCORD"]["DiscordErrorEnabled"] == "True" g.discord_enabled_error = config["DISCORD"]["DiscordErrorEnabled"] == "True"
DISCORD_ENABLED_SUCCESS = config["DISCORD"]["DiscordSuccessEnabled"]== "True" g.discord_enabled_success = config["DISCORD"]["DiscordSuccessEnabled"]== "True"
try :
g.avatar_url = config["OTHER"]["avatar"]
except :
g.avatar_url = "https://cdn.discordapp.com/icons/793934298977009674/d8055bccef6eca4855c349e808d0d788.webp"
if DISCORD_ENABLED_ERROR: if g.discord_enabled_error:
webhookFailure = Webhook.from_url(DISCORD_ERROR_LINK, adapter=RequestsWebhookAdapter()) webhookFailure = Webhook.from_url(g.discord_error_link, adapter=RequestsWebhookAdapter())
if DISCORD_ENABLED_SUCCESS: if g.discord_enabled_success:
webhookSuccess = Webhook.from_url(DISCORD_SUCCESS_LINK, adapter=RequestsWebhookAdapter()) webhookSuccess = Webhook.from_url(g.discord_success_link, adapter=RequestsWebhookAdapter())
# base settings # base settings
FidelityLink = config["SETTINGS"]["FidelityLink"] g.fidelity_link = config["SETTINGS"]["FidelityLink"]
DISCORD_EMBED = config["SETTINGS"]["embeds"] == "True" #print new point value in an embed g.discord_embed = config["SETTINGS"]["embeds"] == "True" #print new point value in an embed
Headless = config["SETTINGS"]["headless"] == "True" g.headless = config["SETTINGS"]["headless"] == "True"
# proxy settings # proxy settings
proxy_enabled = config["PROXY"]["proxy_enabled"] == "True" g.proxy_enabled = config["PROXY"]["proxy_enabled"] == "True"
proxy_address = config["PROXY"]["url"] g.proxy_address = config["PROXY"]["url"]
proxy_port = config["PROXY"]["port"] g.proxy_port = config["PROXY"]["port"]
# MySQL settings # MySQL settings
sql_enabled = config["SQL"]["sql_enabled"] == "True" g.sql_enabled = config["SQL"]["sql_enabled"] == "True"
sql_usr = config["SQL"]["usr"] g.sql_usr = config["SQL"]["usr"]
sql_pwd = config["SQL"]["pwd"] g.sql_pwd = config["SQL"]["pwd"]
sql_host = config["SQL"]["host"] g.sql_host = config["SQL"]["host"]
sql_database = config["SQL"]["database"] g.sql_database = config["SQL"]["database"]
# Other settings
IPV6_CHECKED = config["OTHER"]["ipv6"]
g = open(MotPath, "r", encoding="utf-8") h = open(g.mot_path, "r", encoding="utf-8")
lines = g.readlines() lines = h.readlines()
if len(lines) < 3 : if len(lines) < 3 :
Liste_de_mot = list(lines[0].split(",")) Liste_de_mot = list(lines[0].split(","))
else : else :
Liste_de_mot = [x.replace('\n', "") for x in lines] Liste_de_mot = [x.replace('\n', "") for x in lines]
g.close() h.close()
with open(CREDENTIALS_PATH) as f: with open(g.credential_path) as f:
reader = reader(f) reader = reader(f)
Credentials = list(reader) Credentials = list(reader)
shuffle(Credentials) shuffle(Credentials)
g._cred = Credentials
if g.proxy_enabled :
setup_proxy(g.proxy_address,g.proxy_port)

View File

@ -1,15 +1,10 @@
from modules.imports import * from modules.imports import *
from modules.config import * from modules.config import *
from modules.tools import *
import modules.globals as g
def setup_proxy(ip, port) :
def setup_proxy(ip, port, options, socks=False) :
PROXY = f"{ip}:{port}" PROXY = f"{ip}:{port}"
if socks :
options.set_preference('network.proxy.type', 1)
options.set_preference('network.proxy.socks', ip)
options.set_preference('network.proxy.socks_port', int(port))
options.set_preference("browser.link.open_newwindow", 3)
else :
webdriver.DesiredCapabilities.FIREFOX['proxy'] = { webdriver.DesiredCapabilities.FIREFOX['proxy'] = {
"httpProxy": PROXY, "httpProxy": PROXY,
"sslProxy": PROXY, "sslProxy": PROXY,
@ -25,12 +20,24 @@ def rgpd_popup(driver) -> None:
pass pass
# save webdriver cookies # save webdriver cookies
def save_cookies(driver, _mail): def save_cookies(driver):
pickle.dump(driver.get_cookies(), open(f"{'/'.join(__file__.split('/')[:-2])}/user_data/cookies/{_mail}.pkl", "wb")) if g.dev:
f = open(f"{'/'.join(__file__.split('/')[:-2])}/user_data/cookies/{g._mail}_unsafe.pkl", "w")
for i in driver.get_cookies():
f.write(str(i) + "\n")
f.close()
else :
pickle.dump(driver.get_cookies(), open(f"{'/'.join(__file__.split('/')[:-2])}/user_data/cookies/{g._mail}.pkl", "wb"))
# load cookies previously saved to the driver # load cookies previously saved to the driver
def load_cookies(driver, _mail): def load_cookies(driver):
cookies = pickle.load(open(f"{'/'.join(__file__.split('/')[:-2])}/user_data/cookies/{_mail}.pkl", "rb")) if g.dev:
f = open(f"{'/'.join(__file__.split('/')[:-2])}/user_data/cookies/{g._mail}_unsafe.pkl", "r")
lines = f.readlines()
f.close()
cookies = [literal_eval(x) for x in lines]
else :
cookies = pickle.load(open(f"{'/'.join(__file__.split('/')[:-2])}/user_data/cookies/{g._mail}.pkl", "rb"))
for cookie in cookies: for cookie in cookies:
driver.add_cookie(cookie) driver.add_cookie(cookie)
@ -41,9 +48,6 @@ keys can be an string, but also selenium keys
def send_keys_wait(element, keys): def send_keys_wait(element, keys):
for i in keys: for i in keys:
element.send_keys(i) element.send_keys(i)
if FAST :
pass
else :
sleep(uniform(0.1, 0.3)) sleep(uniform(0.1, 0.3))
@ -52,6 +56,8 @@ def send_keys_wait(element, keys):
def wait_until_visible(search_by: str, identifier: str, timeout = 20, browser = None) -> None: def wait_until_visible(search_by: str, identifier: str, timeout = 20, browser = None) -> None:
try : try :
WebDriverWait(browser, timeout).until(EC.visibility_of_element_located((search_by,identifier)), "element not found") WebDriverWait(browser, timeout).until(EC.visibility_of_element_located((search_by,identifier)), "element not found")
return(True)
except TimeoutException as e: except TimeoutException as e:
print(f"element not found after {timeout}s") printf(f"element not found after {timeout}s")
return(False)

36
modules/globals.py Normal file
View File

@ -0,0 +1,36 @@
driver = None
_mail = '_mail temp'
_password = '_password temp'
_otp = '_otp temp'
display = None
_cred = []
custom_start = False
unban = False
log = False
full_log = False
vnc_enabled = False
vnc_port = 0
points_file = "/"
update_version = False
islinux = True
start_time = 0
mot_path = "/"
credential_path = "/"
discord_success_link = "https://example.com"
discord_error_link = "https://example.com"
discord_enabled_error = False
discord_enabled_success = False
avatar_url = ""
fidelity_link = "None"
discord_embed = False
headless = False
proxy_enabled = False
proxy_address = "0.0.0.0"
proxy_port = "0"
sql_enabled = False
sql_usr = "None"
sql_pwd = "azerty"
sql_host = "https://example.com"
sql_database = "MsRewards"
dev = False
norvege = False

View File

@ -1,24 +1,33 @@
import argparse
import asyncio import asyncio
import csv import configparser
from os import sys, system, path import pickle
from csv import reader
from datetime import datetime, timedelta
from os import path, sys, system
from random import choice, randint, shuffle, uniform from random import choice, randint, shuffle, uniform
from re import findall, search from re import findall, search
from sys import platform from sys import platform
from time import sleep from time import sleep, time
from requests import get
from selenium import webdriver
from selenium.common import exceptions
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.firefox.options import Options
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import Select
from selenium.common.exceptions import WebDriverException, TimeoutException, NoSuchElementException, ElementClickInterceptedException
from discord import Colour, Embed, File, RequestsWebhookAdapter, Webhook
from pyotp import TOTP from pyotp import TOTP
from pyvirtualdisplay import Display from pyvirtualdisplay import Display
from pyvirtualdisplay.smartdisplay import SmartDisplay from pyvirtualdisplay.smartdisplay import SmartDisplay
import pickle from requests import get
from datetime import timedelta, datetime from selenium import webdriver
from discord import Embed, Colour, File from selenium.common import exceptions
from selenium.common.exceptions import (ElementClickInterceptedException,
NoSuchElementException,
StaleElementReferenceException,
TimeoutException, WebDriverException)
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.firefox.options import Options
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import Select, WebDriverWait
from ast import literal_eval
try:
import enquiries
except:
system("") # enable colors in windows cmd

View File

@ -1,18 +1,22 @@
from modules.imports import * from modules.imports import *
from modules.config import * from modules.config import *
from modules.db import *
import modules.globals as g
# add the time arround the text given in [text]& # add the time arround the text given in [text]&
def Timer(text: str, mail: str) -> str: def Timer(text: str) -> str:
return(f"[{mail} - {datetime.today().strftime('%d-%m-%Y')} - {timedelta(seconds = round(float(time() - START_TIME)))}] " + str(text)) return(f"[{g._mail.split('@')[0]} - {datetime.today().strftime('%d/%m')} - {timedelta(seconds = round(float(time() - g.start_time)))}] " + str(text))
# replace the function print, with more options # replace the function print, with more options
# [txt] : string, [driver] : selenium webdriver # [txt] : string, [driver] : selenium webdriver
def printf2(txt, mail, LOG = LOG): def printf(txt):
print(Timer(txt, mail)) print(Timer(txt))
# return current page domain
def get_domain(driver):
return(driver.current_url.split("/")[2])
# check if the user is using IPV4 using ipify.org # check if the user is using IPV4 using ipify.org
# [driver] : selenium webdriver # [driver] : selenium webdriver
@ -26,12 +30,9 @@ def check_ipv4(driver):
return False return False
def custom_sleep(temps): def custom_sleep(temps):
try : try :
if FAST and temps > 50: if g.log : #only print sleep when user see it
sleep(temps/10)
elif LOG: #only print sleep when user see it
points = ["", "", "", "", "", "", "", ""] points = ["", "", "", "", "", "", "", ""]
passe = 0 passe = 0
for i in range(int(temps)): for i in range(int(temps)):
@ -64,20 +65,18 @@ def progressBar(current, total=30, barLength=20, name="Progress"):
def save_points_from_file(file): def save_points_from_file(file):
with open(file) as f: with open(file) as f:
reader = csv.reader(f) read = reader(f)
points_list = list(reader) points_list = list(read)
for item in points_list: for item in points_list:
compte, points = item[0], item[1] compte, points = item[0], item[1]
add_to_database(compte, points, sql_host,sql_usr,sql_pwd,sql_database, save_if_fail=False) add_to_database(compte, points, g.sql_host,g.sql_usr,g.sql_pwd,g.sql_database, save_if_fail=False)
with open(file, "w") as f: with open(file, "w") as f:
f.write("") f.write("")
def select_accounts(multiple = True): def select_accounts(multiple = True):
system("clear") # clear from previous command to allow a clean choice system("clear") # clear from previous command to allow a clean choice
emails = [x[0] for x in Credentials] # list of all email adresses emails = [x[0] for x in g._cred] # list of all email adresses
emails_selected = enquiries.choose(f"quel{'s' if multiple else ''} compte{'s' if multiple else ''} ?", emails, multi=multiple) emails_selected = enquiries.choose(f"quel{'s' if multiple else ''} compte{'s' if multiple else ''} ?", emails, multi=multiple)
return([x for x in Credentials if x[0] in emails_selected]) return([x for x in g._cred if x[0] in emails_selected])

View File

@ -9,3 +9,4 @@ pyvirtualdisplay
pillow pillow
EasyProcess EasyProcess
pyotp pyotp
packaging

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

1
version Normal file
View File

@ -0,0 +1 @@
v5.10.0