25 Commits

Author SHA1 Message Date
3eb193eca3 Disable stream buffering on upstream nginx server 2024-04-10 14:24:57 +02:00
f566b2eeda Potentially fix no-discord 2024-04-10 12:15:14 +02:00
52e88f81b9 More checks on TFA 2024-04-10 12:14:41 +02:00
1a8137783c Even faster cached build 2024-04-10 11:43:54 +02:00
6f13b2532d Add clean.sh 2024-04-10 11:36:33 +02:00
3978c44bbc Use chrome profile to change language 2024-04-10 11:35:46 +02:00
49dc53ed32 Fix 2FA (language setting is not always working) 2024-04-10 11:04:54 +02:00
ba66a96c65 Check if creds are not empty 2024-04-10 10:29:53 +02:00
db157771de Merge flags 2024-04-08 16:51:43 +02:00
cbd1ad93a6 version bump 2024-04-08 16:38:16 +02:00
afabd94f0d Re-implement cookie login
with chrome profiles
2024-04-08 16:36:38 +02:00
81deaf05b0 Update chrome.deb URL 2024-04-08 16:34:36 +02:00
9af0f4aadb build.sh: check permissions 2024-04-03 15:42:14 +02:00
1d16294c04 Add more logs (custom.txt..) to logs view 2024-04-03 15:34:46 +02:00
fae2033061 Simplify Dockerfile to cache building layers 2024-04-03 15:26:02 +02:00
50c4036c73 Merge pull request 'Fix ANSI code formatting' (#9) from augustin64/MsRewards-Reborn:master into master
Reviewed-on: https://gitea.augustin64.fr/piair/MsRewards-Reborn/pulls/9
2024-03-31 12:05:17 +02:00
c683472895 Fix ANSI code formatting 2024-03-29 16:53:59 +01:00
178f2d472a Merge pull request 'Mise en forme des codes ANSI dans les logs' (#8) from augustin64/MsRewards-Reborn:augustin64-ansi-up into master
Reviewed-on: https://gitea.augustin64.fr/piair/MsRewards-Reborn/pulls/8
2024-03-28 23:56:33 +01:00
d3137f858a Mise en forme des codes ANSI dans les logs 2024-03-25 10:41:34 +01:00
d2ad467d4e Oops, pas push le bon fichier 2024-03-24 20:30:09 +01:00
b45e9e549f mise à jour automatique de chrome 2024-03-24 20:27:40 +01:00
200b0d8a86 Trying to fix an issue when an account fail 2024-03-05 21:18:39 +01:00
4a5af6455d Fixed 2FA issue + added better logs 2024-03-01 17:29:15 +01:00
49b691d736 not tested enough apparently 2024-02-28 18:22:15 +01:00
9549a6dea3 not tested enough apparently 2024-02-28 18:12:32 +01:00
19 changed files with 291 additions and 1549 deletions

View File

@ -1,22 +1,43 @@
FROM python:3.10 FROM python:3.10
ENV DEBIAN_FRONTEND noninteractive ENV DEBIAN_FRONTEND noninteractive
WORKDIR /app/ WORKDIR /app/
# Initial apt install
RUN apt update
RUN apt install -y libgtk-4-1 libvulkan1 libxdamage1 \
novnc websockify xvfb nginx nano tzdata \
sqlite3 apt-transport-https software-properties-common \
wget wfrench tigervnc-standalone-server libasound2 \
libatk-bridge2.0-0 libnss3 libnspr4 xvfb libgbm1 libatk1.0-0 \
libu2f-udev libatspi2.0-0 libcups2 libxkbcommon0 libxrandr2 \
libdbus-1-3 xdg-utils fonts-liberation libdrm2
# Additional repos and packages
RUN wget http://security.ubuntu.com/ubuntu/pool/main/o/openssl/libssl1.1_1.1.0g-2ubuntu4_amd64.deb \
&& dpkg -i libssl1.1_1.1.0g-2ubuntu4_amd64.deb
RUN curl -sSL http://mirror.cs.uchicago.edu/google-chrome/pool/main/g/google-chrome-stable/google-chrome-stable_123.0.6312.86-1_amd64.deb -o chrome.deb \
&& dpkg -i chrome.deb
RUN ln -fs /usr/share/zoneinfo/Europe/Paris /etc/localtime
RUN wget -q -O /usr/share/keyrings/grafana.key https://apt.grafana.com/gpg.key \
&& echo "deb [signed-by=/usr/share/keyrings/grafana.key] https://apt.grafana.com stable main" | tee -a /etc/apt/sources.list.d/grafana.list
RUN curl -fsSL https://packages.redis.io/gpg | gpg --dearmor -o /usr/share/keyrings/redis-archive-keyring.gpg
# Install from new repo
RUN apt update \ RUN apt update \
&& wget http://security.ubuntu.com/ubuntu/pool/main/o/openssl/libssl1.1_1.1.0g-2ubuntu4_amd64.deb \ && apt install -y redis grafana
&& dpkg -i libssl1.1_1.1.0g-2ubuntu4_amd64.deb \
&& apt install redis libgtk-4-1 libvulkan1 libxdamage1 -y \ # Configure Grafana
&& curl -sSLO https://nc.piair.xyz/s/BKLsBWoZkTdYjfq/download/chrome.deb \ RUN grafana-cli plugins install frser-sqlite-datasource
&& ln -fs /usr/share/zoneinfo/Europe/Paris /etc/localtime \
&& git clone https://gitea.augustin64.fr/piair/MsRewards-Reborn \ COPY requirements.txt /app/requirements.txt
&& python3 -m pip install -r MsRewards-Reborn/requirements.txt \ RUN python3 -m pip install -r requirements.txt
&& wget -q -O /usr/share/keyrings/grafana.key https://apt.grafana.com/gpg.key \
&& curl -fsSL https://packages.redis.io/gpg | gpg --dearmor -o /usr/share/keyrings/redis-archive-keyring.gpg \ # Setup app
&& echo "deb [signed-by=/usr/share/keyrings/grafana.key] https://apt.grafana.com stable main" | tee -a /etc/apt/sources.list.d/grafana.list \ RUN git clone https://gitea.augustin64.fr/piair/MsRewards-Reborn
&& apt update \ # Use this instead when developping locally:
&& apt install novnc websockify grafana xvfb nginx nano tzdata sqlite3 apt-transport-https software-properties-common wget wfrench tigervnc-standalone-server libasound2 libatk-bridge2.0-0 libnss3 libnspr4 xvfb libgbm1 libatk1.0-0 libu2f-udev libatspi2.0-0 libcups2 libxkbcommon0 libxrandr2 libdbus-1-3 xdg-utils fonts-liberation libdrm2 -y \ # COPY . /app/MsRewards-Reborn
&& bash MsRewards-Reborn/config/config.sh \
&& dpkg -i chrome.deb RUN bash MsRewards-Reborn/config/config.sh
ENV TZ="Europe/Paris" ENV TZ="Europe/Paris"
WORKDIR /app/MsRewards-Reborn/Flask/ WORKDIR /app/MsRewards-Reborn/Flask/
CMD bash start.sh CMD bash start.sh

View File

@ -373,8 +373,18 @@ def config_post():
def logs(): def logs():
with open("/app/MsRewards-Reborn/user_data/configs.json", "r") as inFile: with open("/app/MsRewards-Reborn/user_data/configs.json", "r") as inFile:
configs = json.load(inFile) configs = json.load(inFile)
print(configs)
return(render_template("logs.html", data=configs)) files = [(configs[i]["name"], i) for i in configs]
config_files = [i[1] for i in files]
for f in os.listdir("/app/MsRewards-Reborn/Flask/static/logs"):
fid = ".".join(f.split(".")[:-1]) # filename without .txt
if f != ".gitignore" and fid not in config_files:
files.append((f, fid))
return render_template(
"logs.html",
files=files
)
@app.route("/stats/", methods=["GET", "POST"]) @app.route("/stats/", methods=["GET", "POST"])

View File

@ -8,14 +8,37 @@
<select name="select" onchange="change_logs(this.value)"> <select name="select" onchange="change_logs(this.value)">
<option id="null" value="0">Choisir une config</option> <option id="null" value="0">Choisir une config</option>
{% for i in data %} {% for file in files %}
<option id="{{data[i]['name']}}" value="{{i}}">{{data[i]['name']}}</option> <option id="{{ file[0] }}" value="{{ file[1] }}">{{ file[0] }}</option>
{% endfor %} {% endfor %}
</select> </select>
<br><br> <br><br>
<iframe type="text/html" src="{{url_for('static', filename='logs/1.txt')}}" width="100%" height="85%" id="embed"> <iframe type="text/html" src="{{url_for('static', filename='logs/1.txt')}}" width="100%" height="85%" id="embed"></iframe>
<script defer>
const iframe = document.getElementsByTagName("iframe")[0];
var script = document.createElement('script');
// Wait until ansi_up load
script.onload = function () {
// Wait until iframe load
iframe.onload = function() {
const subdoc = iframe.contentWindow.document;
const subBody = subdoc.getElementsByTagName("body")[0]
let ansiOutput = subBody;
// Depending on the content encoding (and maybe on the browser)
// a <pre> is added around the content of the file
if (subBody.getElementsByTagName("pre").length > 0) {
ansiOutput = subBody.getElementsByTagName("pre")[0];
}
const ansi_up = new AnsiUp();
ansiOutput.innerHTML = ansi_up.ansi_to_html(ansiOutput.innerText);
}
};
script.src = "https://cdn.jsdelivr.net/npm/ansi_up@4.0.4/ansi_up.js";
document.head.appendChild(script);
</script>
{% endif %} {% endif %}
{% endblock %} {% endblock %}

101
V6.py
View File

@ -1,4 +1,4 @@
#!/usr/bin/python3.10 #!/usr/bin/python3
from modules.Classes.Config import Config from modules.Classes.Config import Config
from modules.Classes.DiscordLogger import DiscordLogger from modules.Classes.DiscordLogger import DiscordLogger
from modules.Classes.UserCredentials import UserCredentials from modules.Classes.UserCredentials import UserCredentials
@ -9,6 +9,7 @@ from modules.db import add_to_database
from modules.driver_tools import * from modules.driver_tools import *
from modules.error import * from modules.error import *
from selenium.common.exceptions import NoSuchElementException
# create a webdriver # create a webdriver
def create_driver(mobile=False): def create_driver(mobile=False):
@ -22,16 +23,33 @@ def create_driver(mobile=False):
"AppleWebKit/537.36 (KHTML, like Gecko)" "AppleWebKit/537.36 (KHTML, like Gecko)"
"Chrome/22 Mobile Safari/537.36" "Chrome/22 Mobile Safari/537.36"
) )
chrome_options = webdriver.ChromeOptions()
chrome_profile_dir = init_profile(config.UserCredentials.get_mail())
# Full list on https://github.com/GoogleChrome/chrome-launcher/blob/main/docs/chrome-flags-for-tools.md
arguments = [
"--no-first-run",
"--ash-no-nudges",
"--no-default-browser-check",
"--disable-features=PrivacySandboxSettings4,Translate",
"--disable-search-engine-choice-screen",
f"--user-data-dir={chrome_profile_dir}/"
]
if mobile: if mobile:
chrome_options.add_argument(f"--user-agent={mobile_user_agent}") arguments.append(f"--user-agent={mobile_user_agent}")
else: else:
chrome_options.add_argument(f"--user-agent={pc_user_agent}") arguments.append(f"--user-agent={pc_user_agent}")
# disabled as it may cause detection # disabled as it may cause detection
if config.proxy.is_enabled(): if config.proxy.is_enabled():
chrome_options.add_argument(f'--proxy-server={config.proxy.ip}:{config.proxy.port}') arguments.append(f'--proxy-server={config.proxy.ip}:{config.proxy.port}')
chrome_options = webdriver.ChromeOptions()
for arg in arguments:
chrome_options.add_argument(arg)
driver = uc.Chrome(options=chrome_options) driver = uc.Chrome(options=chrome_options)
set_language(driver)
return driver return driver
@ -152,7 +170,7 @@ def play_quiz4(override: int = None):
except Exception as e: except Exception as e:
log_error(e) log_error(e)
raise ValueError(e) raise ValueError(e)
info("Quiz 8 done.") info("Quiz 4 done.")
custom_sleep(3) custom_sleep(3)
@ -165,6 +183,8 @@ def do_poll():
try: try:
answer_elem.click() answer_elem.click()
except exceptions.ElementNotInteractableException: except exceptions.ElementNotInteractableException:
warning("element not clickable. Waiting a bit and retrying.")
custom_sleep(uniform(2, 2.5))
driver.execute_script("arguments[0].click();", answer_elem) driver.execute_script("arguments[0].click();", answer_elem)
custom_sleep(uniform(2, 2.5)) custom_sleep(uniform(2, 2.5))
except Exception as err: except Exception as err:
@ -190,7 +210,7 @@ def all_cards():
info("no promo card") info("no promo card")
if len(card_list) < 10: # most likely an error during loading if len(card_list) < 10: # most likely an error during loading
if "suspendu" in driver.page_source: if "suspendu" in driver.page_source or "suspended" in driver.page_source:
raise Banned() raise Banned()
driver.refresh() driver.refresh()
card_list = driver.find_elements(By.CLASS_NAME, "c-card-content") card_list = driver.find_elements(By.CLASS_NAME, "c-card-content")
@ -360,22 +380,35 @@ def login_part_1():
driver = config.WebDriver.driver driver = config.WebDriver.driver
driver.get("https://login.live.com") driver.get("https://login.live.com")
wait_until_visible(By.ID, "i0116", browser=driver) wait_until_visible(By.ID, "i0116", browser=driver)
mail_elem = driver.find_element(By.ID, "i0116") send_wait_and_confirm(
send_keys_wait(mail_elem, config.UserCredentials.get_mail()) driver.find_element(By.ID, "i0116"),
mail_elem.send_keys(Keys.ENTER) config.UserCredentials.get_mail()
)
wait_until_visible(By.ID, "i0118", browser=driver) wait_until_visible(By.ID, "i0118", browser=driver)
pwd_elem = driver.find_element(By.ID, "i0118") send_wait_and_confirm(
send_keys_wait(pwd_elem, config.UserCredentials.get_password()) driver.find_element(By.ID, "i0118"),
pwd_elem.send_keys(Keys.ENTER) config.UserCredentials.get_password()
custom_sleep(2) )
# 2FA # 2FA
if "Entrez le code de sécurité" in driver.page_source: try:
try: if not wait_until_visible(By.ID, "idTxtBx_SAOTCC_OTC", browser=driver, timeout=5, raise_error=False):
a2f_elem = driver.find_element(By.ID, "idTxtBx_SAOTCC_OTC") custom_sleep(2)
a2f_elem.send_keys(config.UserCredentials.get_tfa().now()) return
a2f_elem.send_keys(Keys.ENTER)
except Exception as err: tfa = config.UserCredentials.get_tfa()
log_error(err) if tfa is None:
error("2FA needed but no code available for this account, sending error")
raise ValueError("2FA needed but no code available for this account")
else:
a2f_code = tfa.now()
info(f"Need 2FA, I have code: {a2f_code}")
send_wait_and_confirm(
driver.find_element(By.ID, "idTxtBx_SAOTCC_OTC"),
a2f_code
)
except Exception as err:
log_error(err)
# Accept all cookies question, and check if the account is locked # Accept all cookies question, and check if the account is locked
@ -410,9 +443,17 @@ def login_part_2():
# login() tries to login to your Microsoft account. # login() tries to login to your Microsoft account.
# it uses global variable g._mail and g._password to login # it uses global variable g._mail and g._password to login
def login(): def login():
def logged_in():
driver.get("https://login.live.com")
custom_sleep(10)
if get_domain(driver) == "account.microsoft.com":
return True
return False
driver = config.WebDriver.driver driver = config.WebDriver.driver
try: try:
login_part_1() if not logged_in():
login_part_1()
login_part_2() login_part_2()
driver.get("https://rewards.bing.com/") driver.get("https://rewards.bing.com/")
except Banned: except Banned:
@ -610,9 +651,11 @@ def daily_routine(cred: UserCredentials, custom=False):
try: try:
if not custom: # custom already is logged in if not custom: # custom already is logged in
login() login()
except Banned: except Banned:
log_error("This account is locked.") log_error("This account is locked.")
return raise Banned()
except Identity: except Identity:
log_error("This account has an issue.") log_error("This account has an issue.")
return return
@ -666,7 +709,7 @@ def json_start(json_entry, cred: UserCredentials):
config.WebDriver.switch_to_driver("PC") config.WebDriver.switch_to_driver("PC")
driver = config.WebDriver.driver driver = config.WebDriver.driver
try: try:
if str(account_id) in json_entry["unban"]: if "unban" in json_entry and str(account_id) in json_entry["unban"]:
login_part_1() login_part_1()
info("\nGO TO example.com TO PROCEED or wait 1200 secs.") info("\nGO TO example.com TO PROCEED or wait 1200 secs.")
for _ in range(1200): for _ in range(1200):
@ -680,7 +723,7 @@ def json_start(json_entry, cred: UserCredentials):
login() login()
try: try:
if str(account_id) in json_entry["tout"]: if str(account_id) in json_entry["tout"]:
daily_routine(cred) daily_routine(cred, True)
except KeyError: except KeyError:
pass pass
else: else:
@ -744,12 +787,16 @@ def default_start():
config.WebDriver.pc_driver.quit() config.WebDriver.pc_driver.quit()
config.display.stop() config.display.stop()
break break
except Banned:
warning("this account is banned. Switching to next account")
except Exception as e: except Exception as e:
log_error(f"Error not caught. Skipping this account. " + format_error(e)) log_error(f"Error not caught. Skipping this account. " + format_error(e))
critical(f"Error not caught. Skipping this account. {e}") critical(f"Error not caught. Skipping this account. {e}")
config.WebDriver.pc_driver.quit() config.WebDriver.pc_driver.quit()
config.UserCredentials.next_account() finally:
config.UserCredentials.next_account()
config.display.stop() config.display.stop()

