135 Commits

Author SHA1 Message Date
5e5f7f7407 Implement "timezonedates" 2024-10-18 13:03:16 +02:00
0cc42823ff Add new cards (election, dictionary) 2024-10-15 11:51:55 +02:00
56c858fa90 Adding new "explore on Bing" cards 2024-10-08 09:07:01 +02:00
adf91ac8f0 Ignoring MS Security activity (it would be better to detect it before clicking) 2024-10-01 09:03:50 +02:00
2721c76686 Fix LegacyKeyValueFormat warning
"ENV key=value" should be used instead of legacy "ENV key value" format
2024-09-19 11:57:25 +02:00
45ea72a354 Merge remote-tracking branch 'origin/master' 2024-09-14 22:57:48 +02:00
18b35f6f68 adding new custom search cards 2024-09-14 22:57:40 +02:00
c53125479e Check if streak protection expired 2024-08-30 21:48:20 +02:00
df256f2405 Update modules/Tools/update_chrome.py
fix auto update breaking due to path error
2024-08-28 15:48:31 +02:00
31b4d5d7da Actualiser V6.py 2024-07-08 10:00:28 +02:00
574fa45813 Update version 2024-07-05 13:47:08 +02:00
3bb49d1618 Merge remote-tracking branch 'origin/master'
# Conflicts:
#	V6.py
2024-07-05 13:46:04 +02:00
e25334f1bd adding new custom search cards 2024-07-05 13:45:26 +02:00
41312b53b9 c'est bon là 2024-06-18 20:50:55 +02:00
1ac98f14c4 wqMerge branch 'fix4' 2024-06-18 20:38:21 +02:00
a197d44768 Added package tracking card 2024-06-18 20:37:14 +02:00
f9a21f5b98 Added package tracking card 2024-06-18 16:54:37 +02:00
82161973a9 Added weather carad 2024-06-18 16:38:29 +02:00
c7e110787b Debugging auto update 2024-05-16 17:52:12 +02:00
1db1de9606 oops, bad syntax 2024-05-15 10:03:01 +02:00
10d75f9d78 version bump 2024-05-15 09:52:56 +02:00
87fb791436 Explore on Bing: solve more challenges 2024-05-15 09:52:39 +02:00
6995bde8a6 Actualiser version 2024-05-12 18:55:51 +02:00
92069a013e Merge pull request 'Handle Streak-Protection Popup' (#12) from streak-protection into master
Reviewed-on: https://gitea.augustin64.fr/piair/MsRewards-Reborn/pulls/12
2024-05-12 18:55:34 +02:00
906d3e7822 catch another exception 2024-05-12 18:16:24 +02:00
778adc67d2 Et si on l'active ? 2024-05-12 18:07:36 +02:00
402b8cd3ef Close streak protection 2024-05-12 17:55:56 +02:00
3c74aa025e trying to fix web start 2024-04-26 16:06:33 +02:00
3123a1dbd0 trying to auto update chrome + fixed web override ? 2024-04-26 15:51:52 +02:00
27d45e88dd added more exploreOnBing 2024-04-26 15:43:23 +02:00
0685a42922 making scripts executables 2024-04-26 15:37:32 +02:00
6729703827 auto update hooks 2024-04-26 15:35:37 +02:00
304a222de1 fixed readlines ? 2024-04-26 14:51:23 +02:00
04d33f4ecd fixed readlines ? 2024-04-26 14:45:41 +02:00
ac22814605 fixed readlines ? 2024-04-26 14:41:00 +02:00
b7a89b56d0 fixed typo 2024-04-26 14:36:04 +02:00
127d16afea Changed version update logik 2024-04-26 14:32:01 +02:00
9bcbc81c2f Changement des musiques pour celles que Bing connais 2024-04-26 14:13:50 +02:00
12eba5cde7 top habitué au JS 2024-04-26 14:00:33 +02:00
22ea727c47 progress 2024-04-26 13:55:20 +02:00
05a1fd8557 pourquoi les custom attributes 2024-04-26 12:12:28 +02:00
39e226b564 pourquoi les custom attributes 2024-04-26 12:06:55 +02:00
cd00c8ca88 detecting which cutom search to do 2024-04-26 12:03:49 +02:00
43793d2c2c detecting which cutom search to do 2024-04-26 11:51:50 +02:00
ee6ec458fc switched to login on custom start 2024-04-26 11:27:16 +02:00
e6e8bdaa06 Trying to find out why the part1 is starting 2024-04-26 11:17:18 +02:00
9bd96ad876 version bump 2024-04-13 11:09:30 +02:00
ed517e7b03 Fix 'Welcome Tour'
Reviewed-on: https://gitea.augustin64.fr/piair/MsRewards-Reborn/pulls/11
2024-04-13 11:07:04 +02:00
01416c0e11 Check before scrolling, but should be good to merge ! 2024-04-13 11:01:25 +02:00
19cf77c6bd make an actual choice 2024-04-13 10:57:32 +02:00
feb7834d1f sleep a bit 2024-04-13 10:26:53 +02:00
1ea1ff776e wait until visible 2024-04-13 10:26:21 +02:00
ae023688a4 welcome-tour: URL check 2024-04-13 10:15:26 +02:00
fcb40537dc Use newer method 2024-04-13 10:06:21 +02:00
d7d2f49a3f pas la seule occurrence évidemment 2024-04-12 23:46:26 +02:00
68b5de32d6 fix de la popup "explorer le programme"
peu satisfaisant, consiste juste à fermer la popup à chaque fois qu'elle apparaît sans s'en débarrasser définitivement
2024-04-12 23:28:46 +02:00
c5e9fb1267 version bump ? 2024-04-12 20:01:53 +02:00
6ade73617a Make console resizable 2024-04-12 20:01:34 +02:00
37e8f6f61b Fix fake_popen 2024-04-12 16:20:25 +02:00
db6fa9b6b0 Add env variables arguments to flask app
- NO_SUBPROCESS to fake subprocesses calls
- APP_ROOT to use the app outside of Docker
2024-04-12 15:55:14 +02:00
d6988c03b4 Oops.. fixed nginx config 2024-04-12 15:51:20 +02:00
449d2da410 Use a different profile for mobile browser 2024-04-12 09:31:50 +02:00
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
8c224793b0 resize terminal on animation end 2024-02-28 15:04:19 +01:00
36fd92f71c fix json start 2024-02-28 14:44:11 +01:00
0a02eb2033 fix json start 2024-02-28 14:44:01 +01:00
6122d9ee13 fix json start + improve logs 2024-02-28 14:40:12 +01:00
a590d0f1b5 fix json start 2024-02-28 14:29:21 +01:00
64a018044c event on resize 2024-02-28 14:26:25 +01:00
91e7f31bac size issues 2024-02-28 14:17:55 +01:00
295f6d114d size issues 2024-02-28 14:14:29 +01:00
49e0d1b599 the issue seemed to be linked to the use of table instead of div 2024-02-28 14:13:19 +01:00
83eea03c73 the issue seemed to be linked to the use of table instead of div 2024-02-28 14:13:16 +01:00
3d096ec34c close to working 2024-02-28 12:09:32 +01:00
7bdf229fa8 je connais pas le js moi 2024-02-28 12:02:41 +01:00
0abb8a3494 weird errors 2024-02-28 12:00:19 +01:00
231c3b34e3 better terminal 2024-02-28 11:55:55 +01:00
c72aaf3fcc better terminal 2024-02-28 11:53:23 +01:00
675e67055b better terminal 2024-02-28 11:41:16 +01:00
a089fdfdf1 better terminal 2024-02-28 11:41:13 +01:00
0f60d67951 obsolete : module 2024-02-28 11:38:32 +01:00
1c7d1dfcd6 typo 2024-02-28 11:38:21 +01:00
19606e5f4c I'm just a clown, I didn't update... 2024-02-28 11:15:09 +01:00
aaafbb2257 some debug don't work at all ? 2024-02-28 11:13:09 +01:00
8d332f1c3c check if discord works 2024-02-28 11:10:48 +01:00
ced633dd68 refactored log_points 2024-02-28 10:49:27 +01:00
5fe05712bd refactored all_cards 2024-02-28 00:14:42 +01:00
6ec5300c7b the logger should only log my code now 2024-02-27 23:59:39 +01:00
5ca91a7075 the optimisation wasn't that great 2024-02-27 16:26:29 +01:00
d49742646c wrong parameter in rgpd_popup 2024-02-27 16:21:08 +01:00
a88ad8dd47 the issue seems to be due to MS 2024-02-27 16:13:01 +01:00
d9ebccebb8 well the login works, but it will cause issues later with cookies 2024-02-27 16:09:23 +01:00
40f08b4c86 issue indeed fixed, but still can't log in 2024-02-27 16:05:29 +01:00
b072041446 issue indeed fixed, but still can't log in 2024-02-27 16:05:21 +01:00
476f99b931 fix ? 2024-02-27 15:59:23 +01:00
37c5d9cf43 can I go to some website ? 2024-02-27 15:57:25 +01:00
9e274b6d16 weird error 2024-02-27 15:55:37 +01:00
2a3878b919 bump version. Added docker compose 2024-02-27 15:38:19 +01:00
7cc1b415a6 bump version. Added docker compose (thx chatGPT) 2024-02-27 15:35:31 +01:00
6a2d960dd0 bump version. Added docker compose 2024-02-27 15:31:35 +01:00
bff43c8207 bump version. 2024-02-27 15:22:51 +01:00
7a47b7ae9d bump version. 2024-02-27 15:21:30 +01:00
346b9acc04 bump version. 2024-02-27 15:19:53 +01:00
bc94489ca0 bump version. 2024-02-27 15:18:45 +01:00
a601c64feb bump version. 2024-02-27 15:17:11 +01:00
af938eb50a bump version. 2024-02-27 15:14:14 +01:00
2ae80e9c53 bump version. 2024-02-27 15:12:30 +01:00
27f08b5a01 bump version. 2024-02-27 15:12:25 +01:00
84ace32977 bump version. 2024-02-27 15:07:42 +01:00
da6ca1cdfc bump version. 2024-02-27 15:05:19 +01:00
9857607eb3 implemented classes to remove global file 2024-02-27 14:52:55 +01:00
47 changed files with 1607 additions and 347932 deletions

2
.dockerignore Normal file
View File

@ -0,0 +1,2 @@
**/.venv
user_data/*

8
.gitignore vendored
View File

@ -3,15 +3,17 @@ 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
LICENSE
README.md
venv

View File

@ -1,21 +1,42 @@
FROM python:3.10 FROM python:3.10
ENV DEBIAN_FRONTEND noninteractive ENV DEBIAN_FRONTEND=noninteractive
WORKDIR /app/ WORKDIR /app/
RUN apt update \
&& wget http://security.ubuntu.com/ubuntu/pool/main/o/openssl/libssl1.1_1.1.0g-2ubuntu4_amd64.deb \ # Initial apt install
&& dpkg -i libssl1.1_1.1.0g-2ubuntu4_amd64.deb \ RUN apt update
&& apt install redis libgtk-4-1 libvulkan1 libxdamage1 -y \ RUN apt install -y libgtk-4-1 libvulkan1 libxdamage1 \
&& curl -sSLO https://nc.piair.xyz/s/BKLsBWoZkTdYjfq/download/chrome.deb \ novnc websockify xvfb nginx nano tzdata \
&& ln -fs /usr/share/zoneinfo/Europe/Paris /etc/localtime \ sqlite3 apt-transport-https software-properties-common \
&& git clone https://gitea.augustin64.fr/piair/MsRewards-Reborn \ wget wfrench tigervnc-standalone-server libasound2 \
&& python3 -m pip install -r MsRewards-Reborn/requirements.txt \ libatk-bridge2.0-0 libnss3 libnspr4 xvfb libgbm1 libatk1.0-0 \
&& wget -q -O /usr/share/keyrings/grafana.key https://apt.grafana.com/gpg.key \ libu2f-udev libatspi2.0-0 libcups2 libxkbcommon0 libxrandr2 \
&& curl -fsSL https://packages.redis.io/gpg | gpg --dearmor -o /usr/share/keyrings/redis-archive-keyring.gpg \ libdbus-1-3 xdg-utils fonts-liberation libdrm2
&& 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 \ # Additional repos and packages
&& 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 \ RUN wget http://security.ubuntu.com/ubuntu/pool/main/o/openssl/libssl1.1_1.1.0g-2ubuntu4_amd64.deb \
&& bash MsRewards-Reborn/config/config.sh \ && 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 && 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 \
&& apt install -y redis grafana
# Configure Grafana
RUN grafana-cli plugins install frser-sqlite-datasource
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" ENV TZ="Europe/Paris"
WORKDIR /app/MsRewards-Reborn/Flask/ WORKDIR /app/MsRewards-Reborn/Flask/

View File

@ -13,11 +13,27 @@ 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')
@ -32,7 +48,7 @@ def generate_output():
# the end # the end
global password global password
with open("/app/MsRewards-Reborn/user_data/flask.json", "r") as inFile: with open(get_path("user_data/flask.json"), "r") as inFile:
data = json.load(inFile) data = json.load(inFile)
password = data["password"] password = data["password"]
@ -40,7 +56,7 @@ secret = data["secret"]
if secret == "": if secret == "":
import secrets import secrets
secret = secrets.token_hex() secret = secrets.token_hex()
with open("/app/MsRewards-Reborn/user_data/flask.json", "w") as inFile: with open(get_path("user_data/flask.json"), "w") as inFile:
data = { data = {
"password": password, "password": password,
"secret": secret "secret": secret
@ -70,14 +86,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(f"/app/MsRewards-Reborn/Flask/static/logs/{i}.txt", 'a') # so that data written to it will be appended log = open(get_path(f"Flask/static/logs/{i}.txt"), 'a') # so that data written to it will be appended
subprocess.Popen([f"python3 -u /app/MsRewards-Reborn/V6.py -c {i}"], stdout=log, stderr=log, shell=True) subprocess.Popen([f"python3 -u {get_path('V6.py')} -c {i}"], stdout=log, stderr=log, shell=True)
log.close() log.close()
TriggerDict = {} TriggerDict = {}
def update_jobs(): def update_jobs():
with open("/app/MsRewards-Reborn/user_data/configs.json", "r") as inFile: with open(get_path("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 :
@ -120,7 +136,7 @@ app = Flask(__name__)
@app.context_processor @app.context_processor
def inject_default_variables(): def inject_default_variables():
with open("/app/MsRewards-Reborn/version", "r") as f: with open(get_path("version"), "r") as f:
version = f.readline().replace("\n", '') version = f.readline().replace("\n", '')
return dict(version=version) return dict(version=version)
""" """
@ -175,7 +191,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("/app/MsRewards-Reborn/user_data/flask.json", "w") as inFile: with open(get_path("user_data/flask.json"), "w") as inFile:
data = { data = {
"password": password, "password": password,
"secret": secret "secret": secret
@ -201,21 +217,21 @@ def load_user(userid):
@app.route("/") @app.route("/")
def main(): def main():
with open("/app/MsRewards-Reborn/user_data/configs.json", "r") as inFile: with open(get_path("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("/app/MsRewards-Reborn/user_data/discord.json", "r") as inFile: with open(get_path("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("/app/MsRewards-Reborn/user_data/discord.json", "r") as inFile: with open(get_path("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" :
@ -237,7 +253,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("/app/MsRewards-Reborn/user_data/discord.json", "w") as outFile: with open(get_path("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)))
@ -249,7 +265,7 @@ def dev2():
@app.route("/settings/") @app.route("/settings/")
def settings_get(): def settings_get():
with open("/app/MsRewards-Reborn/user_data/settings.json", "r") as inFile: with open(get_path("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))
@ -259,21 +275,21 @@ def settings_post():
settings = {} settings = {}
action = request.form action = request.form
settings['avatarlink'] = action["avatarlink"] settings['avatarlink'] = action["avatarlink"]
with open("/app/MsRewards-Reborn/user_data/settings.json", "w") as inFile: with open(get_path("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("/app/MsRewards-Reborn/user_data/proxy.json", "r") as inFile: with open(get_path("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("/app/MsRewards-Reborn/user_data/proxy.json", "r") as inFile: with open(get_path("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)
@ -290,21 +306,21 @@ def proxy_post():
except : except :
print("error : probably bad config") print("error : probably bad config")
with open("/app/MsRewards-Reborn/user_data/proxy.json", "w") as outFile: with open(get_path("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("/app/MsRewards-Reborn/user_data/configs.json", "r") as inFile: with open(get_path("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("/app/MsRewards-Reborn/user_data/configs.json", "r") as inFile: with open(get_path("user_data/configs.json"), "r") as inFile:
configs = json.load(inFile) configs = json.load(inFile)
data = dict(request.form) data = dict(request.form)
@ -318,7 +334,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("/app/MsRewards-Reborn/user_data/configs.json", "w") as inFile: with open(get_path("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))
@ -326,11 +342,11 @@ def schedule_post():
@app.route("/config/") @app.route("/config/")
def config_get(): def config_get():
with open("/app/MsRewards-Reborn/user_data/proxy.json", "r") as inFile: with open(get_path("user_data/proxy.json"), "r") as inFile:
proxys = json.load(inFile) proxys = json.load(inFile)
with open("/app/MsRewards-Reborn/user_data/discord.json", "r") as inFile: with open(get_path("user_data/discord.json"), "r") as inFile:
discords = json.load(inFile) discords = json.load(inFile)
with open("/app/MsRewards-Reborn/user_data/configs.json", "r") as inFile: with open(get_path("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)))
@ -338,11 +354,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("/app/MsRewards-Reborn/user_data/proxy.json", "r") as inFile: with open(get_path("user_data/proxy.json"), "r") as inFile:
proxys = json.load(inFile) proxys = json.load(inFile)
with open("/app/MsRewards-Reborn/user_data/discord.json", "r") as inFile: with open(get_path("user_data/discord.json"), "r") as inFile:
discords = json.load(inFile) discords = json.load(inFile)
with open("/app/MsRewards-Reborn/user_data/configs.json", "r") as inFile: with open(get_path("user_data/configs.json"), "r") as inFile:
configs = json.load(inFile) configs = json.load(inFile)
if action["data"] == "delete": if action["data"] == "delete":
@ -365,16 +381,26 @@ def config_post():
"enabled":"False", "enabled":"False",
"accounts": comptes "accounts": comptes
} }
with open("/app/MsRewards-Reborn/user_data/configs.json", "w") as outFile: with open(get_path("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("/app/MsRewards-Reborn/user_data/configs.json", "r") as inFile: with open(get_path("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(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"])
@ -385,21 +411,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(f"/app/MsRewards-Reborn/Flask/static/logs/custom.txt", 'w') # so that data written to it will be appended log = open(get_path("Flask/static/logs/custom.txt"), 'w') # so that data written to it will be appended
subprocess.Popen([f"python3 -u /app/MsRewards-Reborn/V6.py -c {json['config'][0]} --json \"{json}\""], stdout=log, stderr=log, shell=True) subprocess.Popen([f"python3 -u {get_path('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("/app/MsRewards-Reborn/user_data/configs.json", "r") as inFile: with open(get_path("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='/app/MsRewards-Reborn/user_data/', path=filename, as_attachment=True) return send_from_directory(directory=get_path("user_data/"), path=filename, as_attachment=True)
def allowed_file(filename): def allowed_file(filename):
@ -420,8 +446,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('/app/MsRewards-Reborn/user_data/', filename)) print(os.path.join(get_path("user_data/"), filename))
file.save(os.path.join('/app/MsRewards-Reborn/user_data/', filename)) file.save(os.path.join(get_path("user_data/"), filename))
i += 1 i += 1
print(i) print(i)
@ -439,4 +465,7 @@ def maxi(dict):
update_jobs() update_jobs()
subprocess.Popen(["bash",'/app/MsRewards-Reborn/config/request.sh']) subprocess.Popen(["bash", get_path("config/request.sh")])
if __name__ == "__main__":
app.run()

View File

@ -1,5 +1,5 @@
nohup bash /app/MsRewards-Reborn/sse.sh & nohup redis-server &> nohup_redis.out &
nohup bash /app/MsRewards-Reborn/sse.sh &> nohup_sse.out &
service grafana-server start service grafana-server start
service nginx start service nginx start
nohup redis-server &
gunicorn --reload --worker-class gevent -b 0.0.0.0:6666 'app:app' gunicorn --reload --worker-class gevent -b 0.0.0.0:6666 'app:app'

View File

@ -0,0 +1,17 @@
#console {
height: 100%;
width: 20%;
float: left;
resize: horizontal;
overflow: auto;
}
#vnc-container {
height: 100%;
width: 80%;
float: left;
}
.container {
height: 100%;
}

20
Flask/static/node_modules/.package-lock.json generated vendored Normal file
View File

@ -0,0 +1,20 @@
{
"name": "static",
"lockfileVersion": 3,
"requires": true,
"packages": {
"node_modules/xterm": {
"version": "5.3.0",
"resolved": "https://registry.npmjs.org/xterm/-/xterm-5.3.0.tgz",
"integrity": "sha512-8QqjlekLUFTrU6x7xck1MsPzPA571K5zNqWm0M0oroYEWVOptZ0+ubQSkQ3uxIEhcIHRujJy6emDWX4A7qyFzg=="
},
"node_modules/xterm-addon-fit": {
"version": "0.8.0",
"resolved": "https://registry.npmjs.org/xterm-addon-fit/-/xterm-addon-fit-0.8.0.tgz",
"integrity": "sha512-yj3Np7XlvxxhYF/EJ7p3KHaMt6OdwQ+HDu573Vx1lRXsVxOcnVJs51RgjZOouIZOczTsskaS+CpXspK81/DLqw==",
"peerDependencies": {
"xterm": "^5.0.0"
}
}
}
}

View File

@ -0,0 +1,2 @@
!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.FitAddon=t():e.FitAddon=t()}(self,(()=>(()=>{"use strict";var e={};return(()=>{var t=e;Object.defineProperty(t,"__esModule",{value:!0}),t.FitAddon=void 0,t.FitAddon=class{activate(e){this._terminal=e}dispose(){}fit(){const e=this.proposeDimensions();if(!e||!this._terminal||isNaN(e.cols)||isNaN(e.rows))return;const t=this._terminal._core;this._terminal.rows===e.rows&&this._terminal.cols===e.cols||(t._renderService.clear(),this._terminal.resize(e.cols,e.rows))}proposeDimensions(){if(!this._terminal)return;if(!this._terminal.element||!this._terminal.element.parentElement)return;const e=this._terminal._core,t=e._renderService.dimensions;if(0===t.css.cell.width||0===t.css.cell.height)return;const r=0===this._terminal.options.scrollback?0:e.viewport.scrollBarWidth,i=window.getComputedStyle(this._terminal.element.parentElement),o=parseInt(i.getPropertyValue("height")),s=Math.max(0,parseInt(i.getPropertyValue("width"))),n=window.getComputedStyle(this._terminal.element),l=o-(parseInt(n.getPropertyValue("padding-top"))+parseInt(n.getPropertyValue("padding-bottom"))),a=s-(parseInt(n.getPropertyValue("padding-right"))+parseInt(n.getPropertyValue("padding-left")))-r;return{cols:Math.max(2,Math.floor(a/t.css.cell.width)),rows:Math.max(1,Math.floor(l/t.css.cell.height))}}}})(),e})()));
//# sourceMappingURL=xterm-addon-fit.js.map

File diff suppressed because one or more lines are too long

26
Flask/static/node_modules/xterm-addon-fit/package.json generated vendored Normal file
View File

@ -0,0 +1,26 @@
{
"name": "xterm-addon-fit",
"version": "0.8.0",
"author": {
"name": "The xterm.js authors",
"url": "https://xtermjs.org/"
},
"main": "lib/xterm-addon-fit.js",
"types": "typings/xterm-addon-fit.d.ts",
"repository": "https://github.com/xtermjs/xterm.js",
"license": "MIT",
"keywords": [
"terminal",
"xterm",
"xterm.js"
],
"scripts": {
"build": "../../node_modules/.bin/tsc -p .",
"prepackage": "npm run build",
"package": "../../node_modules/.bin/webpack",
"prepublishOnly": "npm run package"
},
"peerDependencies": {
"xterm": "^5.0.0"
}
}

209
Flask/static/node_modules/xterm/css/xterm.css generated vendored Normal file
View File

@ -0,0 +1,209 @@
/**
* Copyright (c) 2014 The xterm.js authors. All rights reserved.
* Copyright (c) 2012-2013, Christopher Jeffrey (MIT License)
* https://github.com/chjj/term.js
* @license MIT
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* Originally forked from (with the author's permission):
* Fabrice Bellard's javascript vt100 for jslinux:
* http://bellard.org/jslinux/
* Copyright (c) 2011 Fabrice Bellard
* The original design remains. The terminal itself
* has been extended to include xterm CSI codes, among
* other features.
*/
/**
* Default styles for xterm.js
*/
.xterm {
cursor: text;
position: relative;
user-select: none;
-ms-user-select: none;
-webkit-user-select: none;
}
.xterm.focus,
.xterm:focus {
outline: none;
}
.xterm .xterm-helpers {
position: absolute;
top: 0;
/**
* The z-index of the helpers must be higher than the canvases in order for
* IMEs to appear on top.
*/
z-index: 5;
}
.xterm .xterm-helper-textarea {
padding: 0;
border: 0;
margin: 0;
/* Move textarea out of the screen to the far left, so that the cursor is not visible */
position: absolute;
opacity: 0;
left: -9999em;
top: 0;
width: 0;
height: 0;
z-index: -5;
/** Prevent wrapping so the IME appears against the textarea at the correct position */
white-space: nowrap;
overflow: hidden;
resize: none;
}
.xterm .composition-view {
/* TODO: Composition position got messed up somewhere */
background: #000;
color: #FFF;
display: none;
position: absolute;
white-space: nowrap;
z-index: 1;
}
.xterm .composition-view.active {
display: block;
}
.xterm .xterm-viewport {
/* On OS X this is required in order for the scroll bar to appear fully opaque */
background-color: #000;
overflow-y: scroll;
cursor: default;
position: absolute;
right: 0;
left: 0;
top: 0;
bottom: 0;
}
.xterm .xterm-screen {
position: relative;
}
.xterm .xterm-screen canvas {
position: absolute;
left: 0;
top: 0;
}
.xterm .xterm-scroll-area {
visibility: hidden;
}
.xterm-char-measure-element {
display: inline-block;
visibility: hidden;
position: absolute;
top: 0;
left: -9999em;
line-height: normal;
}
.xterm.enable-mouse-events {
/* When mouse events are enabled (eg. tmux), revert to the standard pointer cursor */
cursor: default;
}
.xterm.xterm-cursor-pointer,
.xterm .xterm-cursor-pointer {
cursor: pointer;
}
.xterm.column-select.focus {
/* Column selection mode */
cursor: crosshair;
}
.xterm .xterm-accessibility,
.xterm .xterm-message {
position: absolute;
left: 0;
top: 0;
bottom: 0;
right: 0;
z-index: 10;
color: transparent;
pointer-events: none;
}
.xterm .live-region {
position: absolute;
left: -9999px;
width: 1px;
height: 1px;
overflow: hidden;
}
.xterm-dim {
/* Dim should not apply to background, so the opacity of the foreground color is applied
* explicitly in the generated class and reset to 1 here */
opacity: 1 !important;
}
.xterm-underline-1 { text-decoration: underline; }
.xterm-underline-2 { text-decoration: double underline; }
.xterm-underline-3 { text-decoration: wavy underline; }
.xterm-underline-4 { text-decoration: dotted underline; }
.xterm-underline-5 { text-decoration: dashed underline; }
.xterm-overline {
text-decoration: overline;
}
.xterm-overline.xterm-underline-1 { text-decoration: overline underline; }
.xterm-overline.xterm-underline-2 { text-decoration: overline double underline; }
.xterm-overline.xterm-underline-3 { text-decoration: overline wavy underline; }
.xterm-overline.xterm-underline-4 { text-decoration: overline dotted underline; }
.xterm-overline.xterm-underline-5 { text-decoration: overline dashed underline; }
.xterm-strikethrough {
text-decoration: line-through;
}
.xterm-screen .xterm-decoration-container .xterm-decoration {
z-index: 6;
position: absolute;
}
.xterm-screen .xterm-decoration-container .xterm-decoration.xterm-decoration-top-layer {
z-index: 7;
}
.xterm-decoration-overview-ruler {
z-index: 8;
position: absolute;
top: 0;
right: 0;
pointer-events: none;
}
.xterm-decoration-top {
z-index: 2;
position: relative;
}

2
Flask/static/node_modules/xterm/lib/xterm.js generated vendored Normal file

File diff suppressed because one or more lines are too long

1
Flask/static/node_modules/xterm/lib/xterm.js.map generated vendored Normal file

File diff suppressed because one or more lines are too long

100
Flask/static/node_modules/xterm/package.json generated vendored Normal file
View File

@ -0,0 +1,100 @@
{
"name": "xterm",
"description": "Full xterm terminal, in your browser",
"version": "5.3.0",
"main": "lib/xterm.js",
"style": "css/xterm.css",
"types": "typings/xterm.d.ts",
"repository": "https://github.com/xtermjs/xterm.js",
"license": "MIT",
"keywords": [
"cli",
"command-line",
"console",
"pty",
"shell",
"ssh",
"styles",
"terminal-emulator",
"terminal",
"tty",
"vt100",
"webgl",
"xterm"
],
"scripts": {
"prepackage": "npm run build",
"package": "webpack",
"package-headless": "webpack --config ./webpack.config.headless.js",
"postpackage-headless": "node ./bin/package_headless.js",
"start": "node demo/start",
"build-demo": "webpack --config ./demo/webpack.config.js",
"start-debug": "node --inspect-brk demo/start",
"lint": "eslint -c .eslintrc.json --max-warnings 0 --ext .ts src/ addons/",
"lint-api": "eslint --no-eslintrc -c .eslintrc.json.typings --max-warnings 0 --no-ignore --ext .d.ts typings/",
"test": "npm run test-unit",
"posttest": "npm run lint",
"test-api": "npm run test-api-chromium",
"test-api-chromium": "node ./bin/test_api.js --browser=chromium --timeout=20000",
"test-api-firefox": "node ./bin/test_api.js --browser=firefox --timeout=20000",
"test-api-webkit": "node ./bin/test_api.js --browser=webkit --timeout=20000",
"test-playwright": "playwright test -c ./out-test/playwright/playwright.config.js --workers 4",
"test-playwright-chromium": "playwright test -c ./out-test/playwright/playwright.config.js --workers 4 --project='Chrome Stable'",
"test-playwright-firefox": "playwright test -c ./out-test/playwright/playwright.config.js --workers 4 --project='Firefox Stable'",
"test-playwright-webkit": "playwright test -c ./out-test/playwright/playwright.config.js --workers 4 --project='WebKit'",
"test-playwright-debug": "playwright test -c ./out-test/playwright/playwright.config.js --headed --workers 1 --timeout 30000",
"test-unit": "node ./bin/test.js",
"test-unit-coverage": "node ./bin/test.js --coverage",
"test-unit-dev": "cross-env NODE_PATH='./out' mocha",
"build": "tsc -b ./tsconfig.all.json",
"install-addons": "node ./bin/install-addons.js",
"presetup": "npm run install-addons",
"setup": "npm run build",
"prepublishOnly": "npm run package",
"watch": "tsc -b -w ./tsconfig.all.json --preserveWatchOutput",
"benchmark": "NODE_PATH=./out xterm-benchmark -r 5 -c test/benchmark/benchmark.json",
"benchmark-baseline": "NODE_PATH=./out xterm-benchmark -r 5 -c test/benchmark/benchmark.json --baseline out-test/benchmark/test/benchmark/*benchmark.js",
"benchmark-eval": "NODE_PATH=./out xterm-benchmark -r 5 -c test/benchmark/benchmark.json --eval out-test/benchmark/test/benchmark/*benchmark.js",
"clean": "rm -rf lib out addons/*/lib addons/*/out",
"vtfeatures": "node bin/extract_vtfeatures.js src/**/*.ts src/*.ts"
},
"devDependencies": {
"@playwright/test": "^1.37.1",
"@types/chai": "^4.2.22",
"@types/debug": "^4.1.7",
"@types/deep-equal": "^1.0.1",
"@types/express": "4",
"@types/express-ws": "^3.0.1",
"@types/glob": "^7.2.0",
"@types/jsdom": "^16.2.13",
"@types/mocha": "^9.0.0",
"@types/node": "^18.16.0",
"@types/utf8": "^3.0.0",
"@types/webpack": "^5.28.0",
"@types/ws": "^8.2.0",
"@typescript-eslint/eslint-plugin": "^6.2.00",
"@typescript-eslint/parser": "^6.2.00",
"chai": "^4.3.4",
"cross-env": "^7.0.3",
"deep-equal": "^2.0.5",
"eslint": "^8.45.0",
"eslint-plugin-jsdoc": "^39.3.6",
"express": "^4.17.1",
"express-ws": "^5.0.2",
"glob": "^7.2.0",
"jsdom": "^18.0.1",
"mocha": "^10.1.0",
"mustache": "^4.2.0",
"node-pty": "^0.10.1",
"nyc": "^15.1.0",
"source-map-loader": "^3.0.0",
"source-map-support": "^0.5.20",
"ts-loader": "^9.3.1",
"typescript": "^5.1.6",
"utf8": "^3.0.0",
"webpack": "^5.61.0",
"webpack-cli": "^4.9.1",
"ws": "^8.2.3",
"xterm-benchmark": "^0.3.1"
}
}

26
Flask/static/package-lock.json generated Normal file
View File

@ -0,0 +1,26 @@
{
"name": "static",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"dependencies": {
"xterm": "^5.3.0",
"xterm-addon-fit": "^0.8.0"
}
},
"node_modules/xterm": {
"version": "5.3.0",
"resolved": "https://registry.npmjs.org/xterm/-/xterm-5.3.0.tgz",
"integrity": "sha512-8QqjlekLUFTrU6x7xck1MsPzPA571K5zNqWm0M0oroYEWVOptZ0+ubQSkQ3uxIEhcIHRujJy6emDWX4A7qyFzg=="
},
"node_modules/xterm-addon-fit": {
"version": "0.8.0",
"resolved": "https://registry.npmjs.org/xterm-addon-fit/-/xterm-addon-fit-0.8.0.tgz",
"integrity": "sha512-yj3Np7XlvxxhYF/EJ7p3KHaMt6OdwQ+HDu573Vx1lRXsVxOcnVJs51RgjZOouIZOczTsskaS+CpXspK81/DLqw==",
"peerDependencies": {
"xterm": "^5.0.0"
}
}
}
}

