Release v1.0.0: autoinstall main.py, plattformübergreifender Start, Doku komplett
27
.gitignore
vendored
@ -1,37 +1,32 @@
|
||||
# Build- und Cache-Ordner ignorieren
|
||||
.dev/__pycache__/
|
||||
.dev/upload/
|
||||
.dev/logs/
|
||||
.dev/build/
|
||||
.dev/dist/
|
||||
.app/__pycache__/
|
||||
.app/upload/
|
||||
.app/logs/
|
||||
.app/build/
|
||||
.app/dist/
|
||||
|
||||
# PyInstaller & kompiliertes Python
|
||||
*.spec
|
||||
#*.exe
|
||||
*.dll
|
||||
*.so
|
||||
*.dylib
|
||||
*.pyd
|
||||
|
||||
# Virtuelle Umgebung ignorieren (falls vorhanden)
|
||||
.dev/.venv/
|
||||
.dev/.env/
|
||||
.dev/.idea/
|
||||
.dev/.vscode/
|
||||
.app/.venv/
|
||||
.app/.env/
|
||||
.app/.idea/
|
||||
.app/.vscode/
|
||||
|
||||
# Zertifikate und sensible Dateien
|
||||
.dev/*.pem
|
||||
.app/*.pem
|
||||
*.crt
|
||||
*.key
|
||||
|
||||
# Sonstiges (Windows & macOS Systemdateien)
|
||||
Desktop.ini
|
||||
#Desktop.ini
|
||||
Thumbs.db
|
||||
.DS_Store
|
||||
|
||||
# .exe-Dateien überall ignorieren...
|
||||
*.exe
|
||||
|
||||
# ... außer im .dev/Output/ Verzeichnis (Ausnahme!)
|
||||
!./Output/
|
||||
!./Output/*
|
||||
|
24
CHANGELOG.md
Normal file
@ -0,0 +1,24 @@
|
||||
# CHANGELOG
|
||||
|
||||
## pyUpload (TKInter-Version 1.0)
|
||||
|
||||
- 2025-04-21
|
||||
|
||||
- Geändert
|
||||
- `main.py` übernimmt nun automatisch die Erstellung der virtuellen Umgebung `.venv` und die Installation der Abhängigkeiten aus `requirements.txt`
|
||||
- Entfernt: `install.cmd` und `startUpload.cmd` wurden vollständig ersetzt durch neue Startlogik
|
||||
- `start.cmd` wurde vereinfacht, prüft nun auf vorhandenes `python` und startet `main.py` über absoluten Pfad
|
||||
- `main.py` setzt bei Start automatisch `os.chdir()` auf das eigene Verzeichnis, um relative Pfade sicher zu behandeln
|
||||
|
||||
- Hinzugefügt
|
||||
- Neue plattformunabhängige `start.sh` für Linux/macOS
|
||||
- Automatischer Restart nach Installation über `os.execv()` in `main.py`
|
||||
- Neue Sicherheits- und Netzwerkinformationen in der `README.md`
|
||||
- Erweiterung der `README.md` um Speicherort der Uploads und Projektstruktur
|
||||
- Hinweis auf Projektstatus und neue Version unter <https://github.com/realAscot/pyUpload2>
|
||||
- Neue LICENSE-Datei (proprietär, nicht zur Weitergabe)
|
||||
|
||||
- Fixes
|
||||
- PowerShell-Inkompatibilitäten mit `set /p` entfernt
|
||||
- `.cmd`-Startskripte reagieren jetzt korrekt auf STRG+C
|
||||
- Mehrere Markdown-Korrekturen (Codeblöcke, Leerzeilen, Lesbarkeit)
|
17
LICENSE
Normal file
@ -0,0 +1,17 @@
|
||||
# LICENSE
|
||||
|
||||
Copyright (c) 2025 Adam Skotarczak <adam@skotarczak.net>
|
||||
|
||||
Alle Rechte vorbehalten.
|
||||
|
||||
Diese Software ist urheberrechtlich geschützt. Die Verwendung, Vervielfältigung, Verbreitung oder Änderung
|
||||
dieser Software oder von Teilen davon ist ohne vorherige schriftliche Genehmigung des Autors ausdrücklich untersagt.
|
||||
|
||||
Die Software darf ausschließlich für private, interne oder zu Prüf- und Testzwecken verwendet werden.
|
||||
Eine kommerzielle Nutzung oder Weitergabe an Dritte ist nicht gestattet.
|
||||
|
||||
Die Bereitstellung dieser Software erfolgt OHNE JEGLICHE GARANTIE,
|
||||
weder ausdrücklich noch stillschweigend, einschließlich, aber nicht beschränkt auf die Garantien
|
||||
der Marktgängigkeit oder Eignung für einen bestimmten Zweck.
|
||||
|
||||
Durch die Nutzung dieser Software erklärst du dich mit den oben genannten Bedingungen einverstanden.
|
35
Makefile
@ -1,35 +0,0 @@
|
||||
.PHONY: exe release clean
|
||||
|
||||
# Variablen
|
||||
PYTHON = python3
|
||||
SCRIPT = pyUpload.py
|
||||
EXE_NAME = pyUpload
|
||||
BUILD_DIR = build
|
||||
DIST_DIR = release
|
||||
REQ_FILE = requirements.txt
|
||||
|
||||
exe:
|
||||
@echo "Erzeuge ausführbare Datei..."
|
||||
@mkdir -p $(BUILD_DIR)
|
||||
pyinstaller --onefile --add-data "template.html;." --add-data "success.html;." --add-data "favicon.ico;." --windowed --icon favicon.ico --name $(EXE_NAME) $(SCRIPT)
|
||||
@mv dist/$(EXE_NAME) $(BUILD_DIR)/
|
||||
@echo "Erstellung abgeschlossen: $(BUILD_DIR)/$(EXE_NAME)"
|
||||
|
||||
release: exe
|
||||
@echo "Erstelle Release-Paket..."
|
||||
@mkdir -p $(DIST_DIR)
|
||||
@cp $(BUILD_DIR)/$(EXE_NAME) $(DIST_DIR)/
|
||||
@cp $(REQ_FILE) $(DIST_DIR)/
|
||||
@cp template.html success.html favicon.ico $(DIST_DIR)/
|
||||
@echo "Release-Paket bereit in $(DIST_DIR)"
|
||||
|
||||
zip: release
|
||||
@echo "Erstelle ZIP-Archiv..."
|
||||
@cd $(DIST_DIR) && zip -r ../$(ZIP_NAME) $(EXE_NAME) template.html success.html favicon.ico
|
||||
@echo "ZIP-Archiv erstellt: $(ZIP_NAME)"
|
||||
|
||||
clean:
|
||||
@echo "Bereinige Projektverzeichnis..."
|
||||
@rm -rf $(BUILD_DIR) $(DIST_DIR) build dist __pycache__ *.spec
|
||||
@echo "Bereinigung abgeschlossen."
|
||||
|
175
README.md
@ -1,104 +1,137 @@
|
||||
## pyUpload - Sicherer Datei-Upload-Server für eine einfache und sichere Dateiübertragung
|
||||
# pyUpload (TKInter Version)
|
||||
|
||||
### Beschreibung
|
||||

|
||||
|
||||
pyUpload ist eine leistungsstarke und dennoch einfache Lösung für den sicheren Datei-Upload über HTTPS. Es richtet sich an Privatnutzer, die eine schnelle Möglichkeit suchen, Dateien zwischen Geräten zu übertragen, sowie an Unternehmen oder Teams, die eine sichere Lösung für den internen Datenaustausch benötigen. Dieses Programm eignet sich ideal, um Dateien schnell und unkompliziert von einem Smartphone oder einem anderen Gerät auf einen Computer zu übertragen.
|
||||
## ⚠️ Projektstatus: Eingefroren – Nur noch Bugfixes
|
||||
|
||||
Anstatt zusätzliche Apps oder USB-Kabel zu nutzen, kann der Benutzer den Server starten, den automatisch generierten QR-Code mit dem Smartphone scannen und die Dateien direkt über die Weboberfläche hochladen. Der Computer speichert die hochgeladenen Dateien strukturiert in individuellen Verzeichnissen für jedes Gerät.
|
||||
Diese Version von **pyUpload** wird **nicht weiterentwickelt** und erhält nur noch Fehlerbehebungen.
|
||||
Die neue Version mit Flask-Backend ist **BALD** verfügbar unter:
|
||||
|
||||
Zusätzlich erstellt pyUpload bei Bedarf automatisch ein selbstsigniertes SSL-Zertifikat, um eine verschlüsselte Verbindung sicherzustellen. Damit bleibt die Dateiübertragung geschützt und zuverlässig.
|
||||
🔗 **<https://github.com/realAscot/pyUpload2>**
|
||||
|
||||
### Features – Die Vorteile von pyUpload auf einen Blick
|
||||
---
|
||||
|
||||
- **Sichere Dateiübertragung per HTTPS** – Alle Daten werden verschlüsselt übertragen.
|
||||
- **Automatische Erstellung eines selbstsignierten SSL-Zertifikats** – Keine zusätzliche Konfiguration notwendig.
|
||||
- **Intuitive, webbasierte Benutzeroberfläche** – Einfach zu bedienen, keine Installation erforderlich.
|
||||
- **Strukturierte Speicherung** – Dateien werden in client-spezifischen Verzeichnissen gespeichert.
|
||||
- **Zentralisierte und client-spezifische Logging-Funktion** – Detaillierte Nachverfolgung aller Uploads.
|
||||
- **Flexible Nutzung mit oder ohne GUI** – Start als Desktop-Anwendung oder reine Konsolen-Version möglich.
|
||||
- **Schnelle Einrichtung** – Download, Entpacken und sofort loslegen!
|
||||
## pyUpload – Sicherer Datei-Upload-Server über HTTPS (lokal & offline)
|
||||
|
||||
### Installationsanleitung – So startest du pyUpload
|
||||
Diese Version basiert auf **Tkinter (GUI + QR)** sowie einer optionalen **reinen CLI-Nutzung**.
|
||||
Sie ist vollständig lokal lauffähig – ganz ohne Installation von externen Tools oder komplexen Abhängigkeiten.
|
||||
|
||||
Es gibt drei Möglichkeiten, pyUpload zu nutzen:
|
||||
- **Manuelle Installation** in einer vorhandenen Python-Umgebung, in der alle notwendigen Bibliotheken manuell installiert werden.
|
||||
- **Nutzung einer vorgefertigten, ausführbaren .exe (Windows) Version**, die mit pyinstaller kompiliert wurde.
|
||||
- **Nutzung in einer virtuellen Python-Umgebung**, die automatisch durch `install.bat` eingerichtet wird. Anschließend kann das Programm mit `start.bat` gestartet werden.
|
||||
---
|
||||
|
||||
#### 1. Manuelle Installation für Python-Nutzer
|
||||
## 🛠 Features
|
||||
|
||||
1. Stelle sicher, dass **Python 3** auf deinem System installiert ist.
|
||||
2. Installiere alle benötigten Abhängigkeiten mit folgendem Befehl:
|
||||
- **HTTPS-gesicherter Datei-Upload**
|
||||
- **Selbstsigniertes SSL-Zertifikat bei Bedarf**
|
||||
- **QR-Code-basierte Verbindung für Smartphones**
|
||||
- **Client-spezifische Verzeichnisse und Logs**
|
||||
- **GUI und Konsolen-Modus verfügbar**
|
||||
- **automatische Einrichtung von `.venv` und Abhängigkeiten**
|
||||
- **kein Installationsskript mehr nötig – alles passiert beim Start von `main.py`**
|
||||
|
||||
```
|
||||
pip install -r requirements.txt
|
||||
```
|
||||
3. Starte den Server mit:
|
||||
---
|
||||
|
||||
```
|
||||
python pyUpload.py
|
||||
```
|
||||
4. Falls du keine grafische Benutzeroberfläche benötigst, kannst du den Server im Konsolenmodus starten:
|
||||
## 🚀 Schnellstart
|
||||
|
||||
```
|
||||
python pyUpload.py --nogui
|
||||
### ▶️ Für Windows:
|
||||
|
||||
1. Lade das Projekt herunter oder klone es:
|
||||
|
||||
```sh
|
||||
|
||||
git clone https://github.com/realAscot/pyUpload
|
||||
```
|
||||
|
||||
#### 2. Nutzung der fertigen .exe Download-Version
|
||||
2. Starte die App mit:
|
||||
|
||||
Falls du keine Python-Installation benötigst, kannst du die vorgefertigte **ZIP-Version** von pyUpload herunterladen. Diese enthält bereits alle notwendigen Dateien und ist sofort einsatzbereit.
|
||||
|
||||
1. Lade die neueste **pyUpload.zip** von der offiziellen Website herunter, inklusive virtueller Umgebung.
|
||||
2. Entpacke die ZIP-Datei in einen beliebigen Ordner.
|
||||
3. Starte die enthaltene `pyUpload.exe`.
|
||||
4. Falls die grafische Benutzeroberfläche nicht benötigt wird, kann die `pyUpload.exe` direkt in der Konsole mit `--nogui` gestartet werden:
|
||||
|
||||
```
|
||||
pyUpload.exe --nogui
|
||||
```
|
||||
5. Eine Übersicht aller verfügbaren Befehle und Optionen erhältst du mit:
|
||||
|
||||
```
|
||||
pyUpload.exe --help
|
||||
```cmd
|
||||
start.cmd
|
||||
```
|
||||
|
||||
#### 3. Nutzung in virtueller Python-Umgebung
|
||||
Alternativ in PowerShell:
|
||||
|
||||
Lade die ZIP-Datei mit der virtuellen Installationsumgebung herunter und starte die `install.bat` durch Doppelklick. Es öffnet sich ein Konsolenfenster (CLI) und eine virtuelle Umgebung für pyUpload wird erstellt. Anschließend kann das Programm mit der `start.bat` gestartet werden. In der Grundeinstellung wird eine GUI mit QR-Code gestartet.
|
||||
```powershell
|
||||
cmd /c start.cmd
|
||||
```
|
||||
|
||||
### Zugriff auf die Weboberfläche
|
||||
### 🐧 Für Linux / macOS:
|
||||
|
||||
- Sobald der Server läuft, kann er über die lokale IP-Adresse aufgerufen werden:
|
||||
|
||||
```
|
||||
https://<server-ip>:4443
|
||||
```
|
||||
- Falls die GUI-Version gestartet wurde, erscheint ein **QR-Code**, der die Verbindungsadresse enthält. Dies ermöglicht eine einfache Verbindung mit Smartphones und Tablets.
|
||||
1. Stelle sicher, dass Python 3.8+ installiert ist:
|
||||
|
||||
### Datei-Upload leicht gemacht – So funktioniert es
|
||||
```bash
|
||||
python3 --version
|
||||
```
|
||||
|
||||
1. Öffne die **Weboberfläche** im Browser.
|
||||
2. Wähle die gewünschte **Datei aus** und klicke auf **„Hochladen“**.
|
||||
3. Nach erfolgreichem Upload erscheint eine **Bestätigungsseite**, die den Abschluss der Übertragung bestätigt.
|
||||
2. Mache das Startscript ausführbar:
|
||||
|
||||
### SSL-Zertifikatswarnung in Browsern umgehen
|
||||
```bash
|
||||
chmod +x start.sh
|
||||
```
|
||||
|
||||
Da pyUpload ein **selbstsigniertes SSL-Zertifikat** nutzt, wird es beim ersten Zugriff zu einer Warnung des Browsers kommen. Alternativ kann ein eigenes SSL-Zertifikat hinterlegt werden, indem die Zertifikats- und Schlüsseldateien `cert.pem` und `key.pem` durch eigene, signierte Zertifikate ersetzt werden. Um die verschlüsselte Verbindung zu akzeptieren, gibt es zwei Möglichkeiten:
|
||||
3. Starte die App:
|
||||
|
||||
- In den meisten Browsern gibt es eine Option wie **„Erweitert“** oder **„Trotzdem fortfahren“**, um die Warnung zu übergehen.
|
||||
- Alternativ kann das Zertifikat **manuell importiert und als vertrauenswürdig markiert** werden, um künftige Warnmeldungen zu vermeiden.
|
||||
```bash
|
||||
./start.sh
|
||||
```
|
||||
|
||||
### Logging und Fehlerbehandlung – Transparenz und Kontrolle
|
||||
---
|
||||
|
||||
- Alle **Uploads und Anfragen** werden in **zentralen sowie client-spezifischen Logdateien** gespeichert. Diese befinden sich im `logs/`-Verzeichnis.
|
||||
- Falls während der Nutzung von pyUpload **Probleme auftreten**, bietet ein Blick in diese Logdateien wertvolle Hinweise zur Fehlerbehebung.
|
||||
Beim ersten Start wird automatisch:
|
||||
|
||||
### Autoren & Mitwirkende
|
||||
- eine virtuelle Umgebung `.venv/` im `app/`-Verzeichnis erzeugt
|
||||
- `requirements.txt` installiert
|
||||
- das Programm danach neu aus der Umgebung gestartet
|
||||
|
||||
Danke an alle, die zu diesem Projekt beigetragen haben!
|
||||
---
|
||||
|
||||
- **[Adam Skotarczak](https://github.com/AJaquet)** - Projektleitung & Entwicklung
|
||||
## 🧩 Kommandozeilenoptionen
|
||||
|
||||
### Lizenz und Autor
|
||||
```sh
|
||||
python app\main.py --nogui # Start ohne GUI / QR
|
||||
python app\main.py --port 9999 # Custom-Port verwenden
|
||||
```
|
||||
|
||||
- **Entwickelt von Adam Skotarczak (C) 2025**.
|
||||
---
|
||||
|
||||
## 🌐 Zugriff im Browser
|
||||
|
||||
Sobald gestartet:
|
||||
|
||||
```https
|
||||
https://<lokale-IP>:4443
|
||||
```
|
||||
|
||||
Alternativ QR-Code scannen (GUI-Modus).
|
||||
Dateien werden im `upload/<Client-IP>/` gespeichert.
|
||||
|
||||
---
|
||||
|
||||
## 📁 Logs & Uploads
|
||||
|
||||
- **Uploads**: im Ordner `upload/` nach Client-IP
|
||||
- **Zentrale Logs**: `logs/pyupload.log`
|
||||
- **Pro-Client Logs**: `logs/<Client-IP>.log`
|
||||
|
||||
---
|
||||
|
||||
## 🔐 Hinweis zur SSL-Zertifikatswarnung
|
||||
|
||||
Beim ersten Aufruf im Browser erscheint eine Warnung wegen des selbstsignierten Zertifikats.
|
||||
Du kannst:
|
||||
|
||||
- auf **„Erweitert“ > „Trotzdem fortfahren“** klicken
|
||||
- eigene Zertifikate in `cert.pem` und `key.pem` hinterlegen
|
||||
|
||||
---
|
||||
|
||||
## 👨💻 Autor
|
||||
|
||||
- **Adam Skotarczak**
|
||||
Kontakt: [adam@skotarczak.net](mailto:adam@skotarczak.net)
|
||||
GitHub: [realAscot](https://github.com/realAscot)
|
||||
|
||||
---
|
||||
|
||||
## 📝 Lizenz
|
||||
|
||||
- Proprietär, © 2025 Adam Skotarczak
|
||||
**Keine Weitergabe ohne ausdrückliche Genehmigung**
|
||||
|
@ -1,4 +0,0 @@
|
||||
# Entwicklertagebuch
|
||||
|
||||
## 08.03.25
|
||||
Heute habe ich die mit innoSetup auf einem Rechner installiert auf dem überhaupt kein Python installiert war und dies funktionierte nicht. Klar auch, die venv Umgebung setzt eine Python Installation vorraus und arbeitet mit absoluten Pfaden. Der nächste Versuch wird mit einer portablen Python Version durchgeführt.
|
BIN
app/favicon.ico
Normal file
After Width: | Height: | Size: 93 KiB |
@ -6,6 +6,30 @@
|
||||
|
||||
import os
|
||||
import sys
|
||||
import subprocess
|
||||
|
||||
# Pfade definieren
|
||||
os.chdir(os.path.dirname(os.path.abspath(__file__)))
|
||||
|
||||
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||
VENV_DIR = os.path.join(BASE_DIR, ".venv")
|
||||
VENV_PYTHON = os.path.join(VENV_DIR, "Scripts", "python.exe") if os.name == "nt" else os.path.join(VENV_DIR, "bin", "python")
|
||||
REQUIREMENTS_FILE = os.path.join(BASE_DIR, "requirements.txt")
|
||||
|
||||
# Wenn wir NICHT in der venv sind → prüfen, ob venv existiert
|
||||
if sys.prefix == sys.base_prefix and not os.path.exists(VENV_DIR):
|
||||
print("[Setup] Virtuelle Umgebung wird erstellt...")
|
||||
subprocess.run([sys.executable, "-m", "venv", "--copies", VENV_DIR], check=True)
|
||||
|
||||
print("[Setup] requirements.txt wird installiert...")
|
||||
subprocess.run([VENV_PYTHON, "-m", "pip", "install", "--upgrade", "pip"], check=True)
|
||||
subprocess.run([VENV_PYTHON, "-m", "pip", "install", "-r", REQUIREMENTS_FILE], check=True)
|
||||
|
||||
print("[Setup] Starte erneut mit aktivierter Umgebung...")
|
||||
os.execv(VENV_PYTHON, [VENV_PYTHON] + sys.argv)
|
||||
|
||||
# Wir sind jetzt sicher in der richtigen Umgebung → Rest des Programms geht hier weiter:
|
||||
|
||||
import ssl
|
||||
import logging
|
||||
import socket
|
||||
@ -13,43 +37,35 @@ import argparse
|
||||
import threading
|
||||
from http.server import HTTPServer, BaseHTTPRequestHandler
|
||||
from datetime import datetime, timedelta, timezone
|
||||
|
||||
from cryptography import x509
|
||||
from cryptography.x509.oid import NameOID
|
||||
from cryptography.hazmat.primitives import hashes, serialization
|
||||
from cryptography.hazmat.primitives.asymmetric import rsa
|
||||
|
||||
# -------------------------------------------------------------------
|
||||
# Virtuelle Umgebung (aktuell noch in der pyUpload.bat)
|
||||
# Virtuelle Umgebung aktivieren (wenn nicht aktiv)
|
||||
# -------------------------------------------------------------------
|
||||
|
||||
# Name der virtuellen Umgebung
|
||||
VENV_DIR = ".venv"
|
||||
|
||||
def activate_venv():
|
||||
"""Aktiviert die virtuelle Umgebung automatisch, falls sie nicht aktiv ist."""
|
||||
if sys.prefix != os.path.abspath(VENV_DIR):
|
||||
venv_path = os.path.join(os.path.dirname(__file__), VENV_DIR)
|
||||
|
||||
if os.name == "nt": # Windows
|
||||
if os.name == "nt":
|
||||
activate_script = os.path.join(venv_path, "Scripts", "activate.bat")
|
||||
else: # Linux/macOS
|
||||
else:
|
||||
activate_script = os.path.join(venv_path, "bin", "activate")
|
||||
|
||||
if os.path.exists(activate_script):
|
||||
print(f"Aktiviere virtuelle Umgebung: {VENV_DIR}")
|
||||
os.system(f'"{activate_script}"')
|
||||
else:
|
||||
print(f"FEHLER: Virtuelle Umgebung nicht gefunden ({VENV_DIR}). Bitte zuerst install.bat ausführen.")
|
||||
print(f"FEHLER: Virtuelle Umgebung nicht gefunden ({VENV_DIR}). Bitte zuerst install.cmd ausführen.")
|
||||
sys.exit(1)
|
||||
|
||||
# Virtuelle Umgebung aktivieren, wenn sie nicht aktiv ist
|
||||
|
||||
activate_venv()
|
||||
|
||||
# -------------------------------------------------------------------
|
||||
# Globale Konfigurationen & Verzeichnisse
|
||||
# Globale Konfigurationen & Logging
|
||||
# -------------------------------------------------------------------
|
||||
|
||||
UPLOAD_DIR = 'upload'
|
||||
LOG_DIR = 'logs'
|
||||
CERT_FILE = 'cert.pem'
|
||||
@ -69,15 +85,13 @@ central_logger = logging.getLogger("central_logger")
|
||||
client_loggers = {}
|
||||
|
||||
# -------------------------------------------------------------------
|
||||
# HTTP-Request-Handler
|
||||
# HTTP-Handler für Upload und Logging
|
||||
# -------------------------------------------------------------------
|
||||
|
||||
class SecureHTTPRequestHandler(BaseHTTPRequestHandler):
|
||||
def log_message(self, format, *args):
|
||||
"""Sammelt Log-Einträge in Client-spezifische Dateien und die Zentrale-Logdatei."""
|
||||
client_ip = self.client_address[0]
|
||||
message = format % args
|
||||
|
||||
# Einmalig pro Client-IP einen dedizierten Logger anlegen.
|
||||
if client_ip not in client_loggers:
|
||||
logger = logging.getLogger(f'client_{client_ip}')
|
||||
logger.setLevel(logging.INFO)
|
||||
@ -86,13 +100,10 @@ class SecureHTTPRequestHandler(BaseHTTPRequestHandler):
|
||||
handler.setFormatter(logging.Formatter('%(asctime)s - %(message)s'))
|
||||
logger.addHandler(handler)
|
||||
client_loggers[client_ip] = logger
|
||||
|
||||
# In den Client-spezifischen Logger und in den zentralen Logger schreiben.
|
||||
client_loggers[client_ip].info(message)
|
||||
central_logger.info(f"{client_ip} - {message}")
|
||||
|
||||
def send_html_response(self, filename):
|
||||
"""Liefert eine HTML-Datei als HTTP-Response zurück."""
|
||||
try:
|
||||
with open(filename, "r", encoding="utf-8") as f:
|
||||
content = f.read()
|
||||
@ -104,7 +115,6 @@ class SecureHTTPRequestHandler(BaseHTTPRequestHandler):
|
||||
self.send_error(500, "HTML-Template nicht gefunden")
|
||||
|
||||
def do_GET(self):
|
||||
"""Ausliefern der Upload-Seite (template.html)."""
|
||||
if self.path == '/':
|
||||
self.send_html_response("template.html")
|
||||
else:
|
||||
@ -112,63 +122,50 @@ class SecureHTTPRequestHandler(BaseHTTPRequestHandler):
|
||||
self.log_message('404 Not Found: %s', self.path)
|
||||
|
||||
def do_POST(self):
|
||||
"""Behandelt Datei-Uploads (multipart/form-data) direkt als Stream."""
|
||||
try:
|
||||
content_type = self.headers.get('Content-Type')
|
||||
content_length = int(self.headers.get('Content-Length', 0))
|
||||
|
||||
if not content_type or 'multipart/form-data' not in content_type:
|
||||
self.send_error(400, "Ungültiger Content-Type")
|
||||
self.log_message('400 Bad Request: Ungültiger Content-Type')
|
||||
return
|
||||
|
||||
if content_length == 0:
|
||||
self.send_error(400, "Leere Anfrage erhalten")
|
||||
self.log_message('400 Bad Request: Leere Anfrage')
|
||||
return
|
||||
|
||||
client_ip = self.client_address[0]
|
||||
client_upload_dir = os.path.join(UPLOAD_DIR, client_ip)
|
||||
os.makedirs(client_upload_dir, exist_ok=True)
|
||||
|
||||
boundary = content_type.split("boundary=")[-1].encode()
|
||||
raw_data = self.rfile.read(content_length)
|
||||
parts = raw_data.split(b"--" + boundary)
|
||||
|
||||
found_file = False
|
||||
|
||||
for part in parts:
|
||||
if b"Content-Disposition" in part:
|
||||
headers, file_data = part.split(b"\r\n\r\n", 1)
|
||||
filename_start = headers.find(b'filename="') + 10
|
||||
filename_end = headers.find(b'"', filename_start)
|
||||
filename = headers[filename_start:filename_end].decode()
|
||||
|
||||
if filename: # Falls tatsächlich ein Dateiname vorhanden ist
|
||||
if filename:
|
||||
file_path = os.path.join(client_upload_dir, os.path.basename(filename))
|
||||
with open(file_path, "wb") as f:
|
||||
# Entferne das trailing CRLF oder "--"
|
||||
f.write(file_data.rstrip(b"\r\n--"))
|
||||
self.log_message(f"Datei {filename} erfolgreich hochgeladen.")
|
||||
found_file = True
|
||||
|
||||
if not found_file:
|
||||
self.send_error(400, "Keine Datei im Upload enthalten")
|
||||
self.log_message('400 Bad Request: Keine Datei übermittelt')
|
||||
return
|
||||
|
||||
# Erfolgsseite senden
|
||||
self.send_html_response("success.html")
|
||||
|
||||
except Exception as e:
|
||||
self.log_message(f"Fehler: {e}")
|
||||
self.send_error(500, "Interner Serverfehler")
|
||||
|
||||
# -------------------------------------------------------------------
|
||||
# HTTPS-Server-Setup
|
||||
# HTTPS-Server mit selbstsigniertem Zertifikat
|
||||
# -------------------------------------------------------------------
|
||||
|
||||
def generate_self_signed_cert(cert_file, key_file):
|
||||
"""Erzeugt ein selbstsigniertes SSL-Zertifikat, falls keines vorhanden ist."""
|
||||
key = rsa.generate_private_key(public_exponent=65537, key_size=2048)
|
||||
subject = issuer = x509.Name([
|
||||
x509.NameAttribute(NameOID.COUNTRY_NAME, "DE"),
|
||||
@ -191,7 +188,6 @@ def generate_self_signed_cert(cert_file, key_file):
|
||||
)
|
||||
.sign(key, hashes.SHA256())
|
||||
)
|
||||
|
||||
with open(cert_file, "wb") as f:
|
||||
f.write(cert.public_bytes(serialization.Encoding.PEM))
|
||||
with open(key_file, "wb") as f:
|
||||
@ -202,7 +198,6 @@ def generate_self_signed_cert(cert_file, key_file):
|
||||
))
|
||||
|
||||
def get_server_ip():
|
||||
"""Bestimmt die lokale IP-Adresse, um sie z.B. für den QR-Code zu nutzen."""
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
try:
|
||||
s.connect(("8.8.8.8", 80))
|
||||
@ -214,63 +209,51 @@ def get_server_ip():
|
||||
return ip
|
||||
|
||||
def create_https_server(port, handler_class=SecureHTTPRequestHandler):
|
||||
"""Erzeugt ein HTTPS-Serverobjekt (aber startet ihn noch nicht)."""
|
||||
if not os.path.exists(CERT_FILE) or not os.path.exists(KEY_FILE):
|
||||
print("SSL-Zertifikat nicht gefunden. Erstelle selbstsigniertes Zertifikat...")
|
||||
generate_self_signed_cert(CERT_FILE, KEY_FILE)
|
||||
print("Selbstsigniertes SSL-Zertifikat erstellt.")
|
||||
|
||||
server_address = ('', port)
|
||||
httpd = HTTPServer(server_address, handler_class)
|
||||
|
||||
context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
|
||||
context.load_cert_chain(certfile=CERT_FILE, keyfile=KEY_FILE)
|
||||
httpd.socket = context.wrap_socket(httpd.socket, server_side=True)
|
||||
return httpd
|
||||
|
||||
# -------------------------------------------------------------------
|
||||
# Startfunktionen (GUI / no-GUI)
|
||||
# Server starten (mit oder ohne GUI)
|
||||
# -------------------------------------------------------------------
|
||||
|
||||
def run_server_nogui(port):
|
||||
httpd = create_https_server(port)
|
||||
server_ip = get_server_ip()
|
||||
|
||||
try:
|
||||
print(f"Starte HTTPS-Server auf https://{server_ip}:{port}")
|
||||
print("Drücke STRG+C, um zu beenden.")
|
||||
print("warte auf Verbindungen ... \n")
|
||||
print("warte auf Verbindungen ...")
|
||||
print(f"Öffne im Browser: https://{server_ip}:{port}")
|
||||
print("Du musst Dich im gleichen Netzwerk befinden (Lan/ Wlan)")
|
||||
print("Du musst Dich im gleichen Netzwerk befinden (LAN/WLAN)")
|
||||
httpd.serve_forever()
|
||||
|
||||
except KeyboardInterrupt:
|
||||
# Nur eine kurze Meldung ausgeben und dann sauber herunterfahren
|
||||
print("\nSTRG+C erkannt. Fahre Server herunter...")
|
||||
|
||||
except Exception as e:
|
||||
print(f"Fehler aufgetreten: {e}")
|
||||
logging.error("Serverfehler", exc_info=True)
|
||||
|
||||
finally:
|
||||
httpd.server_close()
|
||||
logging.shutdown()
|
||||
print("Server wurde sauber beendet.")
|
||||
|
||||
|
||||
def run_server_with_gui(port):
|
||||
# Nur für QR-Code und GUI benötigt:
|
||||
import qrcode
|
||||
import webbrowser
|
||||
from PIL import Image, ImageTk
|
||||
import tkinter as tk
|
||||
|
||||
"""Startet den Server in einem Hintergrund-Thread und öffnet eine tkinter-GUI mit QR-Code."""
|
||||
# 1) Erzeuge den Server (aber noch kein serve_forever).
|
||||
httpd = create_https_server(port)
|
||||
server_ip = get_server_ip()
|
||||
url = f"https://{server_ip}:{port}"
|
||||
|
||||
# 2) Hintergrund-Thread starten
|
||||
def server_thread():
|
||||
try:
|
||||
print(f"Starte HTTPS-Server auf {url}")
|
||||
@ -281,20 +264,16 @@ def run_server_with_gui(port):
|
||||
httpd.server_close()
|
||||
logging.shutdown()
|
||||
|
||||
t = threading.Thread(target=server_thread, daemon=True)
|
||||
t.start()
|
||||
threading.Thread(target=server_thread, daemon=True).start()
|
||||
|
||||
# 3) tkinter-GUI aufbauen
|
||||
root = tk.Tk()
|
||||
root.title("pyUpload - Secure File Upload")
|
||||
|
||||
# Favicon setzen (nur unter Windows direkt mit .ico möglich)
|
||||
try:
|
||||
root.iconbitmap("favicon.ico")
|
||||
except Exception as e:
|
||||
print(f"Konnte das Icon nicht setzen: {e}")
|
||||
|
||||
# Labels erzeugen
|
||||
labels = [
|
||||
tk.Label(root, text="HTTPS-Upload-Server läuft!", font=("Arial", 14)),
|
||||
tk.Label(root, text=f"IP-Adresse: {server_ip}", font=("Arial", 11)),
|
||||
@ -302,70 +281,48 @@ def run_server_with_gui(port):
|
||||
tk.Label(root, text="Scanne den QR-Code:", font=("Arial", 11))
|
||||
]
|
||||
|
||||
# Alle Labels packen und größte Breite ermitteln
|
||||
max_width = 0
|
||||
total_height = 20 # Grundhöhe als Puffer für Abstände
|
||||
max_width, total_height = 0, 20
|
||||
for label in labels:
|
||||
label.pack(pady=5)
|
||||
label.update_idletasks() # Breite und Höhe berechnen
|
||||
label.update_idletasks()
|
||||
max_width = max(max_width, label.winfo_reqwidth())
|
||||
total_height += label.winfo_reqheight() + 10 # Höhe sammeln
|
||||
total_height += label.winfo_reqheight() + 10
|
||||
|
||||
# QR-Code generieren
|
||||
url = f"https://{server_ip}:{port}"
|
||||
qr = qrcode.QRCode(version=1, box_size=8, border=2)
|
||||
qr.add_data(url)
|
||||
qr.make(fit=True)
|
||||
img_qr = qr.make_image(fill_color="black", back_color="white")
|
||||
|
||||
# QR-Code als Tkinter-Image einbinden
|
||||
img_tk = ImageTk.PhotoImage(img_qr)
|
||||
label_qr = tk.Label(root, image=img_tk)
|
||||
label_qr.pack()
|
||||
|
||||
tk.Label(root, image=img_tk).pack()
|
||||
total_height += img_tk.height() + 20
|
||||
|
||||
# Copyright-Vermerk
|
||||
label_copyright = tk.Label(root, text="Adam Skotarczak (C) 2025", font=("Arial", 9), fg="gray")
|
||||
label_copyright.pack(pady=5)
|
||||
total_height += label_copyright.winfo_reqheight() + 10
|
||||
|
||||
# Funktion für klickbaren Link
|
||||
def open_browser(event):
|
||||
webbrowser.open("https://www.ionivation.com/pyUpload")
|
||||
|
||||
# Klickbarer Link unter Copyright
|
||||
link_label = tk.Label(root, text="Infos: www.ionivation.com/pyUpload", font=("Arial", 10), fg="blue", cursor="hand2")
|
||||
link_label.pack()
|
||||
link_label.bind("<Button-1>", open_browser)
|
||||
total_height += link_label.winfo_reqheight() + 10
|
||||
|
||||
# Funktion zum Beenden
|
||||
def on_quit():
|
||||
root.destroy()
|
||||
|
||||
# Beenden-Button
|
||||
btn_quit = tk.Button(root, text="Beenden", command=on_quit, font=("Arial", 10))
|
||||
btn_quit.pack(pady=10)
|
||||
total_height += btn_quit.winfo_reqheight() + 20
|
||||
|
||||
# Endgültige Fenstergröße setzen
|
||||
tk.Button(root, text="Beenden", command=root.destroy, font=("Arial", 10)).pack(pady=10)
|
||||
root.geometry(f"{max_width + 40}x{total_height + 50}")
|
||||
|
||||
# 4) GUI-Loop starten
|
||||
root.mainloop()
|
||||
|
||||
# -------------------------------------------------------------------
|
||||
# Hauptprogramm mit CLI
|
||||
# Kommandozeilenparser & Einstiegspunkt
|
||||
# -------------------------------------------------------------------
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="Secure file upload server with optional GUI/QR-Code.")
|
||||
parser.add_argument("--port", "-p", type=int, default=4443, help="Port, auf dem der Server lauscht (Standard: 4443)")
|
||||
parser.add_argument("--nogui", "-n", action="store_true", help="Ohne GUI & QR-Code im reinen CLI-Modus starten")
|
||||
|
||||
args = parser.parse_args()
|
||||
print(f"Gestartet mit Port {args.port}, GUI: {not args.nogui}")
|
||||
|
||||
if args.nogui:
|
||||
run_server_nogui(args.port)
|
||||
else:
|
3
app/requirements.txt
Normal file
@ -0,0 +1,3 @@
|
||||
cryptography==44.0.2
|
||||
Pillow==11.1.0
|
||||
qrcode==8.0
|
BIN
app/upload/192.168.178.139/IMG_20250419_174717705.jpg
Normal file
After Width: | Height: | Size: 1.8 MiB |
BIN
app/upload/192.168.178.139/IMG_20250419_174723133.jpg
Normal file
After Width: | Height: | Size: 1.7 MiB |
Before Width: | Height: | Size: 122 KiB |
BIN
assets/logo-1.0-alpha.png
Normal file
After Width: | Height: | Size: 1.5 MiB |
BIN
assets/logo-1.0.png
Normal file
After Width: | Height: | Size: 1.3 MiB |
Before Width: | Height: | Size: 173 KiB |
Before Width: | Height: | Size: 51 KiB |
@ -1,19 +0,0 @@
|
||||
|
||||
## exe erstellen:
|
||||
|
||||
### pyinstaller
|
||||
|
||||
pip install pyinstaller
|
||||
pyinstaller --onefile --add-data "template.html;." --add-data "success.html;." --add-data "favicon.ico;." --windowed --icon favicon.ico pyUpload.py
|
||||
pyinstaller --add-data "template.html;." --add-data "success.html;." --add-data "favicon.ico;." --windowed --icon favicon.ico pyUpload.py
|
||||
|
||||
### nuitka
|
||||
|
||||
python setup.py build
|
||||
nuitka --standalone --onefile --enable-plugin=tk-inter --windows-console-mode=disable --windows-icon-from-ico=favicon.ico pyUpload.py
|
||||
|
||||
|
||||
|
||||
## requirements.txt:
|
||||
|
||||
pipreqs . --force
|
67
build.bat
@ -1,67 +0,0 @@
|
||||
@echo off
|
||||
setlocal
|
||||
|
||||
:: Variablen
|
||||
set SCRIPT=pyUpload.py
|
||||
set EXE_NAME=pyUpload.exe
|
||||
set BUILD_DIR=build
|
||||
set DIST_DIR=release
|
||||
set ZIP_NAME=pyUpload.zip
|
||||
set REQ_FILE=requirements.txt
|
||||
|
||||
:: Liste von Dateien/Ordnern, die beim "clean" entfernt werden sollen
|
||||
set DELETE_LIST=build dist __pycache__ *.spec *.zip temp_* logs\* cache\* pyUpload.build\* pyUpload.dist\* upload\* *.pem
|
||||
|
||||
:: Menü anzeigen
|
||||
echo Wähle eine Option:
|
||||
echo 1 - Erstelle ausführbare Datei (exe 1)
|
||||
echo 2 - Erstelle Release-Paket (release 1+2)
|
||||
echo 3 - Erstelle ZIP-Archiv (zip 1+2+3)
|
||||
echo 4 - Aufraeumen (clean)
|
||||
set /p CHOICE=Eingabe (1-4):
|
||||
|
||||
if "%CHOICE%"=="1" goto exe
|
||||
if "%CHOICE%"=="2" goto release
|
||||
if "%CHOICE%"=="3" goto zip
|
||||
if "%CHOICE%"=="4" goto clean
|
||||
echo Ungültige Eingabe!
|
||||
exit /b
|
||||
|
||||
:exe
|
||||
echo Erzeuge ausführbare Datei...
|
||||
mkdir %BUILD_DIR% 2>nul
|
||||
pyinstaller --onefile --add-data "template.html;." --add-data "success.html;." --add-data "favicon.ico;." --windowed --icon favicon.ico --name %EXE_NAME% %SCRIPT%
|
||||
move dist\%EXE_NAME% %BUILD_DIR%\
|
||||
echo Erstellung abgeschlossen: %BUILD_DIR%\%EXE_NAME%
|
||||
exit /b
|
||||
|
||||
:release
|
||||
call :exe
|
||||
echo Erstelle Release-Paket...
|
||||
mkdir %DIST_DIR% 2>nul
|
||||
copy %BUILD_DIR%\%EXE_NAME% %DIST_DIR%\
|
||||
copy %REQ_FILE% %DIST_DIR%\
|
||||
copy template.html success.html favicon.ico %DIST_DIR%\
|
||||
echo Release-Paket bereit in %DIST_DIR%
|
||||
exit /b
|
||||
|
||||
:zip
|
||||
call :release
|
||||
echo Erstelle ZIP-Archiv...
|
||||
powershell Compress-Archive -Path "%DIST_DIR%\%EXE_NAME%", "%DIST_DIR%\template.html", "%DIST_DIR%\success.html", "%DIST_DIR%\favicon.ico" -DestinationPath "%ZIP_NAME%"
|
||||
echo ZIP-Archiv erstellt: %ZIP_NAME%
|
||||
exit /b
|
||||
|
||||
:clean
|
||||
echo Bereinige Projektverzeichnis...
|
||||
|
||||
:: Durchläuft alle Dateien/Ordner in DELETE_LIST
|
||||
for %%F in (%DELETE_LIST%) do (
|
||||
if exist %%F (
|
||||
echo Entferne: %%F
|
||||
rmdir /s /q %%F 2>nul || del /q %%F 2>nul
|
||||
)
|
||||
)
|
||||
|
||||
echo Bereinigung abgeschlossen.
|
||||
exit /b
|
10
dev/LICENSE
@ -1,10 +0,0 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2025 Adam Scotarczak (adam@skotarczak.net) - ionivation.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
BIN
dev/favicon.ico
Before Width: | Height: | Size: 122 KiB |
@ -1,54 +0,0 @@
|
||||
@echo off
|
||||
setlocal
|
||||
|
||||
:: Prüfen, ob Python installiert ist
|
||||
where python >nul 2>nul
|
||||
if %ERRORLEVEL% NEQ 0 (
|
||||
echo Fehler: Python ist nicht installiert oder nicht im PATH!
|
||||
echo Bitte installiere Python und starte die Installation erneut.
|
||||
pause
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
:: Python-Version prüfen (Mindestversion 3.8)
|
||||
for /f "tokens=2 delims= " %%v in ('python --version 2^>^&1') do set PYTHON_VERSION=%%v
|
||||
for /f "tokens=1,2 delims=." %%a in ("%PYTHON_VERSION%") do (
|
||||
if %%a LSS 3 (
|
||||
echo Fehler: Python 3.8 oder höher ist erforderlich!
|
||||
pause
|
||||
exit /b 1
|
||||
)
|
||||
if %%a==3 if %%b LSS 8 (
|
||||
echo Fehler: Python 3.8 oder höher ist erforderlich!
|
||||
pause
|
||||
exit /b 1
|
||||
)
|
||||
)
|
||||
|
||||
:: Virtuelle Umgebung erstellen, falls sie nicht existiert
|
||||
if not exist .venv (
|
||||
echo Erstelle virtuelle Server-Umgebung ...
|
||||
python -m venv --copies .venv
|
||||
if %ERRORLEVEL% NEQ 0 (
|
||||
echo Fehler beim Erstellen der virtuellen Umgebung!
|
||||
pause
|
||||
exit /b 2
|
||||
)
|
||||
)
|
||||
|
||||
:: Aktivieren der virtuellen Umgebung
|
||||
call .venv\Scripts\activate
|
||||
|
||||
:: Installieren der Abhängigkeiten
|
||||
echo Installiere Abhaengigkeiten aus dem Internet ...
|
||||
pip install --no-warn-script-location --disable-pip-version-check -r requirements.txt
|
||||
if %ERRORLEVEL% NEQ 0 (
|
||||
echo Fehler beim Installieren der Abhaengigkeiten!
|
||||
pause
|
||||
exit /b 3
|
||||
)
|
||||
|
||||
:: Erfolgsmeldung
|
||||
echo.
|
||||
echo Installation abgeschlossen.
|
||||
timeout /t 3 >nul & exit /b 0
|
@ -1,9 +0,0 @@
|
||||
# patchlog pyUpload
|
||||
|
||||
|
||||
**1.0.0 Erste Version - 12.03.25**
|
||||
|
||||
**Funktionsumfang:**
|
||||
|
||||
- Startet standartmässig TKInter GUI
|
||||
- Hilfe mit `--help` verfügbar
|
@ -1,33 +0,0 @@
|
||||
@echo off
|
||||
setlocal
|
||||
goto code
|
||||
|
||||
(C) 2025 Adam Scotarczak
|
||||
|
||||
options for pyUpload.py:
|
||||
|
||||
usage: pyUpload.py [-h] [--port PORT] [--nogui]
|
||||
|
||||
-h, --help show this help message and exit
|
||||
--port, -p PORT Port, auf dem der Server lauscht (Standard: 4443)
|
||||
--nogui, -n Ohne GUI & QR-Code im reinen CLI-Modus starten
|
||||
|
||||
:code
|
||||
:: Prüfen, ob die virtuelle Umgebung existiert
|
||||
if not exist .venv (
|
||||
echo Virtuelle Umgebung nicht gefunden! Bitte zuerst install.bat ausführen.
|
||||
pause
|
||||
exit /b
|
||||
)
|
||||
|
||||
:: Aktivieren der virtuellen Umgebung
|
||||
call .venv\Scripts\activate
|
||||
echo Virtuelle Umgebung in pyUpload.bat gestartet!
|
||||
|
||||
:: Starten des Upload-Servers mit Übergabe aller übergebenen Parameter
|
||||
python pyUpload.py %*
|
||||
|
||||
:: Nach Beenden der Anwendung
|
||||
deactivate
|
||||
|
||||
echo Virtuelle Umgebung beendet!
|
@ -1,3 +0,0 @@
|
||||
cryptography==44.0.2
|
||||
Pillow==11.1.0
|
||||
qrcode==8.0
|
@ -1,7 +0,0 @@
|
||||
# pyUpload Roadmap und ToDo
|
||||
|
||||
|
||||
- ***README.md überarbeiten***
|
||||
Entspricht aktuell nicht mehr dem Entwicklungsstand da auf innoSetup umgestiegen worden ist und Installationsscript eingefügt wurde.
|
||||
|
||||
- ***Auf pyQt6 umbauen statt tkinter?***
|
93
info.md
@ -1,93 +0,0 @@
|
||||
## pyUpload - Sicherer Datei-Upload-Server für eine einfache und sichere Dateiübertragung
|
||||
|
||||
### Beschreibung
|
||||
|
||||
pyUpload ist eine leistungsstarke und dennoch einfache Lösung für den sicheren Datei-Upload über HTTPS. Dieses Programm eignet sich ideal, um Dateien schnell und unkompliziert von einem Smartphone oder einem anderen Gerät auf einen Computer zu übertragen.
|
||||
|
||||
Anstatt zusätzliche Apps oder USB-Kabel zu nutzen, kann der Benutzer den Server starten, den automatisch generierten QR-Code mit dem Smartphone scannen und die Dateien direkt über die Weboberfläche hochladen. Der Computer speichert die hochgeladenen Dateien strukturiert in individuellen Verzeichnissen für jedes Gerät.
|
||||
|
||||
Zusätzlich erstellt pyUpload bei Bedarf automatisch ein selbstsigniertes SSL-Zertifikat, um eine verschlüsselte Verbindung sicherzustellen. Damit bleibt die Dateiübertragung geschützt und zuverlässig.
|
||||
|
||||
### Download
|
||||
- **Portabel für Windows als .zip**
|
||||
[download id="2323"]
|
||||
|
||||
> Aktuell ist der Download der portablen und Compilierten Version gesperrt da es von diversen Virenscannern als Bedrohung eingestuft wird. Bei Interesse ist das Programm aktuell nur auf Anfrage per eMail erhältlich. In Kürze erfolgt eine Veröffentlichung inklusive Code auf GitHub.
|
||||
|
||||
|
||||
### Features – Die Vorteile von pyUpload auf einen Blick
|
||||
|
||||
- **Sichere Dateiübertragung per HTTPS** – Alle Daten werden verschlüsselt übertragen.
|
||||
- **Automatische Erstellung eines selbstsignierten SSL-Zertifikats** – Keine zusätzliche Konfiguration notwendig.
|
||||
- **Intuitive, webbasierte Benutzeroberfläche** – Einfach zu bedienen, keine Installation erforderlich.
|
||||
- **Strukturierte Speicherung** – Dateien werden in client-spezifischen Verzeichnissen gespeichert.
|
||||
- **Zentralisierte und client-spezifische Logging-Funktion** – Detaillierte Nachverfolgung aller Uploads.
|
||||
- **Flexible Nutzung mit oder ohne GUI** – Start als Desktop-Anwendung oder reine Konsolen-Version möglich.
|
||||
- **Schnelle Einrichtung** – Download, Entpacken und sofort loslegen!
|
||||
|
||||
### Installationsanleitung – So startest du pyUpload
|
||||
|
||||
Es gibt zwei Möglichkeiten, pyUpload zu nutzen: Entweder die manuelle Installation oder die Nutzung einer vorgefertigten, ausführbaren Version.
|
||||
|
||||
#### 1. Nutzung der fertigen Download-Version
|
||||
|
||||
Falls du keine Python-Installation benötigst, kannst du die vorgefertigte **ZIP-Version** von pyUpload herunterladen. Diese enthält bereits alle notwendigen Dateien und ist sofort einsatzbereit.
|
||||
|
||||
1. Lade die neueste **pyUpload.zip** von der offiziellen Website herunter.
|
||||
2. Entpacke die ZIP-Datei in einen beliebigen Ordner.
|
||||
3. Starte die enthaltene `pyUpload.exe`.
|
||||
4. Falls die grafische Benutzeroberfläche nicht benötigt wird, kann die `pyUpload.exe` direkt in der Konsole mit `--nogui` gestartet werden:
|
||||
```sh
|
||||
pyUpload.exe --nogui
|
||||
```
|
||||
5. Eine Übersicht aller verfügbaren Befehle und Optionen erhältst du mit:
|
||||
```sh
|
||||
pyUpload.exe --help
|
||||
```
|
||||
|
||||
#### 2. Manuelle Installation für Python-Nutzer
|
||||
|
||||
1. Stelle sicher, dass **Python 3** auf deinem System installiert ist.
|
||||
2. Installiere alle benötigten Abhängigkeiten mit folgendem Befehl:
|
||||
```sh
|
||||
pip install -r requirements.txt
|
||||
```
|
||||
3. Starte den Server mit:
|
||||
```sh
|
||||
python pyUpload.py
|
||||
```
|
||||
4. Falls du keine grafische Benutzeroberfläche benötigst, kannst du den Server im Konsolenmodus starten:
|
||||
```sh
|
||||
python pyUpload.py --nogui
|
||||
```
|
||||
|
||||
### Zugriff auf die Weboberfläche
|
||||
|
||||
- Sobald der Server läuft, kann er über die lokale IP-Adresse aufgerufen werden:
|
||||
```
|
||||
https://<server-ip>:4443
|
||||
```
|
||||
- Falls die GUI-Version gestartet wurde, erscheint ein **QR-Code**, der die Verbindungsadresse enthält. Dies ermöglicht eine einfache Verbindung mit Smartphones und Tablets.
|
||||
|
||||
### Datei-Upload leicht gemacht – So funktioniert es
|
||||
|
||||
1. Öffne die **Weboberfläche** im Browser.
|
||||
2. Wähle die gewünschte **Datei aus** und klicke auf **„Hochladen“**.
|
||||
3. Nach erfolgreichem Upload erscheint eine **Bestätigungsseite**, die den Abschluss der Übertragung bestätigt.
|
||||
|
||||
### SSL-Zertifikatswarnung in Browsern umgehen
|
||||
|
||||
Da pyUpload ein **selbstsigniertes SSL-Zertifikat** nutzt, kann es beim ersten Zugriff zu einer Warnung des Browsers kommen. Um die verschlüsselte Verbindung zu akzeptieren, gibt es zwei Möglichkeiten:
|
||||
|
||||
- In den meisten Browsern gibt es eine Option wie **„Erweitert“** oder **„Trotzdem fortfahren“**, um die Warnung zu übergehen.
|
||||
- Alternativ kann das Zertifikat **manuell importiert und als vertrauenswürdig markiert** werden, um künftige Warnmeldungen zu vermeiden.
|
||||
|
||||
### Logging und Fehlerbehandlung – Transparenz und Kontrolle
|
||||
|
||||
- Alle **Uploads und Anfragen** werden in **zentralen sowie client-spezifischen Logdateien** gespeichert. Diese befinden sich im `logs/`-Verzeichnis.
|
||||
- Falls während der Nutzung von pyUpload **Probleme auftreten**, bietet ein Blick in diese Logdateien wertvolle Hinweise zur Fehlerbehebung.
|
||||
|
||||
### Lizenz und Autor
|
||||
|
||||
- **Entwickelt von Adam Skotarczak (C) 2025**.
|
||||
|
@ -1,84 +0,0 @@
|
||||
; Define AppVersion as a constant
|
||||
#define AppVersion "1.0.0"
|
||||
#define BasePath ".\dev"
|
||||
|
||||
; Source: "{#BasePath}\*"; DestDir: "{app}"; Flags: ignoreversion;
|
||||
|
||||
|
||||
[Setup]
|
||||
AppId={{832B3E5D-14BC-4823-A911-00C9B79AD040}
|
||||
AppName=pyUpload
|
||||
AppVersion={#AppVersion}
|
||||
AppVerName=pyUpload {#AppVersion} (win)
|
||||
AppPublisher=Adam Skotarczak (ionivation.com)
|
||||
AppPublisherURL=https://www.ionivation.com/pyupload/
|
||||
AppSupportURL=https://www.ionivation.com/pyupload/
|
||||
AppUpdatesURL=https://www.ionivation.com/pyupload/
|
||||
DefaultDirName={userappdata}\pyUpload
|
||||
DisableProgramGroupPage=yes
|
||||
LicenseFile={#BasePath}\LICENSE
|
||||
PrivilegesRequired=lowest
|
||||
;PrivilegesRequiredOverridesAllowed=dialog
|
||||
OutputBaseFilename=pyUpload-Setup-{#AppVersion}
|
||||
SolidCompression=yes
|
||||
WizardStyle=modern
|
||||
SetupIconFile={#BasePath}\favicon.ico
|
||||
DisableDirPage=yes
|
||||
|
||||
[Languages]
|
||||
Name: "german"; MessagesFile: "compiler:Languages\German.isl"
|
||||
Name: "english"; MessagesFile: "compiler:Default.isl"
|
||||
|
||||
[Files]
|
||||
Source: "{#BasePath}\pyUpload.bat"; DestDir: "{app}"; Flags: ignoreversion
|
||||
Source: "{#BasePath}\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs
|
||||
|
||||
[Dirs]
|
||||
Name: "{app}\upload"; Flags: uninsalwaysuninstall
|
||||
|
||||
[Icons]
|
||||
Name: "{autoprograms}\pyUpload"; Filename: "{app}\pyUpload.bat"; IconFilename: "{app}\favicon.ico";
|
||||
Name: "{autodesktop}\pyUpload"; Filename: "{app}\pyUpload.bat"; IconFilename: "{app}\favicon.ico"; Tasks: desktopicon
|
||||
Name: "{userdesktop}\pyUpload-Uploads"; Filename: "{app}\upload"; IconFilename: "{app}\favicon.ico"; Tasks: desktopicon
|
||||
|
||||
|
||||
[Tasks]
|
||||
Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked
|
||||
|
||||
[Run]
|
||||
Filename: "{app}\install.bat"; Parameters: ""; WorkingDir: "{app}\"; Flags: waituntilterminated
|
||||
;Flags: runhidden
|
||||
|
||||
Filename: "{app}\pyUpload.bat"; Description: "{cm:LaunchProgram,pyUpload}"; Flags: shellexec postinstall skipifsilent
|
||||
|
||||
[Code]
|
||||
function IsPythonInstalled(): Boolean;
|
||||
var
|
||||
PythonPath: String;
|
||||
ResultCode: Integer;
|
||||
begin
|
||||
// Prüfe Registry für alle möglichen Python-Versionen (dynamisch)
|
||||
if RegQueryStringValue(HKLM, 'SOFTWARE\Python\PythonCore', '', PythonPath) or
|
||||
RegQueryStringValue(HKLM, 'SOFTWARE\WOW6432Node\Python\PythonCore', '', PythonPath) then
|
||||
begin
|
||||
Result := True;
|
||||
Exit;
|
||||
end;
|
||||
|
||||
// Prüfe mit python --version, falls kein Registry-Eintrag gefunden wurde
|
||||
Result := Exec('cmd.exe', '/c python --version', '', SW_HIDE, ewWaitUntilTerminated, ResultCode);
|
||||
end;
|
||||
|
||||
function InitializeSetup(): Boolean;
|
||||
begin
|
||||
if not IsPythonInstalled() then
|
||||
begin
|
||||
MsgBox('Python ist nicht installiert oder nicht erreichbar! Bitte installiere Python.', mbError, MB_OK);
|
||||
Result := False; // Installation abbrechen
|
||||
end
|
||||
else
|
||||
begin
|
||||
Result := True;
|
||||
end;
|
||||
end;
|
||||
|
19
start.cmd
Normal file
@ -0,0 +1,19 @@
|
||||
@echo off
|
||||
setlocal
|
||||
chcp 65001 >nul
|
||||
|
||||
:: Prüfen, ob python vorhanden ist
|
||||
where python >nul 2>nul
|
||||
if errorlevel 1 (
|
||||
echo [Fehler] Python wurde nicht gefunden.
|
||||
echo Bitte installiere Python 3.8 oder höher: https://www.python.org/downloads/windows/
|
||||
pause
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
:: Verzeichnis von start.cmd ermitteln (robust, egal von wo gestartet)
|
||||
set SCRIPT_DIR=%~dp0
|
||||
|
||||
:: Starte die Anwendung direkt aus app\
|
||||
python "%SCRIPT_DIR%app\main.py" %*
|
||||
|
14
start.sh
Normal file
@ -0,0 +1,14 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Verzeichnis dieser Datei bestimmen
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
|
||||
# Python-Interpreter prüfen
|
||||
if ! command -v python3 &> /dev/null; then
|
||||
echo "[Fehler] Python 3 ist nicht installiert."
|
||||
echo "Bitte installiere es über deine Paketverwaltung (z.B. apt, dnf, brew)."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Starte das Hauptskript
|
||||
python3 "$SCRIPT_DIR/app/main.py" "$@"
|