View File

@ -1 +1,12 @@
sudo docker build --no-cache --network host -t msrewards . && sudo docker run -d --restart unless-stopped -p 1234:1234 -p 2345:2345 -ti --shm-size=2gb --name MsRewards msrewards #!/bin/bash
docker-do () { # Check if sudo needs to be used
if id -nG "$(whoami)" | grep -qw "docker"; then
docker $@
else
sudo docker $@
fi
}
docker-do build --network host -t msrewards .
docker-do run -d --restart unless-stopped -p 1234:1234 -p 2345:2345 -ti --shm-size=2gb --name MsRewards msrewards

13
clean.sh Executable file
View File

@ -0,0 +1,13 @@
#!/bin/bash
docker-do () { # Check if sudo needs to be used
if id -nG "$(whoami)" | grep -qw "docker"; then
docker $@
else
sudo docker $@
fi
}
docker-do stop MsRewards
docker-do rm MsRewards
docker-do image rm msrewards

View File

@ -46,6 +46,7 @@ server {
proxy_pass "http://127.0.0.1:6666"; proxy_pass "http://127.0.0.1:6666";
chunked_transfer_encoding off; chunked_transfer_encoding off;
proxy_buffering off; proxy_buffering off;
set_header X-Accel-Buffering no;
} }
} }
@ -59,7 +60,6 @@ sqlite3 /app/MsRewards-Reborn/MsRewards.db "CREATE TABLE comptes (id INTEGER PRI
printf "\nconfigurating grafana\n" printf "\nconfigurating grafana\n"
cp /app/MsRewards-Reborn/config/grafana.ini /etc/grafana/ cp /app/MsRewards-Reborn/config/grafana.ini /etc/grafana/
grafana-cli plugins install frser-sqlite-datasource
printf "setting up default dashboard" printf "setting up default dashboard"
cp /app/MsRewards-Reborn/config/Stats-dashbord.json /usr/share/grafana/public/dashboards/home.json cp /app/MsRewards-Reborn/config/Stats-dashbord.json /usr/share/grafana/public/dashboards/home.json

