Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
ec06207
migrated to tauri 2.0
girish946 Jun 21, 2026
63bb8ab
updated gh action
girish946 Jun 21, 2026
5f1335c
update the turi action version
girish946 Jun 21, 2026
bfb1292
used patch scripts for different desktop envs
girish946 Jun 21, 2026
6a28cdc
removed the use of litho binary and fixed it's usage while starting u…
girish946 Jun 23, 2026
371ad17
feat(ui): native file picker, themes, and privilege status
girish946 Jun 23, 2026
cbb6823
disabled the window decorations
girish946 Jun 24, 2026
e529e44
feat(gui): add fixed-device safety UX and removable-first device sele…
girish946 Jun 24, 2026
4243536
fixed github workflow
girish946 Jun 24, 2026
e23da92
fixed prepare-litho-sidecar.sh
girish946 Jun 24, 2026
261bde8
fixed git clone command for litho
girish946 Jun 24, 2026
c334582
Merge pull request #2 from girish946/temp-dev
girish946 Jun 24, 2026
7ddd4b0
feat(io): optimal block size, optional verify, and real-io sidecar
girish946 Jun 24, 2026
f1e1001
Merge pull request #3 from girish946/temp-dev
girish946 Jun 25, 2026
abeb026
fixed building the sidecar binary
girish946 Jun 25, 2026
e4628ed
feat(gui): bundle vendor assets locally and refresh UI polish
girish946 Jun 25, 2026
f43ae74
feat(sidecar): cooperative cancel via litho cancel flag file
girish946 Jun 27, 2026
ac23a29
updated the gitignore and minor change in index.html
girish946 Jun 27, 2026
052206d
updated the branch for litho in gh action
girish946 Jun 27, 2026
fe7b231
updated the window size
girish946 Jul 5, 2026
4ac5e63
started tauri build for windows
girish946 Jul 5, 2026
49b02eb
feat(windows): add UAC handoff, CI build, and platform window chrome
girish946 Jul 5, 2026
160a37e
fixed windows pipeline.
girish946 Jul 5, 2026
1209e08
updated the icons and fixed the flash screen
girish946 Jul 5, 2026
477bd8e
updated the build pipeline for windows
girish946 Jul 5, 2026
49084d1
updated the gh pipeline
girish946 Jul 5, 2026
ed82a29
updated the build pipeline for liblzma
girish946 Jul 5, 2026
54f27d1
updated the use of polkit agent and sudo on linux
girish946 Jul 5, 2026
cf4160f
handled unmounting devices
girish946 Jul 5, 2026
76018c6
updated the README and added banner, window image
girish946 Jul 5, 2026
347e6e6
updated README
girish946 Jul 6, 2026
6e497b7
applied rustfmt
girish946 Jul 6, 2026
65bd60d
applied clippy
girish946 Jul 6, 2026
a0e7713
applied clippy fixes
girish946 Jul 6, 2026
da0d1fc
reverted clippy fix
girish946 Jul 6, 2026
317e178
reverted clippy fix
girish946 Jul 6, 2026
5971579
minor change for indicating the status
girish946 Jul 7, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
156 changes: 132 additions & 24 deletions .github/workflows/build.yaml
Original file line number Diff line number Diff line change
@@ -1,54 +1,162 @@
name: "build"
name: build

# This will trigger the action on each push to the `release` branch.
on:
push:
branches:
- "*"
pull_request:

env:
LITHO_REPO: https://github.com/girish946/litho.git
LITHO_BRANCH: windows-implementation

jobs:
publish-tauri:
build-tauri-linux:
permissions:
contents: write
strategy:
fail-fast: false
matrix:
# platform: [macos-latest, ubuntu-20.04, windows-latest]
platform: [ubuntu-20.04]

runs-on: ${{ matrix.platform }}
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4

# liblitho is a path dependency at ../../litho (sibling of this repo).
- name: Checkout litho
run: git clone --depth 1 --branch "${{ env.LITHO_BRANCH }}" "${{ env.LITHO_REPO }}" ../litho

- name: install dependencies (ubuntu only)
run: |
sudo apt-get update
sudo apt-get install -y libwebkit2gtk-4.1-dev libappindicator3-dev librsvg2-dev patchelf

