Compare commits

...

10 commits

6 changed files with 318 additions and 0 deletions

4
.gitignore vendored
View file

@ -1 +1,5 @@
.idea .idea
.gitignore
__pycache__/tray_manager.cpython-311.pyc
__pycache__/creds.cpython-311.pyc
__pycache__/alcasar.cpython-311.pyc

71
alcasar-install.bat Normal file

File diff suppressed because one or more lines are too long

View file

@ -4,6 +4,7 @@ from enum import Enum
import requests import requests
from bs4 import BeautifulSoup from bs4 import BeautifulSoup
print("Hello AlcasarAuto!")
class ConnectionResults(Enum): class ConnectionResults(Enum):
"""Enumeration used for connection result""" """Enumeration used for connection result"""

202
credsmanager.py Normal file
View file

@ -0,0 +1,202 @@
from json import dumps as js_d, loads as js_l
from cryptography.fernet import Fernet
from subprocess import Popen, PIPE
from os.path import exists
class CredentialsManager():
"""Used to acces crypted json credentials path using fernet"""
def __init__(self, credentials_file_path: str, reg_key_path: str = "CredentialsManager", key_name: str = "fernkey"):
"""Create a CredentialsManager object used to acces crypted json credentials path using fernet\n
Parameters
----------
* credentials_file_path : str\n
The path of your credentials file, MUST be .json, if not or if file doesn't exist, create a new one
* reg_key_path : str\n
The path where the fernet key will be or is stored in the windows registery.\n
>>> "IN THE CURRENT USER REG PATH (HKEY_CURRENT_USER\\) ONLY. ENTER NAME OF THE 'FOLDER' YOU WANT THE KEY TO BE IN"\n
* key_name : str\n
The name of the registery key in which the encryption key will be stored"""
# Storing the reg key path in self to acces it later
self.reg_key_path = f"HKEY_CURRENT_USER\\{reg_key_path}"
# Storing the reg key name in self to acces it later
self.reg_key_name = key_name
# Get/Create a new key
self.key = self.get_key()
# Initialise our Fernet object with the key, will raise a error if key wasn't create and returned None
self.Fernet = Fernet(key=self.key)
# Replace credential file extansion by .json
# Replace last element after a dot by json in the file path
# Store it in self to acces it later
self.creds_file_path = credentials_file_path.replace(credentials_file_path.split(".")[-1], "json")
# Check if credentials file exist, if not, try creating new one and write empty line
if not exists(self.creds_file_path):
with open(self.creds_file_path, "w") as f:
f.write("")
def get_key(self) -> bytes | None:
"""Get the Fernet encryption key in the windows registery, if not found, create a new one"""
# Get key using reg QUERY in subprocess
proces = Popen(f"reg QUERY {self.reg_key_path} /v {self.reg_key_name}", stdout=PIPE, stderr=PIPE)
# Check if error output is not empty
if proces.stderr.read() !=b'':
# Create a new key and return it
return self.create_key()
else:
# Return key as binary
return proces.stdout.read().decode("CP850").rsplit()[3].encode()
def create_key(self):
"""Create a new key, store it in the windows registery and return it"""
# Generate a new key with Fernet
key = Fernet.generate_key()
# Add it to registery using reg ADD in subprocess
proces = Popen(f"reg ADD {self.reg_key_path} /v {self.reg_key_name} /d {key.decode()}", stdout=PIPE, stderr=PIPE)
# Check if process executed successfully, if yes return key, if not return None
if proces.stderr.read() == b'':
self.key = key
return key
return
def delete_key(self, delete_dir: bool = False):
"""Delete the encryption key from the windows registery, return True if removed successfully, and False if not.\n
>>> "WARNING YOU CAN'T RETRIEVE ENCRYPTED DATA AFTER REMOVAL"\n
Parameters
-----------
* delete_dir bool (Defaukt = False)\n
If set on True, also delete the directory of the stored key\n
>>> "WARNING ALL THE KEYS CONTAINED IN THE DIRECTORY WILL BE DELETED" """
if delete_dir:
# Delete directory and all the key from registery using reg DELETE in subprocess
command = f"reg DELETE {self.reg_key_path} /f"
else:
# Delete key from registery using reg DELETE in subprocess
command = f"reg DELETE {self.reg_key_path} /v {self.reg_key_name} /f"
# Execute command
proces = Popen(command, stdout=PIPE, stderr=PIPE)
# Check if process executed successfully, if yes return True, if not return False
if proces.stderr.read() == b'':
return True
return False
def decrypt(self, data: bytes) -> dict:
"""Return the decrypted version of the encrypted bytes as a json dict"""
# Decrypt using Fernet, then decode into str, then load it with json
return js_l(self.Fernet.decrypt(data).decode())
def encrypt(self, data: str) -> bytes:
"""Return the encrypted version of the Serialize (means it's a dict encoded as a str by json) json dict as encrypted bytes"""
# Dump using json, then encode it into UTF-8, then encrypt it using Fernet
return self.Fernet.encrypt(js_d(data).encode())
def get_credentials(self):
"""Return the decrypted dict of username and passwords (format : {username: password, ...})"""
# Open credentials file
with open(self.creds_file_path, "rb") as f:
# Read content of the file
data = f.read()
# If file is empty, return an empty dict to avoid Fernet from crashing while trying to decrypt void
if data == b"":
return {}
# Decrypt and return the dict
return self.decrypt(data)
def write_credentials(self, new_credentials_dict: dict[str: str]):
"""Write the dict data in the credentials file\n
Parameters
----------
* new_credentials_dict : {str: str}\n
The dict to encrypt and write in the credentials file\n
>>> "WARNING. ERASE ALL EXISTING DATA IN THE FILE, IF YOU WANT TO APPEND DATA, SEE CredentialsManager.add_credentials()" """
# Open credentials file
with open(self.creds_file_path, "wb") as f:
# Encrypt, and write the encrypted data in the file
f.write(self.encrypt(new_credentials_dict))
return
def add_credentials(self, new_credentials_data_dict: dict[str: str]):
"""Append data to the encrypted json credentials file\n
Parameters
----------
* new_credentials_data_dict: {str: str}\n
The data to append to the encrypted credentials json dict"""
# Use get_credentials and write_credentials
# Get current data
old_dict = self.get_credentials()
# Set our new dict with the old value to keep
new_dict = old_dict
# Get all the keys of the new data
# For each key add them to the new dict
for key in new_credentials_data_dict.keys():
new_dict[key] = new_credentials_data_dict[key]
# Write our new dict to the encrypted json credentials file
self.write_credentials(new_dict)
return
def remove_credentials(self, credentials_to_remove: dict[str: str], match_password: bool = True):
"""Remove the specified data from the encrypted json credentials file\n
Parameters
----------
* credentials_to_remove : {str: str}\n
The data to remove from the encrypted credentials json dict
* match_password : bool (Default = True)\n
If set on True, the username AND password must match to be removed, if set on False, ONLY username must match"""
# Use get_credentials and write_credentials
# Get current data
dict = self.get_credentials()
# Get all the keys to remove
# For each key, if the key is in the dict, remove it
# Using a try except in case the key isn't in the dict
for key in credentials_to_remove.keys():
try:
# If match_password is True, check if passwords are equals, if not, pass
if match_password:
if dict[key] == credentials_to_remove[key]:
dict.pop(key)
else:
dict.pop(key)
except:
pass
# Write our dict to the encrypted json credentials file
self.write_credentials(dict)
return