File diff suppressed because it is too large Load Diff

View File

@ -50,9 +50,14 @@ class Config:
""" """
self.discord = DiscordConfig() self.discord = DiscordConfig()
self.discord.avatar_url = settings["avatarlink"] self.discord.avatar_url = settings["avatarlink"]
self.discord.wh_link = discord[config[args.config]["discord"]]["errorsL"]
if self.discord.wh_link != "": if (
"discord" in config[args.config]
and config[args.config]["discord"] in discord
and "errorsL" in discord[config[args.config]["discord"]]
and discord[config[args.config]["discord"]]["errorsL"] != ""
):
self.discord.wh_link = discord[config[args.config]["discord"]]["errorsL"]
self.discord.wh = Webhook.from_url(self.discord.wh_link, adapter=RequestsWebhookAdapter()) self.discord.wh = Webhook.from_url(self.discord.wh_link, adapter=RequestsWebhookAdapter())
else: else:
self.discord.wh = FakeWebHook() self.discord.wh = FakeWebHook()

View File

@ -9,6 +9,6 @@ class DiscordConfig:
class FakeWebHook: class FakeWebHook:
def send(self, *args): def send(self, *args, **kwargs):
debug(f"Used a webhook call without webhook url with {args}") debug(f"Used a webhook call without webhook url with {args} {kwargs}")