View File

@ -0,0 +1,6 @@
{
"dependencies": {
"xterm": "^5.3.0",
"xterm-addon-fit": "^0.8.0"
}
}

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 %}

View File

@ -1,35 +1,48 @@
{% extends "base.html" %} {% extends "base.html" %}
{% block left_pannel %}override{% endblock %} {% block left_pannel %}override{% endblock %}
{% block content %} {% block content %}
{%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 %}
<table> <link rel="stylesheet" href="{{ url_for('static', filename='css/vnc-post.css') }}"/>
<tr> <link rel="stylesheet" href="{{ url_for('static', filename='node_modules/xterm/css/xterm.css') }}"/>
<td width="20%" height="90%"> <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>
document.getElementsByClassName("content")[0].style.padding = "0 0"
</script>
<div class="container">
<div id="console"></div> <div id="console"></div>
</td> <div id="vnc-container">
<td width="80%"> <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"></iframe> width="100%" height="100%" frameborder="0">
</td> </iframe>
</tr> </div>
</table> </div>
<script>
var term = new Terminal();
const fitAddon = new FitAddon.FitAddon();
term.loadAddon(fitAddon);
term.open(document.getElementById('console'));
fitAddon.fit()
addEventListener("transitionend", (event) => {
fitAddon.fit()
});
document.getElementById("console").style.textAlign = "left"
<script>
const consoleElement = document.getElementById('console');
const eventSource = new EventSource('/stream'); const eventSource = new EventSource('/stream');
eventSource.onmessage = (event) => { eventSource.onmessage = (event) => {
document.getElementById("console").innerHTML = event.data + document.getElementById("console").innerHTML term.writeln(event.data)
}; };
addEventListener("resize", (event) => {
fitAddon.fit()
});
</script>
</script> {% endif %}
{% endif %} {% endblock %}
{%endblock %}

