v2.2.2
This commit is contained in:
parent
f3e39fb8e6
commit
e5f5d32aab
124 changed files with 11892 additions and 2461 deletions
|
|
@ -1,34 +1,21 @@
|
|||
================================================================================
|
||||
ZUPT-GUI — Cross-Platform Desktop Frontend for Zupt
|
||||
MIT License
|
||||
|
||||
Copyright (C) 2026 Cristian Cezar Moisés
|
||||
Contact for commercial licensing: sac@securityops.co
|
||||
Copyright (c) 2026 Cristian Cezar Moisés
|
||||
|
||||
================================================================================
|
||||
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:
|
||||
|
||||
Zupt-GUI is free software: you can redistribute it and/or modify it under
|
||||
the terms of the GNU Affero General Public License as published by the Free
|
||||
Software Foundation, either version 3 of the License, or (at your option)
|
||||
any later version.
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
Zupt-GUI is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
COMMERCIAL LICENSING
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
For commercial licensing — including embedding into proprietary appliances,
|
||||
hosted backup-as-a-service products, or any other use that is incompatible
|
||||
with the AGPL's source-disclosure requirements — please contact:
|
||||
|
||||
sac@securityops.co
|
||||
|
||||
The full AGPL-3.0 text is available in the parent directory's LICENSE file
|
||||
and at <https://www.gnu.org/licenses/agpl-3.0.txt>.
|
||||
================================================================================
|
||||
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.
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
# Zupt GUI — Cross-Platform Post-Quantum Backup
|
||||
|
||||
Desktop application for [zupt](https://github.com/cristiancmoises/zupt) backup compression with ML-KEM-768 + X25519 post-quantum hybrid encryption.
|
||||
Desktop application for [zupt](https://git.securityops.co/cristiancmoises/zupt) backup compression with ML-KEM-768 + X25519 post-quantum hybrid encryption.
|
||||
|
||||
Works on GNU/Linux, BSD, macOS, and Windows.
|
||||
|
||||
|
|
@ -111,7 +111,7 @@ The GUI calls the zupt CLI binary — all cryptography runs in native C, not Pyt
|
|||
|----------|--------|------|
|
||||
| Any | pip | `pip install .` |
|
||||
| Debian/Ubuntu/Mint | .deb | `packaging/deb/control` |
|
||||
| Fedora/openSUSE | .rpm | `rpmbuild -ba packaging/rpm/zupt-gui.spec` |
|
||||
| Fedora/RHEL | .rpm | `rpmbuild -ba packaging/rpm/zupt-gui.spec` |
|
||||
| Universal Linux | .AppImage | `packaging/appimage/build-appimage.sh` |
|
||||
| Sandboxed Linux | .flatpak | `packaging/flatpak/dev.zupt.gui.yml` |
|
||||
| Windows | .exe installer | `packaging/windows/build-windows.bat` |
|
||||
|
|
@ -119,11 +119,8 @@ The GUI calls the zupt CLI binary — all cryptography runs in native C, not Pyt
|
|||
|
||||
## Credits
|
||||
|
||||
- **zupt** v2.1.6 — Cristian Cezar Moises ([github](https://github.com/cristiancmoises/zupt))
|
||||
- **libzupt** v1.0.2 — Alessandro de Oliveira Faria ([github](https://github.com/cabelo/libzupt))
|
||||
- **zupt** v2.2.2 — Cristian Cezar Moisés ([github](https://git.securityops.co/cristiancmoises/zupt))
|
||||
|
||||
## License
|
||||
|
||||
**AGPL-3.0-or-later** — see [LICENSE-GUI](LICENSE-GUI) and the project-root [LICENSE](../LICENSE).
|
||||
|
||||
For commercial licensing inquiries, contact: **sac@securityops.co**
|
||||
AGPL-3.0-or-later
|
||||
|
|
|
|||
2
gui/install.sh
Normal file → Executable file
2
gui/install.sh
Normal file → Executable file
|
|
@ -1,4 +1,6 @@
|
|||
#!/bin/bash
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
# Copyright (c) 2025-2026 Cristian Cezar Moisés
|
||||
# Install Zupt GUI + desktop integration
|
||||
# Run: sudo ./install.sh (or ./install.sh --user for per-user install)
|
||||
set -e
|
||||
|
|
|
|||
2
gui/packaging/appimage/build-appimage.sh
Normal file → Executable file
2
gui/packaging/appimage/build-appimage.sh
Normal file → Executable file
|
|
@ -1,4 +1,6 @@
|
|||
#!/bin/bash
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
# Copyright (c) 2025-2026 Cristian Cezar Moisés
|
||||
# Build Zupt GUI AppImage
|
||||
# Requires: appimagetool, python3, pip
|
||||
set -e
|
||||
|
|
|
|||
94
gui/packaging/build-gui-deb.sh
Executable file
94
gui/packaging/build-gui-deb.sh
Executable file
|
|
@ -0,0 +1,94 @@
|
|||
#!/bin/bash
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
# Copyright (c) 2025-2026 Cristian Cezar Moisés
|
||||
# Build zupt-gui .deb package
|
||||
set -e
|
||||
cd "$(dirname "$0")/.."
|
||||
|
||||
VERSION="${VERSION:-2.2.1}"
|
||||
ARCH="all"
|
||||
PKG="zupt-gui_${VERSION}_${ARCH}"
|
||||
ROOT="/tmp/$PKG"
|
||||
|
||||
rm -rf "$ROOT"
|
||||
mkdir -p "$ROOT/DEBIAN" \
|
||||
"$ROOT/usr/bin" \
|
||||
"$ROOT/usr/lib/python3/dist-packages" \
|
||||
"$ROOT/usr/share/applications" \
|
||||
"$ROOT/usr/share/icons/hicolor/256x256/apps" \
|
||||
"$ROOT/usr/share/doc/zupt-gui"
|
||||
|
||||
# Python module
|
||||
install -m 644 src/zupt_gui.py "$ROOT/usr/lib/python3/dist-packages/zupt_gui.py"
|
||||
|
||||
# Launcher
|
||||
cat > "$ROOT/usr/bin/zupt-gui" <<'LAUNCH'
|
||||
#!/usr/bin/env python3
|
||||
import sys
|
||||
sys.path.insert(0, "/usr/lib/python3/dist-packages")
|
||||
from zupt_gui import main
|
||||
sys.exit(main())
|
||||
LAUNCH
|
||||
chmod +x "$ROOT/usr/bin/zupt-gui"
|
||||
|
||||
# Desktop file
|
||||
install -m 644 packaging/zupt-gui.desktop "$ROOT/usr/share/applications/" 2>/dev/null || cat > "$ROOT/usr/share/applications/zupt-gui.desktop" <<'DESK'
|
||||
[Desktop Entry]
|
||||
Name=Zupt GUI
|
||||
GenericName=Post-Quantum Backup Utility
|
||||
Comment=Compress and encrypt files with hybrid PQ crypto
|
||||
Exec=zupt-gui
|
||||
Terminal=false
|
||||
Type=Application
|
||||
Categories=Utility;Archiving;Security;
|
||||
Icon=zupt-gui
|
||||
DESK
|
||||
|
||||
# Icon (use a real one if assets exist)
|
||||
if [ -f assets/zupt-256.png ]; then
|
||||
install -m 644 assets/zupt-256.png "$ROOT/usr/share/icons/hicolor/256x256/apps/zupt-gui.png"
|
||||
elif [ -d ../assets ] && [ -f ../assets/zupt-256.png ]; then
|
||||
install -m 644 ../assets/zupt-256.png "$ROOT/usr/share/icons/hicolor/256x256/apps/zupt-gui.png"
|
||||
else
|
||||
# 1×1 placeholder
|
||||
printf '\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x01\x00\x00\x00\x01\x08\x06\x00\x00\x00\x1f\x15\xc4\x89\x00\x00\x00\rIDATx\x9cc\xfc\xcf\xc0\x00\x00\x00\x05\x00\x01\xa5\xf6E@\x00\x00\x00\x00IEND\xaeB`\x82' > "$ROOT/usr/share/icons/hicolor/256x256/apps/zupt-gui.png"
|
||||
fi
|
||||
|
||||
# Docs
|
||||
install -m 644 README.md "$ROOT/usr/share/doc/zupt-gui/"
|
||||
gzip -9n -c ../CHANGELOG.md > "$ROOT/usr/share/doc/zupt-gui/changelog.gz" 2>/dev/null || true
|
||||
|
||||
cat > "$ROOT/usr/share/doc/zupt-gui/copyright" <<'COPYRIGHT'
|
||||
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
|
||||
Upstream-Name: zupt-gui
|
||||
Upstream-Contact: Cristian Cezar Moisés <zupt@riseup.net>
|
||||
Source: https://git.securityops.co/cristiancmoises/zupt
|
||||
|
||||
Files: *
|
||||
Copyright: 2025-2026 Cristian Cezar Moisés
|
||||
License: AGPL-3.0+
|
||||
COPYRIGHT
|
||||
|
||||
INSTALLED_SIZE=$(du -sk "$ROOT" | cut -f1)
|
||||
cat > "$ROOT/DEBIAN/control" <<EOF
|
||||
Package: zupt-gui
|
||||
Version: $VERSION
|
||||
Section: utils
|
||||
Priority: optional
|
||||
Architecture: $ARCH
|
||||
Depends: python3 (>= 3.9), python3-pyside6, zupt (>= 2.2.0)
|
||||
Maintainer: Cristian Cezar Moisés <zupt@riseup.net>
|
||||
Installed-Size: $INSTALLED_SIZE
|
||||
Homepage: https://git.securityops.co/cristiancmoises/zupt
|
||||
Description: Zupt GUI — Post-Quantum Backup Utility
|
||||
Cross-platform graphical interface for the zupt backup compression
|
||||
utility with post-quantum hybrid encryption (ML-KEM-768 + X25519).
|
||||
.
|
||||
v2.2+ uses libzuptsdk under the hood for HKDF-SHA3 hybrid combiner,
|
||||
32-byte key commitment, HPKE binding (RFC 9180), and anti-fault
|
||||
double-decapsulation. Supports legacy archives via auto-detection.
|
||||
EOF
|
||||
|
||||
dpkg-deb --build --root-owner-group "$ROOT" "/tmp/$PKG.deb"
|
||||
echo "Built: /tmp/$PKG.deb"
|
||||
dpkg-deb --info "/tmp/$PKG.deb" | head -12
|
||||
|
|
@ -1,3 +1,5 @@
|
|||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
# Copyright (c) 2026 Cristian Cezar Moisés
|
||||
app-id: dev.zupt.gui
|
||||
runtime: org.freedesktop.Platform
|
||||
runtime-version: '24.08'
|
||||
|
|
@ -24,7 +26,7 @@ modules:
|
|||
- install -Dm755 zupt /app/bin/zupt
|
||||
sources:
|
||||
- type: git
|
||||
url: https://github.com/cristiancmoises/zupt
|
||||
url: https://git.securityops.co/cristiancmoises/zupt
|
||||
tag: v2.1.6
|
||||
|
||||
- name: zupt-gui
|
||||
|
|
|
|||
|
|
@ -1,43 +0,0 @@
|
|||
Name: zupt-gui
|
||||
Version: 1.0.0
|
||||
Release: 1%{?dist}
|
||||
Summary: Zupt GUI — Post-Quantum Backup Utility
|
||||
License: AGPL-3.0-or-later
|
||||
URL: https://github.com/cristiancmoises/zupt
|
||||
Source0: %{name}-%{version}.tar.gz
|
||||
BuildArch: noarch
|
||||
|
||||
Requires: python3 >= 3.9
|
||||
Requires: python3-pyside6
|
||||
Requires: zupt >= 2.1.7
|
||||
|
||||
%description
|
||||
Cross-platform graphical interface for the zupt backup compression
|
||||
utility with post-quantum hybrid encryption (ML-KEM-768 + X25519),
|
||||
hardware-adaptive codecs, block-level deduplication, and full-disk
|
||||
backup/restore support.
|
||||
|
||||
%install
|
||||
mkdir -p %{buildroot}%{_bindir}
|
||||
mkdir -p %{buildroot}%{_datadir}/zupt-gui
|
||||
mkdir -p %{buildroot}%{_datadir}/applications
|
||||
mkdir -p %{buildroot}%{_datadir}/icons/hicolor/256x256/apps
|
||||
|
||||
install -m 755 src/zupt_gui.py %{buildroot}%{_datadir}/zupt-gui/zupt_gui.py
|
||||
install -m 644 packaging/zupt-gui.desktop %{buildroot}%{_datadir}/applications/
|
||||
|
||||
cat > %{buildroot}%{_bindir}/zupt-gui << 'EOF'
|
||||
#!/bin/sh
|
||||
exec python3 %{_datadir}/zupt-gui/zupt_gui.py "$@"
|
||||
EOF
|
||||
chmod 755 %{buildroot}%{_bindir}/zupt-gui
|
||||
|
||||
%files
|
||||
%license LICENSE
|
||||
%{_bindir}/zupt-gui
|
||||
%{_datadir}/zupt-gui/
|
||||
%{_datadir}/applications/zupt-gui.desktop
|
||||
|
||||
%changelog
|
||||
* Mon Apr 21 2026 Cristian Cezar Moises - 1.0.0-1
|
||||
- Initial release
|
||||
|
|
@ -1,14 +1,16 @@
|
|||
#!/usr/bin/env python3
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
# Copyright (c) 2025-2026 Cristian Cezar Moisés
|
||||
from setuptools import setup, find_packages
|
||||
|
||||
setup(
|
||||
name="zupt-gui",
|
||||
version="1.0.0",
|
||||
version="1.1.1",
|
||||
description="Zupt GUI — Cross-Platform Post-Quantum Backup Utility",
|
||||
long_description=open("README.md").read(),
|
||||
long_description_content_type="text/markdown",
|
||||
author="Cristian Cezar Moisés",
|
||||
url="https://github.com/cristiancmoises/zupt",
|
||||
url="https://git.securityops.co/cristiancmoises/zupt",
|
||||
license="AGPL-3.0-or-later",
|
||||
packages=find_packages(where="src"),
|
||||
package_dir={"": "src"},
|
||||
|
|
|
|||
|
|
@ -1,15 +1,47 @@
|
|||
#!/usr/bin/env python3
|
||||
"""Zupt GUI — Cross-Platform Post-Quantum Backup. Requires PySide6."""
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
# Copyright (c) 2025-2026 Cristian Cezar Moisés
|
||||
"""Zupt GUI — Cross-Platform Post-Quantum Backup.
|
||||
|
||||
Tries PySide6 first (preferred), falls back to PyQt6 if PySide6 is
|
||||
not installed. PyQt6 is the default available package on Debian/Ubuntu
|
||||
without requiring pip; PySide6 ships with broader signal/slot semantics
|
||||
but the API surface used here is portable between the two.
|
||||
"""
|
||||
import sys, os, subprocess, shutil
|
||||
from pathlib import Path
|
||||
from PySide6.QtWidgets import (
|
||||
QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout,
|
||||
QLabel, QPushButton, QLineEdit, QComboBox, QFileDialog,
|
||||
QTextEdit, QProgressBar, QTabWidget, QFrame, QCheckBox,
|
||||
QSpinBox, QMessageBox, QStatusBar, QScrollArea
|
||||
)
|
||||
from PySide6.QtCore import Qt, Signal, QObject, QThread
|
||||
from PySide6.QtGui import QPalette, QColor, QIcon, QPixmap
|
||||
|
||||
# Try PySide6, fall back to PyQt6. The two have nearly-identical APIs;
|
||||
# the only adjustment needed is Signal/pyqtSignal naming, handled below.
|
||||
try:
|
||||
from PySide6.QtWidgets import (
|
||||
QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout,
|
||||
QLabel, QPushButton, QLineEdit, QComboBox, QFileDialog,
|
||||
QTextEdit, QProgressBar, QTabWidget, QFrame, QCheckBox,
|
||||
QSpinBox, QMessageBox, QStatusBar, QScrollArea
|
||||
)
|
||||
from PySide6.QtCore import Qt, Signal, QObject, QThread
|
||||
from PySide6.QtGui import QPalette, QColor, QIcon, QPixmap
|
||||
QT_BINDING = "PySide6"
|
||||
except ImportError:
|
||||
try:
|
||||
from PyQt6.QtWidgets import (
|
||||
QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout,
|
||||
QLabel, QPushButton, QLineEdit, QComboBox, QFileDialog,
|
||||
QTextEdit, QProgressBar, QTabWidget, QFrame, QCheckBox,
|
||||
QSpinBox, QMessageBox, QStatusBar, QScrollArea
|
||||
)
|
||||
from PyQt6.QtCore import Qt, pyqtSignal as Signal, QObject, QThread
|
||||
from PyQt6.QtGui import QPalette, QColor, QIcon, QPixmap
|
||||
QT_BINDING = "PyQt6"
|
||||
except ImportError:
|
||||
sys.stderr.write(
|
||||
"ERROR: zupt-gui requires PySide6 or PyQt6. Install one of:\n"
|
||||
" Debian/Ubuntu: sudo apt install python3-pyqt6\n"
|
||||
" Fedora/RHEL: sudo dnf install python3-pyqt6\n"
|
||||
" pip (any OS): pip install PySide6\n"
|
||||
)
|
||||
sys.exit(1)
|
||||
|
||||
# ── Find zupt binary ──
|
||||
def _find_zupt():
|
||||
|
|
@ -146,7 +178,7 @@ def Log(h=150):
|
|||
t = QTextEdit(); t.setReadOnly(True); t.setMaximumHeight(h); return t
|
||||
|
||||
def PwField(ph="Optional"):
|
||||
pw = QLineEdit(); pw.setEchoMode(QLineEdit.Password); pw.setPlaceholderText(ph); return pw
|
||||
pw = QLineEdit(); pw.setEchoMode(QLineEdit.EchoMode.Password); pw.setPlaceholderText(ph); return pw
|
||||
|
||||
class PathField(QWidget):
|
||||
def __init__(self, ph="", mode="open", filters="All Files (*)"):
|
||||
|
|
@ -178,7 +210,7 @@ class PathField(QWidget):
|
|||
if ps: self.edit.setText("|".join(ps) if self.mode == "multi" else ps[0])
|
||||
|
||||
def scrollable(w):
|
||||
sa = QScrollArea(); sa.setWidgetResizable(True); sa.setWidget(w); sa.setFrameShape(QFrame.NoFrame); return sa
|
||||
sa = QScrollArea(); sa.setWidgetResizable(True); sa.setWidget(w); sa.setFrameShape(QFrame.Shape.NoFrame); return sa
|
||||
|
||||
def run_async(parent, cmd, btn, log, progress=None):
|
||||
log.clear(); btn.setEnabled(False)
|
||||
|
|
@ -213,6 +245,11 @@ class KeysTab(QWidget):
|
|||
self.gen_priv = PathField("e.g. ~/zupt_private.key", "save", "Key (*.key);;All (*)")
|
||||
v.addWidget(self.gen_priv)
|
||||
|
||||
self.gen_sdk = QCheckBox("SDK v2 format (HKDF combiner + commitment + HPKE — recommended)")
|
||||
self.gen_sdk.setChecked(True)
|
||||
self.gen_sdk.setToolTip("Generates a libzuptsdk-format keypair. Use --pq-sdk in CLI or 'SDK v2' checkbox in compress to use these keys. Disable for legacy --pq compatibility.")
|
||||
v.addWidget(self.gen_sdk)
|
||||
|
||||
self.gen_btn = QPushButton("Generate Keypair")
|
||||
self.gen_btn.clicked.connect(self._generate)
|
||||
v.addWidget(self.gen_btn)
|
||||
|
|
@ -245,16 +282,25 @@ class KeysTab(QWidget):
|
|||
p = self.gen_priv.path() or str(Path.home() / "zupt_private.key")
|
||||
self.gen_priv.edit.setText(p)
|
||||
self.gen_log.clear(); self.gen_btn.setEnabled(False)
|
||||
code, _, err = run_zupt(["keygen", "-o", p])
|
||||
self.gen_log.append(err.strip())
|
||||
if code == 0:
|
||||
pub = p.rsplit(".", 1)[0] + "_public.key" if "." in p else p + ".pub"
|
||||
c2, _, e2 = run_zupt(["keygen", "--pub", "-o", pub, "-k", p])
|
||||
self.gen_log.append(e2.strip())
|
||||
if c2 == 0:
|
||||
self.gen_log.append(f"\nPrivate key: {p}\nPublic key: {pub}")
|
||||
if self.gen_sdk.isChecked():
|
||||
# SDK keygen creates both files in one step.
|
||||
code, _, err = run_zupt(["keygen", "--sdk", "-o", p])
|
||||
self.gen_log.append(err.strip())
|
||||
if code == 0:
|
||||
self.gen_log.append(f"\nPrivate key: {p}\nPublic key: {p}.pub")
|
||||
else:
|
||||
self.gen_log.append("\nFailed.")
|
||||
else:
|
||||
self.gen_log.append("\nFailed.")
|
||||
code, _, err = run_zupt(["keygen", "-o", p])
|
||||
self.gen_log.append(err.strip())
|
||||
if code == 0:
|
||||
pub = p.rsplit(".", 1)[0] + "_public.key" if "." in p else p + ".pub"
|
||||
c2, _, e2 = run_zupt(["keygen", "--pub", "-o", pub, "-k", p])
|
||||
self.gen_log.append(e2.strip())
|
||||
if c2 == 0:
|
||||
self.gen_log.append(f"\nPrivate key: {p}\nPublic key: {pub}")
|
||||
else:
|
||||
self.gen_log.append("\nFailed.")
|
||||
self.gen_btn.setEnabled(True)
|
||||
|
||||
def _export(self):
|
||||
|
|
@ -296,7 +342,11 @@ class CompressTab(QWidget):
|
|||
v.addLayout(row); v.addWidget(Sep())
|
||||
enc = QHBoxLayout(); enc.setSpacing(16)
|
||||
pw = QVBoxLayout(); pw.addWidget(H("Password")); self.pw = PwField("AES-256"); pw.addWidget(self.pw); enc.addLayout(pw)
|
||||
pq = QVBoxLayout(); pq.addWidget(H("PQ public key")); self.pq = PathField("Optional .key", filters="Key (*.key);;All (*)"); pq.addWidget(self.pq); enc.addLayout(pq)
|
||||
pq = QVBoxLayout(); pq.addWidget(H("PQ public key")); self.pq = PathField("Optional .key", filters="Key (*.key *.pub);;All (*)"); pq.addWidget(self.pq); enc.addLayout(pq)
|
||||
sdk_box = QVBoxLayout(); sdk_box.addWidget(H("Mode"))
|
||||
self.sdk = QCheckBox("Use SDK v2 (HKDF + commitment + HPKE)"); self.sdk.setChecked(True)
|
||||
self.sdk.setToolTip("v2.2+ uses libzuptsdk: HKDF-SHA3 combiner, key commitment, HPKE binding, Argon2id. Disable for legacy --pq compatibility.")
|
||||
sdk_box.addWidget(self.sdk); sdk_box.addStretch(); enc.addLayout(sdk_box)
|
||||
v.addLayout(enc)
|
||||
self.btn = QPushButton("Compress"); self.btn.clicked.connect(self._run); v.addWidget(self.btn)
|
||||
self.progress = QProgressBar(); self.progress.setRange(0,0); self.progress.hide(); v.addWidget(self.progress)
|
||||
|
|
@ -319,7 +369,9 @@ class CompressTab(QWidget):
|
|||
if self.dedup.isChecked(): cmd.append("--dedup")
|
||||
if self.solid.isChecked(): cmd.append("--solid")
|
||||
if self.pw.text(): cmd += ["-p", self.pw.text()]
|
||||
if self.pq.path(): cmd += ["--pq", self.pq.path()]
|
||||
if self.pq.path():
|
||||
flag = "--pq-sdk" if self.sdk.isChecked() else "--pq"
|
||||
cmd += [flag, self.pq.path()]
|
||||
cmd.append(dst); cmd.extend(srcs)
|
||||
run_async(self, cmd, self.btn, self.log, self.progress)
|
||||
|
||||
|
|
@ -337,6 +389,10 @@ class ExtractTab(QWidget):
|
|||
enc = QHBoxLayout(); enc.setSpacing(16)
|
||||
pw = QVBoxLayout(); pw.addWidget(H("Password")); self.pw = PwField(); pw.addWidget(self.pw); enc.addLayout(pw)
|
||||
pq = QVBoxLayout(); pq.addWidget(H("PQ private key")); self.pq = PathField("Optional .key", filters="Key (*.key);;All (*)"); pq.addWidget(self.pq); enc.addLayout(pq)
|
||||
sdk_box = QVBoxLayout(); sdk_box.addWidget(H("Mode"))
|
||||
self.sdk = QCheckBox("Auto-detect (SDK or legacy)"); self.sdk.setChecked(True)
|
||||
self.sdk.setToolTip("Tries --pq-sdk first, falls back to --pq for legacy archives.")
|
||||
sdk_box.addWidget(self.sdk); sdk_box.addStretch(); enc.addLayout(sdk_box)
|
||||
v.addLayout(enc)
|
||||
self.btn = QPushButton("Extract"); self.btn.setObjectName("green"); self.btn.clicked.connect(self._run); v.addWidget(self.btn)
|
||||
self.progress = QProgressBar(); self.progress.setRange(0,0); self.progress.hide(); v.addWidget(self.progress)
|
||||
|
|
@ -350,7 +406,12 @@ class ExtractTab(QWidget):
|
|||
cmd = ["extract"]
|
||||
if self.out.path(): cmd += ["-o", self.out.path()]
|
||||
if self.pw.text(): cmd += ["-p", self.pw.text()]
|
||||
if self.pq.path(): cmd += ["--pq", self.pq.path()]
|
||||
if self.pq.path():
|
||||
# Auto-detect: zupt's extract auto-discovers enc type from header,
|
||||
# so passing --pq-sdk works for both SDK and legacy keyfiles when
|
||||
# the archive is SDK-encoded; --pq is needed for legacy archives.
|
||||
flag = "--pq-sdk" if self.sdk.isChecked() else "--pq"
|
||||
cmd += [flag, self.pq.path()]
|
||||
cmd.append(arc)
|
||||
run_async(self, cmd, self.btn, self.log, self.progress)
|
||||
|
||||
|
|
@ -433,7 +494,8 @@ class DiskTab(QWidget):
|
|||
def _restore(self):
|
||||
a, t = self.rarc.path(), self.rtgt.path()
|
||||
if not a or not t: QMessageBox.warning(self, "Zupt", "Set archive and target."); return
|
||||
if QMessageBox.warning(self, "Confirm", f"OVERWRITE {t}?", QMessageBox.Yes|QMessageBox.Cancel) != QMessageBox.Yes: return
|
||||
SB = QMessageBox.StandardButton
|
||||
if QMessageBox.warning(self, "Confirm", f"OVERWRITE {t}?", SB.Yes|SB.Cancel) != SB.Yes: return
|
||||
cmd = ["disk", "restore"]
|
||||
if self.rpw.text(): cmd += ["-p", self.rpw.text()]
|
||||
cmd += [a, t]; run_async(self, cmd, self.rbtn, self.rlog)
|
||||
|
|
@ -462,11 +524,11 @@ class AboutTab(QWidget):
|
|||
("SHA3/SHAKE FIPS 202 Hash / XOF", "color:#5a7a88;font-size:12px;font-family:monospace;"),
|
||||
("", ""),
|
||||
("CREDITS", "color:#00dde0;font-size:10px;font-weight:700;letter-spacing:2px;font-family:monospace;"),
|
||||
("zupt Cristian Cezar Moises AGPL-3.0", "color:#5a7a88;font-size:12px;font-family:monospace;"),
|
||||
("github.com/cristiancmoises/zupt", "color:#3a5868;font-size:11px;font-family:monospace;"),
|
||||
("zupt Cristian Cezar Moises MIT", "color:#5a7a88;font-size:12px;font-family:monospace;"),
|
||||
("git.securityops.co/cristiancmoises/zupt", "color:#3a5868;font-size:11px;font-family:monospace;"),
|
||||
("", ""),
|
||||
("libzupt Alessandro de Oliveira Faria MIT", "color:#5a7a88;font-size:12px;font-family:monospace;"),
|
||||
("github.com/cabelo/libzupt", "color:#3a5868;font-size:11px;font-family:monospace;"),
|
||||
("zupt Cristian Cezar Moises AGPL-3.0+", "color:#5a7a88;font-size:12px;font-family:monospace;"),
|
||||
("git.securityops.co/cristiancmoises/zupt", "color:#3a5868;font-size:11px;font-family:monospace;"),
|
||||
("", ""),
|
||||
("WEBSITE", "color:#00dde0;font-size:10px;font-weight:700;letter-spacing:2px;font-family:monospace;"),
|
||||
("https://zupt.securityops.co", "color:#5a7a88;font-size:12px;font-family:monospace;"),
|
||||
|
|
@ -555,10 +617,13 @@ def main():
|
|||
app.setStyle("Fusion")
|
||||
app.setStyleSheet(STYLE)
|
||||
pal = QPalette()
|
||||
for role, c in [(QPalette.Window,"#0a0a0a"),(QPalette.WindowText,"#90acb8"),
|
||||
(QPalette.Base,"#0e1820"),(QPalette.Text,"#c0dce8"),
|
||||
(QPalette.Button,"#0a2028"),(QPalette.ButtonText,"#00dde0"),
|
||||
(QPalette.Highlight,"#004858"),(QPalette.HighlightedText,"#00dde0")]:
|
||||
# PyQt6 requires scoped enums (QPalette.ColorRole.Window); PySide6 supports
|
||||
# both forms but we use the scoped form for cross-binding compatibility.
|
||||
CR = QPalette.ColorRole
|
||||
for role, c in [(CR.Window,"#0a0a0a"),(CR.WindowText,"#90acb8"),
|
||||
(CR.Base,"#0e1820"),(CR.Text,"#c0dce8"),
|
||||
(CR.Button,"#0a2028"),(CR.ButtonText,"#00dde0"),
|
||||
(CR.Highlight,"#004858"),(CR.HighlightedText,"#00dde0")]:
|
||||
pal.setColor(role, QColor(c))
|
||||
app.setPalette(pal)
|
||||
win = ZuptWindow(compress_files=compress_files, extract_file=extract_file)
|
||||
|
|
|
|||
0
gui/zupt-gui
Normal file → Executable file
0
gui/zupt-gui
Normal file → Executable file
Loading…
Reference in a new issue