View File

@ -30,7 +30,7 @@ class DiscordLogger:
) )
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=self.config.UserCredentials.creds.get_mail()) embed.set_footer(text=self.config.UserCredentials.get_mail() + " - " + self.config.WebDriver.current_driver())
self.config.discord.wh.send(embed=embed, username="error", file=file, avatar_url=self.config.discord.avatar_url) self.config.discord.wh.send(embed=embed, username="error", file=file, avatar_url=self.config.discord.avatar_url)
self.config.discord.wh.send(username="error", file=File("page.html"), avatar_url=self.config.discord.avatar_url) self.config.discord.wh.send(username="error", file=File("page.html"), avatar_url=self.config.discord.avatar_url)

View File

@ -20,3 +20,6 @@ class Driver:
case _: case _:
raise ValueError("The driver must be either pc or mobile") raise ValueError("The driver must be either pc or mobile")
def current_driver(self):
return "PC" if self.pc_driver == self.driver else "Mobile"

View File

@ -30,8 +30,9 @@ class UserCredentials:
def get_tfa(self): def get_tfa(self):
if not self.tfa_enable(): if not self.tfa_enable():
warning("Warning: TFA is not enabled. Calling get_tfa is an expected behaviour.") warning("Warning: TFA is not enabled. Can't get a TFA code.")
return TOTP(self.data[self.current]["tfa"]) return None
return TOTP(self.data[self.current]["2fa"])
def next_account(self): def next_account(self):
self.current += 1 self.current += 1
@ -41,4 +42,5 @@ class UserCredentials:
debug("No new credentials.") debug("No new credentials.")
def is_valid(self): def is_valid(self):
return self.current < self.total return (self.current < self.total
and self.get_mail() != "" and self.get_mail is not None)

