Compare commits
5 Commits
9031e1d04d
...
last_async
| Author | SHA1 | Date | |
|---|---|---|---|
| be72749b53 | |||
| dc2adfbca5 | |||
| a693338891 | |||
| bfa6865109 | |||
| 3155154083 |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -1,3 +1,4 @@
|
|||||||
.venv
|
.venv
|
||||||
OxApp.dist
|
OxApp.dist
|
||||||
installer
|
installer
|
||||||
|
OxApp.bin
|
||||||
2
.idea/misc.xml
generated
2
.idea/misc.xml
generated
@@ -3,7 +3,7 @@
|
|||||||
<component name="Black">
|
<component name="Black">
|
||||||
<option name="sdkName" value="Python 3.13 (oxapp25)" />
|
<option name="sdkName" value="Python 3.13 (oxapp25)" />
|
||||||
</component>
|
</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">
|
<component name="PythonCompatibilityInspectionAdvertiser">
|
||||||
<option name="version" value="3" />
|
<option name="version" value="3" />
|
||||||
</component>
|
</component>
|
||||||
|
|||||||
2
.idea/oxapp25.iml
generated
2
.idea/oxapp25.iml
generated
@@ -4,7 +4,7 @@
|
|||||||
<content url="file://$MODULE_DIR$">
|
<content url="file://$MODULE_DIR$">
|
||||||
<excludeFolder url="file://$MODULE_DIR$/.venv" />
|
<excludeFolder url="file://$MODULE_DIR$/.venv" />
|
||||||
</content>
|
</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" />
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
</component>
|
</component>
|
||||||
</module>
|
</module>
|
||||||
2
Makefile
2
Makefile
@@ -16,7 +16,7 @@ resources:
|
|||||||
|
|
||||||
# Déploie l'application avec pyside6-deploy
|
# Déploie l'application avec pyside6-deploy
|
||||||
deploy:
|
deploy:
|
||||||
pyside6-deploy -c pysidedeploy.spec
|
pyside6-deploy -c pysidedeploy_linux.spec
|
||||||
|
|
||||||
# Crée l'exécutable avec PyInstaller
|
# Crée l'exécutable avec PyInstaller
|
||||||
pyinstaller:
|
pyinstaller:
|
||||||
|
|||||||
116
main.py
116
main.py
@@ -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.QtGui import QPalette, QColor
|
||||||
from PySide6.QtNetwork import QLocalServer, QLocalSocket
|
from PySide6.QtNetwork import QLocalServer, QLocalSocket
|
||||||
from PySide6.QtWidgets import QApplication
|
from PySide6.QtWidgets import QApplication
|
||||||
@@ -7,14 +7,8 @@ import qasync
|
|||||||
import sys
|
import sys
|
||||||
import asyncio
|
import asyncio
|
||||||
import os
|
import os
|
||||||
import platform
|
|
||||||
import argparse
|
import argparse
|
||||||
import hashlib
|
|
||||||
import random
|
|
||||||
import string
|
|
||||||
import base64
|
|
||||||
import logging
|
import logging
|
||||||
from pathlib import Path
|
|
||||||
|
|
||||||
from src.logs import configure_logging
|
from src.logs import configure_logging
|
||||||
from windows.main_window import MainWindow
|
from windows.main_window import MainWindow
|
||||||
@@ -63,9 +57,6 @@ class SingleApplication(QApplication):
|
|||||||
self.app_id = app_id
|
self.app_id = app_id
|
||||||
self.logger.debug(f"ID de l'application: {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.server = None
|
||||||
self.is_primary_instance = self.try_connect_to_primary()
|
self.is_primary_instance = self.try_connect_to_primary()
|
||||||
|
|
||||||
@@ -77,7 +68,8 @@ class SingleApplication(QApplication):
|
|||||||
self.logger.debug("Signal newConnection connecté")
|
self.logger.debug("Signal newConnection connecté")
|
||||||
|
|
||||||
if not self.server.listen(self.app_id):
|
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
|
# En cas d'erreur (serveur déjà existant mais zombie), on le supprime et on réessaie
|
||||||
QLocalServer.removeServer(self.app_id)
|
QLocalServer.removeServer(self.app_id)
|
||||||
if self.server.listen(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")
|
self.logger.info("Instance secondaire détectée, fermeture de l'application")
|
||||||
QTimer.singleShot(0, self.quit)
|
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):
|
def try_connect_to_primary(self):
|
||||||
"""
|
"""
|
||||||
Essaie de se connecter à l'instance primaire de l'application
|
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 []
|
args = sys.argv[1:] if len(sys.argv) > 1 else []
|
||||||
self.logger.debug(f"Arguments à transmettre: {args}")
|
self.logger.debug(f"Arguments à transmettre: {args}")
|
||||||
|
|
||||||
encrypt_args = self.encrypt_data(";".join(args))
|
# Envoi des arguments sans chiffrement
|
||||||
self.logger.debug("Arguments chiffrés pour transmission")
|
args_str = ";".join(args)
|
||||||
|
self.logger.debug("Arguments à envoyer: " + args_str)
|
||||||
|
|
||||||
# Envoyer les arguments à l'instance primaire
|
# Envoyer les arguments à l'instance primaire
|
||||||
stream = QDataStream(socket)
|
stream = QDataStream(socket)
|
||||||
stream.writeQString(encrypt_args)
|
stream.writeQString(args_str)
|
||||||
socket.flush()
|
socket.flush()
|
||||||
self.logger.debug("Données envoyées à l'instance primaire")
|
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")
|
self.logger.debug("Données disponibles pour lecture")
|
||||||
stream = QDataStream(socket)
|
stream = QDataStream(socket)
|
||||||
|
|
||||||
encrypted_args = stream.readQString()
|
# Lecture des arguments sans déchiffrement
|
||||||
self.logger.debug(f"Arguments chiffrés reçus (longueur: {len(encrypted_args)})")
|
args_str = stream.readQString()
|
||||||
|
self.logger.debug(f"Arguments reçus: {args_str}")
|
||||||
|
|
||||||
args_str = self.decrypt_data(encrypted_args)
|
# Émettre un signal pour informer l'application des fichiers à ouvrir
|
||||||
if args_str:
|
args = args_str.split(";") if args_str else []
|
||||||
self.logger.debug(f"Arguments déchiffrés: {args_str}")
|
if args:
|
||||||
|
self.logger.info(f"Émission du signal files_received avec {len(args)} arguments")
|
||||||
# Émettre un signal pour informer l'application des fichiers à ouvrir
|
self.files_received.emit(args)
|
||||||
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")
|
|
||||||
else:
|
else:
|
||||||
self.logger.warning("Échec du déchiffrement des arguments")
|
self.logger.debug("Aucun argument à traiter")
|
||||||
else:
|
else:
|
||||||
self.logger.warning("Délai d'attente dépassé pour la lecture des données")
|
self.logger.warning("Délai d'attente dépassé pour la lecture des données")
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ input_file = D:\Dev\oxapp25\main.py
|
|||||||
exec_directory = .
|
exec_directory = .
|
||||||
|
|
||||||
# path to .pyproject project file
|
# path to .pyproject project file
|
||||||
project_file =
|
project_file =
|
||||||
|
|
||||||
# application icon
|
# application icon
|
||||||
icon = D:\Dev\oxapp25\oxpanel.ico
|
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
|
# comma separated path to qml files required
|
||||||
# normally all the qml files required by the project are added automatically
|
# normally all the qml files required by the project are added automatically
|
||||||
qml_files =
|
qml_files =
|
||||||
|
|
||||||
# excluded qml plugin binaries
|
# excluded qml plugin binaries
|
||||||
excluded_qml_plugins =
|
excluded_qml_plugins =
|
||||||
|
|
||||||
# qt modules used. comma separated
|
# qt modules used. comma separated
|
||||||
modules = WebEngineCore,WebEngineWidgets,WebChannel,Core,Gui,Widgets,Network
|
modules = Network,WebEngineCore,Widgets,Gui,WebEngineWidgets,Core,WebChannel
|
||||||
|
|
||||||
# qt plugins used by the application. only relevant for desktop deployment. for qt plugins used
|
# qt plugins used by the application. only relevant for desktop deployment. for qt plugins used
|
||||||
# in android application see [android][plugins]
|
# in android application see [android][plugins]
|
||||||
@@ -52,26 +52,26 @@ plugins = networkinformation,styles,networkaccess,tls
|
|||||||
[android]
|
[android]
|
||||||
|
|
||||||
# path to pyside wheel
|
# path to pyside wheel
|
||||||
wheel_pyside =
|
wheel_pyside =
|
||||||
|
|
||||||
# path to shiboken wheel
|
# path to shiboken wheel
|
||||||
wheel_shiboken =
|
wheel_shiboken =
|
||||||
|
|
||||||
# plugins to be copied to libs folder of the packaged application. comma separated
|
# plugins to be copied to libs folder of the packaged application. comma separated
|
||||||
plugins =
|
plugins =
|
||||||
|
|
||||||
[nuitka]
|
[nuitka]
|
||||||
|
|
||||||
# usage description for permissions requested by the app as found in the info.plist file
|
# usage description for permissions requested by the app as found in the info.plist file
|
||||||
# of the app bundle
|
# of the app bundle
|
||||||
# eg = extra_args = --show-modules --follow-stdlib
|
# eg = extra_args = --show-modules --follow-stdlib
|
||||||
macos.permissions =
|
macos.permissions =
|
||||||
|
|
||||||
# mode of using nuitka. accepts standalone or onefile. default is onefile.
|
# mode of using nuitka. accepts standalone or onefile. default is onefile.
|
||||||
mode = standalone
|
mode = standalone
|
||||||
|
|
||||||
# (str) specify any extra nuitka arguments
|
# (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]
|
[buildozer]
|
||||||
|
|
||||||
@@ -81,22 +81,21 @@ extra_args = --quiet --noinclude-qt-translations --windows-console-mode=disable
|
|||||||
mode = release
|
mode = release
|
||||||
|
|
||||||
# contrains path to pyside6 and shiboken6 recipe dir
|
# contrains path to pyside6 and shiboken6 recipe dir
|
||||||
recipe_dir =
|
recipe_dir =
|
||||||
|
|
||||||
# path to extra qt android jars to be loaded by the application
|
# 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
|
# if empty uses default ndk path downloaded by buildozer
|
||||||
ndk_path =
|
ndk_path =
|
||||||
|
|
||||||
# if empty uses default sdk path downloaded by buildozer
|
# if empty uses default sdk path downloaded by buildozer
|
||||||
sdk_path =
|
sdk_path =
|
||||||
|
|
||||||
# other libraries to be loaded. comma separated.
|
# other libraries to be loaded. comma separated.
|
||||||
# loaded at app startup
|
# loaded at app startup
|
||||||
local_libs =
|
local_libs =
|
||||||
|
|
||||||
# architecture of deployed platform
|
# architecture of deployed platform
|
||||||
# possible values = ["aarch64", "armv7a", "i686", "x86_64"]
|
# possible values = ["aarch64", "armv7a", "i686", "x86_64"]
|
||||||
arch =
|
arch =
|
||||||
|
|
||||||
|
|||||||
99
pysidedeploy_linux.spec
Executable file
99
pysidedeploy_linux.spec
Executable 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 =
|
||||||
|
|
||||||
Reference in New Issue
Block a user