mirror of
				https://gitea.augustin64.fr/piair/MsRewards-Reborn.git
				synced 2025-10-30 22:13:52 +01:00 
			
		
		
		
	Compare commits
	
		
			65 Commits
		
	
	
		
			dev
			...
			6995bde8a6
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | 6995bde8a6 | ||
|  | 92069a013e | ||
|  | 906d3e7822 | ||
|  | 778adc67d2 | ||
|  | 402b8cd3ef | ||
|  | 3c74aa025e | ||
|  | 3123a1dbd0 | ||
|  | 27d45e88dd | ||
|  | 0685a42922 | ||
|  | 6729703827 | ||
|  | 304a222de1 | ||
|  | 04d33f4ecd | ||
|  | ac22814605 | ||
|  | b7a89b56d0 | ||
|  | 127d16afea | ||
|  | 9bcbc81c2f | ||
|  | 12eba5cde7 | ||
|  | 22ea727c47 | ||
|  | 05a1fd8557 | ||
|  | 39e226b564 | ||
|  | cd00c8ca88 | ||
|  | 43793d2c2c | ||
|  | ee6ec458fc | ||
|  | e6e8bdaa06 | ||
|  | 9bd96ad876 | ||
|  | ed517e7b03 | ||
|  | 01416c0e11 | ||
|  | 19cf77c6bd | ||
|  | feb7834d1f | ||
|  | 1ea1ff776e | ||
|  | ae023688a4 | ||
|  | fcb40537dc | ||
|  | d7d2f49a3f | ||
|  | 68b5de32d6 | ||
|  | 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/* | ||||||
							
								
								
									
										5
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										5
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -3,18 +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 | *.ts | ||||||
| LICENSE | LICENSE | ||||||
| README.md | README.md | ||||||
|  | venv | ||||||
|   | |||||||
							
								
								
									
										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> | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										354
									
								
								V6.py
									
									
									
									
									
								
							
							
						
						
									
										354
									
								
								V6.py
									
									
									
									
									
								
							| @@ -1,8 +1,11 @@ | |||||||
| #!/usr/bin/python3.10 | #!/usr/bin/python3 | ||||||
|  | import random | ||||||
|  | import subprocess | ||||||
|  |  | ||||||
| from modules.Classes.Config import Config | from modules.Classes.Config import Config | ||||||
| from modules.Classes.DiscordLogger import DiscordLogger | from modules.Classes.DiscordLogger import DiscordLogger | ||||||
| from modules.Classes.UserCredentials import UserCredentials | from modules.Classes.UserCredentials import UserCredentials | ||||||
| from modules.Tools.logger import warning, critical | from modules.Tools.logger import critical, warning | ||||||
| from modules.cards import * | from modules.cards import * | ||||||
| from modules.config import * | from modules.config import * | ||||||
| from modules.db import add_to_database | from modules.db import add_to_database | ||||||
| @@ -22,16 +25,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 +172,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 +185,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: | ||||||
| @@ -177,6 +199,43 @@ def do_poll(): | |||||||
| # Find each playable card and tries to click on it to earn points | # Find each playable card and tries to click on it to earn points | ||||||
| def all_cards(): | def all_cards(): | ||||||
|     driver = config.WebDriver.driver |     driver = config.WebDriver.driver | ||||||
|  |  | ||||||
|  |     def check_welcome_tour() -> bool: | ||||||
|  |         if "rewards.bing.com/welcometour" not in driver.current_url: | ||||||
|  |             return False | ||||||
|  |  | ||||||
|  |         info("Popup 'Explorer le programme' reçue") | ||||||
|  |         wait_until_visible(By.ID, "welcome-tour", timeout=5, browser=driver) | ||||||
|  |         custom_sleep(1.5) | ||||||
|  |  | ||||||
|  |         welcome_tour = driver.find_element(By.ID, "welcome-tour") | ||||||
|  |         interest_button_box = welcome_tour.find_element(By.CLASS_NAME, "interest-buttons") | ||||||
|  |         interests = interest_button_box.find_elements(By.CLASS_NAME, "ng-binding") | ||||||
|  |         debug("Got the following interests: " + str(interests)) | ||||||
|  |         random.choice(interests).click()  # Choose interest | ||||||
|  |         custom_sleep(1.5) | ||||||
|  |  | ||||||
|  |         claim_button = welcome_tour.find_element(By.ID, "claim-button") | ||||||
|  |         claim_button.click()  # submit | ||||||
|  |         custom_sleep(1.5) | ||||||
|  |         return True | ||||||
|  |  | ||||||
|  |     def check_streak_protection() -> bool: | ||||||
|  |         """ | ||||||
|  |         Ne perdez plus jamais votre série ! | ||||||
|  |         """ | ||||||
|  |         try: | ||||||
|  |             streak_protection_close = driver.find_element(By.ID, "streak-protection-popup-close-cross") | ||||||
|  |             streak_protection_activate = driver.find_elements(By.CLASS_NAME, "earningPagePopUpPopUpSelectButton") | ||||||
|  |             streak_protection_activate[0].click() | ||||||
|  |             info("Popup 'Streak Protection' reçue") | ||||||
|  |             custom_sleep(1.5) | ||||||
|  |  | ||||||
|  |             return True | ||||||
|  |         except (exceptions.NoSuchElementException, exceptions.ElementNotInteractableException, IndexError): | ||||||
|  |             # les éléments sont présents dans le DOM même quand la popup n'est pas visible apparemment | ||||||
|  |             return False | ||||||
|  |          | ||||||
|     driver.get("https://rewards.bing.com") |     driver.get("https://rewards.bing.com") | ||||||
|     wait_until_visible(By.CLASS_NAME, "c-card-content", 10, driver) |     wait_until_visible(By.CLASS_NAME, "c-card-content", 10, driver) | ||||||
|  |  | ||||||
| @@ -190,7 +249,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") | ||||||
| @@ -220,39 +279,55 @@ def all_cards(): | |||||||
|                 if i == len(card_list) and i > 15: |                 if i == len(card_list) and i > 15: | ||||||
|                     checked = False |                     checked = False | ||||||
|  |  | ||||||
|         if checked: |         if not checked: | ||||||
|             custom_sleep(1.5) |             continue | ||||||
|  |  | ||||||
|  |         try: | ||||||
|  |             activity = findall("data-bi-id=\"([^\"]+)\"", card_list[i].get_attribute("innerHTML"))[0] | ||||||
|  |         except Exception as e: | ||||||
|  |             warning("Can't find activity." + str(e)) | ||||||
|  |             activity = "" | ||||||
|  |  | ||||||
|  |         custom_sleep(1.5) | ||||||
|  |         check_welcome_tour() | ||||||
|  |         check_streak_protection() | ||||||
|  |         driver.execute_script("arguments[0].scrollIntoView();", card_list[i]) | ||||||
|  |         custom_sleep(1.5) | ||||||
|  |         card_list[i].click() | ||||||
|  |  | ||||||
|  |         if len(driver.window_handles) > 1: | ||||||
|  |             driver.switch_to.window(driver.window_handles[1]) | ||||||
|  |             try_play(driver.title, activity) | ||||||
|  |             close_tab(driver.window_handles[1]) | ||||||
|  |  | ||||||
|  |         try: | ||||||
|  |             driver.refresh() | ||||||
|  |             card_list = driver.find_elements(By.CLASS_NAME, "c-card-content") | ||||||
|  |  | ||||||
|  |             if "mee-icon-AddMedium" not in card_list[i].get_attribute("innerHTML"): | ||||||
|  |                 continue | ||||||
|  |  | ||||||
|  |             check_welcome_tour() | ||||||
|  |             check_streak_protection() | ||||||
|             driver.execute_script("arguments[0].scrollIntoView();", card_list[i]) |             driver.execute_script("arguments[0].scrollIntoView();", card_list[i]) | ||||||
|             custom_sleep(1.5) |  | ||||||
|             card_list[i].click() |             card_list[i].click() | ||||||
|  |  | ||||||
|             if len(driver.window_handles) > 1: |             driver.switch_to.window(driver.window_handles[1]) | ||||||
|                 driver.switch_to.window(driver.window_handles[1]) |             custom_sleep(10) | ||||||
|                 try_play(driver.title) |             log_error(f"Card {i} Can't be completed. Why MS ?") | ||||||
|                 close_tab(driver.window_handles[1]) |  | ||||||
|  |  | ||||||
|             try: |             try: | ||||||
|                 driver.refresh() |                 try_play(driver.title)  # go back to the main page | ||||||
|                 card_list = driver.find_elements(By.CLASS_NAME, "c-card-content") |                 try: | ||||||
|  |                     close_tab(driver.window_handles[1]) | ||||||
|  |                 except Exception as e: | ||||||
|  |                     debug(e) | ||||||
|  |             except Exception as e: | ||||||
|  |                 debug(e) | ||||||
|  |                 driver.get("https://rewards.bing.com") | ||||||
|  |  | ||||||
|                 if "mee-icon-AddMedium" in card_list[i].get_attribute("innerHTML"): |         except Exception as err: | ||||||
|                     driver.execute_script("arguments[0].scrollIntoView();", card_list[i]) |             log_error(err) | ||||||
|                     card_list[i].click() |         custom_sleep(3) | ||||||
|                     driver.switch_to.window(driver.window_handles[1]) |  | ||||||
|                     custom_sleep(10) |  | ||||||
|                     log_error(f"Card {i} Can't be completed. Why MS ?") |  | ||||||
|                     try: |  | ||||||
|                         try_play(driver.title)  # go back to the main page |  | ||||||
|                         try: |  | ||||||
|                             close_tab(driver.window_handles[1]) |  | ||||||
|                         except Exception as e: |  | ||||||
|                             debug(e) |  | ||||||
|                     except Exception as e: |  | ||||||
|                         debug(e) |  | ||||||
|                         driver.get("https://rewards.bing.com") |  | ||||||
|             except Exception as err: |  | ||||||
|                 log_error(err) |  | ||||||
|             custom_sleep(3) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| def promo(): | def promo(): | ||||||
| @@ -290,8 +365,35 @@ def promo(): | |||||||
|         custom_sleep(3) |         custom_sleep(3) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def explore_on_bing(activity: str, config: Config): | ||||||
|  |     driver = config.WebDriver.driver | ||||||
|  |  | ||||||
|  |     def search_bing(txt): | ||||||
|  |         search_elm = driver.find_element(By.ID, "sb_form_q") | ||||||
|  |         send_keys_wait(search_elm, txt) | ||||||
|  |         send_keys_wait(search_elm, Keys.ENTER) | ||||||
|  |  | ||||||
|  |     if "lyrics" in activity: | ||||||
|  |         search_bing( | ||||||
|  |             f"paroles de {['Gata', 'Pyramide', 'Dolce Camara', 'Position', 'Mami Wata'][randint(0, 4)]}")  # merci bing copilot pour les titres | ||||||
|  |     elif "flight" in activity: | ||||||
|  |         search_bing( | ||||||
|  |             f"vol {['Paris - New York', 'Londres Amsterdam', 'Bora-Bora Miami', 'Los Angeles Toulouse', 'Rome Dubai'][randint(0, 4)]}") | ||||||
|  |     elif "shopping" in activity: | ||||||
|  |         search_bing(f"idée cadeau {['Noel', 'Anniversaire'][randint(0, 1)]}") | ||||||
|  |     elif "movie" in activity: | ||||||
|  |         search_bing( | ||||||
|  |             f"Distribution {['Code 8 part 2', 'The Hunger Games: The ballad of Songbirds & Snakes', 'Rebel Moon: Part Two', 'Dune II', 'Wonka'][randint(0, 4)]}") | ||||||
|  |     elif "translator" in activity: | ||||||
|  |         search_bing(f"traduction {config.wordlist.get_word()} en anglais") | ||||||
|  |     elif "map" in activity: | ||||||
|  |         search_bing(f"{['Paris', 'Nice', 'Marseille', 'Bordeaux', 'Lyon'][randint(0, 4)]} carte") | ||||||
|  |     else: | ||||||
|  |         log_error(f"Explore on bing: {activity} not found.") | ||||||
|  |  | ||||||
|  |  | ||||||
| # Find out which type of action to do | # Find out which type of action to do | ||||||
| def try_play(nom="unknown"): | def try_play(nom="unknown", activity=""): | ||||||
|     driver = config.WebDriver.driver |     driver = config.WebDriver.driver | ||||||
|     rgpd_popup(config) |     rgpd_popup(config) | ||||||
|  |  | ||||||
| @@ -337,7 +439,7 @@ def try_play(nom="unknown"): | |||||||
|         info("On fidelity page.") |         info("On fidelity page.") | ||||||
|         fidelity() |         fidelity() | ||||||
|  |  | ||||||
|     elif wait_until_visible(By.ID, "rqStartQuiz", 5, driver): |     elif wait_until_visible(By.ID, "rqStartQuiz", 5, driver, raise_error=False): | ||||||
|         custom_sleep(3) |         custom_sleep(3) | ||||||
|         driver.find_element(By.ID, "rqStartQuiz").click()  # start the quiz |         driver.find_element(By.ID, "rqStartQuiz").click()  # start the quiz | ||||||
|         answer_number = driver.page_source.count("rqAnswerOption") |         answer_number = driver.page_source.count("rqAnswerOption") | ||||||
| @@ -347,9 +449,12 @@ def try_play(nom="unknown"): | |||||||
|         number = driver.page_source.count("rqAnswerOption") |         number = driver.page_source.count("rqAnswerOption") | ||||||
|         warning(f"recovery detected. quiz : {number}") |         warning(f"recovery detected. quiz : {number}") | ||||||
|         play(number - 1) |         play(number - 1) | ||||||
|  |     elif "exploreonbing" in activity: | ||||||
|  |         info(f"Explore on bing: {activity}") | ||||||
|  |         explore_on_bing(activity, config) | ||||||
|  |         custom_sleep(uniform(3, 5)) | ||||||
|     else: |     else: | ||||||
|         info(f"Nothing to do on page `{nom}`") |         info(f"Nothing obvious to do on page `{nom}`.") | ||||||
|         custom_sleep(uniform(3, 5)) |         custom_sleep(uniform(3, 5)) | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -360,22 +465,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 +528,19 @@ def login_part_2(): | |||||||
| # login() tries to login to your Microsoft account. | # login() tries to login to your Microsoft account. | ||||||
| # it uses global variable g._mail and g._password to login | # it uses global variable g._mail and g._password to login | ||||||
| def login(): | def login(): | ||||||
|  |     def logged_in(): | ||||||
|  |         driver.get("https://login.live.com") | ||||||
|  |         custom_sleep(10) | ||||||
|  |         debug(get_domain(driver)) | ||||||
|  |         if get_domain(driver) == "account.microsoft.com": | ||||||
|  |             return True | ||||||
|  |         return False | ||||||
|  |  | ||||||
|  |     info("Logging in...") | ||||||
|     driver = config.WebDriver.driver |     driver = config.WebDriver.driver | ||||||
|     try: |     try: | ||||||
|         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: | ||||||
| @@ -537,19 +665,23 @@ def fidelity(): | |||||||
|         pause = driver.find_element(By.CSS_SELECTOR, f'[class="c-action-toggle c-glyph f-toggle glyph-pause"]') |         pause = driver.find_element(By.CSS_SELECTOR, f'[class="c-action-toggle c-glyph f-toggle glyph-pause"]') | ||||||
|         pause.click() |         pause.click() | ||||||
|     except Exception as e: |     except Exception as e: | ||||||
|         error(f"Error while clicking pause. Probably no cards. {e}") |         debug("No pause button.") | ||||||
|         return "no cards" |  | ||||||
|     cartes = driver.find_elements(By.CSS_SELECTOR, f'[ng-repeat="item in $ctrl.transcludedItems"]') |     cartes = driver.find_elements(By.CSS_SELECTOR, f'[ng-repeat="item in $ctrl.transcludedItems"]') | ||||||
|     nb_cartes = len(cartes) |     nb_cartes = len(cartes) | ||||||
|  |     if nb_cartes == 0: | ||||||
|  |         warning("No fidelity cards detected") | ||||||
|  |         return "No cards." | ||||||
|     checked_list_all = driver.find_elements(By.CSS_SELECTOR, f'[ng-if="$ctrl.complete"]') |     checked_list_all = driver.find_elements(By.CSS_SELECTOR, f'[ng-if="$ctrl.complete"]') | ||||||
|     for i in range(nb_cartes): |     for i in range(nb_cartes): | ||||||
|         cartes[i].click() |         cartes[i].click() | ||||||
|         checked_txt = checked_list_all[i].get_attribute("innerHTML") |         checked_txt = checked_list_all[i].get_attribute("innerHTML") | ||||||
|         ok = checked_txt.count("StatusCircleOuter checkmark") |         ok = checked_txt.count("StatusCircleOuter checkmark") | ||||||
|         total = checked_txt.count("StatusCircleOuter") |         total = checked_txt.count("StatusCircleOuter") | ||||||
|         if (ok != total): |         if ok != total: | ||||||
|             elm = driver.find_elements(By.CLASS_NAME, 'clickable-link')[i] |             elm = driver.find_elements(By.CLASS_NAME, 'clickable-link')[i] | ||||||
|             if not "moviesandtv" in elm.get_attribute("innerHTML"):  # not the film card |             # legacy code. Should be removed | ||||||
|  |             if "moviesandtv" not in elm.get_attribute("innerHTML"):  # not the film card | ||||||
|                 elm.click() |                 elm.click() | ||||||
|                 driver.switch_to.window(driver.window_handles[len(driver.window_handles) - 1]) |                 driver.switch_to.window(driver.window_handles[len(driver.window_handles) - 1]) | ||||||
|                 sub_fidelity() |                 sub_fidelity() | ||||||
| @@ -610,9 +742,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 | ||||||
| @@ -665,53 +799,53 @@ def json_start(json_entry, cred: UserCredentials): | |||||||
|             config.WebDriver.set_pc_driver(create_driver()) |             config.WebDriver.set_pc_driver(create_driver()) | ||||||
|             config.WebDriver.switch_to_driver("PC") |             config.WebDriver.switch_to_driver("PC") | ||||||
|             driver = config.WebDriver.driver |             driver = config.WebDriver.driver | ||||||
|             try: |             if "unban" in json_entry and str(account_id) in json_entry["unban"]: | ||||||
|                 if str(account_id) in json_entry["unban"]: |                 login() | ||||||
|                     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): |                     sleep(1) | ||||||
|                         sleep(1) |                     if driver.current_url == "https://example.com/": | ||||||
|                         if driver.current_url == "https://example.com/": |                         info("proceeding") | ||||||
|                             info("proceeding") |                         break | ||||||
|                             break |             else: | ||||||
|                 else: |  | ||||||
|                     login() |  | ||||||
|             except KeyError: |  | ||||||
|                 login() |                 login() | ||||||
|             try: |             try: | ||||||
|                 if str(account_id) in json_entry["tout"]: |                 if str(account_id) in json_entry["tout"]: | ||||||
|                     daily_routine(cred) |                     daily_routine(cred, True) | ||||||
|  |  | ||||||
|  |                 else: | ||||||
|  |                     try: | ||||||
|  |                         if str(account_id) in json_entry["daily"]: | ||||||
|  |                             try: | ||||||
|  |                                 all_cards() | ||||||
|  |                             except Exception as e: | ||||||
|  |                                 log_error(e) | ||||||
|  |                     except KeyError: | ||||||
|  |                         pass | ||||||
|  |                     try: | ||||||
|  |                         if str(account_id) in json_entry["pc"]: | ||||||
|  |                             try: | ||||||
|  |                                 bing_pc_search() | ||||||
|  |                             except Exception as e: | ||||||
|  |                                 log_error(e) | ||||||
|  |                     except KeyError: | ||||||
|  |                         pass | ||||||
|  |                     try: | ||||||
|  |                         if str(account_id) in json_entry["mobile"]: | ||||||
|  |                             try: | ||||||
|  |                                 bing_mobile_search(cred) | ||||||
|  |                             except Exception as e: | ||||||
|  |                                 log_error(e) | ||||||
|  |                     except KeyError: | ||||||
|  |                         pass | ||||||
|  |  | ||||||
|             except KeyError: |             except KeyError: | ||||||
|                 pass |                 pass | ||||||
|             else: |             try: | ||||||
|                 try: |                 log_points() | ||||||
|                     if str(account_id) in json_entry["daily"]: |             except Exception as e: | ||||||
|                         try: |                 error(f"CustomStart {e}") | ||||||
|                             all_cards() |  | ||||||
|                         except Exception as e: |  | ||||||
|                             log_error(e) |  | ||||||
|                 except KeyError: |  | ||||||
|                     pass |  | ||||||
|                 try: |  | ||||||
|                     if str(account_id) in json_entry["pc"]: |  | ||||||
|                         try: |  | ||||||
|                             bing_pc_search() |  | ||||||
|                         except Exception as e: |  | ||||||
|                             log_error(e) |  | ||||||
|                 except KeyError: |  | ||||||
|                     pass |  | ||||||
|                 try: |  | ||||||
|                     if str(account_id) in json_entry["mobile"]: |  | ||||||
|                         try: |  | ||||||
|                             bing_mobile_search(cred) |  | ||||||
|                         except Exception as e: |  | ||||||
|                             log_error(e) |  | ||||||
|                 except KeyError: |  | ||||||
|                     pass |  | ||||||
|                 try: |  | ||||||
|                     log_points() |  | ||||||
|                 except Exception as e: |  | ||||||
|                     error(f"CustomStart {e}") |  | ||||||
|             driver.close() |             driver.close() | ||||||
|         cred.next_account() |         cred.next_account() | ||||||
|         account_id += 1 |         account_id += 1 | ||||||
| @@ -728,13 +862,16 @@ def default_start(): | |||||||
|     while config.UserCredentials.is_valid(): |     while config.UserCredentials.is_valid(): | ||||||
|         custom_sleep(1) |         custom_sleep(1) | ||||||
|         info("Starting and configuring driver.") |         info("Starting and configuring driver.") | ||||||
|         config.WebDriver.set_pc_driver(create_driver()) |         try: | ||||||
|  |             config.WebDriver.set_pc_driver(create_driver()) | ||||||
|  |         except: | ||||||
|  |             subprocess.Popen(["python3", "/app/MsRewards-Reborn/modules/Tools/update_chrome.py"]) | ||||||
|  |             config.WebDriver.set_pc_driver(create_driver()) | ||||||
|         config.WebDriver.switch_to_driver("PC") |         config.WebDriver.switch_to_driver("PC") | ||||||
|         info("Driver started.") |         info("Driver started.") | ||||||
|         config.WebDriver.pc_driver.implicitly_wait(3) |         config.WebDriver.pc_driver.implicitly_wait(3) | ||||||
|         try: |         try: | ||||||
|             wait_time = uniform(1200, 3600) |             wait_time = uniform(1200, 3600) | ||||||
|             wait_time = 10  # the display closes when I ctrl + c |  | ||||||
|             info(f"Waiting for {round(wait_time / 60)}min before starting") |             info(f"Waiting for {round(wait_time / 60)}min before starting") | ||||||
|             custom_sleep(wait_time) |             custom_sleep(wait_time) | ||||||
|             daily_routine(config.UserCredentials) |             daily_routine(config.UserCredentials) | ||||||
| @@ -744,12 +881,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() | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -758,7 +899,6 @@ def log_error(msg): | |||||||
|  |  | ||||||
|  |  | ||||||
| def check_updated(): | def check_updated(): | ||||||
|     debug(f"updated: {config.has_been_updated()}") |  | ||||||
|     if config.has_been_updated(): |     if config.has_been_updated(): | ||||||
|         config.discord.wh.send(f"Updated to {config.version}", username="update", |         config.discord.wh.send(f"Updated to {config.version}", username="update", | ||||||
|                                avatar_url="https://cdn-icons-png.flaticon.com/512/1688/1688988.png") |                                avatar_url="https://cdn-icons-png.flaticon.com/512/1688/1688988.png") | ||||||
|   | |||||||
							
								
								
									
										13
									
								
								build.sh
									
									
									
									
									
								
							
							
						
						
									
										13
									
								
								build.sh
									
									
									
									
									
								
							| @@ -1 +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
											
										
									
								
							
							
								
								
									
										12
									
								
								hooks/bump.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										12
									
								
								hooks/bump.sh
									
									
									
									
									
										Executable 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
									
								
							
							
						
						
									
										1
									
								
								hooks/pre-commit
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1 @@ | |||||||
|  | sh hooks/bump.sh | ||||||
| @@ -22,7 +22,8 @@ class Config: | |||||||
|             proxy = json.load(inFile) |             proxy = json.load(inFile) | ||||||
|         with open("/app/MsRewards-Reborn/user_data/configs.json", "r") as inFile: |         with open("/app/MsRewards-Reborn/user_data/configs.json", "r") as inFile: | ||||||
|             config = json.load(inFile) |             config = json.load(inFile) | ||||||
|  |         with open("/app/MsRewards-Reborn/user_data/version", "r") as inFile: | ||||||
|  |             version = inFile.readline() | ||||||
|         """ |         """ | ||||||
|         setup standalone stuff |         setup standalone stuff | ||||||
|         """ |         """ | ||||||
| @@ -31,10 +32,9 @@ class Config: | |||||||
|         self.json_entry = args.json.replace("'", "\"") |         self.json_entry = args.json.replace("'", "\"") | ||||||
|         self.wordlist = WordList("/usr/share/dict/french") |         self.wordlist = WordList("/usr/share/dict/french") | ||||||
|         self.vnc = args.vnc |         self.vnc = args.vnc | ||||||
|         self.version = args.update_version |  | ||||||
|         self.WebDriver = Driver() |         self.WebDriver = Driver() | ||||||
|         self.display = None |         self.display = None | ||||||
|  |         self.version = version | ||||||
|         """ |         """ | ||||||
|         setup UserCredential |         setup UserCredential | ||||||
|         """ |         """ | ||||||
| @@ -50,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() | ||||||
| @@ -76,4 +81,11 @@ class Config: | |||||||
|         self.display = display |         self.display = display | ||||||
|  |  | ||||||
|     def has_been_updated(self): |     def has_been_updated(self): | ||||||
|         return self.version != "None" |         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 | ||||||
|   | |||||||
| @@ -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,7 +1,9 @@ | |||||||
|  | import json | ||||||
|  | import os | ||||||
| from random import uniform | from random import uniform | ||||||
|  |  | ||||||
| from selenium.common import TimeoutException | from selenium.common import TimeoutException | ||||||
| from selenium.webdriver import ActionChains, Keys | from selenium.webdriver import Keys | ||||||
| from selenium.webdriver.common.by import By | from selenium.webdriver.common.by import By | ||||||
| from selenium.webdriver.support import expected_conditions | from selenium.webdriver.support import expected_conditions | ||||||
| from selenium.webdriver.support.wait import WebDriverWait | from selenium.webdriver.support.wait import WebDriverWait | ||||||
| @@ -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 | ||||||
| @@ -61,12 +70,18 @@ def send_keys_wait(element, keys: str) -> None: | |||||||
|         sleep(uniform(0.1, 0.3)) |         sleep(uniform(0.1, 0.3)) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def send_wait_and_confirm(element, keys: str) -> None: | ||||||
|  |     send_keys_wait(element, keys) | ||||||
|  |     element.send_keys(Keys.ENTER) | ||||||
|  |  | ||||||
|  |  | ||||||
| # Wait for the presence of the element identifier or [timeout]s | # Wait for the presence of the element identifier or [timeout]s | ||||||
| def wait_until_visible(search_by: str, identifier: str, timeout: int = 20, browser=None) -> 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") |         f = error if raise_error else debug | ||||||
|  |         f(f"element {identifier} not found after {timeout}s") | ||||||
|         return False |         return False | ||||||
|   | |||||||
							
								
								
									
										1
									
								
								user_data/version
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								user_data/version
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | |||||||
|  | 0.0.0 | ||||||
		Reference in New Issue
	
	Block a user