View File

@ -0,0 +1,8 @@
import undetected_chromedriver as uc
from pyvirtualdisplay.smartdisplay import SmartDisplay
display = SmartDisplay(size=(1920, 1080))
display.start()
driver = uc.Chrome()
driver.close()
driver.close()

View File

@ -30,7 +30,7 @@ class ColoredFormatter(logging.Formatter):
# Set up the root logger # Set up the root logger
root_logger = logging.getLogger(__name__) root_logger = logging.getLogger(__name__)
root_logger.setLevel(logging.DEBUG) root_logger.setLevel(logging.INFO)
# Create a console handler and set the formatter # Create a console handler and set the formatter
ch = logging.StreamHandler() ch = logging.StreamHandler()

View File

@ -10,7 +10,7 @@ def get_domain(driver):
def custom_sleep(temps): def custom_sleep(temps):
try: try:
if True: # todo: change this awful condition if False: # todo: change this awful condition
points = ["", "", "", "", "", "", "", ""] points = ["", "", "", "", "", "", "", ""]
passe = 0 passe = 0
for _ in range(int(temps)): for _ in range(int(temps)):

View File

@ -0,0 +1,48 @@
import requests
import re
from packaging import version
import subprocess
from logger import critical, info, error
errorMessage = subprocess.run(['python3', 'generate_error.py'], check=False, stdout=subprocess.PIPE,
stderr=subprocess.PIPE).stderr.decode("utf-8")
versionPattern = "This version of ChromeDriver only supports Chrome version ([0-9]+)"
try:
versionN = re.search(versionPattern, errorMessage)[1]
except Exception as e:
critical("Can't get version number from error")
error(e)
exit(0)
info(f"Needed version : '{versionN}'")
downloadUrl = "http://mirror.cs.uchicago.edu/google-chrome/pool/main/g/google-chrome-stable/"
r = requests.get(downloadUrl)
content = r.text
exactVersionList = re.findall(f"(google-chrome-stable_({versionN}.[0-9.]+)[^<^>^\"]+)", content)
try:
best = exactVersionList[0]
except Exception as e:
critical("No version matches required version")
error(e)
exit(0)
for i in exactVersionList:
if version.parse(i[1]) > version.parse(best[1]):
best = i
chromeDebURL = f"http://mirror.cs.uchicago.edu/google-chrome/pool/main/g/google-chrome-stable/{best[0]}"
info(f"chrome deb URL : {chromeDebURL}")
info("downloading chrome")
subprocess.call(['wget', "-O", "/tmp/chrome.deb", chromeDebURL])
info("Chrome deb downloaded. Installing chrome")
subprocess.call(["dpkg", "-i", "/tmp/chrome.deb"])
info("Chrome installed")

