fix(linux): move captures out of protected CUPS cache
Some checks failed
Desktop Release / Bootstrap updater signing key (push) Has been cancelled
Desktop Release / Windows x64 NSIS (push) Has been cancelled
Desktop Release / Linux x64 DEB + AppImage (push) Has been cancelled
Desktop Release / Publish public desktop release (push) Has been cancelled

This commit is contained in:
Admin 2026-09-24 09:56:17 +00:00
parent 4dc1be87bb
commit 54137bdf86
6 changed files with 63 additions and 11 deletions

View File

@ -1,6 +1,6 @@
{
"name": "@fieldlens/print",
"version": "0.1.14",
"version": "0.1.15",
"private": true,
"type": "module",
"scripts": {

View File

@ -1,6 +1,6 @@
[package]
name = "fieldlens-print"
version = "0.1.14"
version = "0.1.15"
description = "FieldLens print-stream barcode capture companion"
authors = ["Arrowstack"]
edition = "2021"

View File

@ -25,7 +25,7 @@ use crate::{
};
#[cfg(target_os = "linux")]
const SYSTEM_CUPS_SPOOL_DIR: &str = "/var/cache/cups/fieldlens-print";
const SYSTEM_CUPS_SPOOL_DIR: &str = "/var/lib/fieldlens-print/capture";
#[cfg(target_os = "linux")]
const TEST_CAPTURE_SINK_ADDR: &str = "127.0.0.1:9101";

View File

@ -20,14 +20,14 @@ const TEST_CAPTURE_DEVICE_URI: &str = "socket://127.0.0.1:9101";
const WINDOWS_PORT_NAME: &str = "FieldLensPrint-9100";
#[cfg(target_os = "linux")]
const FIELDLENS_CUPS_SPOOL_DIR: &str = "/var/cache/cups/fieldlens-print";
const FIELDLENS_CUPS_SPOOL_DIR: &str = "/var/lib/fieldlens-print/capture";
#[cfg(target_os = "linux")]
const FIELDLENS_CUPS_FILTER: &str = r#"#!/usr/bin/python3
import os
import re
import sys
CACHE = os.path.join(os.environ.get("CUPS_CACHEDIR", "/var/cache/cups"), "fieldlens-print")
CACHE = "/var/lib/fieldlens-print/capture"\nOWNER_UID = __FIELDLENS_OWNER_UID__\nOWNER_GID = __FIELDLENS_OWNER_GID__
def safe(value):
value = re.sub(r"[^A-Za-z0-9._-]+", "-", value or "job").strip("-")
@ -84,7 +84,13 @@ try:
capture.flush()
capture.close()
capture = None
os.chmod(part_path, 0o644)
os.chmod(part_path, 0o600)
try:
os.chown(part_path, OWNER_UID, OWNER_GID)
except PermissionError:
# On this Linux lane CUPS runs filters as root. Keep printing alive
# if a future CUPS policy drops privileges; repair can surface it.
pass
os.replace(part_path, final_path)
captured_ok = True
print(f"INFO: FieldLens captured {name}", file=sys.stderr)
@ -111,9 +117,12 @@ target_printer = sys.argv[1]
target_port = sys.argv[2]
temp_filter = sys.argv[3]
filter_path = sys.argv[4]
owner_uid = int(sys.argv[5])
owner_gid = int(sys.argv[6])
source_ppd = os.path.join("/etc/cups/ppd", f"{target_printer}.ppd")
spool_dir = "/var/cache/cups/fieldlens-print"
spool_dir = "/var/lib/fieldlens-print/capture"
old_spool_dir = "/var/cache/cups/fieldlens-print"
with open(source_ppd, "r", encoding="utf-8", errors="replace") as source:
original = source.read()
@ -142,7 +151,31 @@ try:
target.write(cleaned)
subprocess.run(["install", "-m", "0755", temp_filter, filter_path], check=True)
subprocess.run(["install", "-d", "-m", "0777", spool_dir], check=True)
os.makedirs(spool_dir, exist_ok=True)
os.chown(spool_dir, owner_uid, owner_gid)
os.chmod(spool_dir, 0o700)
# Bring forward captures stranded by 0.1.13/0.1.14 in CUPS' protected
# cache. Ignore directories and partial writes.
if os.path.isdir(old_spool_dir):
for name in os.listdir(old_spool_dir):
source = os.path.join(old_spool_dir, name)
if not os.path.isfile(source) or name.endswith(".part"):
continue
target = os.path.join(spool_dir, name)
if os.path.exists(target):
root, ext = os.path.splitext(name)
target = os.path.join(spool_dir, f"{root}-migrated{ext}")
try:
os.replace(source, target)
except OSError:
continue
try:
os.chown(target, owner_uid, owner_gid)
os.chmod(target, 0o600)
except OSError:
pass
subprocess.run([
"lpadmin", "-p", "FieldLens-Print", "-E",
@ -685,7 +718,24 @@ fn install_linux_virtual_printer(target_printer: &str) -> Result<()> {
uuid::Uuid::new_v4()
));
fs::write(&temp_filter, FIELDLENS_CUPS_FILTER)
let uid = Command::new("id")
.arg("-u")
.output()
.context("read current Linux user id")?;
let gid = Command::new("id")
.arg("-g")
.output()
.context("read current Linux group id")?;
if !uid.status.success() || !gid.status.success() {
return Err(anyhow!("could not determine the current Linux user for capture ownership"));
}
let uid = String::from_utf8_lossy(&uid.stdout).trim().to_string();
let gid = String::from_utf8_lossy(&gid.stdout).trim().to_string();
let filter_script = FIELDLENS_CUPS_FILTER
.replace("__FIELDLENS_OWNER_UID__", &uid)
.replace("__FIELDLENS_OWNER_GID__", &gid);
fs::write(&temp_filter, filter_script)
.context("write FieldLens CUPS capture filter")?;
fs::write(&temp_helper, FIELDLENS_CUPS_REPAIR_HELPER)
.context("write FieldLens CUPS repair helper")?;
@ -697,6 +747,8 @@ fn install_linux_virtual_printer(target_printer: &str) -> Result<()> {
.arg(&target.port)
.arg(&temp_filter)
.arg(&filter_path)
.arg(&uid)
.arg(&gid)
.status()
.context("run elevated FieldLens CUPS repair")?;

View File

@ -1,7 +1,7 @@
{
"$schema": "https://schema.tauri.app/config/2",
"productName": "FieldLens Print",
"version": "0.1.14",
"version": "0.1.15",
"identifier": "dev.arrowstack.fieldlens.print",
"build": {
"beforeDevCommand": "npm run dev",

View File

@ -85,7 +85,7 @@ let config: AppConfig
let jobs: Job[] = []
let status: Status
let loginTimer: number | undefined
let currentVersion = '0.1.14'
let currentVersion = '0.1.15'
let bundleType: BundleType | null = null
let availableUpdate: Update | null = null
let availableManualUpdate: ManualUpdate | null = null