View file

@ -1,5 +1,8 @@
import time import time
import os, sys
sys.path.append(os.path.dirname(__file__))
import settings_manager import settings_manager
from alcasar import Alcasar from alcasar import Alcasar
from tray_manager import TrayManager from tray_manager import TrayManager

37
setup.py Normal file
View file

@ -0,0 +1,37 @@
import subprocess as sp
from urllib import request
import tempfile
from os import path, mkdir
import zipfile
# Create a temporary directory
temp_dir = tempfile.mkdtemp()
# Download the python zip
print("Downloading Python...")
python_files = path.join(temp_dir, "python.zip")
request.urlretrieve("https://www.python.org/ftp/python/3.13.0/python-3.13.0a2-embed-amd64.zip",
python_files)
# Create the installation folder
mkdir(r"C:\ProgramData\AlcasarAuto")
mkdir(r"C:\ProgramData\AlcasarAuto\python")
# Extract the zipfile
print("Extracting zipfile...")
zipfile.ZipFile(file=python_files).extractall(r"C:\ProgramData\AlcasarAuto\python")
# Install pip
print("Installing Pip...")
request.urlretrieve("https://bootstrap.pypa.io/get-pip.py",
r"C:\ProgramData\AlcasarAuto\python\get-pip.py")
sp.call([r"C:\ProgramData\AlcasarAuto\python", "get-pip.py"])
print("Updating imports...")
with open(r"C:\ProgramData\AlcasarAuto\python\get-pip.py", "a") as file:
file.write("Lib\nLib\\site-packages")
# Install libs
print("Istalling dependencies...")
for i in ["requests", "bs4"]:
sp.call([r"C:\ProgramData\AlcasarAuto\python", "-m", "pip", "install", i])