818
V6.py

File diff suppressed because it is too large Load Diff

View File

@ -1 +1,12 @@
sudo docker build --no-cache --network host -t msrewards . && sudo docker run -d --restart unless-stopped -p 1234:1234 -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;
add_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

19
docker-compose.yml Normal file
View File

@ -0,0 +1,19 @@
version: '3.8'
services:
msrewards:
build:
context: .
dockerfile: Dockerfile
# optional if you have Dockerfile in the same directory
# arguments:
# - ARG_NAME=value # If you have build arguments
image: msrewards
container_name: MsRewards
restart: unless-stopped
ports:
- "1234:1234"
- "2345:2345"
shm_size: 2gb
volumes:
- "./data/:/data"

12
hooks/bump.sh Executable file
View File

@ -0,0 +1,12 @@
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
hooks/pre-commit Executable file
View File

@ -0,0 +1 @@
sh hooks/bump.sh

View File

@ -1,15 +1,91 @@
import json import json
from discord import Webhook, RequestsWebhookAdapter
from modules.Classes.DiscordConfig import DiscordConfig, FakeWebHook
from modules.Classes.Driver import Driver
from modules.Classes.Proxy import Proxy
from modules.Classes.UserCredentials import UserCredentials from modules.Classes.UserCredentials import UserCredentials
from modules.Classes.WordList import WordList
class Config: class Config:
def __init__(self, args): def __init__(self, args):
"""
open config file
"""
with open("/app/MsRewards-Reborn/user_data/discord.json", "r") as inFile:
discord = json.load(inFile)
with open("/app/MsRewards-Reborn/user_data/settings.json", "r") as inFile:
settings = json.load(inFile)
with open("/app/MsRewards-Reborn/user_data/proxy.json", "r") as inFile:
proxy = json.load(inFile)
with open("/app/MsRewards-Reborn/user_data/configs.json", "r") as inFile:
config = json.load(inFile)
with open("/app/MsRewards-Reborn/user_data/version", "r") as inFile:
version = inFile.readline()
"""
setup standalone stuff
"""
self.args = args self.args = args
self.start = "json" if args.json else "default"
self.json_entry = args.json.replace("'", "\"")
self.wordlist = WordList("/usr/share/dict/french")
self.vnc = args.vnc
self.WebDriver = Driver()
self.display = None
self.version = version
"""
setup UserCredential
"""
self.UserCredentials = UserCredentials() self.UserCredentials = UserCredentials()
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)
for i in configs[str(args.config)]["accounts"]: for i in configs[str(args.config)]["accounts"]:
d = configs[str(args.config)]["accounts"][i] d = configs[str(args.config)]["accounts"][i]
self.UserCredentials.add(d["mail"], d["pwd"], d["2fa"]) self.UserCredentials.add(d["mail"], d["pwd"], d["2fa"])
"""
Setup discord
"""
self.discord = DiscordConfig()
self.discord.avatar_url = settings["avatarlink"]
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())
else:
self.discord.wh = FakeWebHook()
"""
setup proxy
"""
proxy_conf = config[args.config]["proxy"]
if proxy_conf != "-1":
proxy_address = proxy[config[args.config]["proxy"]]["address"]
proxy_port = proxy[config[args.config]["proxy"]]["port"]
else:
proxy_address = ""
proxy_port = ""
self.proxy = Proxy(proxy_conf, proxy_address, proxy_port)
def vnc_enabled(self):
return self.vnc != "None"
def set_display(self, display):
self.display = display
def has_been_updated(self):
with open('/app/MsRewards-Reborn/version', "r") as inFile:
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

View File

@ -0,0 +1,14 @@
from modules.Tools.logger import debug
class DiscordConfig:
def __init__(self):
self.avatar_url = ""
self.wh_link = None
self.wh = None
class FakeWebHook:
def send(self, *args, **kwargs):
debug(f"Used a webhook call without webhook url with {args} {kwargs}")

View File

@ -0,0 +1,36 @@
from discord import Embed, Colour, File
from modules.Classes.Config import Config
from modules.Tools.logger import error
from modules.Tools.tools import format_error
class DiscordLogger:
def __init__(self, config: Config):
self.config = config
def send(self, message: str):
driver = self.config.WebDriver.driver
if type(message) is not str:
message = format_error(message)
error(message)
with open("page.html", "w") as f:
try:
f.write(driver.page_source)
except Exception as e:
error(e)
f.write("the driver has closed or crashed. Can't access page content")
img = self.config.display.waitgrab()
img.save("screenshot.png")
embed = Embed(
title="An Error has occurred",
description=str(message),
colour=Colour.red(),
)
file = File("screenshot.png")
embed.set_image(url="attachment://screenshot.png")
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)

25
modules/Classes/Driver.py Normal file
View File

@ -0,0 +1,25 @@
class Driver:
def __init__(self):
self.pc_driver = None
self.mobile_driver = None
self.driver = None
def set_pc_driver(self, pc_driver):
self.pc_driver = pc_driver
def set_mobile_driver(self, mobile_driver):
self.mobile_driver = mobile_driver
def switch_to_driver(self, driver: str):
match driver.lower():
case "pc":
self.driver = self.pc_driver
case "mobile":
self.driver = self.mobile_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"

