Compare commits
8
Commits
7e99d59042
...
v0.2.3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5cd45831e2 | ||
|
|
71f6a70829 | ||
|
|
b751b71223 | ||
|
|
afb057692d | ||
|
|
eeae143dc6 | ||
|
|
992c3daad7 | ||
|
|
9684238a53 | ||
|
|
e8674e730f |
No files matched your search
@@ -38,15 +38,21 @@ jobs:
|
|||||||
squashfs-tools \
|
squashfs-tools \
|
||||||
dpkg-dev \
|
dpkg-dev \
|
||||||
curl \
|
curl \
|
||||||
minisign \
|
|
||||||
python3
|
python3
|
||||||
|
|
||||||
- name: Setup Rust Toolchain
|
- name: Setup Rust Toolchain
|
||||||
uses: actions-rust-lang/setup-rust-toolchain@v1.11.0
|
uses: actions-rust-lang/setup-rust-toolchain@v1.11.0
|
||||||
with:
|
with:
|
||||||
toolchain: stable
|
toolchain: stable
|
||||||
|
# Die Action installiert mit --profile minimal; ohne diese Komponenten
|
||||||
|
# schlagen cargo fmt und cargo clippy in den Quality Gates sofort fehl
|
||||||
|
components: rustfmt, clippy
|
||||||
cache: true
|
cache: true
|
||||||
|
|
||||||
|
- name: Install rsign2 (Release-Signatur)
|
||||||
|
# RUSTFLAGS leeren: die Toolchain-Action setzt -D warnings, das soll nicht für rsign2 gelten
|
||||||
|
run: RUSTFLAGS="" cargo install rsign2 --locked --version 0.6.7
|
||||||
|
|
||||||
- name: Code Quality & Testing (Quality Gates)
|
- name: Code Quality & Testing (Quality Gates)
|
||||||
run: |
|
run: |
|
||||||
cargo fmt --check
|
cargo fmt --check
|
||||||
|
|||||||
Generated
+1
-1
@@ -1048,7 +1048,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ink-notes"
|
name = "ink-notes"
|
||||||
version = "0.1.1"
|
version = "0.2.3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytemuck",
|
"bytemuck",
|
||||||
"egui",
|
"egui",
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "ink-notes"
|
name = "ink-notes"
|
||||||
version = "0.1.1"
|
version = "0.2.3"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
description = "Latenzoptimierte Vektor-Notizbuch- und Inking-Anwendung für Linux"
|
description = "Latenzoptimierte Vektor-Notizbuch- und Inking-Anwendung für Linux"
|
||||||
repository = "https://gitea.pansi.eu/harald/ink-notes"
|
repository = "https://gitea.pansi.eu/harald/ink-notes"
|
||||||
|
|||||||
@@ -88,19 +88,19 @@ Ergebnis in `target/`:
|
|||||||
|
|
||||||
### Release-Signatur einrichten (einmalig)
|
### Release-Signatur einrichten (einmalig)
|
||||||
|
|
||||||
In-App-Updates werden nur mit gültiger Minisign-Signatur installiert. Einmalig ein Schlüsselpaar erzeugen (ohne Passwort, da es nur als CI-Secret verwendet wird):
|
In-App-Updates werden nur mit gültiger Minisign-Signatur installiert. Signiert wird mit [rsign2](https://crates.io/crates/rsign2), einer Minisign-kompatiblen Implementierung (`cargo install rsign2 --locked`). Einmalig ein Schlüsselpaar erzeugen (ohne Passwort, da es nur als CI-Secret verwendet wird):
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
minisign -G -W -p ink-notes.pub -s ink-notes.key
|
|
||||||
# oder ohne minisign-Paket, mit dem kompatiblen rsign2 (cargo install rsign2):
|
|
||||||
rsign generate -W -p ink-notes.pub -s ink-notes.key
|
rsign generate -W -p ink-notes.pub -s ink-notes.key
|
||||||
```
|
```
|
||||||
|
|
||||||
|
> **Wichtig:** Schlüssel und Signierwerkzeug müssen zusammenpassen. `rsign generate -W` verschlüsselt den Schlüssel mit einem leeren Passwort; das `minisign`-CLI (z. B. Ubuntu-Paket 0.11) kann ihn ohne Terminal nicht laden. `build-release.sh` und die CI signieren deshalb mit `rsign`.
|
||||||
|
|
||||||
1. Die zweite Zeile aus `ink-notes.pub` (beginnt mit `RW`) in `src/updater.rs` als `UPDATE_SIGNING_PUBLIC_KEY` eintragen und committen.
|
1. Die zweite Zeile aus `ink-notes.pub` (beginnt mit `RW`) in `src/updater.rs` als `UPDATE_SIGNING_PUBLIC_KEY` eintragen und committen.
|
||||||
2. Den kompletten Inhalt von `ink-notes.key` in Gitea unter *Repository → Einstellungen → Actions → Secrets* als `MINISIGN_SECRET_KEY` anlegen.
|
2. Den kompletten Inhalt von `ink-notes.key` in Gitea unter *Repository → Einstellungen → Actions → Secrets* als `MINISIGN_SECRET_KEY` anlegen.
|
||||||
3. `ink-notes.key` sicher offline aufbewahren und vom Rechner löschen. Geht der Schlüssel verloren, können bestehende Installationen keine Updates mehr prüfen.
|
3. `ink-notes.key` sicher offline aufbewahren und vom Rechner löschen. Geht der Schlüssel verloren, können bestehende Installationen keine Updates mehr prüfen.
|
||||||
|
|
||||||
Lokal signiert `build-release.sh` nur, wenn `MINISIGN_SECRET_KEY` gesetzt ist. In der CI ist die Signatur Pflicht (`INK_NOTES_REQUIRE_SIGNATURE=1`), und das Skript prüft, dass der geheime Schlüssel zum eingebauten öffentlichen Schlüssel passt.
|
Lokal signiert `build-release.sh` nur, wenn `MINISIGN_SECRET_KEY` gesetzt und `rsign` installiert ist. In der CI ist die Signatur Pflicht (`INK_NOTES_REQUIRE_SIGNATURE=1`), und das Skript prüft, dass der geheime Schlüssel zum eingebauten öffentlichen Schlüssel passt.
|
||||||
|
|
||||||
### 2. Installation auf Zorin OS 18 / Ubuntu 24.04
|
### 2. Installation auf Zorin OS 18 / Ubuntu 24.04
|
||||||
|
|
||||||
|
|||||||
@@ -7,8 +7,9 @@ Latenzoptimierte Vektor-Notizbuch- und Inking-Anwendung für Linux (Zorin OS 18
|
|||||||
- **Touchscreen Multi-Touch**: Stufenloses 2-Finger Pinch-to-Zoom und Panning mit umschaltbarem Finger-Zeichenmodus
|
- **Touchscreen Multi-Touch**: Stufenloses 2-Finger Pinch-to-Zoom und Panning mit umschaltbarem Finger-Zeichenmodus
|
||||||
- **Zwei-Stufen-Inking-Modell**: Kausale Echtzeit-Glättung via 1€-Filter & akausale Ecken-Erhaltung (Corner Preservation)
|
- **Zwei-Stufen-Inking-Modell**: Kausale Echtzeit-Glättung via 1€-Filter & akausale Ecken-Erhaltung (Corner Preservation)
|
||||||
- **Geometrie- und Formerkennung**: Geraden, Rechtecke, Kreise, Rauten, Polygone & Koordinatensysteme (Draw-and-Hold)
|
- **Geometrie- und Formerkennung**: Geraden, Rechtecke, Kreise, Rauten, Polygone & Koordinatensysteme (Draw-and-Hold)
|
||||||
- **Multi-Dokumenten-Manager**: Unbegrenzte Notizbücher mit atomarem Autosave
|
- **Multi-Dokumenten-Manager**: Unbegrenzte Notizbücher mit atomarem Autosave, Papierkorb und fortlaufenden Backups
|
||||||
- **In-App Updater**: Automatische Versionsprüfung und sichere Atomar-Aktualisierung via Gitea Releases
|
- **Datensicherheit**: Versioniertes Dateiformat mit Migration, Quarantäne beschädigter Seiten, Schutz vor Doppelöffnung und Crash-getestetem Speichern
|
||||||
|
- **In-App Updater**: Automatische Versionsprüfung und sichere Atomar-Aktualisierung via Gitea Releases – mit Pflicht-Signaturprüfung (Minisign) und durchgängigem HTTPS
|
||||||
- **Vektor-PDF-Export**: Verlustfreie Ausgabe für Druck und Weitergabe
|
- **Vektor-PDF-Export**: Verlustfreie Ausgabe für Druck und Weitergabe
|
||||||
|
|
||||||
### Installation:
|
### Installation:
|
||||||
|
|||||||
@@ -30,23 +30,38 @@ echo "=== Berechne SHA256-Prüfsummen in target/${CHECKSUM_FILE} ==="
|
|||||||
cd "${ROOT_DIR}/target"
|
cd "${ROOT_DIR}/target"
|
||||||
sha256sum "${DEB_NAME}" "${APPIMAGE_NAME}" > "${CHECKSUM_FILE}"
|
sha256sum "${DEB_NAME}" "${APPIMAGE_NAME}" > "${CHECKSUM_FILE}"
|
||||||
|
|
||||||
# 4. Prüfsummen mit Minisign signieren (Pflicht für In-App-Updates)
|
# 4. Prüfsummen signieren (Pflicht für In-App-Updates)
|
||||||
|
# Signiert wird mit rsign2 (minisign-kompatibles Format): Der Schlüssel wurde mit
|
||||||
|
# `rsign generate -W` erzeugt; das minisign-CLI kann ihn ohne Terminal nicht laden.
|
||||||
SIGNATURE_FILE="${CHECKSUM_FILE}.minisig"
|
SIGNATURE_FILE="${CHECKSUM_FILE}.minisig"
|
||||||
rm -f "${SIGNATURE_FILE}"
|
rm -f "${SIGNATURE_FILE}"
|
||||||
EMBEDDED_PUBKEY=$(grep -m1 'pub const UPDATE_SIGNING_PUBLIC_KEY' "${ROOT_DIR}/src/updater.rs" | cut -d '"' -f2)
|
# Schlüssel kann von rustfmt in die Folgezeile umgebrochen sein
|
||||||
|
EMBEDDED_PUBKEY=$(grep -m1 -A1 'pub const UPDATE_SIGNING_PUBLIC_KEY' "${ROOT_DIR}/src/updater.rs" | grep -o '"[^"]*"' | head -n1 | tr -d '"')
|
||||||
if [ -n "${MINISIGN_SECRET_KEY:-}" ]; then
|
if [ -n "${MINISIGN_SECRET_KEY:-}" ]; then
|
||||||
if [ -z "${EMBEDDED_PUBKEY}" ]; then
|
if [ -z "${EMBEDDED_PUBKEY}" ]; then
|
||||||
echo "FEHLER: UPDATE_SIGNING_PUBLIC_KEY in src/updater.rs ist leer – diese Version könnte keine Updates prüfen."
|
echo "FEHLER: UPDATE_SIGNING_PUBLIC_KEY in src/updater.rs ist leer – diese Version könnte keine Updates prüfen."
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
echo "=== Signiere ${CHECKSUM_FILE} mit Minisign ==="
|
if ! command -v rsign >/dev/null 2>&1; then
|
||||||
|
echo "FEHLER: rsign nicht gefunden (Installation: cargo install rsign2 --locked)."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo "=== Signiere ${CHECKSUM_FILE} mit rsign2 ==="
|
||||||
KEY_FILE="$(mktemp)"
|
KEY_FILE="$(mktemp)"
|
||||||
trap 'rm -f "${KEY_FILE}"' EXIT
|
trap 'rm -f "${KEY_FILE}"' EXIT
|
||||||
printf '%s\n' "${MINISIGN_SECRET_KEY}" > "${KEY_FILE}"
|
printf '%s\n' "${MINISIGN_SECRET_KEY}" > "${KEY_FILE}"
|
||||||
minisign -S -s "${KEY_FILE}" -m "${CHECKSUM_FILE}" -t "ink-notes v${VERSION}"
|
rsign sign -W -s "${KEY_FILE}" -t "ink-notes v${VERSION}" -x "${SIGNATURE_FILE}" "${CHECKSUM_FILE}"
|
||||||
rm -f "${KEY_FILE}"
|
rm -f "${KEY_FILE}"
|
||||||
# Stellt sicher, dass der geheime Schlüssel zum eingebauten öffentlichen Schlüssel passt
|
# Stellt sicher, dass der geheime Schlüssel zum eingebauten öffentlichen Schlüssel passt
|
||||||
minisign -V -P "${EMBEDDED_PUBKEY}" -m "${CHECKSUM_FILE}"
|
# rsign beendet sich bei falscher Key-ID mit Exit-Code 0, daher zusätzlich die Meldung prüfen
|
||||||
|
if ! VERIFY_OUT=$(rsign verify -P "${EMBEDDED_PUBKEY}" -x "${SIGNATURE_FILE}" "${CHECKSUM_FILE}" 2>&1) \
|
||||||
|
|| ! grep -q "Signature and comment signature verified" <<<"${VERIFY_OUT}"; then
|
||||||
|
echo "${VERIFY_OUT}"
|
||||||
|
echo "FEHLER: Signatur passt nicht zum eingebauten öffentlichen Schlüssel (UPDATE_SIGNING_PUBLIC_KEY)."
|
||||||
|
rm -f "${SIGNATURE_FILE}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo "${VERIFY_OUT}"
|
||||||
elif [ "${INK_NOTES_REQUIRE_SIGNATURE:-0}" = "1" ]; then
|
elif [ "${INK_NOTES_REQUIRE_SIGNATURE:-0}" = "1" ]; then
|
||||||
echo "FEHLER: MINISIGN_SECRET_KEY ist nicht gesetzt, eine Signatur ist aber Pflicht."
|
echo "FEHLER: MINISIGN_SECRET_KEY ist nicht gesetzt, eine Signatur ist aber Pflicht."
|
||||||
exit 1
|
exit 1
|
||||||
|
|||||||
+13
-16
@@ -1522,12 +1522,6 @@ mod tests {
|
|||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
fn test_io_error_does_not_quarantine_and_does_not_overwrite() {
|
fn test_io_error_does_not_quarantine_and_does_not_overwrite() {
|
||||||
use crate::document::PersistState;
|
use crate::document::PersistState;
|
||||||
use std::os::unix::fs::PermissionsExt;
|
|
||||||
|
|
||||||
// Skip test if running as root
|
|
||||||
if std::env::var("USER").unwrap_or_default() == "root" {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let temp_dir = tempfile::tempdir().expect("tempdir");
|
let temp_dir = tempfile::tempdir().expect("tempdir");
|
||||||
let path = temp_dir.path();
|
let path = temp_dir.path();
|
||||||
@@ -1535,19 +1529,17 @@ mod tests {
|
|||||||
let manifest = NotebookManifest::new("nb_io", "Test IO");
|
let manifest = NotebookManifest::new("nb_io", "Test IO");
|
||||||
save_manifest(path, &manifest).unwrap();
|
save_manifest(path, &manifest).unwrap();
|
||||||
|
|
||||||
|
// I/O-Fehler simulieren, der auch als root auftritt (CI-Runner laufen oft als root,
|
||||||
|
// dort greift ein chmod 000 nicht): page_1.json ist ein Verzeichnis -> EISDIR beim Lesen
|
||||||
let original_content = br#"{"id": 1, "background": "Grid5mm", "strokes": []}"#;
|
let original_content = br#"{"id": 1, "background": "Grid5mm", "strokes": []}"#;
|
||||||
let page_file = path.join("page_1.json");
|
let page_path = path.join("page_1.json");
|
||||||
fs::write(&page_file, original_content).unwrap();
|
fs::create_dir(&page_path).unwrap();
|
||||||
|
let marker = page_path.join("original");
|
||||||
// Make file unreadable
|
fs::write(&marker, original_content).unwrap();
|
||||||
fs::set_permissions(&page_file, fs::Permissions::from_mode(0o000)).unwrap();
|
|
||||||
|
|
||||||
let (nb, mut m) =
|
let (nb, mut m) =
|
||||||
load_notebook(path).expect("load_notebook should succeed with fallback page");
|
load_notebook(path).expect("load_notebook should succeed with fallback page");
|
||||||
|
|
||||||
// Restore permissions for inspection
|
|
||||||
fs::set_permissions(&page_file, fs::Permissions::from_mode(0o600)).unwrap();
|
|
||||||
|
|
||||||
let dir_entries: Vec<String> = fs::read_dir(path)
|
let dir_entries: Vec<String> = fs::read_dir(path)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.flatten()
|
.flatten()
|
||||||
@@ -1566,10 +1558,15 @@ mod tests {
|
|||||||
);
|
);
|
||||||
|
|
||||||
save_notebook(path, &nb, &mut m).unwrap();
|
save_notebook(path, &nb, &mut m).unwrap();
|
||||||
|
|
||||||
|
assert!(
|
||||||
|
page_path.is_dir(),
|
||||||
|
"Original page path must not be replaced"
|
||||||
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
fs::read(&page_file).unwrap(),
|
fs::read(&marker).unwrap(),
|
||||||
original_content,
|
original_content,
|
||||||
"Original file content must not be overwritten"
|
"Original content must not be overwritten"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+2
-1
@@ -317,7 +317,8 @@ pub fn verify_checksum(
|
|||||||
/// signiert sein muss. Ist er leer, lehnt diese Version alle In-App-Updates ab.
|
/// signiert sein muss. Ist er leer, lehnt diese Version alle In-App-Updates ab.
|
||||||
/// Erzeugen: `minisign -G -W -p ink-notes.pub -s ink-notes.key`, dann die zweite Zeile
|
/// Erzeugen: `minisign -G -W -p ink-notes.pub -s ink-notes.key`, dann die zweite Zeile
|
||||||
/// aus `ink-notes.pub` hier eintragen (siehe README, Abschnitt Release-Signatur).
|
/// aus `ink-notes.pub` hier eintragen (siehe README, Abschnitt Release-Signatur).
|
||||||
pub const UPDATE_SIGNING_PUBLIC_KEY: &str = "";
|
pub const UPDATE_SIGNING_PUBLIC_KEY: &str =
|
||||||
|
"RWTZqQ0ZDCn+PHTpqgI8NwjtgtkJk5QyJ0FYHWZlCZtABsXBcdPDv9WI";
|
||||||
|
|
||||||
/// Name des Prüfsummen-Assets eines Releases.
|
/// Name des Prüfsummen-Assets eines Releases.
|
||||||
pub const CHECKSUMS_ASSET_NAME: &str = "SHA256SUMS.txt";
|
pub const CHECKSUMS_ASSET_NAME: &str = "SHA256SUMS.txt";
|
||||||
|
|||||||
Reference in new issue
Block a user