10 Commits

Author SHA1 Message Date
be72749b53 update idea 2025-05-23 00:36:08 +02:00
dc2adfbca5 Merge remote-tracking branch 'origin/master' 2025-04-22 02:13:15 +02:00
a693338891 disable encryption inter process 2025-04-22 02:12:58 +02:00
bfa6865109 Merge remote-tracking branch 'origin/master' 2025-04-20 12:00:24 +02:00
9031e1d04d icon png integration 2025-04-20 11:59:39 +02:00
3155154083 linux integration 2025-04-20 11:58:46 +02:00
012ab977a7 some fix 2025-04-20 04:40:14 +02:00
ce8d9d639a wtf ? 2025-04-20 03:36:58 +02:00
a061ee20a8 add http2 2025-04-20 01:46:58 +02:00
ed5a381262 Init 2025-04-19 23:09:40 +02:00
12 changed files with 175 additions and 122 deletions

4
.gitignore vendored
View File

@@ -1,2 +1,4 @@
.venv
OxApp.dist
OxApp.dist
installer
OxApp.bin

2
.idea/misc.xml generated
View File

@@ -3,7 +3,7 @@
<component name="Black">
<option name="sdkName" value="Python 3.13 (oxapp25)" />
</component>
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.13 virtualenv at D:\Dev\oxapp25\.venv" project-jdk-type="Python SDK" />
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.13 (oxapp25)" project-jdk-type="Python SDK" />
<component name="PythonCompatibilityInspectionAdvertiser">
<option name="version" value="3" />
</component>

2
.idea/oxapp25.iml generated
View File

@@ -4,7 +4,7 @@
<content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/.venv" />
</content>
<orderEntry type="jdk" jdkName="Python 3.13 virtualenv at D:\Dev\oxapp25\.venv" jdkType="Python SDK" />
<orderEntry type="jdk" jdkName="Python 3.13 (oxapp25)" jdkType="Python SDK" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

32
Makefile Normal file
View File

@@ -0,0 +1,32 @@
# Makefile pour OxApp - équivalent Linux du build.bat
.PHONY: help resources deploy pyinstaller installer
# Commande par défaut - affiche l'aide
help:
@echo "Commandes disponibles:"
@echo " make resources - Compile les ressources"
@echo " make deploy - Déploie l'application"
@echo " make pyinstaller - Crée l'exécutable avec PyInstaller"
@echo " make installer - Crée l'installateur"
# Compile les ressources
resources:
pyside6-rcc resources.qrc -o resources_rc.py
# Déploie l'application avec pyside6-deploy
deploy:
pyside6-deploy -c pysidedeploy_linux.spec
# Crée l'exécutable avec PyInstaller
pyinstaller:
pyinstaller OxApp.spec --noconfirm
# Crée l'installateur
# Note: Inno Setup est spécifique à Windows, vous devrez utiliser
# un équivalent Linux comme makeself, AppImage, ou Flatpak
installer:
@echo "La création d'installateur sur Linux nécessite un outil différent d'Inno Setup."
@echo "Options recommandées: makeself, AppImage, ou Flatpak"
@echo "Exemple avec makeself (si installé):"
@echo " makeself.sh ./dist/OxApp \"OxApp\" \"OxApp Installation\" ./dist/Ox

View File

@@ -5,8 +5,12 @@ if "%1"=="resources" (
pyside6-deploy.exe -c pysidedeploy.spec
) else if "%1"=="pyinstaller" (
pyinstaller OxApp.spec --noconfirm
) else if "%1"=="installer" (
"C:\Program Files (x86)\Inno Setup 6\ISCC.exe" "setup.iss"
) else (
echo Commandes disponibles:
echo build.bat resources - Compile les ressources
echo build.bat deploy - Déploie l'application
echo build.bat pyinstaller - Crée l'exécutable avec PyInstaller
echo build.bat installer - Crée l'installateur avec Inno Setup
)

116
main.py
View File