9
modules/Classes/Proxy.py Normal file
View File

@ -0,0 +1,9 @@
class Proxy:
def __init__(self, enabled: str, ip: str = None, port: str = None):
self.ip = ip
self.port = port
self.enabled = enabled != "-1"
def is_enabled(self):
return self.enabled

View File

@ -1,4 +1,5 @@
import json from pyotp import TOTP
from modules.Tools.logger import debug, warning from modules.Tools.logger import debug, warning
@ -9,7 +10,8 @@ class UserCredentials:
self.total = 0 self.total = 0
def add(self, username: str, password: str, tfa: str = None): def add(self, username: str, password: str, tfa: str = None):
debug(f"adding account with data : Username: {username}, Password: {password}, 2FA: {'None' if tfa == '' else tfa}") debug(
f"adding account with data : Username: {username}, Password: {password}, 2FA: {'None' if tfa == '' else tfa}")
self.data[self.total] = { self.data[self.total] = {
"username": username, "username": username,
"password": password, "password": password,
@ -28,12 +30,17 @@ 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 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
if self.is_valid():
debug(f"New credentials: {self.data[self.current]}") debug(f"New credentials: {self.data[self.current]}")
else:
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,13 @@
import random
class WordList:
def __init__(self, path):
with open(path, "r", encoding="utf-8") as h:
lines = h.readlines()
self.words = [x.replace('\n', "") for x in lines]
random.shuffle(self.words)
def get_word(self):
return self.words.pop(0)

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

@ -29,8 +29,8 @@ class ColoredFormatter(logging.Formatter):
# Set up the root logger # Set up the root logger
root_logger = logging.getLogger() 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()

36
modules/Tools/tools.py Normal file
View File

@ -0,0 +1,36 @@
from time import sleep
from modules.Tools.logger import info, error
# return current page domain
def get_domain(driver):
return driver.current_url.split("/")[2]
def custom_sleep(temps):
try:
if False: # todo: change this awful condition
points = ["", "", "", "", "", "", "", ""]
passe = 0
for _ in range(int(temps)):
for i in range(8):
sleep(0.125)
passe += 0.125
print(f"{points[i]} - {round(float(temps) - passe, 3)}", end="\r")
print(" ", end="\r")
else:
sleep(temps)
except KeyboardInterrupt:
info("Wait canceled.")
except Exception as err:
error(err)
def format_error(e) -> str:
tb = e.__traceback__
txt = ""
while tb is not None:
txt = txt + f" -> {tb.tb_frame.f_code.co_name} ({tb.tb_lineno}) "
tb = tb.tb_next
return txt + "\n" + str(e)

View File

@ -0,0 +1,50 @@
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")

View File

@ -1,14 +1,5 @@
#!/usr/bin/python3.10 #!/usr/bin/python3.10
from modules.driver_tools import *
from modules.imports import * from modules.imports import *
import modules.globals as g
import json
class FakeWebHook:
def send(self, text="", username='', avatar_url='', embed="", file=""):
print(text)
parser = argparse.ArgumentParser() parser = argparse.ArgumentParser()
@ -39,69 +30,4 @@ parser.add_argument(
default="" default=""
) )
with open("/app/MsRewards-Reborn/user_data/discord.json", "r") as inFile:
discord = json.load(inFile)
with open("/app/MsRewards-Reborn/user_data/settings.json", "r") as inFile:
settings = json.load(inFile)
with open("/app/MsRewards-Reborn/user_data/proxy.json", "r") as inFile:
proxy = json.load(inFile)
with open("/app/MsRewards-Reborn/user_data/configs.json", "r") as inFile:
config = json.load(inFile)
args = parser.parse_args() args = parser.parse_args()
g.json_start = args.json
g.vnc_enabled = args.vnc != "None"
g.vnc_port = args.vnc
g.update_version = args.update_version
# global variables used later in the code
g.start_time = time()
# path configurations
g.mot_path = "/usr/share/dict/french"
g.credential_path = "/app/MsRewards-Reborn/user_data/login.csv"
discord_conf = config[args.config]["discord"]
# discord configuration
g.discord_success_link = discord[discord_conf]["successL"]
g.discord_error_link = discord[discord_conf]["errorsL"]
g.discord_enabled_error = discord[discord_conf]["errorsT"] == "True"
g.discord_enabled_success = discord[discord_conf]["successT"] == "True"
g.avatar_url = settings["avatarlink"]
if not g.json_start:
if g.discord_enabled_error:
webhookFailure = Webhook.from_url(g.discord_error_link, adapter=RequestsWebhookAdapter())
if g.discord_enabled_success:
webhookSuccess = Webhook.from_url(g.discord_success_link, adapter=RequestsWebhookAdapter())
else:
webhookFailure = FakeWebHook()
webhookSuccess = FakeWebHook()
# base settings
g.discord_embed = False # send new point value in an embed, fixed for now
g.headless = False
# proxy settings
g.proxy_enabled = config[args.config]["proxy"] != "-1"
if g.proxy_enabled:
g.proxy_address = proxy[config[args.config]["proxy"]]["address"]
g.proxy_port = proxy[config[args.config]["proxy"]]["port"]
# list of words
with open(g.mot_path, "r", encoding="utf-8") as h:
lines = h.readlines()
if len(lines) < 3:
Liste_de_mot = list(lines[0].split(","))
else:
Liste_de_mot = [x.replace('\n', "") for x in lines]
if g.proxy_enabled:
setup_proxy(g.proxy_address, g.proxy_port)

View File

@ -1,67 +1,66 @@
import sqlite3 import sqlite3
#Create a new row, for the account [compte] whith [points] points
def add_row(compte, points, mycursor, mydb): # Create a new row, for the account [compte] whith [points] points
def add_row(account, points, mycursor, mydb):
sql = "INSERT INTO daily (compte, points, date) VALUES (?, ?, date())" sql = "INSERT INTO daily (compte, points, date) VALUES (?, ?, date())"
val = (compte, points) val = (account, points)
mycursor.execute(sql, val) mycursor.execute(sql, val)
mydb.commit() mydb.commit()
#printf(mycursor.rowcount, "record created.") # printf(mycursor.rowcount, "record created.")
#update the ammount of points for the account [compte] # update the ammount of points for the account [compte]
def update_row(compte, points, mycursor, mydb): def update_row(account, points, mycursor, mydb):
sql = f"UPDATE daily SET points = {points} WHERE compte = '{compte}' AND date = date() ;" sql = f"UPDATE daily SET points = {points} WHERE compte = '{account}' AND date = date() ;"
mycursor.execute(sql) mycursor.execute(sql)
mydb.commit() mydb.commit()
#printf(mycursor.rowcount, "record(s) updated")
# update the value of last_pts for the table comptes # update the value of last_pts for the table comptes
def update_last(compte, points, mycursor, mydb): def update_last(account, points, mycursor, mydb):
sql1 = f"UPDATE comptes SET last_pts = {points} WHERE compte = '{compte}';" sql1 = f"UPDATE comptes SET last_pts = {points} WHERE compte = '{account}';"
sql2 = f"select * from comptes where compte = '{compte}'" sql2 = f"select * from comptes where compte = '{account}'"
sql3 = f"INSERT INTO comptes (compte, last_pts,banned) VALUES ('{compte}', {points}, 0)" sql3 = f"INSERT INTO comptes (compte, last_pts,banned) VALUES ('{account}', {points}, 0)"
cmd = mycursor.execute(sql2) cmd = mycursor.execute(sql2)
if len(list(cmd)) == 0: if len(list(cmd)) == 0:
mycursor.execute(sql3) mycursor.execute(sql3)
else : else:
mycursor.execute(sql1) mycursor.execute(sql1)
mydb.commit() mydb.commit()
#printf(mycursor.rowcount, "record(s) updated")
# if return if there already is a line in the database for the account [compte]. if same_point is enabled, the line must also have the same number of points
# Return if there already is a line in the database for the account [account].
# if same_point is enabled, the line must also have the same number of points
# SQLITE # SQLITE
def get_row(compte, points, mycursor, same_points = True): def get_row(account, points, mycursor, same_points=True):
if same_points : if same_points:
mycursor.execute(f"SELECT * FROM daily WHERE points = {points} AND compte = '{compte}' AND date = date() ;") mycursor.execute(f"SELECT * FROM daily WHERE points = {points} AND compte = '{account}' AND date = date() ;")
else : else:
mycursor.execute(f"SELECT * FROM daily WHERE compte = '{compte}' AND date = date() ;") mycursor.execute(f"SELECT * FROM daily WHERE compte = '{account}' AND date = date() ;")
myresult = mycursor.fetchall() myresult = mycursor.fetchall()
return(len(myresult) == 1) return (len(myresult) == 1)
def add_to_database(compte, points, save_if_fail=True): def add_to_database(account, points):
if points is None: if points is None:
pass pass
else: else:
mydb = sqlite3.connect("/app/MsRewards-Reborn/MsRewards.db") mydb = sqlite3.connect("/app/MsRewards-Reborn/MsRewards.db")
mycursor = mydb.cursor() mycursor = mydb.cursor()
if get_row(compte, points,mycursor, True): #check if the row exist with the same ammount of points and do nothind if it does
#printf("les points sont deja bon") if get_row(account, points, mycursor, True):
#return(0) # check if the row exist with the same amount of points and do nothing if it does
pass pass
elif get_row(compte, points,mycursor, False) : #check if the row exist, but without the same ammount of points and update the point account then
update_row(compte, points,mycursor,mydb) # check if the row exist, but without the same amount of points and update the point account then
#printf("row updated") elif get_row(account, points, mycursor, False):
#return(1) update_row(account, points, mycursor, mydb)
else : # if the row don't exist, create it with the good ammount of points
add_row(compte, points,mycursor,mydb) else: # if the row don't exist, create it with the good amount of points
#return(2) #printf("row added") add_row(account, points, mycursor, mydb)
if int(points) > 10 :
update_last(compte, points, mycursor, mydb) if int(points) > 10:
update_last(account, points, mycursor, mydb)
mycursor.close() mycursor.close()
mydb.close() mydb.close()

View File

@ -1,96 +1,87 @@
from modules.imports import * import json
from modules.config import * import os
from modules.tools import * from random import uniform
import modules.globals as g
from selenium.common import TimeoutException
from selenium.webdriver import Keys
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions
from selenium.webdriver.support.wait import WebDriverWait
from modules.Tools.logger import debug
from modules.Tools.tools import *
def set_language(ldriver): def init_profile(mail, mobile=False):
ldriver.get("chrome://settings/languages") if not mobile:
action = ActionChains(ldriver) chrome_profile_dir = "/app/MsRewards-Reborn/user_data/profile/" + mail
action.reset_actions() else:
# select language chrome_profile_dir = "/app/MsRewards-Reborn/user_data/profile/mobile-" + mail
x_coord = 1200
y_coord = 150
action.move_by_offset(x_coord, y_coord).click().perform()
sleep(0.5)
# scroll down
action.reset_actions()
elm = ldriver.find_element(By.XPATH, "/html/body")
ActionChains(ldriver)\
.send_keys("french")\
.pause(0.5)\
.send_keys(Keys.TAB + Keys.TAB + Keys.ENTER + Keys.TAB + Keys.TAB + Keys.ENTER)\
.perform()
x_coord = 1163
y_coord = 717
action.move_by_offset(x_coord, y_coord).click().perform()
# put to the top
sleep(0.5)
action.reset_actions()
x_coord = 1257
y_coord = 328
action.move_by_offset(x_coord, y_coord).click().perform()
action.click().perform()
os.makedirs(chrome_profile_dir, exist_ok=True)
def setup_proxy(ip: str, port: str) -> None: preferences_file = os.path.join(chrome_profile_dir, "Default", "Preferences")
PROXY = f"{ip}:{port}" if not os.path.exists(preferences_file):
webdriver.DesiredCapabilities.FIREFOX['proxy'] = { os.makedirs(os.path.join(chrome_profile_dir, "Default"), exist_ok=True)
"httpProxy": PROXY, with open(preferences_file, "w") as f:
"sslProxy": PROXY, json.dump(
"proxyType": "MANUAL", {
"intl": {
"accept_languages": "fr-FR,en-US,en",
"selected_languages": "fr-FR,en-US,en"
} }
}, f
)
else:
with open(preferences_file, "r") as f:
settings = json.load(f)
if "intl" not in settings:
settings["intl"] = {}
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
def rgpd_popup(driver) -> None: def rgpd_popup(config) -> None:
for i in ["bnp_btn_accept", "bnp_hfly_cta2", "bnp_hfly_close"] : for i in ["bnp_btn_accept", "bnp_hfly_cta2", "bnp_hfly_close"]:
try: try:
driver.find_element(By.ID, i).click() config.WebDriver.driver.find_element(By.ID, i).click()
except: except Exception as err:
pass debug(err)
# save webdriver cookies
def save_cookies(driver) -> None:
if g.dev:
f = open(f"{'/'.join(__file__.split('/')[:-2])}/user_data/cookies/{g._mail}_unsafe.pkl", "w")
for i in driver.get_cookies():
f.write(str(i) + "\n")
f.close()
else :
pickle.dump(driver.get_cookies(), open(f"{'/'.join(__file__.split('/')[:-2])}/user_data/cookies/{g._mail}.pkl", "wb"))
# load cookies previously saved to the driver
def load_cookies(driver) -> None:
if g.dev:
f = open(f"{'/'.join(__file__.split('/')[:-2])}/user_data/cookies/{g._mail}_unsafe.pkl", "r")
lines = f.readlines()
f.close()
cookies = [literal_eval(x) for x in lines]
else :
cookies = pickle.load(open(f"{'/'.join(__file__.split('/')[:-2])}/user_data/cookies/{g._mail}.pkl", "rb"))
for cookie in cookies:
driver.add_cookie(cookie)
""" """
send_keys_wait([selenium element:element, str:keys]) send the different keys to the field element, with a random time between each press to simulate human action. send_keys_wait([selenium element:element, str:keys]) send the different keys to the field element, with a random
time between each press to simulate human action.
keys can be an string, but also selenium keys keys can be an string, but also selenium keys
""" """
def send_keys_wait(element, keys: str) -> None: def send_keys_wait(element, keys: str) -> None:
for i in keys: for i in keys:
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 = 20, browser = None) -> None: def wait_until_visible(search_by: str, identifier: str, timeout: int = 20, browser=None, raise_error=True) -> bool:
try : try:
WebDriverWait(browser, timeout).until(EC.visibility_of_element_located((search_by,identifier)), "element not found") WebDriverWait(browser, timeout).until(
return(True) expected_conditions.visibility_of_element_located((search_by, identifier)), "element not found")
return True
except TimeoutException as e: except TimeoutException as e:
printf(f"element {identifier} not found after {timeout}s") f = error if raise_error else debug
return(False) f(f"element {identifier} not found after {timeout}s")
return False

