Initial commit: QSafe Android 1.1.0 and Windows 1.0.4

This commit is contained in:
Курнат Андрей
2026-11-01 15:28:12 +03:00
commit 9845944bb8
91 changed files with 6496 additions and 0 deletions
+76
View File
@@ -0,0 +1,76 @@
#!/bin/bash
set -euo pipefail
umask 077
stage="$(cd "$(dirname "$0")" && pwd)"
mountpoint -q /mnt/data || { echo 'External disk is not mounted'; exit 1; }
findmnt -n -o OPTIONS /mnt/data | tr ',' '\n' | grep -qx rw
test -f "$stage/token.sha256"
if ! id qsafe >/dev/null 2>&1; then useradd --system --home-dir /nonexistent --shell /usr/sbin/nologin qsafe; fi
install -d -o root -g root -m 755 /opt/qsafe
install -d -o qsafe -g qsafe -m 700 /mnt/data/qsafe/data
install -d -o root -g qsafe -m 750 /etc/qsafe
install -d -o root -g root -m 700 /var/backups/qsafe /var/backups/qsafe-install
install -m 644 "$stage/server.py" "$stage/backup.py" /opt/qsafe/
if test -f /etc/qsafe/token.sha256; then
cmp -s "$stage/token.sha256" /etc/qsafe/token.sha256 || { echo 'Existing connection key differs; refusing to rotate it'; exit 1; }
else
install -o root -g qsafe -m 640 "$stage/token.sha256" /etc/qsafe/token.sha256
fi
cat > /etc/systemd/system/qsafe.service <<'EOF'
[Unit]
Description=QSafe encrypted vault synchronization
After=network.target
RequiresMountsFor=/mnt/data/qsafe/data
[Service]
Type=simple
User=qsafe
Group=qsafe
UMask=0077
ExecStart=/usr/bin/python3 /opt/qsafe/server.py --data /mnt/data/qsafe/data --token-hash-file /etc/qsafe/token.sha256
Restart=on-failure
RestartSec=3
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=/mnt/data/qsafe/data
RestrictAddressFamilies=AF_INET AF_INET6 AF_UNIX
MemoryMax=256M
TasksMax=48
[Install]
WantedBy=multi-user.target
EOF
cat > /etc/systemd/system/qsafe-backup.service <<'EOF'
[Unit]
Description=QSafe verified encrypted backup to SD card
RequiresMountsFor=/mnt/data/qsafe/data
[Service]
Type=oneshot
UMask=0077
ExecStart=/usr/bin/python3 /opt/qsafe/backup.py /mnt/data/qsafe/data/vault.sqlite3 /var/backups/qsafe
NoNewPrivileges=true
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=/var/backups/qsafe /mnt/data/qsafe/data
EOF
cat > /etc/systemd/system/qsafe-backup.timer <<'EOF'
[Unit]
Description=Daily QSafe encrypted backup
[Timer]
OnCalendar=*-*-* 04:25:00
Persistent=true
RandomizedDelaySec=300
[Install]
WantedBy=timers.target
EOF
: "${QSAFE_LAN_IP:?Set the Pi private IPv4; public vault endpoints are forbidden}"
python3 "$stage/lan-only.py" --ip "$QSAFE_LAN_IP"
systemctl daemon-reload
systemctl enable --now qsafe.service qsafe-backup.timer
systemctl restart qsafe.service
for i in $(seq 1 20); do
if curl -fsS http://127.0.0.1:18792/health; then break; fi
sleep 1
done
systemctl start qsafe-backup.service
systemctl is-active qsafe.service caddy.service qsafe-backup.timer