- name: setup node
uses: actions/setup-node@v4
with:
node-version: 20
node-version: lts/*

- name: install Rust stable
uses: dtolnay/rust-toolchain@stable

- name: install dependencies (ubuntu only)
if: matrix.platform == 'ubuntu-20.04'
run: |
sudo apt-get update
sudo apt-get install -y libgtk-3-dev libwebkit2gtk-4.0-dev libappindicator3-dev librsvg2-dev patchelf
- name: Rust cache
uses: swatinem/rust-cache@v2
with:
workspaces: |
./src-tauri -> target
../litho -> target

- name: install frontend dependencies
run: yarn install # change this to npm or pnpm depending on which one you use
run: npm install

- name: vendor frontend assets
run: npm run vendor-assets

- name: generate app icons
run: npm run generate-icons

# Omit tagName and releaseId to build only (no GitHub release upload).
- uses: tauri-apps/tauri-action@v0
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
#with:
# tagName: app-v__VERSION__ # the action automatically replaces \_\_VERSION\_\_ with the app version
# releaseName: "App v__VERSION__"
# releaseBody: "See the assets to download this version and install."
# releaseDraft: true
# prerelease: false
with:
tauriScript: bash scripts/tauri-build.sh

- uses: actions/upload-artifact@v4
with:
name: builds
name: linux-builds
path: |
src-tauri/target/release/bundle/deb/*.deb
src-tauri/target/release/bundle/appimage/*.AppImage
src-tauri/target/release/bundle/rpm/*.rpm

build-tauri-windows:
permissions:
contents: write
runs-on: windows-latest
steps:
- uses: actions/checkout@v4

- name: Checkout litho
shell: bash
run: git clone --depth 1 --branch "${{ env.LITHO_BRANCH }}" "${{ env.LITHO_REPO }}" ../litho

# windows-latest ships OpenSSL at C:\Program Files\OpenSSL (see actions/runner-images Install-OpenSSL.ps1).
# openssl-sys needs OPENSSL_* pointing at the MSVC import libs (lib\VC\x64\MD\), not lib\ alone.
- name: Configure pre-installed OpenSSL for openssl-sys
shell: pwsh
run: |
$opensslDir = 'C:\Program Files\OpenSSL'
if (-not (Test-Path $opensslDir)) {
Write-Error "Pre-installed OpenSSL not found at $opensslDir"
exit 1
}

$libMatch = Get-ChildItem -Path $opensslDir -Recurse -Filter 'libcrypto.lib' -ErrorAction SilentlyContinue | Select-Object -First 1
if (-not $libMatch) {
Write-Error "libcrypto.lib not found under $opensslDir"
exit 1
}
$libDir = $libMatch.DirectoryName

$includeDir = Join-Path $opensslDir 'include'
if (-not (Test-Path $includeDir)) {
Write-Error "OpenSSL include dir not found at $includeDir"
exit 1
}

Write-Host "OPENSSL_DIR=$opensslDir"
Write-Host "OPENSSL_LIB_DIR=$libDir"
Write-Host "OPENSSL_INCLUDE_DIR=$includeDir"
Add-Content -Path $env:GITHUB_ENV -Value "OPENSSL_DIR=$opensslDir"
Add-Content -Path $env:GITHUB_ENV -Value "OPENSSL_LIB_DIR=$libDir"
Add-Content -Path $env:GITHUB_ENV -Value "OPENSSL_INCLUDE_DIR=$includeDir"

# windows-latest ships vcpkg at C:\vcpkg (VCPKG_INSTALLATION_ROOT). rust-lzma needs VCPKG_ROOT
# and the liblzma port installed (find_package does not auto-install).
- name: Configure pre-installed vcpkg for rust-lzma
shell: pwsh
run: |
$vcpkgRoot = 'C:\vcpkg'
$vcpkgExe = Join-Path $vcpkgRoot 'vcpkg.exe'
if (-not (Test-Path $vcpkgExe)) {
Write-Error "Pre-installed vcpkg not found at $vcpkgExe"
exit 1
}
Write-Host "Installing static liblzma via $vcpkgExe ..."
& $vcpkgExe install liblzma:x64-windows-static-md
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
Add-Content -Path $env:GITHUB_ENV -Value "VCPKG_ROOT=$vcpkgRoot"

- name: setup node
uses: actions/setup-node@v4
with:
node-version: lts/*

- name: install Rust stable
uses: dtolnay/rust-toolchain@stable

- name: Rust cache
uses: swatinem/rust-cache@v2
with:
workspaces: |
./src-tauri -> target
../litho -> target

- name: install frontend dependencies
run: npm install

- name: vendor frontend assets
run: npm run vendor-assets

- name: generate app icons
run: npm run generate-icons

- uses: tauri-apps/tauri-action@v0
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tauriScript: powershell -ExecutionPolicy Bypass -File scripts/tauri-build.ps1

- uses: actions/upload-artifact@v4
with:
name: windows-builds
path: |
src-tauri/target/release/bundle/msi/*.msi
src-tauri/target/release/bundle/nsis/*.exe
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,9 @@ dist-ssr
*.njsproj
*.sln
*.sw?

# frontend framework files and fonts
src/vendor/*

# sidecar files
src-tauri/binaries/*
180 changes: 170 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,28 +1,188 @@
# Lithographer

GUI for [litho](https://github.com/girish946/litho) written in Rust using [tauri](https://tauri.studio/).

GUI for [litho](https://github.com/girish946/litho) — flash disk images and clone block devices with a native desktop app built on [Tauri 2](https://tauri.app/).

<p align="center">
<img src="src/assets/logo.png"></img>
<img src="src/assets/lithographer-banner-dark.jpg" alt="Lithographer logo">
</p>

Lithographer stays **unprivileged**. Device enumeration and validation run in-process via `liblitho`; privileged flash/clone work is delegated to a bundled **`litho` sidecar** that speaks a line-oriented GUI protocol on stdout.

## Features

- **Flash** and **clone** with real block I/O (sidecar built with `real-io`)
- **Device picker** — removable devices listed first; fixed-disk extra confirmation in litho
- **Native file dialog** — open image for flash, save path for clone (`rfd`)
- **Optimal I/O block size** — computed from target device capacity (not a fixed 4 KiB)
- **Optional SHA-256 verify** — checkbox for flash operations (off by default)
- **Cooperative cancel** — cancel flag file works across `pkexec` / UAC elevation boundaries
- **Privilege diagnostics** — live badge (root / polkit / UAC / unprivileged) from startup checks
- **Light / dark themes** with persisted preference
- **Linux:** AppImage, `.deb`, `.rpm` bundles; Wayland compatibility hook for Hyprland and similar compositors
- **Windows:** MSI/NSIS installers; UAC handoff relaunches the app elevated so litho stdout pipes correctly

## Architecture

```
Lithographer (user session)
├─ liblitho in-process → device list, validation, optimal block size
└─ litho sidecar → pkexec / direct (Linux) or piped child (Windows)
└─ litho -o gui flash|clone … --cancel-file <path> [--verify]
```

**Linux elevation:** `pkexec litho …` by default. On AppImage, `litho` is copied to `$TMPDIR/lithographer-litho-<pid>` first because `pkexec` cannot execute binaries inside the FUSE mount. The staged copy is removed when the app exits.

**Windows elevation:** Lithographer relaunches itself via UAC (`--auto-run …`) so `litho.exe` runs as a hidden piped child inside the elevated GUI process (elevating litho directly would break stdout capture).

**Cancel across elevation:** stdin and parent signals do not reliably reach a `pkexec` child. Lithographer creates `~/.cache/litho/cancel-<pid>-<ts>.flag`, passes `--cancel-file` to litho, and writes `cancel` into the file on user cancel. Litho polls the file every ~50 ms.

## Requirements

### Linux

- [Tauri 2 prerequisites](https://tauri.app/start/prerequisites/) (`webkit2gtk-4.1`, etc.)
- `pkexec` (polkit) for unprivileged flash/clone
- On **Fedora GNOME**: polkit auth is built into `gnome-shell` (the retired `polkit-gnome-authentication-agent-1` package is not required)

### Windows

- [Tauri 2 prerequisites](https://tauri.app/start/prerequisites/) (WebView2, Visual Studio Build Tools)
- OpenSSL (CI uses the runner pre-install at `C:\Program Files\OpenSSL`)
- Administrator approval via UAC for flash/clone

## Repository layout

Clone **lithographer** and its sibling dependency **litho** (required for `liblitho` and the bundled sidecar):

```bash
git clone https://github.com/girish946/lithographer.git
git clone --branch windows-implementation https://github.com/girish946/litho.git
```

The repos must sit side by side (`…/litho` next to `…/lithographer`). GitHub Actions checks out `litho` from the `windows-implementation` branch the same way.

## Build

### Prerequisites
```bash
cd lithographer
npm install
npm run tauri:build
```

As of now lithographer only supports building for Linux. You need to have the [Prerequisites for tauri](https://tauri.app/v1/guides/getting-started/prerequisites/) installed on the system.
### npm scripts

| Script | Description |
|--------|-------------|
| `npm run tauri:dev` | Prepare sidecar + `tauri dev` |
| `npm run tauri:build` | Prepare sidecar + `tauri build` + post-build AppImage Wayland patch |
| `npm run prepare-sidecar` | Build `litho` with `real-io` into `src-tauri/binaries/` |
| `npm run vendor-assets` | Bundle frontend fonts/CSS locally (offline-friendly) |
| `npm run generate-icons` | Regenerate app icons from source artwork |

The sidecar build (`src-tauri/scripts/prepare-litho-sidecar.sh`) runs:

```bash
$ git clone https://github.com/girish946/lithographer.git
$ cd lithographer
$ cargo tauri build -b appimage
cargo build --release --no-default-features --features real-io --bin litho
```

### Build outputs

| Platform | Artifacts |
|----------|-----------|
| Linux | `src-tauri/target/release/bundle/appimage/lithographer_*_amd64.AppImage` |
| Linux | `src-tauri/target/release/bundle/deb/*.deb`, `rpm/*.rpm` |
| Windows | `src-tauri/target/release/bundle/msi/*.msi`, `nsis/*.exe` |

## Usage

### Linux

```bash
$ ./src-tauri/target/release/bundle/appimage/lithographer_0.0.1_amd64.AppImage
./src-tauri/target/release/bundle/appimage/lithographer_0.1.0_amd64.AppImage
```

<img src="src/assets/lithographer-window.png"></img>
The AppImage includes a post-build Wayland compatibility hook (`src-tauri/scripts/patch-appimage-wayland.sh` injects `src-tauri/appimage/apprun-wayland-compat.sh`). On some setups the `.deb` package is more reliable because it uses system WebKitGTK.

### Windows

Run the MSI/NSIS installer output, or during development:

```bash
npm run tauri:dev
```

### Privilege elevation options (Linux)

| Method | Auth UI | When to use |
|--------|---------|-------------|
| **`pkexec` (default)** | GNOME Shell / polkit dialog (password, fingerprint) | Normal Fedora/Ubuntu GNOME sessions |
| **`LITHOGRAPHER_ELEVATION=sudo`** | Graphical `sudo` askpass (`SUDO_ASKPASS`, `ksshaskpass`, `zenity`, …) | Polkit misbehaving |
| **`LITHOGRAPHER_ELEVATION=run0`** | Polkit via systemd | Fedora 41+ with `run0` on PATH |
| **Run app elevated** | One prompt at startup | `sudo ./lithographer*.AppImage` — litho spawns directly, no per-operation `pkexec` |

```bash
# Polkit path (default)
./lithographer_0.1.0_amd64.AppImage

# sudo askpass fallback
LITHOGRAPHER_ELEVATION=sudo ./lithographer_0.1.0_amd64.AppImage

# Whole session elevated
sudo ./lithographer_0.1.0_amd64.AppImage
```

### Privilege elevation (Windows)

When you start flash/clone without Administrator rights, Lithographer prompts for UAC and relaunches with `--auto-run` so progress streams in the elevated window. The original unprivileged window exits after handoff.

## Development

```bash
# One-time: build litho sidecar
npm run prepare-sidecar

# Dev loop (hot reload)
npm run tauri:dev
```

After changing litho CLI protocol or cancel behaviour, rebuild the sidecar before testing Lithographer:

```bash
npm run prepare-sidecar
```

### Startup diagnostics

The privilege badge and `get_startup_diagnostics` Tauri command report:

- elevated vs unprivileged state
- elevation backend (`pkexec`, `sudo -A`, `run0`, `uac`)
- polkit agent or `gnome-shell (built-in polkit)` on Fedora GNOME
- preview of the litho spawn command

## CI

GitHub Actions (`.github/workflows/build.yaml`):

- **ubuntu-22.04** — AppImage, `.deb`, `.rpm`
- **windows-latest** — MSI and NSIS (OpenSSL + vcpkg `liblzma` for the litho sidecar)

Both jobs clone `litho` from the `windows-implementation` branch.

## Screenshots

<img src="src/assets/lithographer-window.png" alt="Lithographer main window">

## Safety

- Always double-check the target device. Flashing the wrong disk destroys data.
- Prefer removable USB drives for flash targets.
- Device validation (system disk, mounts, partition paths) runs in litho before any write.

## Related

- [litho](https://github.com/girish946/litho) — CLI, library, and `litho-tui`

## License

See `src-tauri/Cargo.toml`.
Loading
Loading