mirror of
https://gitea.augustin64.fr/piair/MsRewards-Reborn.git
synced 2025-07-01 04:13:57 +02:00
Compare commits
17 Commits
dev
...
db157771de
Author | SHA1 | Date | |
---|---|---|---|
db157771de | |||
cbd1ad93a6 | |||
afabd94f0d | |||
81deaf05b0 | |||
9af0f4aadb | |||
1d16294c04 | |||
fae2033061 | |||
50c4036c73 | |||
c683472895 | |||
178f2d472a | |||
d3137f858a | |||
d2ad467d4e | |||
b45e9e549f | |||
200b0d8a86 | |||
4a5af6455d | |||
49b691d736 | |||
9549a6dea3 |
50
Dockerfile
50
Dockerfile
@ -1,22 +1,40 @@
|
||||
FROM python:3.10
|
||||
ENV DEBIAN_FRONTEND noninteractive
|
||||
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 \
|
||||
&& 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 \
|
||||
&& apt install redis libgtk-4-1 libvulkan1 libxdamage1 -y \
|
||||
&& curl -sSLO https://nc.piair.xyz/s/BKLsBWoZkTdYjfq/download/chrome.deb \
|
||||
&& ln -fs /usr/share/zoneinfo/Europe/Paris /etc/localtime \
|
||||
&& git clone https://gitea.augustin64.fr/piair/MsRewards-Reborn \
|
||||
&& python3 -m pip install -r MsRewards-Reborn/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 \
|
||||
&& echo "deb [signed-by=/usr/share/keyrings/grafana.key] https://apt.grafana.com stable main" | tee -a /etc/apt/sources.list.d/grafana.list \
|
||||
&& apt update \
|
||||
&& 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 \
|
||||
&& bash MsRewards-Reborn/config/config.sh \
|
||||
&& dpkg -i chrome.deb
|
||||
|
||||
ENV TZ="Europe/Paris"
|
||||
&& apt install -y redis grafana
|
||||
|
||||
COPY requirements.txt /app/requirements.txt
|
||||
RUN python3 -m pip install -r requirements.txt
|
||||
|
||||
# Setup app
|
||||
RUN git clone https://gitea.augustin64.fr/piair/MsRewards-Reborn
|
||||
# Use this instead when developping locally:
|
||||
# COPY . /app/MsRewards-Reborn
|
||||
|
||||
RUN bash MsRewards-Reborn/config/config.sh
|
||||
|
||||
ENV TZ="Europe/Paris"
|
||||
WORKDIR /app/MsRewards-Reborn/Flask/
|
||||
CMD bash start.sh
|
||||
|
14
Flask/app.py
14
Flask/app.py
@ -373,8 +373,18 @@ def config_post():
|
||||
def logs():
|
||||
with open("/app/MsRewards-Reborn/user_data/configs.json", "r") as 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"])
|
||||
|
@ -8,14 +8,37 @@
|
||||
|
||||
<select name="select" onchange="change_logs(this.value)">
|
||||
<option id="null" value="0">Choisir une config</option>
|
||||
{% for i in data %}
|
||||
<option id="{{data[i]['name']}}" value="{{i}}">{{data[i]['name']}}</option>
|
||||
{% for file in files %}
|
||||
<option id="{{ file[0] }}" value="{{ file[1] }}">{{ file[0] }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
<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 %}
|
||||
{% endblock %}
|
59
V6.py
59
V6.py
@ -1,4 +1,4 @@
|
||||
#!/usr/bin/python3.10
|
||||
#!/usr/bin/python3
|
||||
from modules.Classes.Config import Config
|
||||
from modules.Classes.DiscordLogger import DiscordLogger
|
||||
from modules.Classes.UserCredentials import UserCredentials
|
||||
@ -9,6 +9,7 @@ from modules.db import add_to_database
|
||||
from modules.driver_tools import *
|
||||
from modules.error import *
|
||||
|
||||
import os
|
||||
|
||||
# create a webdriver
|
||||
def create_driver(mobile=False):
|
||||
@ -22,14 +23,34 @@ def create_driver(mobile=False):
|
||||
"AppleWebKit/537.36 (KHTML, like Gecko)"
|
||||
"Chrome/22 Mobile Safari/537.36"
|
||||
)
|
||||
chrome_options = webdriver.ChromeOptions()
|
||||
|
||||
# Profile dir
|
||||
chrome_profile_dir = "/app/MsRewards-Reborn/user_data/profile/"+config.UserCredentials.get_mail()
|
||||
os.makedirs(chrome_profile_dir, exist_ok=True)
|
||||
|
||||
# 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:
|
||||
chrome_options.add_argument(f"--user-agent={mobile_user_agent}")
|
||||
arguments.append(f"--user-agent={mobile_user_agent}")
|
||||
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
|
||||
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)
|
||||
set_language(driver)
|
||||
return driver
|
||||
@ -152,7 +173,7 @@ def play_quiz4(override: int = None):
|
||||
except Exception as e:
|
||||
log_error(e)
|
||||
raise ValueError(e)
|
||||
info("Quiz 8 done.")
|
||||
info("Quiz 4 done.")
|
||||
custom_sleep(3)
|
||||
|
||||
|
||||
@ -165,6 +186,8 @@ def do_poll():
|
||||
try:
|
||||
answer_elem.click()
|
||||
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)
|
||||
custom_sleep(uniform(2, 2.5))
|
||||
except Exception as err:
|
||||
@ -190,7 +213,7 @@ def all_cards():
|
||||
info("no promo card")
|
||||
|
||||
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()
|
||||
driver.refresh()
|
||||
card_list = driver.find_elements(By.CLASS_NAME, "c-card-content")
|
||||
@ -410,9 +433,17 @@ def login_part_2():
|
||||
# login() tries to login to your Microsoft account.
|
||||
# it uses global variable g._mail and g._password to 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
|
||||
try:
|
||||
login_part_1()
|
||||
if not logged_in():
|
||||
login_part_1()
|
||||
login_part_2()
|
||||
driver.get("https://rewards.bing.com/")
|
||||
except Banned:
|
||||
@ -610,9 +641,11 @@ def daily_routine(cred: UserCredentials, custom=False):
|
||||
try:
|
||||
if not custom: # custom already is logged in
|
||||
login()
|
||||
|
||||
except Banned:
|
||||
log_error("This account is locked.")
|
||||
return
|
||||
raise Banned()
|
||||
|
||||
except Identity:
|
||||
log_error("This account has an issue.")
|
||||
return
|
||||
@ -680,7 +713,7 @@ def json_start(json_entry, cred: UserCredentials):
|
||||
login()
|
||||
try:
|
||||
if str(account_id) in json_entry["tout"]:
|
||||
daily_routine(cred)
|
||||
daily_routine(cred, True)
|
||||
except KeyError:
|
||||
pass
|
||||
else:
|
||||
@ -744,12 +777,16 @@ def default_start():
|
||||
config.WebDriver.pc_driver.quit()
|
||||
config.display.stop()
|
||||
break
|
||||
except Banned:
|
||||
warning("this account is banned. Switching to next account")
|
||||
except Exception as e:
|
||||
log_error(f"Error not caught. Skipping this account. " + format_error(e))
|
||||
critical(f"Error not caught. Skipping this account. {e}")
|
||||
config.WebDriver.pc_driver.quit()
|
||||
|
||||
config.UserCredentials.next_account()
|
||||
finally:
|
||||
config.UserCredentials.next_account()
|
||||
|
||||
config.display.stop()
|
||||
|
||||
|
||||
|
13
build.sh
13
build.sh
@ -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
|
||||
|
@ -30,7 +30,7 @@ class DiscordLogger:
|
||||
)
|
||||
file = File("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(username="error", file=File("page.html"), avatar_url=self.config.discord.avatar_url)
|
||||
|
@ -20,3 +20,6 @@ class Driver:
|
||||
|
||||
case _:
|
||||
raise ValueError("The driver must be either pc or mobile")
|
||||
|
||||
def current_driver(self):
|
||||
return "PC" if self.pc_driver == self.driver else "Mobile"
|
||||
|
@ -31,7 +31,7 @@ class UserCredentials:
|
||||
def get_tfa(self):
|
||||
if not self.tfa_enable():
|
||||
warning("Warning: TFA is not enabled. Calling get_tfa is an expected behaviour.")
|
||||
return TOTP(self.data[self.current]["tfa"])
|
||||
return TOTP(self.data[self.current]["2fa"])
|
||||
|
||||
def next_account(self):
|
||||
self.current += 1
|
||||
|
8
modules/Tools/generate_error.py
Normal file
8
modules/Tools/generate_error.py
Normal 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()
|
@ -30,7 +30,7 @@ class ColoredFormatter(logging.Formatter):
|
||||
|
||||
# Set up the root logger
|
||||
root_logger = logging.getLogger(__name__)
|
||||
root_logger.setLevel(logging.DEBUG)
|
||||
root_logger.setLevel(logging.INFO)
|
||||
|
||||
# Create a console handler and set the formatter
|
||||
ch = logging.StreamHandler()
|
||||
|
@ -10,7 +10,7 @@ def get_domain(driver):
|
||||
|
||||
def custom_sleep(temps):
|
||||
try:
|
||||
if True: # todo: change this awful condition
|
||||
if False: # todo: change this awful condition
|
||||
points = ["⢿", "⣻", "⣽", "⣾", "⣷", "⣯", "⣟", "⡿"]
|
||||
passe = 0
|
||||
for _ in range(int(temps)):
|
||||
|
48
modules/Tools/update_chrome.py
Normal file
48
modules/Tools/update_chrome.py
Normal 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")
|
Reference in New Issue
Block a user