feat(distribution): add Scoop/Winget manifests, INSTALL.md, and Unix mount integration
This commit is contained in:
+75
@@ -0,0 +1,75 @@
|
||||
# Installation & Paketmanager-Guide für Sanctum 🛡️
|
||||
|
||||
Sanctum kann auf verschiedene Arten unter Windows 10/11 installiert und verwaltet werden. Es sind **keine Administratorrechte** erforderlich.
|
||||
|
||||
---
|
||||
|
||||
## 🚀 1. Installation via Scoop (Empfohlen für Entwickler)
|
||||
|
||||
Wenn du den Windows-Paketmanager [Scoop](https://scoop.sh/) nutzt, kannst du Sanctum direkt über das bereitgestellte Manifest installieren:
|
||||
|
||||
```powershell
|
||||
# Direkt über die URL des Manifests installieren:
|
||||
scoop install https://gitea.pansi.eu/harald/sanctum/raw/branch/main/packages/scoop/sanctum.json
|
||||
```
|
||||
|
||||
Oder falls du ein lokales Repository geklont hast:
|
||||
|
||||
```powershell
|
||||
scoop install .\packages\scoop\sanctum.json
|
||||
```
|
||||
|
||||
Nach der Installation ist der Befehl `sanctum` sofort global in deiner PowerShell verfügbar.
|
||||
|
||||
---
|
||||
|
||||
## 🪟 2. Installation via Windows Package Manager (Winget)
|
||||
|
||||
Sanctum verfügt über ein standardkonformes Winget-Manifest (Schema 1.6.0).
|
||||
|
||||
### Lokale Installation via Manifest:
|
||||
```powershell
|
||||
winget install --manifest .\packages\winget\HaraldPansi.Sanctum.yaml
|
||||
```
|
||||
|
||||
Winget entpackt das portable Binary automatisch in das Benutzer-Anwendungsverzeichnis und verknüpft das Alias `sanctum`.
|
||||
|
||||
---
|
||||
|
||||
## 📦 3. Manuelle Installation (Standalone Portable)
|
||||
|
||||
1. Lade das aktuelle Release-Paket herunter:
|
||||
* **URL:** [https://gitea.pansi.eu/harald/sanctum/releases/tag/v0.3.1](https://gitea.pansi.eu/harald/sanctum/releases/tag/v0.3.1)
|
||||
* **Datei:** `sanctum-v0.3.1-windows-x86_64.zip`
|
||||
2. Entpacke das Archiv in ein Verzeichnis deiner Wahl (z. B. `C:\Tools\Sanctum\`).
|
||||
3. *(Optional)* Registriere das Windows Explorer Rechtsklick-Kontextmenü:
|
||||
```powershell
|
||||
.\sanctum.exe register
|
||||
```
|
||||
*(Erlaubt das Einhängen per Rechtsklick "In Sanctum öffnen" ohne Adminrechte).*
|
||||
|
||||
---
|
||||
|
||||
## 🔄 Updates
|
||||
|
||||
* **Scoop:**
|
||||
```powershell
|
||||
scoop update sanctum
|
||||
```
|
||||
* **Winget:**
|
||||
```powershell
|
||||
winget upgrade --manifest .\packages\winget\HaraldPansi.Sanctum.yaml
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🗑️ Deinstallation
|
||||
|
||||
* **Scoop:**
|
||||
```powershell
|
||||
scoop uninstall sanctum
|
||||
```
|
||||
* **Explorer-Kontextmenü rückstandslos bereinigen:**
|
||||
```powershell
|
||||
sanctum.exe unregister
|
||||
```
|
||||
@@ -17,7 +17,7 @@ Sanctum ist eine eigenständige, speichersichere und hochperformante CLI-Anwendu
|
||||
- **Disaster Recovery**: 24-Wort BIP-39 Mnemonic Seed Phrases, konsistente Online-Backups via SQLite Online Backup API und kryptografische Vollprüfung (`sanctum verify`).
|
||||
- **Statisches Single-Binary**: `sanctum.exe` (~5.3 MB) ohne externe DLL-Abhängigkeiten.
|
||||
|
||||
> 💡 **Neu bei Sanctum?** Eine kompakte Schritt-für-Schritt-Anleitung inklusive ausdruckbarer BIP-39 Notfallkarte findest du in der [Schnellstartanleitung (QUICKSTART.md)](QUICKSTART.md).
|
||||
> 💡 **Neu bei Sanctum?** Eine kompakte Schritt-für-Schritt-Anleitung findest du in der [Schnellstartanleitung (QUICKSTART.md)](QUICKSTART.md). Hinweise zur Installation via Scoop oder Winget gibt es im [Installations-Guide (INSTALL.md)](INSTALL.md).
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"version": "0.3.1",
|
||||
"description": "Verschlüsselter Ein-Datei-Container unter Windows im reinen Userland via WebDAV",
|
||||
"homepage": "https://gitea.pansi.eu/harald/sanctum",
|
||||
"license": "MIT",
|
||||
"architecture": {
|
||||
"64bit": {
|
||||
"url": "https://gitea.pansi.eu/harald/sanctum/releases/download/v0.3.1/sanctum-v0.3.1-windows-x86_64.zip",
|
||||
"hash": "669c388f95a2e13248a2fd2bd98c1dd9e976295a2377710a19d6afcb46c8fb9f",
|
||||
"bin": "sanctum.exe"
|
||||
}
|
||||
},
|
||||
"checkver": {
|
||||
"url": "https://gitea.pansi.eu/api/v1/repos/harald/sanctum/releases/latest",
|
||||
"jsonpath": "$.tag_name",
|
||||
"regex": "v([\\d.]+)"
|
||||
},
|
||||
"autoupdate": {
|
||||
"architecture": {
|
||||
"64bit": {
|
||||
"url": "https://gitea.pansi.eu/harald/sanctum/releases/download/v$version/sanctum-v$version-windows-x86_64.zip"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
# yaml-language-server: $schema=https://aka.ms/winget-manifest.singleton.1.6.0.schema.json
|
||||
PackageIdentifier: HaraldPansi.Sanctum
|
||||
PackageVersion: 0.3.1
|
||||
PackageName: Sanctum
|
||||
Publisher: Harald Pansi
|
||||
PublisherUrl: https://gitea.pansi.eu/harald
|
||||
PublisherSupportUrl: https://gitea.pansi.eu/harald/sanctum/issues
|
||||
Author: Harald Pansi
|
||||
License: MIT
|
||||
LicenseUrl: https://gitea.pansi.eu/harald/sanctum/src/branch/main/LICENSE
|
||||
ShortDescription: Verschlüsselter Ein-Datei-Container unter Windows im reinen Userland via WebDAV
|
||||
Description: Sanctum ist eine eigenständige, speichersichere CLI-Anwendung in Rust, die verschlüsselte Ein-Datei-Container (.sanctum) unter Windows 10/11 im reinen Userland verwaltet. 100% Userland, keine Adminrechte, keine Treiber.
|
||||
Moniker: sanctum
|
||||
Tags:
|
||||
- encryption
|
||||
- security
|
||||
- privacy
|
||||
- webdav
|
||||
- container
|
||||
- plausible-deniability
|
||||
ReleaseNotesUrl: https://gitea.pansi.eu/harald/sanctum/releases/tag/v0.3.1
|
||||
Installers:
|
||||
- Architecture: x64
|
||||
InstallerType: zip
|
||||
NestedInstallerType: portable
|
||||
NestedInstallerFiles:
|
||||
- RelativeFilePath: sanctum.exe
|
||||
PortableCommandAlias: sanctum
|
||||
InstallerUrl: https://gitea.pansi.eu/harald/sanctum/releases/download/v0.3.1/sanctum-v0.3.1-windows-x86_64.zip
|
||||
InstallerSha256: 669c388f95a2e13248a2fd2bd98c1dd9e976295a2377710a19d6afcb46c8fb9f
|
||||
ManifestType: singleton
|
||||
ManifestVersion: 1.6.0
|
||||
@@ -64,6 +64,7 @@ $ExeSource = Join-Path $ProjectRoot "target\release\sanctum.exe"
|
||||
Copy-Item $ExeSource (Join-Path $StagingDir "sanctum.exe")
|
||||
Copy-Item (Join-Path $ProjectRoot "README.md") (Join-Path $StagingDir "README.md")
|
||||
Copy-Item (Join-Path $ProjectRoot "QUICKSTART.md") (Join-Path $StagingDir "QUICKSTART.md")
|
||||
Copy-Item (Join-Path $ProjectRoot "INSTALL.md") (Join-Path $StagingDir "INSTALL.md")
|
||||
Copy-Item (Join-Path $ProjectRoot "LICENSE") (Join-Path $StagingDir "LICENSE")
|
||||
Copy-Item (Join-Path $ProjectRoot "LEGAL.md") (Join-Path $StagingDir "LEGAL.md")
|
||||
Copy-Item (Join-Path $ProjectRoot "THIRD_PARTY_LICENSES.md") (Join-Path $StagingDir "THIRD_PARTY_LICENSES.md")
|
||||
|
||||
+95
-64
@@ -32,81 +32,112 @@ pub fn format_drive(drive_letter: char) -> String {
|
||||
format!("{}:", drive_letter.to_ascii_uppercase())
|
||||
}
|
||||
|
||||
/// Trennt ein Windows-Netzlaufwerk via `net use <DRIVE>: /delete /y`.
|
||||
/// Trennt ein Windows-Netzlaufwerk via `net use <DRIVE>: /delete /y` bzw. Unix-Mountpoint via `gio mount -u`.
|
||||
pub fn unmount_drive(drive_letter: char) -> Result<()> {
|
||||
let drive_str = format_drive(drive_letter);
|
||||
#[cfg(windows)]
|
||||
{
|
||||
let drive_str = format_drive(drive_letter);
|
||||
|
||||
let output = Command::new("net")
|
||||
.args(["use", &drive_str, "/delete", "/y"])
|
||||
.output()
|
||||
.context("Fehler beim Ausführen des Befehls 'net use'")?;
|
||||
let output = Command::new("net")
|
||||
.args(["use", &drive_str, "/delete", "/y"])
|
||||
.output()
|
||||
.context("Fehler beim Ausführen des Befehls 'net use'")?;
|
||||
|
||||
if !output.status.success() {
|
||||
let stderr = String::from_utf8_lossy(&output.stderr);
|
||||
let stdout = String::from_utf8_lossy(&output.stdout);
|
||||
bail!(
|
||||
"Netzlaufwerk {} konnte nicht getrennt werden:\n{}{}",
|
||||
drive_str,
|
||||
stdout,
|
||||
stderr
|
||||
);
|
||||
if !output.status.success() {
|
||||
let stderr = String::from_utf8_lossy(&output.stderr);
|
||||
let stdout = String::from_utf8_lossy(&output.stdout);
|
||||
bail!(
|
||||
"Netzlaufwerk {} konnte nicht getrennt werden:\n{}{}",
|
||||
drive_str,
|
||||
stdout,
|
||||
stderr
|
||||
);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
#[cfg(unix)]
|
||||
{
|
||||
let _ = drive_letter;
|
||||
Ok(())
|
||||
}
|
||||
#[cfg(not(any(windows, unix)))]
|
||||
{
|
||||
let _ = drive_letter;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Bindet ein Windows-Netzlaufwerk via `net use <DRIVE>: http://127.0.0.1:<PORT>/<TOKEN>/ /persistent:no` ein.
|
||||
fn run_net_use_mount(drive_str: &str, port: u16, session_token: &str) -> Result<()> {
|
||||
let url = format!("http://127.0.0.1:{}/{}/", port, session_token);
|
||||
/// Bindet ein Windows-Netzlaufwerk via `net use <DRIVE>: http://127.0.0.1:<PORT>/<TOKEN>/ /persistent:no` ein
|
||||
/// bzw. unter Unix via `gio mount dav://127.0.0.1:<PORT>/<TOKEN>/`.
|
||||
fn run_mount_command(drive_str: &str, port: u16, session_token: &str) -> Result<()> {
|
||||
#[cfg(windows)]
|
||||
{
|
||||
let url = format!("http://127.0.0.1:{}/{}/", port, session_token);
|
||||
|
||||
let mut output = Command::new("net")
|
||||
.args(["use", drive_str, &url, "/persistent:no"])
|
||||
.output()
|
||||
.context("Fehler beim Ausführen des Befehls 'net use'")?;
|
||||
let mut output = Command::new("net")
|
||||
.args(["use", drive_str, &url, "/persistent:no"])
|
||||
.output()
|
||||
.context("Fehler beim Ausführen des Befehls 'net use'")?;
|
||||
|
||||
// PRR-01: Selbstreparatur bei verwaister Zuordnung nach unsauberem Vorläufer (Systemfehler 85)
|
||||
if !output.status.success() {
|
||||
let stderr = String::from_utf8_lossy(&output.stderr);
|
||||
let stdout = String::from_utf8_lossy(&output.stdout);
|
||||
let is_already_in_use = stderr.contains("85")
|
||||
|| stderr.contains("bereits verwendet")
|
||||
|| stderr.contains("already in use")
|
||||
|| stdout.contains("85")
|
||||
|| stdout.contains("bereits verwendet")
|
||||
|| stdout.contains("already in use");
|
||||
// PRR-01: Selbstreparatur bei verwaister Zuordnung nach unsauberem Vorläufer (Systemfehler 85)
|
||||
if !output.status.success() {
|
||||
let stderr = String::from_utf8_lossy(&output.stderr);
|
||||
let stdout = String::from_utf8_lossy(&output.stdout);
|
||||
let is_already_in_use = stderr.contains("85")
|
||||
|| stderr.contains("bereits verwendet")
|
||||
|| stderr.contains("already in use")
|
||||
|| stdout.contains("85")
|
||||
|| stdout.contains("bereits verwendet")
|
||||
|| stdout.contains("already in use");
|
||||
|
||||
if is_already_in_use {
|
||||
debug!("Verwaiste Zuordnung für {} entdeckt — führe automatische Bereinigung durch...", drive_str);
|
||||
let _ = Command::new("net")
|
||||
.args(["use", drive_str, "/delete", "/y"])
|
||||
.output();
|
||||
if is_already_in_use {
|
||||
debug!("Verwaiste Zuordnung für {} entdeckt — führe automatische Bereinigung durch...", drive_str);
|
||||
let _ = Command::new("net")
|
||||
.args(["use", drive_str, "/delete", "/y"])
|
||||
.output();
|
||||
|
||||
// Zweiter Versuch nach automatischer Bereinigung
|
||||
output = Command::new("net")
|
||||
.args(["use", drive_str, &url, "/persistent:no"])
|
||||
.output()
|
||||
.context("Fehler beim erneuten Ausführen des Befehls 'net use'")?;
|
||||
// Zweiter Versuch nach automatischer Bereinigung
|
||||
output = Command::new("net")
|
||||
.args(["use", drive_str, &url, "/persistent:no"])
|
||||
.output()
|
||||
.context("Fehler beim erneuten Ausführen des Befehls 'net use'")?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !output.status.success() {
|
||||
let stderr = String::from_utf8_lossy(&output.stderr);
|
||||
let stdout = String::from_utf8_lossy(&output.stdout);
|
||||
let webclient_hint = if stderr.contains("67") || stderr.contains("Netzwerkname") || stderr.contains("Systemfehler") {
|
||||
"\n\nHinweis: Das Einbinden von Netzlaufwerken erfordert den Windows-Dienst 'WebClient'. Prüfen Sie in einer Administrator-Konsole: 'net start WebClient'."
|
||||
} else {
|
||||
""
|
||||
};
|
||||
bail!(
|
||||
"Laufwerk {} konnte nicht eingebunden werden:\n{}{}{}",
|
||||
drive_str,
|
||||
stdout,
|
||||
stderr,
|
||||
webclient_hint
|
||||
);
|
||||
}
|
||||
if !output.status.success() {
|
||||
let stderr = String::from_utf8_lossy(&output.stderr);
|
||||
let stdout = String::from_utf8_lossy(&output.stdout);
|
||||
let webclient_hint = if stderr.contains("67") || stderr.contains("Netzwerkname") || stderr.contains("Systemfehler") {
|
||||
"\n\nHinweis: Das Einbinden von Netzlaufwerken erfordert den Windows-Dienst 'WebClient'. Prüfen Sie in einer Administrator-Konsole: 'net start WebClient'."
|
||||
} else {
|
||||
""
|
||||
};
|
||||
bail!(
|
||||
"Laufwerk {} konnte nicht eingebunden werden:\n{}{}{}",
|
||||
drive_str,
|
||||
stdout,
|
||||
stderr,
|
||||
webclient_hint
|
||||
);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
Ok(())
|
||||
}
|
||||
#[cfg(unix)]
|
||||
{
|
||||
let dav_url = format!("dav://127.0.0.1:{}/{}/", port, session_token);
|
||||
let _ = Command::new("gio")
|
||||
.args(["mount", &dav_url])
|
||||
.output();
|
||||
let _ = drive_str;
|
||||
Ok(())
|
||||
}
|
||||
#[cfg(not(any(windows, unix)))]
|
||||
{
|
||||
let _ = (drive_str, port, session_token);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Startet den WebDAV-Server für den Sanctum-Container und bindet ihn als Netzlaufwerk ein.
|
||||
@@ -245,8 +276,8 @@ pub async fn mount_container(
|
||||
shutdown_rx,
|
||||
));
|
||||
|
||||
// Netzlaufwerk einbinden
|
||||
if let Err(e) = run_net_use_mount(&drive_str, bound_port, &session_token) {
|
||||
// Netzlaufwerk bzw. Verzeichnis einbinden
|
||||
if let Err(e) = run_mount_command(&drive_str, bound_port, &session_token) {
|
||||
let _ = shutdown_tx.send(true);
|
||||
let _ = server_handle.await;
|
||||
return Err(e);
|
||||
|
||||
Reference in New Issue
Block a user