Compare commits
No commits in common. "master" and "dev" have entirely different histories.
@ -1,2 +0,0 @@
|
|||||||
**/.venv
|
|
||||||
user_data/*
|
|
5
.gitignore
vendored
5
.gitignore
vendored
@ -3,17 +3,18 @@ geckodriver.log
|
|||||||
.vscode/
|
.vscode/
|
||||||
.idea
|
.idea
|
||||||
venv
|
venv
|
||||||
**/.venv
|
|
||||||
/Git
|
/Git
|
||||||
page.html
|
page.html
|
||||||
screenshot.png
|
screenshot.png
|
||||||
|
login.csv
|
||||||
data
|
data
|
||||||
**/__pycache__
|
**/__pycache__
|
||||||
user_data/*
|
user_data/*
|
||||||
install.sh
|
install.sh
|
||||||
nohup.out
|
nohup.out
|
||||||
|
points.csv
|
||||||
file.png
|
file.png
|
||||||
|
user_data/configs.json
|
||||||
*.ts
|
*.ts
|
||||||
LICENSE
|
LICENSE
|
||||||
README.md
|
README.md
|
||||||
venv
|
|
||||||
|
51
Dockerfile
51
Dockerfile
@ -1,42 +1,21 @@
|
|||||||
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 \
|
||||||
&& apt install -y redis grafana
|
&& 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 \
|
||||||
# Configure Grafana
|
&& apt install redis libgtk-4-1 libvulkan1 libxdamage1 -y \
|
||||||
RUN grafana-cli plugins install frser-sqlite-datasource
|
&& curl -sSLO https://nc.piair.xyz/s/BKLsBWoZkTdYjfq/download/chrome.deb \
|
||||||
|
&& ln -fs /usr/share/zoneinfo/Europe/Paris /etc/localtime \
|
||||||
COPY requirements.txt /app/requirements.txt
|
&& git clone https://gitea.augustin64.fr/piair/MsRewards-Reborn \
|
||||||
RUN python3 -m pip install -r requirements.txt
|
&& python3 -m pip install -r MsRewards-Reborn/requirements.txt \
|
||||||
|
&& wget -q -O /usr/share/keyrings/grafana.key https://apt.grafana.com/gpg.key \
|
||||||
# Setup app
|
&& curl -fsSL https://packages.redis.io/gpg | gpg --dearmor -o /usr/share/keyrings/redis-archive-keyring.gpg \
|
||||||
RUN git clone https://gitea.augustin64.fr/piair/MsRewards-Reborn
|
&& echo "deb [signed-by=/usr/share/keyrings/grafana.key] https://apt.grafana.com stable main" | tee -a /etc/apt/sources.list.d/grafana.list \
|
||||||
# Use this instead when developping locally:
|
&& apt update \
|
||||||
# COPY . /app/MsRewards-Reborn
|
&& 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 \
|
||||||
RUN bash MsRewards-Reborn/config/config.sh
|
&& dpkg -i chrome.deb
|
||||||
|
|
||||||
ENV TZ="Europe/Paris"
|
ENV TZ="Europe/Paris"
|
||||||
WORKDIR /app/MsRewards-Reborn/Flask/
|
WORKDIR /app/MsRewards-Reborn/Flask/
|
||||||
|
101
Flask/app.py
101
Flask/app.py
@ -13,27 +13,11 @@ import re
|
|||||||
from requests import get
|
from requests import get
|
||||||
import redis
|
import redis
|
||||||
|
|
||||||
APP_ROOT = os.getenv("APP_ROOT")
|
|
||||||
if APP_ROOT is None:
|
|
||||||
APP_ROOT = "/app/MsRewards-Reborn/"
|
|
||||||
|
|
||||||
NO_SUBPROCESS = os.getenv("NO_SUBPROCESS")
|
|
||||||
if NO_SUBPROCESS is not None:
|
|
||||||
def fake_popen(*args, **kwargs):
|
|
||||||
print("Calling subprocess.Popen with", args, kwargs)
|
|
||||||
|
|
||||||
subprocess.Popen = fake_popen
|
|
||||||
print("Faking subprocess calls")
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# redis part for live update
|
# redis part for live update
|
||||||
pool = redis.ConnectionPool(host='localhost', port=6379, db=0)
|
pool = redis.ConnectionPool(host='localhost', port=6379, db=0)
|
||||||
r = redis.Redis(connection_pool=pool)
|
r = redis.Redis(connection_pool=pool)
|
||||||
|
|
||||||
def get_path(path):
|
|
||||||
return os.path.join(APP_ROOT, path)
|
|
||||||
|
|
||||||
def generate_output():
|
def generate_output():
|
||||||
pubsub = r.pubsub()
|
pubsub = r.pubsub()
|
||||||
pubsub.subscribe('console')
|
pubsub.subscribe('console')
|
||||||
@ -48,7 +32,7 @@ def generate_output():
|
|||||||
# the end
|
# the end
|
||||||
|
|
||||||
global password
|
global password
|
||||||
with open(get_path("user_data/flask.json"), "r") as inFile:
|
with open("/app/MsRewards-Reborn/user_data/flask.json", "r") as inFile:
|
||||||
data = json.load(inFile)
|
data = json.load(inFile)
|
||||||
|
|
||||||
password = data["password"]
|
password = data["password"]
|
||||||
@ -56,7 +40,7 @@ secret = data["secret"]
|
|||||||
if secret == "":
|
if secret == "":
|
||||||
import secrets
|
import secrets
|
||||||
secret = secrets.token_hex()
|
secret = secrets.token_hex()
|
||||||
with open(get_path("user_data/flask.json"), "w") as inFile:
|
with open("/app/MsRewards-Reborn/user_data/flask.json", "w") as inFile:
|
||||||
data = {
|
data = {
|
||||||
"password": password,
|
"password": password,
|
||||||
"secret": secret
|
"secret": secret
|
||||||
@ -86,14 +70,14 @@ scheduler.add_job( # on relance le job
|
|||||||
|
|
||||||
def start_ms(i):
|
def start_ms(i):
|
||||||
print("\033[32m" + f"Starting config {i}" + "\033[0m")
|
print("\033[32m" + f"Starting config {i}" + "\033[0m")
|
||||||
log = open(get_path(f"Flask/static/logs/{i}.txt"), 'a') # so that data written to it will be appended
|
log = open(f"/app/MsRewards-Reborn/Flask/static/logs/{i}.txt", 'a') # so that data written to it will be appended
|
||||||
subprocess.Popen([f"python3 -u {get_path('V6.py')} -c {i}"], stdout=log, stderr=log, shell=True)
|
subprocess.Popen([f"python3 -u /app/MsRewards-Reborn/V6.py -c {i}"], stdout=log, stderr=log, shell=True)
|
||||||
log.close()
|
log.close()
|
||||||
|
|
||||||
|
|
||||||
TriggerDict = {}
|
TriggerDict = {}
|
||||||
def update_jobs():
|
def update_jobs():
|
||||||
with open(get_path("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)
|
||||||
for i in configs:
|
for i in configs:
|
||||||
try :
|
try :
|
||||||
@ -136,7 +120,7 @@ app = Flask(__name__)
|
|||||||
|
|
||||||
@app.context_processor
|
@app.context_processor
|
||||||
def inject_default_variables():
|
def inject_default_variables():
|
||||||
with open(get_path("version"), "r") as f:
|
with open("/app/MsRewards-Reborn/version", "r") as f:
|
||||||
version = f.readline().replace("\n", '')
|
version = f.readline().replace("\n", '')
|
||||||
return dict(version=version)
|
return dict(version=version)
|
||||||
"""
|
"""
|
||||||
@ -191,7 +175,7 @@ def change_password():
|
|||||||
if request.method == 'POST':
|
if request.method == 'POST':
|
||||||
password = request.form["password"]
|
password = request.form["password"]
|
||||||
subprocess.Popen(["grafana-cli", "admin", "reset-admin-password", password])
|
subprocess.Popen(["grafana-cli", "admin", "reset-admin-password", password])
|
||||||
with open(get_path("user_data/flask.json"), "w") as inFile:
|
with open("/app/MsRewards-Reborn/user_data/flask.json", "w") as inFile:
|
||||||
data = {
|
data = {
|
||||||
"password": password,
|
"password": password,
|
||||||
"secret": secret
|
"secret": secret
|
||||||
@ -217,21 +201,21 @@ def load_user(userid):
|
|||||||
|
|
||||||
@app.route("/")
|
@app.route("/")
|
||||||
def main():
|
def main():
|
||||||
with open(get_path("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)
|
||||||
return(render_template("schedule.html", data=configs))
|
return(render_template("schedule.html", data=configs))
|
||||||
|
|
||||||
|
|
||||||
@app.route("/discord/")
|
@app.route("/discord/")
|
||||||
def discord_get():
|
def discord_get():
|
||||||
with open(get_path("user_data/discord.json"), "r") as inFile:
|
with open("/app/MsRewards-Reborn/user_data/discord.json", "r") as inFile:
|
||||||
data = json.load(inFile)
|
data = json.load(inFile)
|
||||||
return(render_template("discord.html", data=data, len=maxi(data)))
|
return(render_template("discord.html", data=data, len=maxi(data)))
|
||||||
|
|
||||||
|
|
||||||
@app.route("/discord/", methods=["post"])
|
@app.route("/discord/", methods=["post"])
|
||||||
def discord_post():
|
def discord_post():
|
||||||
with open(get_path("user_data/discord.json"), "r") as inFile:
|
with open("/app/MsRewards-Reborn/user_data/discord.json", "r") as inFile:
|
||||||
data = json.load(inFile)
|
data = json.load(inFile)
|
||||||
action = request.form
|
action = request.form
|
||||||
if action['DISCORD'] == "delete" :
|
if action['DISCORD'] == "delete" :
|
||||||
@ -253,7 +237,7 @@ def discord_post():
|
|||||||
name = action["name"] if action["name"] else f"unnamed{action['select']}"
|
name = action["name"] if action["name"] else f"unnamed{action['select']}"
|
||||||
data[config] = {"errorsL" : errorsL, "errorsT": errorsT, "successT": successT, "successL": successL, "name": name}
|
data[config] = {"errorsL" : errorsL, "errorsT": errorsT, "successT": successT, "successL": successL, "name": name}
|
||||||
|
|
||||||
with open(get_path("user_data/discord.json"), "w") as outFile:
|
with open("/app/MsRewards-Reborn/user_data/discord.json", "w") as outFile:
|
||||||
json.dump(data, outFile)
|
json.dump(data, outFile)
|
||||||
return(render_template("discord.html", data=data, len=maxi(data)))
|
return(render_template("discord.html", data=data, len=maxi(data)))
|
||||||
|
|
||||||
@ -265,7 +249,7 @@ def dev2():
|
|||||||
|
|
||||||
@app.route("/settings/")
|
@app.route("/settings/")
|
||||||
def settings_get():
|
def settings_get():
|
||||||
with open(get_path("user_data/settings.json"), "r") as inFile:
|
with open("/app/MsRewards-Reborn/user_data/settings.json", "r") as inFile:
|
||||||
settings = json.load(inFile)
|
settings = json.load(inFile)
|
||||||
return(render_template("settings.html", data=settings))
|
return(render_template("settings.html", data=settings))
|
||||||
|
|
||||||
@ -275,21 +259,21 @@ def settings_post():
|
|||||||
settings = {}
|
settings = {}
|
||||||
action = request.form
|
action = request.form
|
||||||
settings['avatarlink'] = action["avatarlink"]
|
settings['avatarlink'] = action["avatarlink"]
|
||||||
with open(get_path("user_data/settings.json"), "w") as inFile:
|
with open("/app/MsRewards-Reborn/user_data/settings.json", "w") as inFile:
|
||||||
json.dump(settings, inFile)
|
json.dump(settings, inFile)
|
||||||
return(render_template("settings.html", data=settings))
|
return(render_template("settings.html", data=settings))
|
||||||
|
|
||||||
|
|
||||||
@app.route("/proxy/")
|
@app.route("/proxy/")
|
||||||
def proxy_get():
|
def proxy_get():
|
||||||
with open(get_path("user_data/proxy.json"), "r") as inFile:
|
with open("/app/MsRewards-Reborn/user_data/proxy.json", "r") as inFile:
|
||||||
j = json.load(inFile)
|
j = json.load(inFile)
|
||||||
return(render_template("proxy.html", data=j, len=maxi(j)))
|
return(render_template("proxy.html", data=j, len=maxi(j)))
|
||||||
|
|
||||||
|
|
||||||
@app.route("/proxy/", methods=["post"])
|
@app.route("/proxy/", methods=["post"])
|
||||||
def proxy_post():
|
def proxy_post():
|
||||||
with open(get_path("user_data/proxy.json"), "r") as inFile:
|
with open("/app/MsRewards-Reborn/user_data/proxy.json", "r") as inFile:
|
||||||
data = json.load(inFile)
|
data = json.load(inFile)
|
||||||
action = request.form
|
action = request.form
|
||||||
print(action)
|
print(action)
|
||||||
@ -306,21 +290,21 @@ def proxy_post():
|
|||||||
except :
|
except :
|
||||||
print("error : probably bad config")
|
print("error : probably bad config")
|
||||||
|
|
||||||
with open(get_path("user_data/proxy.json"), "w") as outFile:
|
with open("/app/MsRewards-Reborn/user_data/proxy.json", "w") as outFile:
|
||||||
json.dump(data, outFile)
|
json.dump(data, outFile)
|
||||||
return(render_template("proxy.html", data=data, len=maxi(data)))
|
return(render_template("proxy.html", data=data, len=maxi(data)))
|
||||||
|
|
||||||
|
|
||||||
@app.route("/schedule/")
|
@app.route("/schedule/")
|
||||||
def schedule_get():
|
def schedule_get():
|
||||||
with open(get_path("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)
|
||||||
return(render_template("schedule.html", data=configs))
|
return(render_template("schedule.html", data=configs))
|
||||||
|
|
||||||
|
|
||||||
@app.route("/schedule/", methods=["post"])
|
@app.route("/schedule/", methods=["post"])
|
||||||
def schedule_post():
|
def schedule_post():
|
||||||
with open(get_path("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)
|
||||||
|
|
||||||
data = dict(request.form)
|
data = dict(request.form)
|
||||||
@ -334,7 +318,7 @@ def schedule_post():
|
|||||||
configs[i]["time"] = data[f"time{i}"]
|
configs[i]["time"] = data[f"time{i}"]
|
||||||
configs[i]["enabled"] = data[f"switch{i}"] == "on"
|
configs[i]["enabled"] = data[f"switch{i}"] == "on"
|
||||||
|
|
||||||
with open(get_path("user_data/configs.json"), "w") as inFile:
|
with open("/app/MsRewards-Reborn/user_data/configs.json", "w") as inFile:
|
||||||
json.dump(configs, inFile)
|
json.dump(configs, inFile)
|
||||||
update_jobs()
|
update_jobs()
|
||||||
return(render_template("schedule.html", data=configs))
|
return(render_template("schedule.html", data=configs))
|
||||||
@ -342,11 +326,11 @@ def schedule_post():
|
|||||||
|
|
||||||
@app.route("/config/")
|
@app.route("/config/")
|
||||||
def config_get():
|
def config_get():
|
||||||
with open(get_path("user_data/proxy.json"), "r") as inFile:
|
with open("/app/MsRewards-Reborn/user_data/proxy.json", "r") as inFile:
|
||||||
proxys = json.load(inFile)
|
proxys = json.load(inFile)
|
||||||
with open(get_path("user_data/discord.json"), "r") as inFile:
|
with open("/app/MsRewards-Reborn/user_data/discord.json", "r") as inFile:
|
||||||
discords = json.load(inFile)
|
discords = json.load(inFile)
|
||||||
with open(get_path("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)
|
||||||
return(render_template("config.html", data=configs, discords=discords, proxys=proxys, configs=configs, len=maxi(configs)))
|
return(render_template("config.html", data=configs, discords=discords, proxys=proxys, configs=configs, len=maxi(configs)))
|
||||||
|
|
||||||
@ -354,11 +338,11 @@ def config_get():
|
|||||||
@app.route("/config/", methods=["POST"])
|
@app.route("/config/", methods=["POST"])
|
||||||
def config_post():
|
def config_post():
|
||||||
action = request.form
|
action = request.form
|
||||||
with open(get_path("user_data/proxy.json"), "r") as inFile:
|
with open("/app/MsRewards-Reborn/user_data/proxy.json", "r") as inFile:
|
||||||
proxys = json.load(inFile)
|
proxys = json.load(inFile)
|
||||||
with open(get_path("user_data/discord.json"), "r") as inFile:
|
with open("/app/MsRewards-Reborn/user_data/discord.json", "r") as inFile:
|
||||||
discords = json.load(inFile)
|
discords = json.load(inFile)
|
||||||
with open(get_path("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)
|
||||||
|
|
||||||
if action["data"] == "delete":
|
if action["data"] == "delete":
|
||||||
@ -381,26 +365,16 @@ def config_post():
|
|||||||
"enabled":"False",
|
"enabled":"False",
|
||||||
"accounts": comptes
|
"accounts": comptes
|
||||||
}
|
}
|
||||||
with open(get_path("user_data/configs.json"), "w") as outFile:
|
with open("/app/MsRewards-Reborn/user_data/configs.json", "w") as outFile:
|
||||||
json.dump(configs, outFile)
|
json.dump(configs, outFile)
|
||||||
return(render_template("config.html", data=configs, discords=discords, proxys=proxys, configs=configs, len=maxi(configs)))
|
return(render_template("config.html", data=configs, discords=discords, proxys=proxys, configs=configs, len=maxi(configs)))
|
||||||
|
|
||||||
@app.route("/logs/", methods=["GET", "POST"])
|
@app.route("/logs/", methods=["GET", "POST"])
|
||||||
def logs():
|
def logs():
|
||||||
with open(get_path("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)
|
||||||
files = [(configs[i]["name"], i) for i in configs]
|
return(render_template("logs.html", data=configs))
|
||||||
config_files = [i[1] for i in files]
|
|
||||||
for f in os.listdir(get_path("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"])
|
||||||
@ -411,21 +385,21 @@ def stats():
|
|||||||
@app.route("/override/", methods=["POST"])
|
@app.route("/override/", methods=["POST"])
|
||||||
def override_post():
|
def override_post():
|
||||||
json = request.form.to_dict(flat=False)
|
json = request.form.to_dict(flat=False)
|
||||||
log = open(get_path("Flask/static/logs/custom.txt"), 'w') # so that data written to it will be appended
|
log = open(f"/app/MsRewards-Reborn/Flask/static/logs/custom.txt", 'w') # so that data written to it will be appended
|
||||||
subprocess.Popen([f"python3 -u {get_path('V6.py')} -c {json['config'][0]} --json \"{json}\""], stdout=log, stderr=log, shell=True)
|
subprocess.Popen([f"python3 -u /app/MsRewards-Reborn/V6.py -c {json['config'][0]} --json \"{json}\""], stdout=log, stderr=log, shell=True)
|
||||||
log.close()
|
log.close()
|
||||||
return(render_template("vnc_post.html"))
|
return(render_template("vnc_post.html"))
|
||||||
|
|
||||||
@app.route("/override/", methods=["GET"])
|
@app.route("/override/", methods=["GET"])
|
||||||
def override_get():
|
def override_get():
|
||||||
with open(get_path("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)
|
||||||
return(render_template("vnc_get.html", configs=configs))
|
return(render_template("vnc_get.html", configs=configs))
|
||||||
|
|
||||||
@app.route('/download/<path:filename>', methods=['GET', 'POST'])
|
@app.route('/download/<path:filename>', methods=['GET', 'POST'])
|
||||||
@login_required
|
@login_required
|
||||||
def download(filename):
|
def download(filename):
|
||||||
return send_from_directory(directory=get_path("user_data/"), path=filename, as_attachment=True)
|
return send_from_directory(directory='/app/MsRewards-Reborn/user_data/', path=filename, as_attachment=True)
|
||||||
|
|
||||||
|
|
||||||
def allowed_file(filename):
|
def allowed_file(filename):
|
||||||
@ -446,8 +420,8 @@ def upload_file():
|
|||||||
|
|
||||||
elif file and allowed_file(file.filename):
|
elif file and allowed_file(file.filename):
|
||||||
filename = secure_filename(file.filename)
|
filename = secure_filename(file.filename)
|
||||||
print(os.path.join(get_path("user_data/"), filename))
|
print(os.path.join('/app/MsRewards-Reborn/user_data/', filename))
|
||||||
file.save(os.path.join(get_path("user_data/"), filename))
|
file.save(os.path.join('/app/MsRewards-Reborn/user_data/', filename))
|
||||||
|
|
||||||
i += 1
|
i += 1
|
||||||
print(i)
|
print(i)
|
||||||
@ -465,7 +439,4 @@ def maxi(dict):
|
|||||||
|
|
||||||
|
|
||||||
update_jobs()
|
update_jobs()
|
||||||
subprocess.Popen(["bash", get_path("config/request.sh")])
|
subprocess.Popen(["bash",'/app/MsRewards-Reborn/config/request.sh'])
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
app.run()
|
|
||||||
|
@ -1,17 +0,0 @@
|
|||||||
#console {
|
|
||||||
height: 100%;
|
|
||||||
width: 20%;
|
|
||||||
float: left;
|
|
||||||
resize: horizontal;
|
|
||||||
overflow: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
#vnc-container {
|
|
||||||
height: 100%;
|
|
||||||
width: 80%;
|
|
||||||
float: left;
|
|
||||||
}
|
|
||||||
|
|
||||||
.container {
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
@ -8,37 +8,14 @@
|
|||||||
|
|
||||||
<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 file in files %}
|
{% for i in data %}
|
||||||
<option id="{{ file[0] }}" value="{{ file[1] }}">{{ file[0] }}</option>
|
<option id="{{data[i]['name']}}" value="{{i}}">{{data[i]['name']}}</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>
|
<iframe type="text/html" src="{{url_for('static', filename='logs/1.txt')}}" width="100%" height="85%" id="embed">
|
||||||
|
|
||||||
<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 %}
|
@ -6,19 +6,19 @@
|
|||||||
{% if not current_user.is_authenticated %}
|
{% if not current_user.is_authenticated %}
|
||||||
<button class="unselected" onclick="location.href = '/login';">login</button>
|
<button class="unselected" onclick="location.href = '/login';">login</button>
|
||||||
{% else %}
|
{% else %}
|
||||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/vnc-post.css') }}"/>
|
|
||||||
<link rel="stylesheet" href="{{ url_for('static', filename='node_modules/xterm/css/xterm.css') }}"/>
|
<link rel="stylesheet" href="{{ url_for('static', filename='node_modules/xterm/css/xterm.css') }}"/>
|
||||||
<script src="{{ url_for('static', filename='node_modules/xterm/lib/xterm.js') }}"></script>
|
<script src="{{ url_for('static', filename='node_modules/xterm/lib/xterm.js') }}"></script>
|
||||||
<script src="{{ url_for('static', filename='node_modules/xterm-addon-fit/lib/xterm-addon-fit.js') }}"></script>
|
<script src="{{ url_for('static', filename='node_modules/xterm-addon-fit/lib/xterm-addon-fit.js') }}"></script>
|
||||||
<script>
|
<script>
|
||||||
document.getElementsByClassName("content")[0].style.padding = "0 0"
|
document.getElementsByClassName("content")[0].style.padding = "0 0"
|
||||||
</script>
|
</script>
|
||||||
<div class="container">
|
<div style="height: 100%">
|
||||||
<div id="console"></div>
|
|
||||||
<div id="vnc-container">
|
<div id="console" style="height: 100%; width: 20%; float:left;"></div>
|
||||||
|
|
||||||
|
<div style="height: 100%; width: 80%; float:left;">
|
||||||
<iframe src="/novnc/vnc.html?resize=scale&path=novnc/websockify&autoconnect=true&view_only"
|
<iframe src="/novnc/vnc.html?resize=scale&path=novnc/websockify&autoconnect=true&view_only"
|
||||||
width="100%" height="100%" frameborder="0">
|
width="100%" height="100%" frameborder="0"></iframe>
|
||||||
</iframe>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
477
V6.py
477
V6.py
@ -1,11 +1,8 @@
|
|||||||
#!/usr/bin/python3
|
#!/usr/bin/python3.10
|
||||||
import random
|
|
||||||
import subprocess
|
|
||||||
|
|
||||||
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
|
||||||
from modules.Tools.logger import critical, warning
|
from modules.Tools.logger import warning, critical
|
||||||
from modules.cards import *
|
from modules.cards import *
|
||||||
from modules.config import *
|
from modules.config import *
|
||||||
from modules.db import add_to_database
|
from modules.db import add_to_database
|
||||||
@ -25,33 +22,16 @@ 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(), mobile=mobile)
|
|
||||||
|
|
||||||
# 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:
|
||||||
arguments.append(f"--user-agent={mobile_user_agent}")
|
chrome_options.add_argument(f"--user-agent={mobile_user_agent}")
|
||||||
else:
|
else:
|
||||||
arguments.append(f"--user-agent={pc_user_agent}")
|
chrome_options.add_argument(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():
|
||||||
arguments.append(f'--proxy-server={config.proxy.ip}:{config.proxy.port}')
|
chrome_options.add_argument(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
|
||||||
|
|
||||||
|
|
||||||
@ -172,7 +152,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 4 done.")
|
info("Quiz 8 done.")
|
||||||
custom_sleep(3)
|
custom_sleep(3)
|
||||||
|
|
||||||
|
|
||||||
@ -185,8 +165,6 @@ 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:
|
||||||
@ -199,68 +177,6 @@ def do_poll():
|
|||||||
# Find each playable card and tries to click on it to earn points
|
# Find each playable card and tries to click on it to earn points
|
||||||
def all_cards():
|
def all_cards():
|
||||||
driver = config.WebDriver.driver
|
driver = config.WebDriver.driver
|
||||||
|
|
||||||
def check_popups() -> bool:
|
|
||||||
"""
|
|
||||||
Check various annoying popups
|
|
||||||
"""
|
|
||||||
def check_welcome_tour() -> bool:
|
|
||||||
if "rewards.bing.com/welcometour" not in driver.current_url:
|
|
||||||
return False
|
|
||||||
|
|
||||||
info("Popup 'Explorer le programme' reçue")
|
|
||||||
wait_until_visible(By.ID, "welcome-tour", timeout=5, browser=driver)
|
|
||||||
custom_sleep(1.5)
|
|
||||||
|
|
||||||
welcome_tour = driver.find_element(By.ID, "welcome-tour")
|
|
||||||
interest_button_box = welcome_tour.find_element(By.CLASS_NAME, "interest-buttons")
|
|
||||||
interests = interest_button_box.find_elements(By.CLASS_NAME, "ng-binding")
|
|
||||||
debug("Got the following interests: " + str(interests))
|
|
||||||
random.choice(interests).click() # Choose interest
|
|
||||||
custom_sleep(1.5)
|
|
||||||
|
|
||||||
claim_button = welcome_tour.find_element(By.ID, "claim-button")
|
|
||||||
claim_button.click() # submit
|
|
||||||
custom_sleep(1.5)
|
|
||||||
return True
|
|
||||||
|
|
||||||
def check_streak_protection() -> bool:
|
|
||||||
"""
|
|
||||||
Ne perdez plus jamais votre série !
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
streak_protection_close = driver.find_element(By.ID, "streak-protection-popup-close-cross")
|
|
||||||
streak_protection_activate = driver.find_elements(By.CLASS_NAME, "earningPagePopUpPopUpSelectButton")
|
|
||||||
streak_protection_activate[0].click()
|
|
||||||
info("Popup 'Streak Protection' reçue")
|
|
||||||
custom_sleep(1.5)
|
|
||||||
|
|
||||||
return True
|
|
||||||
except (exceptions.NoSuchElementException, exceptions.ElementNotInteractableException, IndexError):
|
|
||||||
# les éléments sont présents dans le DOM même quand la popup n'est pas visible apparemment
|
|
||||||
return False
|
|
||||||
|
|
||||||
def check_streak_protection_expired() -> bool:
|
|
||||||
"""
|
|
||||||
Non, vous avez utilisé tous vos jours de protection contre les séries !
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
streak_protection_close = driver.find_element(By.ID, "streak-protection-popup-close-cross")
|
|
||||||
ok_sad_button = driver.find_elements(By.CLASS_NAME, "dashboardPopUpPopUpSelectButton")
|
|
||||||
ok_sad_button[0].click()
|
|
||||||
info("Popup 'Streak Protection fully used' reçue")
|
|
||||||
custom_sleep(1.5)
|
|
||||||
|
|
||||||
return True
|
|
||||||
except (exceptions.NoSuchElementException, exceptions.ElementNotInteractableException, IndexError):
|
|
||||||
return False
|
|
||||||
|
|
||||||
return (
|
|
||||||
check_welcome_tour()
|
|
||||||
or check_streak_protection()
|
|
||||||
or check_streak_protection_expired()
|
|
||||||
)
|
|
||||||
|
|
||||||
driver.get("https://rewards.bing.com")
|
driver.get("https://rewards.bing.com")
|
||||||
wait_until_visible(By.CLASS_NAME, "c-card-content", 10, driver)
|
wait_until_visible(By.CLASS_NAME, "c-card-content", 10, driver)
|
||||||
|
|
||||||
@ -274,7 +190,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 or "suspended" in driver.page_source:
|
if "suspendu" 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")
|
||||||
@ -304,53 +220,39 @@ def all_cards():
|
|||||||
if i == len(card_list) and i > 15:
|
if i == len(card_list) and i > 15:
|
||||||
checked = False
|
checked = False
|
||||||
|
|
||||||
if not checked:
|
if checked:
|
||||||
continue
|
custom_sleep(1.5)
|
||||||
|
|
||||||
try:
|
|
||||||
activity = findall("data-bi-id=\"([^\"]+)\"", card_list[i].get_attribute("innerHTML"))[0]
|
|
||||||
except Exception as e:
|
|
||||||
warning("Can't find activity." + str(e))
|
|
||||||
activity = ""
|
|
||||||
|
|
||||||
custom_sleep(1.5)
|
|
||||||
check_popups()
|
|
||||||
driver.execute_script("arguments[0].scrollIntoView();", card_list[i])
|
|
||||||
custom_sleep(1.5)
|
|
||||||
card_list[i].click()
|
|
||||||
|
|
||||||
if len(driver.window_handles) > 1:
|
|
||||||
driver.switch_to.window(driver.window_handles[1])
|
|
||||||
try_play(driver.title, activity)
|
|
||||||
close_tab(driver.window_handles[1])
|
|
||||||
|
|
||||||
try:
|
|
||||||
driver.refresh()
|
|
||||||
card_list = driver.find_elements(By.CLASS_NAME, "c-card-content")
|
|
||||||
|
|
||||||
if "mee-icon-AddMedium" not in card_list[i].get_attribute("innerHTML"):
|
|
||||||
continue
|
|
||||||
|
|
||||||
check_popups()
|
|
||||||
driver.execute_script("arguments[0].scrollIntoView();", card_list[i])
|
driver.execute_script("arguments[0].scrollIntoView();", card_list[i])
|
||||||
|
custom_sleep(1.5)
|
||||||
card_list[i].click()
|
card_list[i].click()
|
||||||
|
|
||||||
driver.switch_to.window(driver.window_handles[1])
|
if len(driver.window_handles) > 1:
|
||||||
custom_sleep(10)
|
driver.switch_to.window(driver.window_handles[1])
|
||||||
log_error(f"Card {i} Can't be completed. Why MS ?")
|
try_play(driver.title)
|
||||||
try:
|
close_tab(driver.window_handles[1])
|
||||||
try_play(driver.title) # go back to the main page
|
|
||||||
try:
|
|
||||||
close_tab(driver.window_handles[1])
|
|
||||||
except Exception as e:
|
|
||||||
debug(e)
|
|
||||||
except Exception as e:
|
|
||||||
debug(e)
|
|
||||||
driver.get("https://rewards.bing.com")
|
|
||||||
|
|
||||||
except Exception as err:
|
try:
|
||||||
log_error(err)
|
driver.refresh()
|
||||||
custom_sleep(3)
|
card_list = driver.find_elements(By.CLASS_NAME, "c-card-content")
|
||||||
|
|
||||||
|
if "mee-icon-AddMedium" in card_list[i].get_attribute("innerHTML"):
|
||||||
|
driver.execute_script("arguments[0].scrollIntoView();", card_list[i])
|
||||||
|
card_list[i].click()
|
||||||
|
driver.switch_to.window(driver.window_handles[1])
|
||||||
|
custom_sleep(10)
|
||||||
|
log_error(f"Card {i} Can't be completed. Why MS ?")
|
||||||
|
try:
|
||||||
|
try_play(driver.title) # go back to the main page
|
||||||
|
try:
|
||||||
|
close_tab(driver.window_handles[1])
|
||||||
|
except Exception as e:
|
||||||
|
debug(e)
|
||||||
|
except Exception as e:
|
||||||
|
debug(e)
|
||||||
|
driver.get("https://rewards.bing.com")
|
||||||
|
except Exception as err:
|
||||||
|
log_error(err)
|
||||||
|
custom_sleep(3)
|
||||||
|
|
||||||
|
|
||||||
def promo():
|
def promo():
|
||||||
@ -388,124 +290,8 @@ def promo():
|
|||||||
custom_sleep(3)
|
custom_sleep(3)
|
||||||
|
|
||||||
|
|
||||||
def explore_on_bing(activity: str, config: Config):
|
|
||||||
driver = config.WebDriver.driver
|
|
||||||
|
|
||||||
def search_bing(txt):
|
|
||||||
search_elm = driver.find_element(By.ID, "sb_form_q")
|
|
||||||
send_keys_wait(search_elm, txt)
|
|
||||||
send_keys_wait(search_elm, Keys.ENTER)
|
|
||||||
|
|
||||||
if "lyrics" in activity:
|
|
||||||
search_bing(
|
|
||||||
f"paroles de {['Gata', 'Pyramide', 'Dolce Camara', 'Position', 'Mami Wata'][randint(0, 4)]}") # merci bing copilot pour les titres
|
|
||||||
elif "flight" in activity:
|
|
||||||
search_bing(
|
|
||||||
f"vol {['Paris - New York', 'Londres Amsterdam', 'Bora-Bora Miami', 'Los Angeles Toulouse', 'Rome Dubai'][randint(0, 4)]}")
|
|
||||||
elif "shopping" in activity:
|
|
||||||
search_bing(f"idée cadeau {['Noel', 'Anniversaire'][randint(0, 1)]}")
|
|
||||||
elif "movie" in activity:
|
|
||||||
search_bing(
|
|
||||||
f"Distribution {['Code 8 part 2', 'The Hunger Games: The ballad of Songbirds & Snakes', 'Rebel Moon: Part Two', 'Dune II', 'Wonka'][randint(0, 4)]}")
|
|
||||||
elif "translator" in activity:
|
|
||||||
search_bing(f"traduction {config.wordlist.get_word()} en anglais")
|
|
||||||
elif "map" in activity:
|
|
||||||
search_bing(f"{['Paris', 'Nice', 'Marseille', 'Bordeaux', 'Lyon'][randint(0, 4)]} carte")
|
|
||||||
elif "restaurant" in activity:
|
|
||||||
search_bing(random.choice([
|
|
||||||
"restaurant à proximité",
|
|
||||||
"restaurant pas loin",
|
|
||||||
"manger dans le coin"
|
|
||||||
]))
|
|
||||||
elif "recipe" in activity:
|
|
||||||
search_bing("recette de " + random.choice([
|
|
||||||
"cake aux olives",
|
|
||||||
"tarte tatin",
|
|
||||||
"Kouign Amann",
|
|
||||||
"poulet au Curry",
|
|
||||||
"lasagnes aux épinards et ricotta",
|
|
||||||
"Boeuf Bourguignon",
|
|
||||||
"dessert",
|
|
||||||
"gateau au chocolat",
|
|
||||||
"crêpe sucrée"
|
|
||||||
])) # Merci llama pour les idées
|
|
||||||
elif "currency" in activity:
|
|
||||||
currencies = [
|
|
||||||
"euros",
|
|
||||||
"dollars canadiens",
|
|
||||||
"dollars",
|
|
||||||
"livres",
|
|
||||||
"francs suisses",
|
|
||||||
"roubles",
|
|
||||||
"pesos",
|
|
||||||
"bitcoin",
|
|
||||||
"anciens francs"
|
|
||||||
]
|
|
||||||
chosen = random.sample(currencies, k=2)
|
|
||||||
search_bing(f"convertir {random.randint(2, 120)} {chosen[0]} en {chosen[1]}")
|
|
||||||
elif "weather" in activity:
|
|
||||||
search_bing(f"météo {['Paris', 'Nice', 'Marseille', 'Bordeaux', 'Lyon'][randint(0, 4)]}")
|
|
||||||
elif "packagetracking" in activity:
|
|
||||||
driver.get("https://www.bing.com/?setmkt=en-US&setlang=en-US")
|
|
||||||
search_bing(f"{['fedex', 'UPS'][randint(0, 1)]} package tracking")
|
|
||||||
elif "hotel" in activity:
|
|
||||||
search_bing(f" {['Paris', 'Nice', 'Marseille', 'Bordeaux', 'Lyon'][randint(0, 4)]}")
|
|
||||||
elif "health" in activity:
|
|
||||||
search_bing(f"{['toux', 'douleur dos', 'nez qui coule', 'mal au genoux', 'otite'][randint(0, 4)]}")
|
|
||||||
elif "news" in activity:
|
|
||||||
search_bing(["actualités", "news"][randint(0, 1)])
|
|
||||||
elif "jobs" in activity:
|
|
||||||
search_bing("jobs")
|
|
||||||
elif "realestate" in activity:
|
|
||||||
search_bing(f"appartement à louer {['Paris', 'Nice', 'Marseille', 'Bordeaux', 'Lyon'][randint(0, 4)]}")
|
|
||||||
elif "financemarket" in activity:
|
|
||||||
search_bing(
|
|
||||||
f"cours action {['AIR LIQUIDE', 'Airbus', 'BNP Paribas', 'Michelin', 'Stellantis', 'Vinci'][randint(0, 5)]}")
|
|
||||||
elif "sports" in activity:
|
|
||||||
equipes = random.sample([
|
|
||||||
"Toulon", "toulouse",
|
|
||||||
"stade Rochelais", "castres",
|
|
||||||
"clermont", "perpignan",
|
|
||||||
"aviron bayonnais", "vannes"
|
|
||||||
], k=2)
|
|
||||||
search_bing(f"{['score', 'résultats'][randint(0, 1)]} rugby {equipes[0]} {equipes[1]}")
|
|
||||||
elif "videogames" in activity:
|
|
||||||
search_bing(random.choice([
|
|
||||||
"Minecraft", "GTA V",
|
|
||||||
"Tetris", "PUBG",
|
|
||||||
"Mario Kart 8",
|
|
||||||
"Red Dead Redemption II",
|
|
||||||
"Terraria",
|
|
||||||
"The Witcher",
|
|
||||||
"Animal Crossing",
|
|
||||||
"Pokémon rouge & bleu",
|
|
||||||
"Super Mario Bros",
|
|
||||||
"The legend of Zelda BOTW",
|
|
||||||
"Call of Duty Modern Warfare",
|
|
||||||
"The Witcher III"
|
|
||||||
]))
|
|
||||||
elif "dictionary" in activity:
|
|
||||||
search_bing(f"définition {config.wordlist.get_word()}")
|
|
||||||
elif "election" in activity or "timezonedates" in activity:
|
|
||||||
#! I don't understand the name of "timezonedates" but this seems to be the same activity
|
|
||||||
state = random.choice([
|
|
||||||
"Alaska", "Alabama", "Arkansas", "American Samoa", "Arizona", "California", "Colorado",
|
|
||||||
"Connecticut", "District ", "of Columbia", "Delaware", "Florida", "Georgia", "Guam",
|
|
||||||
"Hawaii", "Iowa", "Idaho", "Illinois", "Indiana", "Kansas", "Kentucky", "Louisiana",
|
|
||||||
"Massachusetts", "Maryland", "Maine", "Michigan", "Minnesota", "Missouri", "Mississippi",
|
|
||||||
"Montana", "North Carolina", "North Dakota", "Nebraska", "New Hampshire", "New Jersey",
|
|
||||||
"New Mexico", "Nevada", "New York", "Ohio", "Oklahoma", "Oregon", "Pennsylvania",
|
|
||||||
"Puerto Rico", "Rhode Island", "South Carolina", "South Dakota", "Tennessee", "Texas",
|
|
||||||
"Utah", "Virginia", "Virgin Islands", "Vermont", "Washington", "Wisconsin",
|
|
||||||
"West Virginia", "Wyoming"
|
|
||||||
])
|
|
||||||
search_bing(f"governor candidates {state} 2024")
|
|
||||||
else:
|
|
||||||
log_error(f"Explore on bing: {activity} not found.")
|
|
||||||
|
|
||||||
|
|
||||||
# Find out which type of action to do
|
# Find out which type of action to do
|
||||||
def try_play(nom="unknown", activity=""):
|
def try_play(nom="unknown"):
|
||||||
driver = config.WebDriver.driver
|
driver = config.WebDriver.driver
|
||||||
rgpd_popup(config)
|
rgpd_popup(config)
|
||||||
|
|
||||||
@ -551,7 +337,7 @@ def try_play(nom="unknown", activity=""):
|
|||||||
info("On fidelity page.")
|
info("On fidelity page.")
|
||||||
fidelity()
|
fidelity()
|
||||||
|
|
||||||
elif wait_until_visible(By.ID, "rqStartQuiz", 5, driver, raise_error=False):
|
elif wait_until_visible(By.ID, "rqStartQuiz", 5, driver):
|
||||||
custom_sleep(3)
|
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")
|
||||||
@ -561,14 +347,9 @@ def try_play(nom="unknown", activity=""):
|
|||||||
number = driver.page_source.count("rqAnswerOption")
|
number = driver.page_source.count("rqAnswerOption")
|
||||||
warning(f"recovery detected. quiz : {number}")
|
warning(f"recovery detected. quiz : {number}")
|
||||||
play(number - 1)
|
play(number - 1)
|
||||||
elif "exploreonbing" in activity:
|
|
||||||
info(f"Explore on bing: {activity}")
|
|
||||||
explore_on_bing(activity, config)
|
|
||||||
custom_sleep(uniform(3, 5))
|
|
||||||
elif "Optimisez votre sécurité avec Microsoft" in driver.page_source:
|
|
||||||
info("Still not paying Office 365 ?")
|
|
||||||
else:
|
else:
|
||||||
info(f"Nothing obvious to do on page `{nom}`.")
|
info(f"Nothing to do on page `{nom}`")
|
||||||
custom_sleep(uniform(3, 5))
|
custom_sleep(uniform(3, 5))
|
||||||
|
|
||||||
|
|
||||||
@ -578,40 +359,23 @@ def login_part_1():
|
|||||||
info("Starting part 1 of login")
|
info("Starting part 1 of login")
|
||||||
driver = config.WebDriver.driver
|
driver = config.WebDriver.driver
|
||||||
driver.get("https://login.live.com")
|
driver.get("https://login.live.com")
|
||||||
try:
|
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()
|
|
||||||
)
|
|
||||||
except exceptions.NoSuchElementException:
|
|
||||||
info("Unable to find mail input for login, might be semi-logged-in")
|
|
||||||
|
|
||||||
wait_until_visible(By.ID, "i0118", browser=driver)
|
wait_until_visible(By.ID, "i0118", browser=driver)
|
||||||
send_wait_and_confirm(
|
pwd_elem = driver.find_element(By.ID, "i0118")
|
||||||
driver.find_element(By.ID, "i0118"),
|
send_keys_wait(pwd_elem, config.UserCredentials.get_password())
|
||||||
config.UserCredentials.get_password()
|
pwd_elem.send_keys(Keys.ENTER)
|
||||||
)
|
custom_sleep(2)
|
||||||
# 2FA
|
# 2FA
|
||||||
try:
|
if "Entrez le code de sécurité" in driver.page_source:
|
||||||
if not wait_until_visible(By.ID, "idTxtBx_SAOTCC_OTC", browser=driver, timeout=5, raise_error=False):
|
try:
|
||||||
custom_sleep(2)
|
a2f_elem = driver.find_element(By.ID, "idTxtBx_SAOTCC_OTC")
|
||||||
return
|
a2f_elem.send_keys(config.UserCredentials.get_tfa().now())
|
||||||
|
a2f_elem.send_keys(Keys.ENTER)
|
||||||
tfa = config.UserCredentials.get_tfa()
|
except Exception as err:
|
||||||
if tfa is None:
|
log_error(err)
|
||||||
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
|
||||||
@ -646,19 +410,9 @@ 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)
|
|
||||||
debug(get_domain(driver))
|
|
||||||
if get_domain(driver) == "account.microsoft.com":
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
info("Logging in...")
|
|
||||||
driver = config.WebDriver.driver
|
driver = config.WebDriver.driver
|
||||||
try:
|
try:
|
||||||
if not logged_in():
|
login_part_1()
|
||||||
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:
|
||||||
@ -783,23 +537,19 @@ def fidelity():
|
|||||||
pause = driver.find_element(By.CSS_SELECTOR, f'[class="c-action-toggle c-glyph f-toggle glyph-pause"]')
|
pause = driver.find_element(By.CSS_SELECTOR, f'[class="c-action-toggle c-glyph f-toggle glyph-pause"]')
|
||||||
pause.click()
|
pause.click()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
debug("No pause button.")
|
error(f"Error while clicking pause. Probably no cards. {e}")
|
||||||
|
return "no cards"
|
||||||
cartes = driver.find_elements(By.CSS_SELECTOR, f'[ng-repeat="item in $ctrl.transcludedItems"]')
|
cartes = driver.find_elements(By.CSS_SELECTOR, f'[ng-repeat="item in $ctrl.transcludedItems"]')
|
||||||
nb_cartes = len(cartes)
|
nb_cartes = len(cartes)
|
||||||
if nb_cartes == 0:
|
|
||||||
warning("No fidelity cards detected")
|
|
||||||
return "No cards."
|
|
||||||
checked_list_all = driver.find_elements(By.CSS_SELECTOR, f'[ng-if="$ctrl.complete"]')
|
checked_list_all = driver.find_elements(By.CSS_SELECTOR, f'[ng-if="$ctrl.complete"]')
|
||||||
for i in range(nb_cartes):
|
for i in range(nb_cartes):
|
||||||
cartes[i].click()
|
cartes[i].click()
|
||||||
checked_txt = checked_list_all[i].get_attribute("innerHTML")
|
checked_txt = checked_list_all[i].get_attribute("innerHTML")
|
||||||
ok = checked_txt.count("StatusCircleOuter checkmark")
|
ok = checked_txt.count("StatusCircleOuter checkmark")
|
||||||
total = checked_txt.count("StatusCircleOuter")
|
total = checked_txt.count("StatusCircleOuter")
|
||||||
if ok != total:
|
if (ok != total):
|
||||||
elm = driver.find_elements(By.CLASS_NAME, 'clickable-link')[i]
|
elm = driver.find_elements(By.CLASS_NAME, 'clickable-link')[i]
|
||||||
# legacy code. Should be removed
|
if not "moviesandtv" in elm.get_attribute("innerHTML"): # not the film card
|
||||||
if "moviesandtv" not in elm.get_attribute("innerHTML"): # not the film card
|
|
||||||
elm.click()
|
elm.click()
|
||||||
driver.switch_to.window(driver.window_handles[len(driver.window_handles) - 1])
|
driver.switch_to.window(driver.window_handles[len(driver.window_handles) - 1])
|
||||||
sub_fidelity()
|
sub_fidelity()
|
||||||
@ -860,11 +610,9 @@ 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.")
|
||||||
raise Banned()
|
return
|
||||||
|
|
||||||
except Identity:
|
except Identity:
|
||||||
log_error("This account has an issue.")
|
log_error("This account has an issue.")
|
||||||
return
|
return
|
||||||
@ -917,53 +665,53 @@ def json_start(json_entry, cred: UserCredentials):
|
|||||||
config.WebDriver.set_pc_driver(create_driver())
|
config.WebDriver.set_pc_driver(create_driver())
|
||||||
config.WebDriver.switch_to_driver("PC")
|
config.WebDriver.switch_to_driver("PC")
|
||||||
driver = config.WebDriver.driver
|
driver = config.WebDriver.driver
|
||||||
if "unban" in json_entry and str(account_id) in json_entry["unban"]:
|
try:
|
||||||
login()
|
if str(account_id) in json_entry["unban"]:
|
||||||
info("\nGO TO example.com TO PROCEED or wait 1200 secs.")
|
login_part_1()
|
||||||
for _ in range(1200):
|
info("\nGO TO example.com TO PROCEED or wait 1200 secs.")
|
||||||
sleep(1)
|
for _ in range(1200):
|
||||||
if driver.current_url == "https://example.com/":
|
sleep(1)
|
||||||
info("proceeding")
|
if driver.current_url == "https://example.com/":
|
||||||
break
|
info("proceeding")
|
||||||
else:
|
break
|
||||||
|
else:
|
||||||
|
login()
|
||||||
|
except KeyError:
|
||||||
login()
|
login()
|
||||||
try:
|
try:
|
||||||
if str(account_id) in json_entry["tout"]:
|
if str(account_id) in json_entry["tout"]:
|
||||||
daily_routine(cred, True)
|
daily_routine(cred)
|
||||||
|
|
||||||
else:
|
|
||||||
try:
|
|
||||||
if str(account_id) in json_entry["daily"]:
|
|
||||||
try:
|
|
||||||
all_cards()
|
|
||||||
except Exception as e:
|
|
||||||
log_error(e)
|
|
||||||
except KeyError:
|
|
||||||
pass
|
|
||||||
try:
|
|
||||||
if str(account_id) in json_entry["pc"]:
|
|
||||||
try:
|
|
||||||
bing_pc_search()
|
|
||||||
except Exception as e:
|
|
||||||
log_error(e)
|
|
||||||
except KeyError:
|
|
||||||
pass
|
|
||||||
try:
|
|
||||||
if str(account_id) in json_entry["mobile"]:
|
|
||||||
try:
|
|
||||||
bing_mobile_search(cred)
|
|
||||||
except Exception as e:
|
|
||||||
log_error(e)
|
|
||||||
except KeyError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
except KeyError:
|
except KeyError:
|
||||||
pass
|
pass
|
||||||
try:
|
else:
|
||||||
log_points()
|
try:
|
||||||
except Exception as e:
|
if str(account_id) in json_entry["daily"]:
|
||||||
error(f"CustomStart {e}")
|
try:
|
||||||
|
all_cards()
|
||||||
|
except Exception as e:
|
||||||
|
log_error(e)
|
||||||
|
except KeyError:
|
||||||
|
pass
|
||||||
|
try:
|
||||||
|
if str(account_id) in json_entry["pc"]:
|
||||||
|
try:
|
||||||
|
bing_pc_search()
|
||||||
|
except Exception as e:
|
||||||
|
log_error(e)
|
||||||
|
except KeyError:
|
||||||
|
pass
|
||||||
|
try:
|
||||||
|
if str(account_id) in json_entry["mobile"]:
|
||||||
|
try:
|
||||||
|
bing_mobile_search(cred)
|
||||||
|
except Exception as e:
|
||||||
|
log_error(e)
|
||||||
|
except KeyError:
|
||||||
|
pass
|
||||||
|
try:
|
||||||
|
log_points()
|
||||||
|
except Exception as e:
|
||||||
|
error(f"CustomStart {e}")
|
||||||
driver.close()
|
driver.close()
|
||||||
cred.next_account()
|
cred.next_account()
|
||||||
account_id += 1
|
account_id += 1
|
||||||
@ -980,17 +728,13 @@ def default_start():
|
|||||||
while config.UserCredentials.is_valid():
|
while config.UserCredentials.is_valid():
|
||||||
custom_sleep(1)
|
custom_sleep(1)
|
||||||
info("Starting and configuring driver.")
|
info("Starting and configuring driver.")
|
||||||
try:
|
config.WebDriver.set_pc_driver(create_driver())
|
||||||
config.WebDriver.set_pc_driver(create_driver())
|
|
||||||
except:
|
|
||||||
info("Could not configure driver. Trying to update it.")
|
|
||||||
subprocess.Popen(["python3", "/app/MsRewards-Reborn/modules/Tools/update_chrome.py"])
|
|
||||||
config.WebDriver.set_pc_driver(create_driver())
|
|
||||||
config.WebDriver.switch_to_driver("PC")
|
config.WebDriver.switch_to_driver("PC")
|
||||||
info("Driver started.")
|
info("Driver started.")
|
||||||
config.WebDriver.pc_driver.implicitly_wait(3)
|
config.WebDriver.pc_driver.implicitly_wait(3)
|
||||||
try:
|
try:
|
||||||
wait_time = uniform(1200, 3600)
|
wait_time = uniform(1200, 3600)
|
||||||
|
wait_time = 10 # the display closes when I ctrl + c
|
||||||
info(f"Waiting for {round(wait_time / 60)}min before starting")
|
info(f"Waiting for {round(wait_time / 60)}min before starting")
|
||||||
custom_sleep(wait_time)
|
custom_sleep(wait_time)
|
||||||
daily_routine(config.UserCredentials)
|
daily_routine(config.UserCredentials)
|
||||||
@ -1000,16 +744,12 @@ 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()
|
||||||
|
|
||||||
finally:
|
config.UserCredentials.next_account()
|
||||||
config.UserCredentials.next_account()
|
|
||||||
|
|
||||||
config.display.stop()
|
config.display.stop()
|
||||||
|
|
||||||
|
|
||||||
@ -1018,6 +758,7 @@ def log_error(msg):
|
|||||||
|
|
||||||
|
|
||||||
def check_updated():
|
def check_updated():
|
||||||
|
debug(f"updated: {config.has_been_updated()}")
|
||||||
if config.has_been_updated():
|
if config.has_been_updated():
|
||||||
config.discord.wh.send(f"Updated to {config.version}", username="update",
|
config.discord.wh.send(f"Updated to {config.version}", username="update",
|
||||||
avatar_url="https://cdn-icons-png.flaticon.com/512/1688/1688988.png")
|
avatar_url="https://cdn-icons-png.flaticon.com/512/1688/1688988.png")
|
||||||
|
13
build.sh
13
build.sh
@ -1,12 +1 @@
|
|||||||
#!/bin/bash
|
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
|
||||||
|
|
||||||
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
13
clean.sh
@ -1,13 +0,0 @@
|
|||||||
#!/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
|
|
@ -46,7 +46,6 @@ 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;
|
||||||
add_header X-Accel-Buffering no;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -60,6 +59,7 @@ 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
|
||||||
|
1459
config/grafana.ini
1459
config/grafana.ini
File diff suppressed because it is too large
Load Diff
@ -1,12 +0,0 @@
|
|||||||
file=version
|
|
||||||
|
|
||||||
if [ "$(git diff HEAD version | wc -w)" -eq 0 ]
|
|
||||||
then
|
|
||||||
echo 'updating minor version'
|
|
||||||
new_path=$(cat $file | awk -F . '{print $1"."$2"."$3+1 }')
|
|
||||||
echo $new_path > $file
|
|
||||||
git add version
|
|
||||||
else
|
|
||||||
echo 'Version have been updated manually'
|
|
||||||
fi
|
|
||||||
echo Version: $(cat $file)
|
|
@ -1 +0,0 @@
|
|||||||
sh hooks/bump.sh
|
|
@ -22,8 +22,7 @@ class Config:
|
|||||||
proxy = json.load(inFile)
|
proxy = json.load(inFile)
|
||||||
with open("/app/MsRewards-Reborn/user_data/configs.json", "r") as inFile:
|
with open("/app/MsRewards-Reborn/user_data/configs.json", "r") as inFile:
|
||||||
config = json.load(inFile)
|
config = json.load(inFile)
|
||||||
with open("/app/MsRewards-Reborn/user_data/version", "r") as inFile:
|
|
||||||
version = inFile.readline()
|
|
||||||
"""
|
"""
|
||||||
setup standalone stuff
|
setup standalone stuff
|
||||||
"""
|
"""
|
||||||
@ -32,9 +31,10 @@ class Config:
|
|||||||
self.json_entry = args.json.replace("'", "\"")
|
self.json_entry = args.json.replace("'", "\"")
|
||||||
self.wordlist = WordList("/usr/share/dict/french")
|
self.wordlist = WordList("/usr/share/dict/french")
|
||||||
self.vnc = args.vnc
|
self.vnc = args.vnc
|
||||||
|
self.version = args.update_version
|
||||||
self.WebDriver = Driver()
|
self.WebDriver = Driver()
|
||||||
self.display = None
|
self.display = None
|
||||||
self.version = version
|
|
||||||
"""
|
"""
|
||||||
setup UserCredential
|
setup UserCredential
|
||||||
"""
|
"""
|
||||||
@ -50,14 +50,9 @@ 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 (
|
if self.discord.wh_link != "":
|
||||||
"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()
|
||||||
@ -81,11 +76,4 @@ class Config:
|
|||||||
self.display = display
|
self.display = display
|
||||||
|
|
||||||
def has_been_updated(self):
|
def has_been_updated(self):
|
||||||
with open('/app/MsRewards-Reborn/version', "r") as inFile:
|
return self.version != "None"
|
||||||
in_file_content = inFile.readlines()
|
|
||||||
if self.version != in_file_content[0]:
|
|
||||||
self.version = in_file_content[0]
|
|
||||||
with open('/app/MsRewards-Reborn/user_data/version', "w") as outFile:
|
|
||||||
outFile.write(self.version)
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
@ -9,6 +9,6 @@ class DiscordConfig:
|
|||||||
|
|
||||||
|
|
||||||
class FakeWebHook:
|
class FakeWebHook:
|
||||||
def send(self, *args, **kwargs):
|
def send(self, *args):
|
||||||
debug(f"Used a webhook call without webhook url with {args} {kwargs}")
|
debug(f"Used a webhook call without webhook url with {args}")
|
||||||
|
|
||||||
|
@ -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.get_mail() + " - " + self.config.WebDriver.current_driver())
|
embed.set_footer(text=self.config.UserCredentials.creds.get_mail())
|
||||||
|
|
||||||
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)
|
||||||
|
@ -11,15 +11,12 @@ class Driver:
|
|||||||
self.mobile_driver = mobile_driver
|
self.mobile_driver = mobile_driver
|
||||||
|
|
||||||
def switch_to_driver(self, driver: str):
|
def switch_to_driver(self, driver: str):
|
||||||
match driver.lower():
|
match driver:
|
||||||
case "pc":
|
case "pc" | "PC" | "Pc":
|
||||||
self.driver = self.pc_driver
|
self.driver = self.pc_driver
|
||||||
|
|
||||||
case "mobile":
|
case "mobile" | "Mobile":
|
||||||
self.driver = self.mobile_driver
|
self.driver = self.mobile_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"
|
|
||||||
|
@ -30,9 +30,8 @@ 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. Can't get a TFA code.")
|
warning("Warning: TFA is not enabled. Calling get_tfa is an expected behaviour.")
|
||||||
return None
|
return TOTP(self.data[self.current]["tfa"])
|
||||||
return TOTP(self.data[self.current]["2fa"])
|
|
||||||
|
|
||||||
def next_account(self):
|
def next_account(self):
|
||||||
self.current += 1
|
self.current += 1
|
||||||
@ -42,5 +41,4 @@ 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)
|
|
||||||
|
@ -1,8 +0,0 @@
|
|||||||
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
|
# Set up the root logger
|
||||||
root_logger = logging.getLogger(__name__)
|
root_logger = logging.getLogger(__name__)
|
||||||
root_logger.setLevel(logging.INFO)
|
root_logger.setLevel(logging.DEBUG)
|
||||||
|
|
||||||
# Create a console handler and set the formatter
|
# Create a console handler and set the formatter
|
||||||
ch = logging.StreamHandler()
|
ch = logging.StreamHandler()
|
||||||
|
@ -10,7 +10,7 @@ def get_domain(driver):
|
|||||||
|
|
||||||
def custom_sleep(temps):
|
def custom_sleep(temps):
|
||||||
try:
|
try:
|
||||||
if False: # todo: change this awful condition
|
if True: # todo: change this awful condition
|
||||||
points = ["⢿", "⣻", "⣽", "⣾", "⣷", "⣯", "⣟", "⡿"]
|
points = ["⢿", "⣻", "⣽", "⣾", "⣷", "⣯", "⣟", "⡿"]
|
||||||
passe = 0
|
passe = 0
|
||||||
for _ in range(int(temps)):
|
for _ in range(int(temps)):
|
||||||
|
@ -1,50 +0,0 @@
|
|||||||
import requests
|
|
||||||
import re
|
|
||||||
from packaging import version
|
|
||||||
import subprocess
|
|
||||||
|
|
||||||
from logger import critical, info, error
|
|
||||||
|
|
||||||
errorMessage = subprocess.run(['python3', '/app/MsRewards-Reborn/modules/Tools/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)
|
|
||||||
info("error message")
|
|
||||||
info(errorMessage)
|
|
||||||
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")
|
|
@ -1,9 +1,7 @@
|
|||||||
import json
|
|
||||||
import os
|
|
||||||
from random import uniform
|
from random import uniform
|
||||||
|
|
||||||
from selenium.common import TimeoutException
|
from selenium.common import TimeoutException
|
||||||
from selenium.webdriver import Keys
|
from selenium.webdriver import ActionChains, Keys
|
||||||
from selenium.webdriver.common.by import By
|
from selenium.webdriver.common.by import By
|
||||||
from selenium.webdriver.support import expected_conditions
|
from selenium.webdriver.support import expected_conditions
|
||||||
from selenium.webdriver.support.wait import WebDriverWait
|
from selenium.webdriver.support.wait import WebDriverWait
|
||||||
@ -12,40 +10,33 @@ from modules.Tools.logger import debug
|
|||||||
from modules.Tools.tools import *
|
from modules.Tools.tools import *
|
||||||
|
|
||||||
|
|
||||||
def init_profile(mail, mobile=False):
|
def set_language(ldriver):
|
||||||
if not mobile:
|
ldriver.get("chrome://settings/languages")
|
||||||
chrome_profile_dir = "/app/MsRewards-Reborn/user_data/profile/" + mail
|
action = ActionChains(ldriver)
|
||||||
else:
|
action.reset_actions()
|
||||||
chrome_profile_dir = "/app/MsRewards-Reborn/user_data/profile/mobile-" + mail
|
# select language
|
||||||
|
x_coord = 1200
|
||||||
os.makedirs(chrome_profile_dir, exist_ok=True)
|
y_coord = 150
|
||||||
|
action.move_by_offset(x_coord, y_coord).click().perform()
|
||||||
preferences_file = os.path.join(chrome_profile_dir, "Default", "Preferences")
|
sleep(0.5)
|
||||||
if not os.path.exists(preferences_file):
|
# scroll down
|
||||||
os.makedirs(os.path.join(chrome_profile_dir, "Default"), exist_ok=True)
|
action.reset_actions()
|
||||||
with open(preferences_file, "w") as f:
|
elm = ldriver.find_element(By.XPATH, "/html/body")
|
||||||
json.dump(
|
ActionChains(ldriver) \
|
||||||
{
|
.send_keys("french") \
|
||||||
"intl": {
|
.pause(0.5) \
|
||||||
"accept_languages": "fr-FR,en-US,en",
|
.send_keys(Keys.TAB + Keys.TAB + Keys.ENTER + Keys.TAB + Keys.TAB + Keys.ENTER) \
|
||||||
"selected_languages": "fr-FR,en-US,en"
|
.perform()
|
||||||
}
|
x_coord = 1163
|
||||||
}, f
|
y_coord = 717
|
||||||
)
|
action.move_by_offset(x_coord, y_coord).click().perform()
|
||||||
else:
|
# put to the top
|
||||||
with open(preferences_file, "r") as f:
|
sleep(0.5)
|
||||||
settings = json.load(f)
|
action.reset_actions()
|
||||||
|
x_coord = 1257
|
||||||
if "intl" not in settings:
|
y_coord = 328
|
||||||
settings["intl"] = {}
|
action.move_by_offset(x_coord, y_coord).click().perform()
|
||||||
|
action.click().perform()
|
||||||
settings["intl"]["accept_languages"] = "fr-FR,en-US,en"
|
|
||||||
settings["intl"]["selected_languages"] = "fr-FR,en-US,en"
|
|
||||||
|
|
||||||
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
|
||||||
@ -70,18 +61,12 @@ def send_keys_wait(element, keys: str) -> None:
|
|||||||
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, raise_error=True) -> bool:
|
def wait_until_visible(search_by: str, identifier: str, timeout: int = 20, browser=None) -> 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:
|
||||||
f = error if raise_error else debug
|
error(f"element {identifier} not found after {timeout}s")
|
||||||
f(f"element {identifier} not found after {timeout}s")
|
|
||||||
return False
|
return False
|
||||||
|
@ -1 +0,0 @@
|
|||||||
0.0.0
|
|
Loading…
Reference in New Issue
Block a user