feat(macos): Verae Timestamping in Print Destination list
Replace buried PDF Services as the primary UX with an IPP Everywhere
virtual printer (ippeveprinter LaunchAgent) named Verae Timestamping.
Jobs save {name}.pdf + {name}-verae-timestamp-{RECEIPTID}.pdf.
Also add /Applications/Verae Print Stamp.app for drop/Open With.
This commit is contained in:
parent
46f2bcd43e
commit
b40e862082
7 changed files with 370 additions and 3 deletions
|
|
@ -9,9 +9,11 @@ Only the SHA-256 digest is sent to Verae. Document bytes never leave the machine
|
|||
```bash
|
||||
cd /Users/marchon/research/PrintToVeraeTimeStamp
|
||||
go build -o "$HOME/bin/verae-print" ./cmd/verae-print
|
||||
verae-print install-macos
|
||||
verae-print install-printer # Print → Destination → Verae Timestamping
|
||||
```
|
||||
|
||||
Optional (buried PDF submenu): `verae-print install-macos`
|
||||
|
||||
Ensure `$HOME/bin` is on your `PATH`. Refresh Verae Time login when the JWT expires:
|
||||
|
||||
```bash
|
||||
|
|
@ -31,7 +33,9 @@ chmod 600 ~/.verae/xverae-token
|
|||
|
||||
## Usage
|
||||
|
||||
In any app: **File → Print → PDF → Timestamp with Verae** (or **Timestamp with Verae (Zapier)**).
|
||||
In any app: **File → Print → Destination → Verae Timestamping → Print**.
|
||||
|
||||
Also: drop a PDF on **Verae Print Stamp** in `/Applications`, or **Open With**.
|
||||
|
||||
CLI:
|
||||
|
||||
|
|
|
|||
|
|
@ -23,6 +23,8 @@ func main() {
|
|||
os.Exit(runStamp(os.Args[2:]))
|
||||
case "install-macos":
|
||||
os.Exit(runInstallMacOS(os.Args[2:]))
|
||||
case "install-printer":
|
||||
os.Exit(runInstallPrinter())
|
||||
case "version", "-version", "--version":
|
||||
fmt.Println(job.HelperVersion)
|
||||
case "help", "-h", "--help":
|
||||
|
|
@ -43,7 +45,8 @@ func usage() {
|
|||
|
||||
Usage:
|
||||
verae-print stamp [--channel=verae|zapier] [--out-dir DIR] [--name STEM] [--open] <file.pdf>
|
||||
verae-print install-macos # install PDF Services menu items
|
||||
verae-print install-printer # Destination list: Verae Timestamping (recommended)
|
||||
verae-print install-macos # also install PDF Services menu items (legacy)
|
||||
verae-print version
|
||||
|
||||
Channels:
|
||||
|
|
@ -117,6 +120,42 @@ func runStamp(args []string) int {
|
|||
return 0
|
||||
}
|
||||
|
||||
func runInstallPrinter() int {
|
||||
script := filepath.Join(repoRootHint(), "platform", "macos", "ipp", "install-ipp-printer.sh")
|
||||
if _, err := os.Stat(script); err != nil {
|
||||
// fall back next to executable
|
||||
exe, _ := os.Executable()
|
||||
exe, _ = filepath.EvalSymlinks(exe)
|
||||
script = filepath.Join(filepath.Dir(exe), "..", "platform", "macos", "ipp", "install-ipp-printer.sh")
|
||||
}
|
||||
if abs, err := filepath.Abs(script); err == nil {
|
||||
script = abs
|
||||
}
|
||||
cmd := exec.Command("/bin/bash", script)
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
cmd.Env = os.Environ()
|
||||
if err := cmd.Run(); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "install-printer failed: %v\n(run platform/macos/ipp/install-ipp-printer.sh)\n", err)
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func repoRootHint() string {
|
||||
// Prefer known research path; else cwd
|
||||
candidates := []string{
|
||||
"/Users/marchon/research/PrintToVeraeTimeStamp",
|
||||
".",
|
||||
}
|
||||
for _, c := range candidates {
|
||||
if st, err := os.Stat(filepath.Join(c, "platform", "macos", "ipp", "install-ipp-printer.sh")); err == nil && !st.IsDir() {
|
||||
return c
|
||||
}
|
||||
}
|
||||
return "."
|
||||
}
|
||||
|
||||
func runInstallMacOS(args []string) int {
|
||||
fs := flag.NewFlagSet("install-macos", flag.ExitOnError)
|
||||
bin := fs.String("bin", "", "path to verae-print binary (default: this executable)")
|
||||
|
|
|
|||
116
platform/macos/cups/backend-verae.sh
Executable file
116
platform/macos/cups/backend-verae.sh
Executable file
|
|
@ -0,0 +1,116 @@
|
|||
#!/bin/bash
|
||||
# CUPS backend: verae — virtual printer "Verae Timestamping"
|
||||
# Discovery (no args): advertise device URI verae:/
|
||||
# Job: spool PDF and run verae-print as the job user (digests only).
|
||||
set -euo pipefail
|
||||
|
||||
LOG_ROOT="/var/log/cups"
|
||||
BACKEND_LOG="${LOG_ROOT}/verae-backend.log"
|
||||
|
||||
log() {
|
||||
echo "$(date -u +%Y-%m-%dT%H:%MZ) $*" >>"$BACKEND_LOG" 2>/dev/null || true
|
||||
}
|
||||
|
||||
# Device discovery
|
||||
if [[ $# -eq 0 ]]; then
|
||||
echo 'direct verae:/ "Verae Timestamping" "Verae Timestamping — digests-only stamp"'
|
||||
exit 0
|
||||
fi
|
||||
|
||||
JOB_ID="${1:-}"
|
||||
JOB_USER="${2:-}"
|
||||
JOB_TITLE="${3:-document}"
|
||||
# copies=$4 options=$5
|
||||
JOB_FILE="${6:-}"
|
||||
|
||||
VERAE_PRINT="${VERAE_PRINT_BIN:-/Users/marchon/bin/verae-print}"
|
||||
CHANNEL="${VERAE_PRINT_CHANNEL:-verae}"
|
||||
|
||||
SPOOL_BASE="/Users/Shared/VeraePrintSpool"
|
||||
# Prefer per-user Application Support when home is known
|
||||
if [[ -n "$JOB_USER" && -d "/Users/$JOB_USER" ]]; then
|
||||
SPOOL_BASE="/Users/$JOB_USER/Library/Application Support/Verae/print-spool"
|
||||
fi
|
||||
|
||||
mkdir -p "$SPOOL_BASE"
|
||||
chmod 700 "$SPOOL_BASE" 2>/dev/null || true
|
||||
|
||||
SAFE_TITLE=$(echo "$JOB_TITLE" | tr -cd 'A-Za-z0-9._ -' | head -c 80)
|
||||
SAFE_TITLE=${SAFE_TITLE:-document}
|
||||
WORK="$SPOOL_BASE/job-${JOB_ID}-$$"
|
||||
mkdir -p "$WORK"
|
||||
|
||||
INPUT="$WORK/input.dat"
|
||||
if [[ -n "$JOB_FILE" && -f "$JOB_FILE" ]]; then
|
||||
cp "$JOB_FILE" "$INPUT"
|
||||
else
|
||||
cat >"$INPUT"
|
||||
fi
|
||||
|
||||
# Normalize to PDF when CUPS gave PostScript / other
|
||||
PDF="$WORK/${SAFE_TITLE}.pdf"
|
||||
CONTENT_TYPE="${CONTENT_TYPE:-application/pdf}"
|
||||
case "$CONTENT_TYPE" in
|
||||
application/pdf|application/x-pdf)
|
||||
cp "$INPUT" "$PDF"
|
||||
;;
|
||||
application/postscript|application/vnd.cups-postscript)
|
||||
if command -v /usr/bin/pstopdf >/dev/null 2>&1; then
|
||||
/usr/bin/pstopdf "$INPUT" -o "$PDF" 2>/dev/null || cp "$INPUT" "$PDF"
|
||||
else
|
||||
# macOS often still delivers PDF despite PS content-type
|
||||
if [[ "$(head -c 4 "$INPUT")" == "%PDF" ]]; then
|
||||
cp "$INPUT" "$PDF"
|
||||
else
|
||||
log "job $JOB_ID: cannot convert $CONTENT_TYPE; saving raw"
|
||||
cp "$INPUT" "$PDF"
|
||||
fi
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
if [[ "$(head -c 4 "$INPUT")" == "%PDF" ]]; then
|
||||
cp "$INPUT" "$PDF"
|
||||
else
|
||||
log "job $JOB_ID: content-type=$CONTENT_TYPE; assuming PDF bytes"
|
||||
cp "$INPUT" "$PDF"
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
log "job=$JOB_ID user=$JOB_USER title=$JOB_TITLE pdf=$PDF channel=$CHANNEL"
|
||||
|
||||
OUT_DIR="/Users/${JOB_USER}/Documents/Verae Timestamps"
|
||||
if [[ -z "$JOB_USER" || ! -d "/Users/$JOB_USER" ]]; then
|
||||
OUT_DIR="$SPOOL_BASE/out"
|
||||
fi
|
||||
mkdir -p "$OUT_DIR"
|
||||
|
||||
run_stamp() {
|
||||
if [[ -x "$VERAE_PRINT" ]]; then
|
||||
"$VERAE_PRINT" stamp -channel "$CHANNEL" -out-dir "$OUT_DIR" -name "$SAFE_TITLE" -open "$PDF"
|
||||
else
|
||||
log "verae-print missing at $VERAE_PRINT"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Drop privileges to job user when we are root
|
||||
if [[ "$(id -u)" -eq 0 && -n "$JOB_USER" && "$JOB_USER" != "root" ]]; then
|
||||
chown -R "$JOB_USER" "$WORK" "$OUT_DIR" 2>/dev/null || true
|
||||
if command -v sudo >/dev/null 2>&1; then
|
||||
sudo -u "$JOB_USER" -H "$VERAE_PRINT" stamp -channel "$CHANNEL" -out-dir "$OUT_DIR" -name "$SAFE_TITLE" -open "$PDF" \
|
||||
>>"$BACKEND_LOG" 2>&1 || {
|
||||
log "stamp failed for job $JOB_ID"
|
||||
# Still exit 0 so the print dialog doesn't hang; user can check log
|
||||
exit 0
|
||||
}
|
||||
else
|
||||
run_stamp >>"$BACKEND_LOG" 2>&1 || true
|
||||
fi
|
||||
else
|
||||
run_stamp >>"$BACKEND_LOG" 2>&1 || true
|
||||
fi
|
||||
|
||||
# Cleanup work dir; keep outputs in OUT_DIR
|
||||
rm -rf "$WORK" 2>/dev/null || true
|
||||
exit 0
|
||||
50
platform/macos/cups/install-printer.sh
Executable file
50
platform/macos/cups/install-printer.sh
Executable file
|
|
@ -0,0 +1,50 @@
|
|||
#!/bin/bash
|
||||
# Install "Verae Timestamping" as a CUPS destination (Print → Destination list).
|
||||
set -euo pipefail
|
||||
|
||||
ROOT="$(cd "$(dirname "$0")/../../.." && pwd)"
|
||||
BIN="${VERAE_PRINT_BIN:-$HOME/bin/verae-print}"
|
||||
BACKEND_SRC="$(cd "$(dirname "$0")" && pwd)/backend-verae.sh"
|
||||
BACKEND_DST="/usr/libexec/cups/backend/verae"
|
||||
QUEUE="Verae_Timestamping"
|
||||
DISPLAY_NAME="Verae Timestamping"
|
||||
|
||||
if [[ ! -x "$BIN" ]]; then
|
||||
echo "Building verae-print → $BIN"
|
||||
mkdir -p "$(dirname "$BIN")"
|
||||
(cd "$ROOT" && go build -o "$BIN" ./cmd/verae-print)
|
||||
fi
|
||||
|
||||
if [[ ! -f "$BACKEND_SRC" ]]; then
|
||||
echo "missing $BACKEND_SRC" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Installing CUPS backend → $BACKEND_DST"
|
||||
TMP="$(mktemp)"
|
||||
sed "s|/Users/marchon/bin/verae-print|$BIN|g" "$BACKEND_SRC" >"$TMP"
|
||||
install -o root -g wheel -m 700 "$TMP" "$BACKEND_DST"
|
||||
rm -f "$TMP"
|
||||
|
||||
# Device discovery check
|
||||
"$BACKEND_DST" || true
|
||||
|
||||
lpstat -p "$QUEUE" &>/dev/null && lpadmin -x "$QUEUE" || true
|
||||
|
||||
# Raw queue: macOS print pipeline usually delivers PDF to the backend
|
||||
lpadmin -p "$QUEUE" \
|
||||
-E \
|
||||
-v "verae:/" \
|
||||
-D "$DISPLAY_NAME" \
|
||||
-L "Digests-only Verae timestamp" \
|
||||
-o printer-is-shared=false \
|
||||
-m raw
|
||||
|
||||
cupsenable "$QUEUE" || true
|
||||
cupsaccept "$QUEUE" || true
|
||||
|
||||
echo "Installed printer queue: $QUEUE ($DISPLAY_NAME)"
|
||||
lpstat -v "$QUEUE" || true
|
||||
echo
|
||||
echo "In any app: Print → Destination → Verae Timestamping → Print"
|
||||
echo "Outputs: ~/Documents/Verae Timestamps/{name}.pdf and {name}-verae-timestamp-{RECEIPTID}.pdf"
|
||||
38
platform/macos/ipp/com.verae.timestamping.ipp.plist
Normal file
38
platform/macos/ipp/com.verae.timestamping.ipp.plist
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>Label</key>
|
||||
<string>com.verae.timestamping.ipp</string>
|
||||
<key>ProgramArguments</key>
|
||||
<array>
|
||||
<string>/usr/bin/ippeveprinter</string>
|
||||
<string>-c</string>
|
||||
<string>/Users/SHARED_PLACEHOLDER/verae-print-command.sh</string>
|
||||
<string>-d</string>
|
||||
<string>/Users/SHARED_PLACEHOLDER/spool</string>
|
||||
<string>-f</string>
|
||||
<string>application/pdf,application/postscript</string>
|
||||
<string>-p</string>
|
||||
<string>8631</string>
|
||||
<string>-n</string>
|
||||
<string>localhost</string>
|
||||
<string>-M</string>
|
||||
<string>Verae</string>
|
||||
<string>-m</string>
|
||||
<string>Timestamping</string>
|
||||
<string>-l</string>
|
||||
<string>Digests-only timestamp</string>
|
||||
<string>--no-web-forms</string>
|
||||
<string>Verae Timestamping</string>
|
||||
</array>
|
||||
<key>RunAtLoad</key>
|
||||
<true/>
|
||||
<key>KeepAlive</key>
|
||||
<true/>
|
||||
<key>StandardOutPath</key>
|
||||
<string>/Users/SHARED_PLACEHOLDER/ippeveprinter.log</string>
|
||||
<key>StandardErrorPath</key>
|
||||
<string>/Users/SHARED_PLACEHOLDER/ippeveprinter.log</string>
|
||||
</dict>
|
||||
</plist>
|
||||
65
platform/macos/ipp/install-ipp-printer.sh
Executable file
65
platform/macos/ipp/install-ipp-printer.sh
Executable file
|
|
@ -0,0 +1,65 @@
|
|||
#!/bin/bash
|
||||
# Advertise "Verae Timestamping" via ippeveprinter (shows in Print → Destination).
|
||||
set -euo pipefail
|
||||
|
||||
ROOT="$(cd "$(dirname "$0")/../../.." && pwd)"
|
||||
BIN="${VERAE_PRINT_BIN:-$HOME/bin/verae-print}"
|
||||
SUPPORT="$HOME/Library/Application Support/Verae/ipp-printer"
|
||||
CMD="$SUPPORT/verae-print-command.sh"
|
||||
PLIST_SRC="$(cd "$(dirname "$0")" && pwd)/com.verae.timestamping.ipp.plist"
|
||||
LAUNCH_AGENTS="$HOME/Library/LaunchAgents"
|
||||
PLIST_DST="$LAUNCH_AGENTS/com.verae.timestamping.ipp.plist"
|
||||
|
||||
if [[ ! -x "$BIN" ]]; then
|
||||
mkdir -p "$(dirname "$BIN")"
|
||||
(cd "$ROOT" && go build -o "$BIN" ./cmd/verae-print)
|
||||
fi
|
||||
|
||||
mkdir -p "$SUPPORT/spool" "$LAUNCH_AGENTS"
|
||||
cp "$(cd "$(dirname "$0")" && pwd)/verae-print-command.sh" "$CMD"
|
||||
chmod 755 "$CMD"
|
||||
# Bake binary path
|
||||
sed -i '' "s|VERAE_PRINT_BIN:-\$HOME/bin/verae-print|VERAE_PRINT_BIN:-$BIN|" "$CMD" 2>/dev/null || true
|
||||
|
||||
# Materialize LaunchAgent with user paths
|
||||
sed "s|/Users/SHARED_PLACEHOLDER|$SUPPORT|g" "$PLIST_SRC" >"$PLIST_DST"
|
||||
|
||||
# Stop previous
|
||||
launchctl bootout "gui/$(id -u)/com.verae.timestamping.ipp" 2>/dev/null || true
|
||||
launchctl unload "$PLIST_DST" 2>/dev/null || true
|
||||
|
||||
# Remove broken CUPS raw/generic queue if present
|
||||
lpstat -p Verae_Timestamping &>/dev/null && lpadmin -x Verae_Timestamping || true
|
||||
# Remove unsigned custom backend if present (optional)
|
||||
if [[ -f /usr/libexec/cups/backend/verae ]]; then
|
||||
rm -f /usr/libexec/cups/backend/verae || true
|
||||
fi
|
||||
|
||||
launchctl bootstrap "gui/$(id -u)" "$PLIST_DST" 2>/dev/null \
|
||||
|| launchctl load -w "$PLIST_DST"
|
||||
|
||||
sleep 1
|
||||
# Also register explicit CUPS queue pointing at local IPP (helps some apps)
|
||||
if curl -sf -o /dev/null --max-time 2 "http://127.0.0.1:8631/" || true; then
|
||||
lpadmin -p Verae_Timestamping -E \
|
||||
-v "ipp://127.0.0.1:8631/ipp/print" \
|
||||
-D "Verae Timestamping" \
|
||||
-L "Digests-only Verae timestamp" \
|
||||
-m everywhere 2>/dev/null \
|
||||
|| lpadmin -p Verae_Timestamping -E \
|
||||
-v "ipp://localhost:8631/ipp/print" \
|
||||
-D "Verae Timestamping" \
|
||||
-m everywhere || true
|
||||
cupsenable Verae_Timestamping 2>/dev/null || true
|
||||
cupsaccept Verae_Timestamping 2>/dev/null || true
|
||||
fi
|
||||
|
||||
echo "Verae Timestamping IPP printer installed."
|
||||
echo "LaunchAgent: $PLIST_DST"
|
||||
echo "Command: $CMD"
|
||||
echo "Check: lpstat -p -d ; lpstat -v"
|
||||
lpstat -p Verae_Timestamping 2>/dev/null || true
|
||||
lpstat -v Verae_Timestamping 2>/dev/null || true
|
||||
echo
|
||||
echo "Print → Destination → Verae Timestamping"
|
||||
echo "Saves to ~/Documents/Verae Timestamps/"
|
||||
55
platform/macos/ipp/verae-print-command.sh
Executable file
55
platform/macos/ipp/verae-print-command.sh
Executable file
|
|
@ -0,0 +1,55 @@
|
|||
#!/bin/bash
|
||||
# ippeveprinter -c handler: PDF (or PS) on stdin → Verae stamp with approved naming.
|
||||
set -euo pipefail
|
||||
|
||||
LOG="${HOME}/Library/Logs/verae-print-ipp.log"
|
||||
mkdir -p "$(dirname "$LOG")"
|
||||
exec >>"$LOG" 2>&1
|
||||
echo "$(date -u +%Y-%m-%dT%H:%MZ) IPP job start env=$(env | grep -E '^IPP_|^CONTENT_|^USER=' | tr '\n' ' ')"
|
||||
|
||||
VERAE_PRINT="${VERAE_PRINT_BIN:-$HOME/bin/verae-print}"
|
||||
CHANNEL="${VERAE_PRINT_CHANNEL:-verae}"
|
||||
OUT_DIR="${HOME}/Documents/Verae Timestamps"
|
||||
mkdir -p "$OUT_DIR"
|
||||
|
||||
TITLE="${IPP_JOB_NAME:-${IPP_DOCUMENT_NAME:-document}}"
|
||||
# Strip path / extension for stem
|
||||
BASE="$(basename "$TITLE")"
|
||||
STEM="${BASE%.*}"
|
||||
STEM="$(echo "$STEM" | tr -cd 'A-Za-z0-9._ -' | head -c 80)"
|
||||
STEM="${STEM:-document}"
|
||||
|
||||
TMPDIR="${TMPDIR:-/tmp}"
|
||||
WORK="$(mktemp -d "${TMPDIR}/verae-ipp.XXXXXX")"
|
||||
RAW="$WORK/job.bin"
|
||||
PDF="$WORK/${STEM}.pdf"
|
||||
|
||||
# ippeveprinter may pass a spool file as argv[1], or feed bytes on stdin
|
||||
if [[ $# -ge 1 && -f "${1:-}" ]]; then
|
||||
echo "input file arg: $1"
|
||||
cp "$1" "$RAW"
|
||||
elif [[ ! -t 0 ]]; then
|
||||
cat >"$RAW"
|
||||
else
|
||||
echo "ERROR: no document on stdin or argv" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ ! -s "$RAW" ]]; then
|
||||
echo "ERROR: empty document" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ "$(head -c 4 "$RAW")" == "%PDF" ]]; then
|
||||
cp "$RAW" "$PDF"
|
||||
elif command -v /usr/bin/pstopdf >/dev/null 2>&1; then
|
||||
/usr/bin/pstopdf "$RAW" -o "$PDF" || cp "$RAW" "$PDF"
|
||||
else
|
||||
cp "$RAW" "$PDF"
|
||||
fi
|
||||
|
||||
echo "stamping stem=$STEM channel=$CHANNEL pdf=$PDF"
|
||||
"$VERAE_PRINT" stamp -channel "$CHANNEL" -out-dir "$OUT_DIR" -name "$STEM" -open "$PDF"
|
||||
echo "ATTR: job-impressions-completed=1" >&2
|
||||
rm -rf "$WORK"
|
||||
exit 0
|
||||
Loading…
Reference in a new issue