@@ -1,4 +1,4 @@
from PySide6.QtCore import QStandardPaths, QDataStream, QByteArray, QIODevice, Signal, Qt, QTimer, QCryptographicHash
from PySide6.QtCore import QDataStream, QIODevice, Signal, QTimer
from PySide6.QtGui import QPalette, QColor
from PySide6.QtNetwork import QLocalServer, QLocalSocket
from PySide6.QtWidgets import QApplication
@@ -7,14 +7,8 @@ import qasync
import sys
import asyncio
import os
import platform
import argparse
import hashlib
import random
import string
import base64
import logging
from pathlib import Path
from src.logs import configure_logging
from windows.main_window import MainWindow
@@ -63,9 +57,6 @@ class SingleApplication(QApplication):
self.app_id = app_id
self.logger.debug(f"ID de l'application: {app_id}")
self.shared_key = hashlib.sha256(app_id.encode()).hexdigest()[:16]
self.logger.debug(f"Clé partagée générée: {self.shared_key}")
self.server = None
self.is_primary_instance = self.try_connect_to_primary()
@@ -77,7 +68,8 @@ class SingleApplication(QApplication):
self.logger.debug("Signal newConnection connecté")
if not self.server.listen(self.app_id):
self.logger.warning(f"Échec de l'écoute sur {self.app_id}, tentative de suppression du serveur existant")
self.logger.warning(
f"Échec de l'écoute sur {self.app_id}, tentative de suppression du serveur existant")
# En cas d'erreur (serveur déjà existant mais zombie), on le supprime et on réessaie
QLocalServer.removeServer(self.app_id)
if self.server.listen(self.app_id):
@@ -90,78 +82,6 @@ class SingleApplication(QApplication):
self.logger.info("Instance secondaire détectée, fermeture de l'application")
QTimer.singleShot(0, self.quit)
def encrypt_data(self, data_str):
"""
Méthode simple pour brouiller les données
Args:
data_str (str): Données à chiffrer
Returns:
str: Données chiffrées en base64
"""
self.logger.debug(f"Chiffrement des données (longueur: {len(data_str)})")
# Générer une "nonce" aléatoire pour éviter que les mêmes données produisent le même résultat
nonce = ''.join(random.choice(string.ascii_letters + string.digits) for _ in range(8))
self.logger.debug(f"Nonce générée: {nonce}")
# Combiner la nonce, la clé et les données
combined = nonce + self.shared_key + data_str
self.logger.debug("Données combinées avec nonce et clé partagée")
# Utiliser SHA-256 pour obtenir un hash
hash_obj = QCryptographicHash(QCryptographicHash.Algorithm.Sha256)
hash_obj.addData(combined.encode())
signature = hash_obj.result().toHex().data().decode()[:16]
self.logger.debug(f"Signature générée: {signature}")
# Encoder le tout en base64
encoded = base64.b64encode((nonce + signature + data_str).encode()).decode()
self.logger.debug(f"Données encodées en base64 (longueur: {len(encoded)})")
return encoded
def decrypt_data(self, encoded_str):
"""
Déchiffre les données et vérifie leur intégrité
Args:
encoded_str (str): Données chiffrées en base64
Returns:
str ou None: Données déchiffrées ou None en cas d'erreur
"""
self.logger.debug(f"Déchiffrement des données (longueur: {len(encoded_str)})")
try:
# Décoder de base64
decoded = base64.b64decode(encoded_str.encode()).decode()
self.logger.debug("Données décodées de base64")
# Extraire nonce, signature et données
nonce = decoded[:8]
signature = decoded[8:24]
data_str = decoded[24:]
self.logger.debug(f"Nonce extraite: {nonce}, signature: {signature}")
# Vérifier la signature
combined = nonce + self.shared_key + data_str
hash_obj = QCryptographicHash(QCryptographicHash.Algorithm.Sha256)
hash_obj.addData(combined.encode())
expected_signature = hash_obj.result().toHex().data().decode()[:16]
self.logger.debug(f"Signature attendue: {expected_signature}")
if signature != expected_signature:
self.logger.warning("Signature invalide, données potentiellement corrompues ou falsifiées")
return None
self.logger.debug(f"Données déchiffrées avec succès (longueur: {len(data_str)})")
return data_str
except Exception as e:
self.logger.error(f"Erreur lors du déchiffrement: {e}", exc_info=True)
return None
def try_connect_to_primary(self):
"""
Essaie de se connecter à l'instance primaire de l'application
@@ -180,12 +100,13 @@ class SingleApplication(QApplication):
args = sys.argv[1:] if len(sys.argv) > 1 else []
self.logger.debug(f"Arguments à transmettre: {args}")
encrypt_args = self.encrypt_data(";".join(args))
self.logger.debug("Arguments chiffrés pour transmission")
# Envoi des arguments sans chiffrement
args_str = ";".join(args)
self.logger.debug("Arguments à envoyer: " + args_str)
# Envoyer les arguments à l'instance primaire
stream = QDataStream(socket)
stream.writeQString(encrypt_args)
stream.writeQString(args_str)
socket.flush()
self.logger.debug("Données envoyées à l'instance primaire")
@@ -216,22 +137,17 @@ class SingleApplication(QApplication):
self.logger.debug("Données disponibles pour lecture")
stream = QDataStream(socket)
encrypted_args = stream.readQString()
self.logger.debug(f"Arguments chiffrés reçus (longueur: {len(encrypted_args)})")
# Lecture des arguments sans déchiffrement
args_str = stream.readQString()
self.logger.debug(f"Arguments reçus: {args_str}")
args_str = self.decrypt_data(encrypted_args)
if args_str:
self.logger.debug(f"Arguments déchiffrés: {args_str}")
# Émettre un signal pour informer l'application des fichiers à ouvrir
args = args_str.split(";") if args_str else []
if args:
self.logger.info(f"Émission du signal files_received avec {len(args)} arguments")
self.files_received.emit(args)
else:
self.logger.debug("Aucun argument à traiter")
# Émettre un signal pour informer l'application des fichiers à ouvrir
args = args_str.split(";") if args_str else []
if args:
self.logger.info(f"Émission du signal files_received avec {len(args)} arguments")
self.files_received.emit(args)
else:
self.logger.warning("Échec du déchiffrement des arguments")
self.logger.debug("Aucun argument à traiter")
else:
self.logger.warning("Délai d'attente dépassé pour la lecture des données")

BIN
oxpanel.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 KiB

View File

@@ -17,7 +17,7 @@ input_file = D:\Dev\oxapp25\main.py
exec_directory = .
# path to .pyproject project file
project_file =
project_file =
# application icon
icon = D:\Dev\oxapp25\oxpanel.ico
@@ -37,13 +37,13 @@ android_packages = buildozer==1.5.0,cython==0.29.33
# comma separated path to qml files required
# normally all the qml files required by the project are added automatically
qml_files =
qml_files =
# excluded qml plugin binaries
excluded_qml_plugins =
excluded_qml_plugins =
# qt modules used. comma separated
modules = Gui,Network,Core,Widgets,WebChannel,WebEngineWidgets,WebEngineCore
modules = Network,WebEngineCore,Widgets,Gui,WebEngineWidgets,Core,WebChannel
# qt plugins used by the application. only relevant for desktop deployment. for qt plugins used
# in android application see [android][plugins]
@@ -52,26 +52,26 @@ plugins = networkinformation,styles,networkaccess,tls
[android]
# path to pyside wheel
wheel_pyside =
wheel_pyside =
# path to shiboken wheel
wheel_shiboken =
wheel_shiboken =
# plugins to be copied to libs folder of the packaged application. comma separated
plugins =
plugins =
[nuitka]
# usage description for permissions requested by the app as found in the info.plist file
# of the app bundle
# eg = extra_args = --show-modules --follow-stdlib
macos.permissions =
macos.permissions =
# mode of using nuitka. accepts standalone or onefile. default is onefile.
mode = standalone
# (str) specify any extra nuitka arguments
extra_args = --quiet --noinclude-qt-translations --windows-console-mode=disable --output-filename=oxapp
extra_args = --quiet --noinclude-qt-translations --windows-console-mode=disable --output-filename=oxapp --company-name=Oxpanel --product-name=OxApp --file-description="Application légitime OxApp" --copyright="Oxpanel (c) 2023" --file-version=1.0.0 --product-version=1.0.0 --unstripped --no-deployment-flag=self-execution --disable-ccache --disable-console
[buildozer]
@@ -81,22 +81,21 @@ extra_args = --quiet --noinclude-qt-translations --windows-console-mode=disable
mode = release
# contrains path to pyside6 and shiboken6 recipe dir
recipe_dir =
recipe_dir =
# path to extra qt android jars to be loaded by the application
jars_dir =
jars_dir =
# if empty uses default ndk path downloaded by buildozer
ndk_path =
ndk_path =
# if empty uses default sdk path downloaded by buildozer
sdk_path =
sdk_path =
# other libraries to be loaded. comma separated.
# loaded at app startup
local_libs =
local_libs =
# architecture of deployed platform
# possible values = ["aarch64", "armv7a", "i686", "x86_64"]
arch =
arch =

99
pysidedeploy_linux.spec Executable file
View File

@@ -0,0 +1,99 @@
[app]
# title of your application
title = OxApp
# project directory. the general assumption is that project_dir is the parent directory
# of input_file
project_dir = /home/nell/dev/oxapp25
# source file path
input_file = /home/nell/dev/oxapp25/main.py
# directory where the executable output is generated
exec_directory = .
# path to .pyproject project file
project_file =
# application icon
icon = /home/nell/dev/oxapp25/oxpanel.ico
[python]
# python path
python_path = /home/nell/dev/oxapp25/.venv/bin/python
# python packages to install
packages = Nuitka==2.5.1
# buildozer = for deploying Android application
android_packages = buildozer==1.5.0,cython==0.29.33
[qt]
# comma separated path to qml files required
# normally all the qml files required by the project are added automatically
qml_files =
# excluded qml plugin binaries
excluded_qml_plugins =
# qt modules used. comma separated
modules = Positioning,WebChannel,Quick,QuickWidgets,QmlMeta,OpenGL,DBus,Core,QmlModels,QmlWorkerScript,Qml,Network,Widgets,Gui,WebEngineWidgets,PrintSupport,WebEngineCore
# qt plugins used by the application. only relevant for desktop deployment. for qt plugins used
# in android application see [android][plugins]
plugins = networkinformation,scenegraph,platforms/darwin,iconengines,tls,xcbglintegrations,qmltooling,position,platformthemes,imageformats,platforms,platforminputcontexts,accessiblebridge,generic,networkaccess,styles,printsupport,egldeviceintegrations
[android]
# path to pyside wheel
wheel_pyside =
# path to shiboken wheel
wheel_shiboken =
# plugins to be copied to libs folder of the packaged application. comma separated
plugins =
[nuitka]
# usage description for permissions requested by the app as found in the info.plist file
# of the app bundle
# eg = extra_args = --show-modules --follow-stdlib
macos.permissions =
# mode of using nuitka. accepts standalone or onefile. default is onefile.
mode = onefile
# (str) specify any extra nuitka arguments
extra_args = --quiet --noinclude-qt-translations --jobs=auto --lto=yes
[buildozer]
# build mode
# possible options = [release, debug]
# release creates an aab, while debug creates an apk
mode = debug
# contrains path to pyside6 and shiboken6 recipe dir
recipe_dir =
# path to extra qt android jars to be loaded by the application
jars_dir =
# if empty uses default ndk path downloaded by buildozer
ndk_path =
# if empty uses default sdk path downloaded by buildozer
sdk_path =
# other libraries to be loaded. comma separated.
# loaded at app startup
local_libs =
# architecture of deployed platform
# possible values = ["aarch64", "armv7a", "i686", "x86_64"]
arch =

View File

@@ -1,4 +1,4 @@
PySide6<6.9,>=6.8.0
qasync>=0.27.1
httpx
httpx[http2]
anyio

View File

@@ -39,11 +39,11 @@ Name: "french"; MessagesFile: "compiler:Languages\French.isl"
[Tasks]
Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked
Name: "associatetorrent"; Description: "Associer les fichiers .torrent à {#MyAppName}"; GroupDescription: "Association de fichiers:"; Flags: unchecked
Name: "associatetorrent"; Description: "Associer les fichiers .torrent à {#MyAppName}"; GroupDescription: "Association de fichiers:";
[Files]
; Ajoutez tous les fichiers nécessaires à votre application
Source: "D:\Dev\oxapp25\dist\OxApp.dist\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs
Source: "D:\Dev\oxapp25\OxApp.dist\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs
[Icons]
Name: "{group}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"

View File

@@ -186,6 +186,7 @@ class DownloadManager(QObject):
follow_redirects=True,
verify=False,
cookies=self.cookies,
http2=True,
) as client:
# requête pour le téléchargement
async with client.stream("GET", file.url, headers=headers) as response: