mirror of
				https://gitea.augustin64.fr/piair/MsRewards-Reborn.git
				synced 2025-10-31 14:23:53 +01:00 
			
		
		
		
	Compare commits
	
		
			31 Commits
		
	
	
		
			dev
			...
			c5e9fb1267
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | c5e9fb1267 | ||
|  | 6ade73617a | ||
|  | 37e8f6f61b | ||
|  | db6fa9b6b0 | ||
|  | d6988c03b4 | ||
|  | 449d2da410 | ||
|  | 3eb193eca3 | ||
|  | f566b2eeda | ||
|  | 52e88f81b9 | ||
|  | 1a8137783c | ||
|  | 6f13b2532d | ||
|  | 3978c44bbc | ||
|  | 49dc53ed32 | ||
|  | ba66a96c65 | ||
|  | db157771de | ||
|  | cbd1ad93a6 | ||
|  | afabd94f0d | ||
|  | 81deaf05b0 | ||
|  | 9af0f4aadb | ||
|  | 1d16294c04 | ||
|  | fae2033061 | ||
|  | 50c4036c73 | ||
|  | c683472895 | ||
|  | 178f2d472a | ||
|  | d3137f858a | ||
|  | d2ad467d4e | ||
|  | b45e9e549f | ||
|  | 200b0d8a86 | ||
|  | 4a5af6455d | ||
|  | 49b691d736 | ||
|  | 9549a6dea3 | 
							
								
								
									
										2
									
								
								.dockerignore
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								.dockerignore
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,2 @@ | |||||||
|  | **/.venv | ||||||
|  | user_data/* | ||||||
							
								
								
									
										4
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -3,18 +3,16 @@ 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 | ||||||
							
								
								
									
										49
									
								
								Dockerfile
									
									
									
									
									
								
							
							
						
						
									
										49
									
								
								Dockerfile
									
									
									
									
									
								
							| @@ -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/ | ||||||
|   | |||||||
							
								
								
									
										101
									
								
								Flask/app.py
									
									
									
									
									
								
							
							
						
						
									
										101
									
								
								Flask/app.py
									
									
									
									
									
								
							| @@ -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() | ||||||
|   | |||||||
							
								
								
									
										17
									
								
								Flask/static/css/vnc-post.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								Flask/static/css/vnc-post.css
									
									
									
									
									
										Normal 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%; | ||||||
|  | } | ||||||
| @@ -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 %} | ||||||
| @@ -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 style="height: 100%"> |         <div class="container"> | ||||||
|  |             <div id="console"></div> | ||||||
|             <div id="console" style="height: 100%; width: 20%; float:left;"></div> |             <div id="vnc-container"> | ||||||
|  |  | ||||||
|             <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"></iframe> |                         width="100%" height="100%" frameborder="0"> | ||||||
|  |                 </iframe> | ||||||
|             </div> |             </div> | ||||||
|         </div> |         </div> | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										100
									
								
								V6.py
									
									
									
									
									
								
							
							
						
						
									
										100
									
								
								V6.py
									
									
									
									
									
								
							| @@ -1,4 +1,4 @@ | |||||||
| #!/usr/bin/python3.10 | #!/usr/bin/python3 | ||||||
| from modules.Classes.Config import Config | from modules.Classes.Config import Config | ||||||
| from modules.Classes.DiscordLogger import DiscordLogger | from modules.Classes.DiscordLogger import DiscordLogger | ||||||
| from modules.Classes.UserCredentials import UserCredentials | from modules.Classes.UserCredentials import UserCredentials | ||||||
| @@ -22,16 +22,33 @@ def create_driver(mobile=False): | |||||||
|         "AppleWebKit/537.36 (KHTML, like Gecko)" |         "AppleWebKit/537.36 (KHTML, like Gecko)" | ||||||
|         "Chrome/22 Mobile Safari/537.36" |         "Chrome/22 Mobile Safari/537.36" | ||||||
|     ) |     ) | ||||||
|     chrome_options = webdriver.ChromeOptions() |  | ||||||
|  |     chrome_profile_dir = init_profile(config.UserCredentials.get_mail(), 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: | ||||||
|         chrome_options.add_argument(f"--user-agent={mobile_user_agent}") |         arguments.append(f"--user-agent={mobile_user_agent}") | ||||||
|     else: |     else: | ||||||
|         chrome_options.add_argument(f"--user-agent={pc_user_agent}") |         arguments.append(f"--user-agent={pc_user_agent}") | ||||||
|  |  | ||||||
|     # disabled as it may cause detection |     # disabled as it may cause detection | ||||||
|     if config.proxy.is_enabled(): |     if config.proxy.is_enabled(): | ||||||
|         chrome_options.add_argument(f'--proxy-server={config.proxy.ip}:{config.proxy.port}') |         arguments.append(f'--proxy-server={config.proxy.ip}:{config.proxy.port}') | ||||||
|  |  | ||||||
|  |     chrome_options = webdriver.ChromeOptions() | ||||||
|  |     for arg in arguments: | ||||||
|  |         chrome_options.add_argument(arg) | ||||||
|  |  | ||||||
|     driver = uc.Chrome(options=chrome_options) |     driver = uc.Chrome(options=chrome_options) | ||||||
|     set_language(driver) |  | ||||||
|     return driver |     return driver | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -152,7 +169,7 @@ def play_quiz4(override: int = None): | |||||||
|     except Exception as e: |     except Exception as e: | ||||||
|         log_error(e) |         log_error(e) | ||||||
|         raise ValueError(e) |         raise ValueError(e) | ||||||
|     info("Quiz 8 done.") |     info("Quiz 4 done.") | ||||||
|     custom_sleep(3) |     custom_sleep(3) | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -165,6 +182,8 @@ def do_poll(): | |||||||
|         try: |         try: | ||||||
|             answer_elem.click() |             answer_elem.click() | ||||||
|         except exceptions.ElementNotInteractableException: |         except exceptions.ElementNotInteractableException: | ||||||
|  |             warning("element not clickable. Waiting a bit and retrying.") | ||||||
|  |             custom_sleep(uniform(2, 2.5)) | ||||||
|             driver.execute_script("arguments[0].click();", answer_elem) |             driver.execute_script("arguments[0].click();", answer_elem) | ||||||
|         custom_sleep(uniform(2, 2.5)) |         custom_sleep(uniform(2, 2.5)) | ||||||
|     except Exception as err: |     except Exception as err: | ||||||
| @@ -190,7 +209,7 @@ def all_cards(): | |||||||
|         info("no promo card") |         info("no promo card") | ||||||
|  |  | ||||||
|     if len(card_list) < 10:  # most likely an error during loading |     if len(card_list) < 10:  # most likely an error during loading | ||||||
|         if "suspendu" in driver.page_source: |         if "suspendu" in driver.page_source or "suspended" in driver.page_source: | ||||||
|             raise Banned() |             raise Banned() | ||||||
|         driver.refresh() |         driver.refresh() | ||||||
|         card_list = driver.find_elements(By.CLASS_NAME, "c-card-content") |         card_list = driver.find_elements(By.CLASS_NAME, "c-card-content") | ||||||
| @@ -360,22 +379,35 @@ def login_part_1(): | |||||||
|     driver = config.WebDriver.driver |     driver = config.WebDriver.driver | ||||||
|     driver.get("https://login.live.com") |     driver.get("https://login.live.com") | ||||||
|     wait_until_visible(By.ID, "i0116", browser=driver) |     wait_until_visible(By.ID, "i0116", browser=driver) | ||||||
|     mail_elem = driver.find_element(By.ID, "i0116") |     send_wait_and_confirm( | ||||||
|     send_keys_wait(mail_elem, config.UserCredentials.get_mail()) |         driver.find_element(By.ID, "i0116"), | ||||||
|     mail_elem.send_keys(Keys.ENTER) |         config.UserCredentials.get_mail() | ||||||
|  |     ) | ||||||
|     wait_until_visible(By.ID, "i0118", browser=driver) |     wait_until_visible(By.ID, "i0118", browser=driver) | ||||||
|     pwd_elem = driver.find_element(By.ID, "i0118") |     send_wait_and_confirm( | ||||||
|     send_keys_wait(pwd_elem, config.UserCredentials.get_password()) |         driver.find_element(By.ID, "i0118"), | ||||||
|     pwd_elem.send_keys(Keys.ENTER) |         config.UserCredentials.get_password() | ||||||
|     custom_sleep(2) |     ) | ||||||
|     # 2FA |     # 2FA | ||||||
|     if "Entrez le code de sécurité" in driver.page_source: |     try: | ||||||
|         try: |         if not wait_until_visible(By.ID, "idTxtBx_SAOTCC_OTC", browser=driver, timeout=5, raise_error=False): | ||||||
|             a2f_elem = driver.find_element(By.ID, "idTxtBx_SAOTCC_OTC") |             custom_sleep(2) | ||||||
|             a2f_elem.send_keys(config.UserCredentials.get_tfa().now()) |             return | ||||||
|             a2f_elem.send_keys(Keys.ENTER) |  | ||||||
|         except Exception as err: |         tfa = config.UserCredentials.get_tfa() | ||||||
|             log_error(err) |         if tfa is None: | ||||||
|  |             error("2FA needed but no code available for this account, sending error") | ||||||
|  |             raise ValueError("2FA needed but no code available for this account") | ||||||
|  |         else: | ||||||
|  |             a2f_code = tfa.now() | ||||||
|  |  | ||||||
|  |         info(f"Need 2FA, I have code: {a2f_code}") | ||||||
|  |         send_wait_and_confirm( | ||||||
|  |             driver.find_element(By.ID, "idTxtBx_SAOTCC_OTC"), | ||||||
|  |             a2f_code | ||||||
|  |         ) | ||||||
|  |     except Exception as err: | ||||||
|  |         log_error(err) | ||||||
|  |  | ||||||
|  |  | ||||||
| # Accept all cookies question, and check if the account is locked | # Accept all cookies question, and check if the account is locked | ||||||
| @@ -410,9 +442,17 @@ def login_part_2(): | |||||||
| # login() tries to login to your Microsoft account. | # login() tries to login to your Microsoft account. | ||||||
| # it uses global variable g._mail and g._password to login | # it uses global variable g._mail and g._password to login | ||||||
| def login(): | def login(): | ||||||
|  |     def logged_in(): | ||||||
|  |         driver.get("https://login.live.com") | ||||||
|  |         custom_sleep(10) | ||||||
|  |         if get_domain(driver) == "account.microsoft.com": | ||||||
|  |             return True | ||||||
|  |         return False | ||||||
|  |  | ||||||
|     driver = config.WebDriver.driver |     driver = config.WebDriver.driver | ||||||
|     try: |     try: | ||||||
|         login_part_1() |         if not logged_in(): | ||||||
|  |             login_part_1() | ||||||
|         login_part_2() |         login_part_2() | ||||||
|         driver.get("https://rewards.bing.com/") |         driver.get("https://rewards.bing.com/") | ||||||
|     except Banned: |     except Banned: | ||||||
| @@ -610,9 +650,11 @@ def daily_routine(cred: UserCredentials, custom=False): | |||||||
|     try: |     try: | ||||||
|         if not custom:  # custom already is logged in |         if not custom:  # custom already is logged in | ||||||
|             login() |             login() | ||||||
|  |  | ||||||
|     except Banned: |     except Banned: | ||||||
|         log_error("This account is locked.") |         log_error("This account is locked.") | ||||||
|         return |         raise Banned() | ||||||
|  |  | ||||||
|     except Identity: |     except Identity: | ||||||
|         log_error("This account has an issue.") |         log_error("This account has an issue.") | ||||||
|         return |         return | ||||||
| @@ -666,7 +708,7 @@ def json_start(json_entry, cred: UserCredentials): | |||||||
|             config.WebDriver.switch_to_driver("PC") |             config.WebDriver.switch_to_driver("PC") | ||||||
|             driver = config.WebDriver.driver |             driver = config.WebDriver.driver | ||||||
|             try: |             try: | ||||||
|                 if str(account_id) in json_entry["unban"]: |                 if "unban" in json_entry and str(account_id) in json_entry["unban"]: | ||||||
|                     login_part_1() |                     login_part_1() | ||||||
|                     info("\nGO TO example.com TO PROCEED or wait 1200 secs.") |                     info("\nGO TO example.com TO PROCEED or wait 1200 secs.") | ||||||
|                     for _ in range(1200): |                     for _ in range(1200): | ||||||
| @@ -680,7 +722,7 @@ def json_start(json_entry, cred: UserCredentials): | |||||||
|                 login() |                 login() | ||||||
|             try: |             try: | ||||||
|                 if str(account_id) in json_entry["tout"]: |                 if str(account_id) in json_entry["tout"]: | ||||||
|                     daily_routine(cred) |                     daily_routine(cred, True) | ||||||
|             except KeyError: |             except KeyError: | ||||||
|                 pass |                 pass | ||||||
|             else: |             else: | ||||||
| @@ -744,12 +786,16 @@ def default_start(): | |||||||
|             config.WebDriver.pc_driver.quit() |             config.WebDriver.pc_driver.quit() | ||||||
|             config.display.stop() |             config.display.stop() | ||||||
|             break |             break | ||||||
|  |         except Banned: | ||||||
|  |             warning("this account is banned. Switching to next account") | ||||||
|         except Exception as e: |         except Exception as e: | ||||||
|             log_error(f"Error not caught. Skipping this account. " + format_error(e)) |             log_error(f"Error not caught. Skipping this account. " + format_error(e)) | ||||||
|             critical(f"Error not caught. Skipping this account. {e}") |             critical(f"Error not caught. Skipping this account. {e}") | ||||||
|             config.WebDriver.pc_driver.quit() |             config.WebDriver.pc_driver.quit() | ||||||
|  |  | ||||||
|         config.UserCredentials.next_account() |         finally: | ||||||
|  |             config.UserCredentials.next_account() | ||||||
|  |  | ||||||
|     config.display.stop() |     config.display.stop() | ||||||
|  |  | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										13
									
								
								build.sh
									
									
									
									
									
								
							
							
						
						
									
										13
									
								
								build.sh
									
									
									
									
									
								
							| @@ -1 +1,12 @@ | |||||||
| sudo docker build --no-cache --network host -t msrewards . && sudo docker run -d --restart unless-stopped -p 1234:1234 -p 2345:2345 -ti --shm-size=2gb --name MsRewards msrewards  | #!/bin/bash | ||||||
|  |  | ||||||
|  | docker-do () { # Check if sudo needs to be used | ||||||
|  |     if id -nG "$(whoami)" | grep -qw "docker"; then | ||||||
|  |         docker $@ | ||||||
|  |     else | ||||||
|  |         sudo docker $@ | ||||||
|  |     fi | ||||||
|  | } | ||||||
|  |  | ||||||
|  | docker-do build --network host -t msrewards . | ||||||
|  | docker-do run -d --restart unless-stopped -p 1234:1234 -p 2345:2345 -ti --shm-size=2gb --name MsRewards msrewards  | ||||||
|   | |||||||
							
								
								
									
										13
									
								
								clean.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										13
									
								
								clean.sh
									
									
									
									
									
										Executable 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 | ||||||
| @@ -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  | ||||||
|   | |||||||
							
								
								
									
										1459
									
								
								config/grafana.ini
									
									
									
									
									
								
							
							
						
						
									
										1459
									
								
								config/grafana.ini
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -50,9 +50,14 @@ class Config: | |||||||
|         """ |         """ | ||||||
|         self.discord = DiscordConfig() |         self.discord = DiscordConfig() | ||||||
|         self.discord.avatar_url = settings["avatarlink"] |         self.discord.avatar_url = settings["avatarlink"] | ||||||
|         self.discord.wh_link = discord[config[args.config]["discord"]]["errorsL"] |  | ||||||
|  |  | ||||||
|         if self.discord.wh_link != "": |         if ( | ||||||
|  |             "discord" in config[args.config] | ||||||
|  |             and config[args.config]["discord"] in discord | ||||||
|  |             and "errorsL" in discord[config[args.config]["discord"]] | ||||||
|  |             and discord[config[args.config]["discord"]]["errorsL"] != "" | ||||||
|  |             ): | ||||||
|  |             self.discord.wh_link = discord[config[args.config]["discord"]]["errorsL"] | ||||||
|             self.discord.wh = Webhook.from_url(self.discord.wh_link, adapter=RequestsWebhookAdapter()) |             self.discord.wh = Webhook.from_url(self.discord.wh_link, adapter=RequestsWebhookAdapter()) | ||||||
|         else: |         else: | ||||||
|             self.discord.wh = FakeWebHook() |             self.discord.wh = FakeWebHook() | ||||||
|   | |||||||
| @@ -9,6 +9,6 @@ class DiscordConfig: | |||||||
|  |  | ||||||
|  |  | ||||||
| class FakeWebHook: | class FakeWebHook: | ||||||
|     def send(self, *args): |     def send(self, *args, **kwargs): | ||||||
|         debug(f"Used a webhook call without webhook url with {args}") |         debug(f"Used a webhook call without webhook url with {args} {kwargs}") | ||||||
|          |          | ||||||
|   | |||||||
| @@ -30,7 +30,7 @@ class DiscordLogger: | |||||||
|         ) |         ) | ||||||
|         file = File("screenshot.png") |         file = File("screenshot.png") | ||||||
|         embed.set_image(url="attachment://screenshot.png") |         embed.set_image(url="attachment://screenshot.png") | ||||||
|         embed.set_footer(text=self.config.UserCredentials.creds.get_mail()) |         embed.set_footer(text=self.config.UserCredentials.get_mail() + " - " + self.config.WebDriver.current_driver()) | ||||||
|  |  | ||||||
|         self.config.discord.wh.send(embed=embed, username="error", file=file, avatar_url=self.config.discord.avatar_url) |         self.config.discord.wh.send(embed=embed, username="error", file=file, avatar_url=self.config.discord.avatar_url) | ||||||
|         self.config.discord.wh.send(username="error", file=File("page.html"), avatar_url=self.config.discord.avatar_url) |         self.config.discord.wh.send(username="error", file=File("page.html"), avatar_url=self.config.discord.avatar_url) | ||||||
|   | |||||||
| @@ -11,12 +11,15 @@ 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: |         match driver.lower(): | ||||||
|             case "pc" | "PC" | "Pc": |             case "pc": | ||||||
|                 self.driver = self.pc_driver |                 self.driver = self.pc_driver | ||||||
|  |  | ||||||
|             case "mobile" | "Mobile": |             case "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,8 +30,9 @@ class UserCredentials: | |||||||
|  |  | ||||||
|     def get_tfa(self): |     def get_tfa(self): | ||||||
|         if not self.tfa_enable(): |         if not self.tfa_enable(): | ||||||
|             warning("Warning: TFA is not enabled. Calling get_tfa is an expected behaviour.") |             warning("Warning: TFA is not enabled. Can't get a TFA code.") | ||||||
|         return TOTP(self.data[self.current]["tfa"]) |             return None | ||||||
|  |         return TOTP(self.data[self.current]["2fa"]) | ||||||
|  |  | ||||||
|     def next_account(self): |     def next_account(self): | ||||||
|         self.current += 1 |         self.current += 1 | ||||||
| @@ -41,4 +42,5 @@ class UserCredentials: | |||||||
|             debug("No new credentials.") |             debug("No new credentials.") | ||||||
|  |  | ||||||
|     def is_valid(self): |     def is_valid(self): | ||||||
|         return self.current < self.total |         return (self.current < self.total | ||||||
|  |                 and self.get_mail() != "" and self.get_mail is not None) | ||||||
|   | |||||||
							
								
								
									
										8
									
								
								modules/Tools/generate_error.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								modules/Tools/generate_error.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,8 @@ | |||||||
|  | import undetected_chromedriver as uc | ||||||
|  | from pyvirtualdisplay.smartdisplay import SmartDisplay | ||||||
|  |  | ||||||
|  | display = SmartDisplay(size=(1920, 1080)) | ||||||
|  | display.start() | ||||||
|  | driver = uc.Chrome() | ||||||
|  | driver.close() | ||||||
|  | driver.close() | ||||||
| @@ -30,7 +30,7 @@ class ColoredFormatter(logging.Formatter): | |||||||
|  |  | ||||||
| # Set up the root logger | # Set up the root logger | ||||||
| root_logger = logging.getLogger(__name__) | root_logger = logging.getLogger(__name__) | ||||||
| root_logger.setLevel(logging.DEBUG) | root_logger.setLevel(logging.INFO) | ||||||
|  |  | ||||||
| # Create a console handler and set the formatter | # Create a console handler and set the formatter | ||||||
| ch = logging.StreamHandler() | ch = logging.StreamHandler() | ||||||
|   | |||||||
| @@ -10,7 +10,7 @@ def get_domain(driver): | |||||||
|  |  | ||||||
| def custom_sleep(temps): | def custom_sleep(temps): | ||||||
|     try: |     try: | ||||||
|         if True:  # todo: change this awful condition |         if False:  # todo: change this awful condition | ||||||
|             points = ["⢿", "⣻", "⣽", "⣾", "⣷", "⣯", "⣟", "⡿"] |             points = ["⢿", "⣻", "⣽", "⣾", "⣷", "⣯", "⣟", "⡿"] | ||||||
|             passe = 0 |             passe = 0 | ||||||
|             for _ in range(int(temps)): |             for _ in range(int(temps)): | ||||||
|   | |||||||
							
								
								
									
										48
									
								
								modules/Tools/update_chrome.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								modules/Tools/update_chrome.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,48 @@ | |||||||
|  | import requests | ||||||
|  | import re | ||||||
|  | from packaging import version | ||||||
|  | import subprocess | ||||||
|  |  | ||||||
|  | from logger import critical, info, error | ||||||
|  |  | ||||||
|  | errorMessage = subprocess.run(['python3', 'generate_error.py'], check=False, stdout=subprocess.PIPE, | ||||||
|  |                               stderr=subprocess.PIPE).stderr.decode("utf-8") | ||||||
|  |  | ||||||
|  | versionPattern = "This version of ChromeDriver only supports Chrome version ([0-9]+)" | ||||||
|  |  | ||||||
|  | try: | ||||||
|  |     versionN = re.search(versionPattern, errorMessage)[1] | ||||||
|  | except Exception as e: | ||||||
|  |     critical("Can't get version number from error") | ||||||
|  |     error(e) | ||||||
|  |     exit(0) | ||||||
|  |  | ||||||
|  | info(f"Needed version : '{versionN}'") | ||||||
|  |  | ||||||
|  | downloadUrl = "http://mirror.cs.uchicago.edu/google-chrome/pool/main/g/google-chrome-stable/" | ||||||
|  | r = requests.get(downloadUrl) | ||||||
|  |  | ||||||
|  | content = r.text | ||||||
|  |  | ||||||
|  | exactVersionList = re.findall(f"(google-chrome-stable_({versionN}.[0-9.]+)[^<^>^\"]+)", content) | ||||||
|  |  | ||||||
|  | try: | ||||||
|  |     best = exactVersionList[0] | ||||||
|  | except Exception as e: | ||||||
|  |     critical("No version matches required version") | ||||||
|  |     error(e) | ||||||
|  |     exit(0) | ||||||
|  |  | ||||||
|  | for i in exactVersionList: | ||||||
|  |     if version.parse(i[1]) > version.parse(best[1]): | ||||||
|  |         best = i | ||||||
|  |  | ||||||
|  | chromeDebURL = f"http://mirror.cs.uchicago.edu/google-chrome/pool/main/g/google-chrome-stable/{best[0]}" | ||||||
|  | info(f"chrome deb URL : {chromeDebURL}") | ||||||
|  | info("downloading chrome") | ||||||
|  |  | ||||||
|  | subprocess.call(['wget', "-O", "/tmp/chrome.deb", chromeDebURL]) | ||||||
|  | info("Chrome deb downloaded. Installing chrome") | ||||||
|  |  | ||||||
|  | subprocess.call(["dpkg", "-i", "/tmp/chrome.deb"]) | ||||||
|  | info("Chrome installed") | ||||||
| @@ -1,3 +1,5 @@ | |||||||
|  | import os | ||||||
|  | import json | ||||||
| from random import uniform | from random import uniform | ||||||
|  |  | ||||||
| from selenium.common import TimeoutException | from selenium.common import TimeoutException | ||||||
| @@ -10,33 +12,40 @@ from modules.Tools.logger import debug | |||||||
| from modules.Tools.tools import * | 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 |     os.makedirs(chrome_profile_dir, exist_ok=True) | ||||||
|     action.move_by_offset(x_coord, y_coord).click().perform() |  | ||||||
|     sleep(0.5) |     preferences_file = os.path.join(chrome_profile_dir, "Default", "Preferences") | ||||||
|     # scroll down |     if not os.path.exists(preferences_file): | ||||||
|     action.reset_actions() |         os.makedirs(os.path.join(chrome_profile_dir, "Default"), exist_ok=True) | ||||||
|     elm = ldriver.find_element(By.XPATH, "/html/body") |         with open(preferences_file, "w") as f: | ||||||
|     ActionChains(ldriver) \ |             json.dump( | ||||||
|         .send_keys("french") \ |                 { | ||||||
|         .pause(0.5) \ |                     "intl": { | ||||||
|         .send_keys(Keys.TAB + Keys.TAB + Keys.ENTER + Keys.TAB + Keys.TAB + Keys.ENTER) \ |                         "accept_languages": "fr-FR,en-US,en", | ||||||
|         .perform() |                         "selected_languages": "fr-FR,en-US,en" | ||||||
|     x_coord = 1163 |                     } | ||||||
|     y_coord = 717 |                }, f | ||||||
|     action.move_by_offset(x_coord, y_coord).click().perform() |             ) | ||||||
|     # put to the top |     else: | ||||||
|     sleep(0.5) |         with open(preferences_file, "r") as f: | ||||||
|     action.reset_actions() |             settings = json.load(f) | ||||||
|     x_coord = 1257 |          | ||||||
|     y_coord = 328 |         if "intl" not in settings: | ||||||
|     action.move_by_offset(x_coord, y_coord).click().perform() |             settings["intl"] = {} | ||||||
|     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 | ||||||
| @@ -60,13 +69,18 @@ def send_keys_wait(element, keys: str) -> None: | |||||||
|         element.send_keys(i) |         element.send_keys(i) | ||||||
|         sleep(uniform(0.1, 0.3)) |         sleep(uniform(0.1, 0.3)) | ||||||
|  |  | ||||||
|  | def send_wait_and_confirm(element, keys: str) -> None: | ||||||
|  |     send_keys_wait(element, keys) | ||||||
|  |     element.send_keys(Keys.ENTER) | ||||||
|  |  | ||||||
|  |  | ||||||
| # Wait for the presence of the element identifier or [timeout]s | # Wait for the presence of the element identifier or [timeout]s | ||||||
| def wait_until_visible(search_by: str, identifier: str, timeout: int = 20, browser=None) -> bool: | def wait_until_visible(search_by: str, identifier: str, timeout: int = 20, browser=None, raise_error=True) -> bool: | ||||||
|     try: |     try: | ||||||
|         WebDriverWait(browser, timeout).until( |         WebDriverWait(browser, timeout).until( | ||||||
|             expected_conditions.visibility_of_element_located((search_by, identifier)), "element not found") |             expected_conditions.visibility_of_element_located((search_by, identifier)), "element not found") | ||||||
|         return True |         return True | ||||||
|     except TimeoutException as e: |     except TimeoutException as e: | ||||||
|         error(f"element {identifier} not found after {timeout}s") |         if raise_error: | ||||||
|  |             error(f"element {identifier} not found after {timeout}s") | ||||||
|         return False |         return False | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user