View File

@ -1,3 +1,5 @@
import os
import json
from random import uniform from random import uniform
from selenium.common import TimeoutException from selenium.common import TimeoutException
@ -10,33 +12,36 @@ from modules.Tools.logger import debug
from modules.Tools.tools import * from modules.Tools.tools import *
def set_language(ldriver): def init_profile(mail):
ldriver.get("chrome://settings/languages") chrome_profile_dir = "/app/MsRewards-Reborn/user_data/profile/"+mail
action = ActionChains(ldriver) os.makedirs(chrome_profile_dir, exist_ok=True)
action.reset_actions()
# select language preferences_file = os.path.join(chrome_profile_dir, "Default", "Preferences")
x_coord = 1200 if not os.path.exists(preferences_file):
y_coord = 150 os.makedirs(os.path.join(chrome_profile_dir, "Default"), exist_ok=True)
action.move_by_offset(x_coord, y_coord).click().perform() with open(preferences_file, "w") as f:
sleep(0.5) json.dump(
# scroll down {
action.reset_actions() "intl": {
elm = ldriver.find_element(By.XPATH, "/html/body") "accept_languages": "fr-FR,en-US,en",
ActionChains(ldriver) \ "selected_languages": "fr-FR,en-US,en"
.send_keys("french") \ }
.pause(0.5) \ }, f
.send_keys(Keys.TAB + Keys.TAB + Keys.ENTER + Keys.TAB + Keys.TAB + Keys.ENTER) \ )
.perform() else:
x_coord = 1163 with open(preferences_file, "r") as f:
y_coord = 717 settings = json.load(f)
action.move_by_offset(x_coord, y_coord).click().perform()
# put to the top if "intl" not in settings:
sleep(0.5) settings["intl"] = {}
action.reset_actions()
x_coord = 1257 settings["intl"]["accept_languages"] = "fr-FR,en-US,en"
y_coord = 328 settings["intl"]["selected_languages"] = "fr-FR,en-US,en"
action.move_by_offset(x_coord, y_coord).click().perform()
action.click().perform() with open(preferences_file, "w") as f:
json.dump(settings, f)
return chrome_profile_dir
# Deal with RGPD popup as well as some random popup like 'are you satisfied' one # Deal with RGPD popup as well as some random popup like 'are you satisfied' one
@ -60,13 +65,18 @@ def send_keys_wait(element, keys: str) -> None:
element.send_keys(i) element.send_keys(i)
sleep(uniform(0.1, 0.3)) sleep(uniform(0.1, 0.3))
def send_wait_and_confirm(element, keys: str) -> None:
send_keys_wait(element, keys)
element.send_keys(Keys.ENTER)
# Wait for the presence of the element identifier or [timeout]s # Wait for the presence of the element identifier or [timeout]s
def wait_until_visible(search_by: str, identifier: str, timeout: int = 20, browser=None) -> bool: def wait_until_visible(search_by: str, identifier: str, timeout: int = 20, browser=None, raise_error=True) -> bool:
try: try:
WebDriverWait(browser, timeout).until( WebDriverWait(browser, timeout).until(
expected_conditions.visibility_of_element_located((search_by, identifier)), "element not found") expected_conditions.visibility_of_element_located((search_by, identifier)), "element not found")
return True return True
except TimeoutException as e: except TimeoutException as e:
error(f"element {identifier} not found after {timeout}s") if raise_error:
error(f"element {identifier} not found after {timeout}s")
return False return False

View File

@ -1 +1 @@
v6.8.38 v6.8.45