View File

@ -1,8 +1,10 @@
class Banned(Exception): class Banned(Exception):
pass pass
class NotBanned(Exception): class NotBanned(Exception):
pass pass
class Identity(Exception): class Identity(Exception):
pass pass

View File

@ -1,30 +0,0 @@
driver = None
display = None
log = False
full_log = False
vnc_enabled = False
vnc_port = 2345
points_file = "/"
update_version = False
start_time = 0
mot_path = "/"
credential_path = "/"
discord_success_link = "https://example.com"
discord_error_link = "https://example.com"
discord_enabled_error = False
discord_enabled_success = False
avatar_url = ""
fidelity_link = "None"
discord_embed = False
headless = False
proxy_enabled = False
proxy_address = "0.0.0.0"
proxy_port = "0"
sql_enabled = False
sql_usr = "None"
sql_pwd = "azerty"
sql_host = "https://example.com"
sql_database = "MsRewards"
norvege = False
database_error_override = False
json_start = ""

View File

@ -1,82 +0,0 @@
from modules.imports import *
from modules.config import *
from modules.db import *
import modules.globals as g
# add the time arround the text given in [text]&
def Timer(text: str) -> str:
return(f"[{g._mail.split('@')[0]} - {datetime.today().strftime('%d/%m')} - {timedelta(seconds = round(float(time() - g.start_time)))}] " + str(text))
# replace the function print, with more options
# [txt] : string, [driver] : selenium webdriver
def printf(txt):
print(Timer(txt))
# return current page domain
def get_domain(driver):
return(driver.current_url.split("/")[2])
# check if the user is using IPV4 using ipify.org
# [driver] : selenium webdriver
# never used here
# can be useful as Ms had issues with IPV6 at some point
def check_ipv4(driver):
driver.get("https://api64.ipify.org")
elm = driver.find_element(By.TAG_NAME, "body")
if len(elm.text.split('.')) == 4 :
return True
return False
def custom_sleep(temps):
try :
if g.log : #only print sleep when user see it
points = ["", "", "", "", "", "", "", ""]
passe = 0
for i in range(int(temps)):
for i in range(8):
sleep(0.125)
passe += 0.125
print(f"{points[i]} - {round(float(temps) - passe, 3)}", end="\r")
print(" ", end="\r")
else:
sleep(temps)
except KeyboardInterrupt :
print("attente annulée")
def format_error(e) -> str:
tb = e.__traceback__
txt = ""
while tb != None :
txt = txt + f" -> {tb.tb_frame.f_code.co_name} ({tb.tb_lineno}) "
tb = tb.tb_next
return(txt + "\n" + str(e))
def progressBar(current, total=30, barLength=20, name="Progress"):
percent = float(current + 1) * 100 / total
arrow = "-" * int(percent / 100 * barLength - 1) + ">"
spaces = " " * (barLength - len(arrow))
print(name + ": [%s%s] %d %%" % (arrow, spaces, percent), end="\r")
def save_points_from_file(file):
with open(file) as f:
read = reader(f)
points_list = list(read)
for item in points_list:
compte, points = item[0], item[1]
add_to_database(compte, points, g.sql_host,g.sql_usr,g.sql_pwd,g.sql_database, save_if_fail=False)
with open(file, "w") as f:
f.write("")
def select_accounts(multiple = True):
system("clear") # clear from previous command to allow a clean choice
emails = [x[0] for x in g._cred] # list of all email adresses
emails_selected = enquiries.choose(f"quel{'s' if multiple else ''} compte{'s' if multiple else ''} ?", emails, multi=multiple)
return([x for x in g._cred if x[0] in emails_selected])

View File

@ -4,7 +4,7 @@ selenium
pillow pillow
pyvirtualdisplay pyvirtualdisplay
undetected_chromedriver undetected_chromedriver
requests requests>=2.31.0
flask flask
flask_sse flask_sse
EasyProcess EasyProcess

File diff suppressed because it is too large Load Diff

1
user_data/version Normal file
View File

@ -0,0 +1 @@
0.0.0

View File

@ -1 +1 @@
v6.8.0 v6.8.65