Save the installer choice as shareReceiptsSMB, recreate the share when it is missing, and show the live smb:// address on the receipts page. Co-authored-by: George Lambert <marchon@gmail.com>
20 KiB
Verae network timestamp printer
Optional IPP Everywhere printer. Phones and other computers on the LAN print to it. The default name is Verae Timestamp plus this computer's name, for example Verae Timestamp (Georges-MacBook-Pro). Settings can change it. A saved name that is still the old shared Verae Timestamp is upgraded on the next start. If that name is already registered on the network, mDNS renames it to Name (2) and the new name is saved. This machine hashes the document, registers the SHA-256 with Verae the same way the desktop drivers do, and keeps the receipt. Document bytes are not uploaded.
The printer is off until you install the standalone package or turn on the driver installer option. Both paths install one service and one tray / menu-bar control. They do not share an install folder: the standalone package never overwrites the driver binary. If both are installed, the service runs whichever binary is the same version or newer, and removing one leaves the other in place.
| Windows | macOS | Debian / Ubuntu | |
|---|---|---|---|
| Standalone installer | VeraeNetPrint-windows-*-setup.exe |
VeraeNetPrint-macos-arm64-0.3.4.pkg |
verae-netprint_*_amd64.deb |
| Driver installer option | Unchecked checkbox on the options page | Customize → “Network timestamp printer” (unselected) | debconf “Enable the Verae network timestamp printer?” (default no), or apt install verae-netprint |
| Service | VeraeNetPrint |
LaunchDaemon com.verae.netprint |
verae-netprint.service |
| Tray / menu bar | verae-netprint-tray.exe (notification area) |
LaunchAgent com.verae.netprint.tray (/Applications/Verae NetPrint.app, Aqua session) |
verae-print tray (StatusNotifier / AppIndicator) |
| Standalone command | %ProgramFiles%\Verae\NetPrint\bin\verae-print.exe |
/Library/Application Support/Verae/NetPrint/bin/verae-print |
/usr/lib/verae-netprint/verae-print |
| Driver command | %ProgramFiles%\Verae\PrintStamp\bin\verae-print.exe |
/Library/Application Support/Verae/PrintStamp/bin/verae-print |
/usr/lib/verae-print/verae-print |
CLI on PATH |
the driver binary when the driver is installed | /usr/local/bin/verae-print points at the driver when it is installed, otherwise at NetPrint |
/usr/bin/verae-print points at the driver when it is installed, otherwise at NetPrint |
| Config | %ProgramData%\Verae\PrintStamp\netprint.json |
/Library/Application Support/Verae/PrintStamp/netprint.json |
/etc/verae/netprint.json |
| Receipts | %ProgramData%\Verae\NetPrint |
/Users/Shared/Verae Receipts |
/var/lib/verae-netprint |
The desktop driver's loopback helper stays on 127.0.0.1:8631. The network printer does not use that port.
Try it
- Install using either path above. The Windows setup starts the tray for the logged-in user at the end of install (not elevated), and again at the next login. macOS and Linux start the menu bar at the next login.
- Open Settings from the icon and paste the same
xVerae-signing key the drivers use (or sign in first withverae-print setupon that machine). The service stores the key; the tray does not edit config files. - On another device, add the printer. Its default name includes the computer, for example Verae Timestamp (Georges-MacBook-Pro). It is advertised with DNS-SD (
_ipp._tcp, plus the AirPrint_universaland IPP Everywhere_printsubtypes) and AirPrint text records. On macOS, Advertise on the network (on by default) callsDNSServiceRegisterwith regtype_ipp._tcp,_universal,_printandkDNSServiceFlagsNoAutoRename. mDNSResponder publishes the subtype PTRs aimed at<name>._ipp._tcp.local, which is whatdns-sd -B _ipp._tcp,_universalanddns-sd -B _ipp._tcp,_printaccept. A second registration advertises_verae._tcp. The host argument is empty so mDNSResponder uses this Mac's hostname and addresses. The UDP 5353 socket stays closed while that registration is up, so the printer is not listed twice. If the name is already in use, the callback reports the conflict and both services are registered again as Name (2). That name is saved and becomes the IPP printer name. IfDNSServiceRegisterfails for another reason, the socket advertises the full set instead. On Windows 10 and laterDnsServiceRegisterpublishes only<name>._ipp._tcp.local, including its SRV, TXT, and address records. It cannot publish a subtype PTR that points at that name, so the service also opens a shared UDP 5353 socket (SO_REUSEADDR, joined to224.0.0.251andff02::fb) that answers only_universal._sub._ipp._tcpand_print._sub._ipp._tcp. Those PTRs point at<name>._ipp._tcp.local. The UDP socket does not answer the base_ipp._tcpPTR and does not send SRV, TXT, or address records, so the two stacks do not advertise two copies of the printer. IfDnsServiceRegisterfails, the UDP socket advertises the full set instead.dns-sd -B _ipp._tcpanddns-sd -B _ipp._tcp,_universaleach list the printer once. On macOS, cupsd keeps127.0.0.1:631and[::1]:631. This printer binds 631 only on the Mac's non-loopback addresses, so printing from another device uses port 631 and localhost CUPS is unchanged. mDNS advertises 631. If none of those LAN binds succeed, it listens on 8632 on every interface and advertises 8632. Status JSONippBindislanorall, andportis the port that was bound. On Windows and Linux the listener is IPv4 plus[::]withIPV6_V6ONLY, trying 631 and falling back to 8632 when 631 is taken. It does not use 8631. A connect to the host's link-local IPv6 address completes; our own A/AAAA records omit fe80 and 169.254. Get-Printer-Attributes includesmedia-col-defaultfor US Letter and A4 anddocument-format-supportedlists the same formats as the TXTpdlrecord: PDF, Apple Raster, PWG Raster, and JPEG. - Print a PDF. Open Receipts from the tray, or browse to
http://<lan-address>:<port>/receipts(the AirPrint admin URL). The page lists recent jobs, newest first, with the stamped PDF and the original. Each job also has a verify link onhttps://explorer.verae.ai/time.
The icon shows running or stopped, the printer name, a LAN address and port, how many jobs arrived today, whether discovery is advertising, and the receipts URL. It can start, stop, and restart the service, turn launch-at-login on or off for the service and for the icon, turn Email stamped PDFs on or off, open recent receipts, and open settings (printer name, forward-to printer, signing key, mail, and the receipts PIN). On Windows it can also allow Public networks. When the active network is Public and that option is off, the menu says other devices cannot reach the printer.
Settings and the tray can mail each completed job. The message subject is Verae timestamp: <job title>. The body contains the receipt ID, the SHA-256, and the .verae.json receipt summary. The certificate PDF and the original document are attached. The default recipient is marchon@gmail.com, and the default server is smtp.gmail.com port 587 with STARTTLS. A Gmail app password works: the username is the Gmail address and the password is the 16-character app password. Mail stays off until the toggle is on and a password is saved. A failure is written to the log and to emailError in the status JSON, then retried in the background. It does not fail the print.
The SMTP password and the optional receipts PIN are not stored in netprint.json. On Windows they are sealed with DPAPI for the service account. On macOS and Linux they are in netprint-secrets.bin next to the config, mode 0600. Neither value is written to the log.
Receipts on the phone
http://<host>:<port>/receipts is served on the same port as IPP, so the existing Private and Domain firewall rules cover it. Public networks stay blocked unless that option is on. An optional PIN (or ?access= token) can be required on the LAN. The loopback control page does not ask for the PIN. The menu bar Open Receipts… item opens the live receiptsUrl from status (for example http://192.168.1.108:631/receipts or http://<hostname>.local:631/receipts), not a fixed address. Open Settings… opens the control page. The menu also shows how to print from an iPhone: Share → Print → Select Printer → the advertised printer name. The status JSON fields are receiptsUrl and receiptsDir. On macOS receiptsDir is /Users/Shared/Verae Receipts. That folder holds the job files and is readable by the console user. The macOS installer Customize pane has Share receipts folder over the network (SMB), off unless you check it. When checked, postinstall shares that folder as Verae Receipts (sharing -a with -s 001 -g 000: SMB only, guest off) and enables com.apple.smbd so File Sharing stays on across reboots. The choice is saved as shareReceiptsSMB in netprint.json. Settings and the menu bar can turn it on or off later. If the choice is on and the share is missing, the daemon recreates it at startup, and the menu-bar app asks it to again at login. Status JSON includes shareReceiptsSMB and smbUrl (for example smb://Georges-MacBook-Pro.local/Verae%20Receipts). The receipts page shows that address. The first connection from iPhone Files needs a username and password from this Mac. Guest access is off. The Windows installers have the same checkbox, off unless you check it or pass /SMB=1, and create a read-only share named Verae Receipts. The program stays in /Library/Application Support/Verae/NetPrint/bin and is not in that folder. An older install that stored jobs next to the program moves those job files on the next start. The page links to the iPhone shortcut and shows a QR code for http://<host>:<port>/ios-shortcut.
Stamp and return
POST http://<host>:<port>/api/stamp accepts a PDF or JPEG, either as the raw body (set X-Filename or Content-Disposition for the title) or as multipart with a file field. It runs the same pipeline as Print-Job, including the same stampWithClient call the desktop driver uses (job.Run against the Verae client, with the document title as the file name). The job is stored, it shows on the receipts page, and it is emailed when email is on. The response is the stamped certificate PDF. Headers X-Verae-Receipt-Id, X-Verae-SHA256, and X-Verae-Receipt-JSON identify the receipt. ?format=zip returns original.pdf, certificate.pdf, and receipt.json. A receipt id beginning with mock-cert is refused, so a test double is not returned outside test builds. The same Private and Domain rule and the same PIN apply. Send the PIN as ?access=, the X-Verae-Access header, or Authorization: Bearer. A failure does not return a PDF.
The server also advertises _verae._tcp (PTR, SRV, and TXT path=/api/stamp) beside the IPP printer. That record is a different service name, so it does not add a second _ipp._tcp advertisement. While Windows DNS-SD owns the printer, the shared UDP socket still answers only the AirPrint subtype PTRs for _ipp._tcp and does not add IPP SRV, TXT, or address records. The _verae._tcp SRV and TXT go out on that socket because DNS-SD does not register that name. Address records stay with the printer advertisement.
The Share sheet steps are in docs/ios-shortcut/README.md. A signed .shortcut file is not in this tree: signing needs the Shortcuts app on a Mac or iPhone. The design for a native share extension in the Verae Timestamping iOS app (com.flightlookup.verae-timestamping) is docs/ios-shortcut/share-extension.md.
Forward-to is optional: a local queue name, or an ipp:// URI. A failed forward does not fail the timestamp.
Firewall
The Windows installers add inbound rules named Verae NetPrint IPP (TCP 631), Verae NetPrint IPP Fallback (TCP 8632), and Verae NetPrint mDNS (UDP 5353) on the private and domain profiles. Each rule sets remoteip=any, which includes IPv4, global IPv6, and link-local fe80::/10. A checkbox, off by default, also allows Public networks. A silent install can pass /PUBLIC=1. The tray has the same switch. The rules are removed when the last NetPrint product is uninstalled. Port 8631 is not opened; that is the driver helper on loopback.
An optional checkbox (silent /QUEUE=1) adds a local Windows printer named Verae Timestamp aimed at http://127.0.0.1:<bound-port>/ipp/print. It is removed when the last NetPrint product is uninstalled. The driver printer Verae TimeStamp PDF is a different queue.
On Debian and Ubuntu, postinst opens the same three ports with ufw when ufw is installed and already active. The rules are removed when the last package is removed.
On macOS, the Application Firewall is per application (System Settings → Network → Firewall). Install runs /usr/libexec/ApplicationFirewall/socketfilterfw --add and --unblockapp on the service binary when that tool is present. If other devices still cannot connect, allow verae-print in that pane. The first time the service advertises or accepts a LAN connection, macOS asks once for Local Network permission for verae-print. Allow it. The menu-bar app may ask as well; allow that too.
macOS package
The Apple Silicon installer is VeraeNetPrint-macos-arm64-0.3.4.pkg. GitHub Actions builds it on a macos-14 runner with pkgbuild and productbuild, then runs pkgutil --expand, pkgutil --check-signature, and installer -pkginfo. It installs:
/Library/Application Support/Verae/NetPrint/bin/verae-print(the arm64 daemon binary)/Applications/Verae NetPrint.app(the menu-bar app:Contents/Info.plistwith bundle idai.verae.netprint,LSUIElement, andNSLocalNetworkUsageDescription;Contents/MacOS/verae-print,Contents/MacOS/verae-menubar, andContents/MacOS/verae-airdrop)- LaunchDaemon
com.verae.netprint(root, the print server, the binary under Application Support) - LaunchAgent
com.verae.netprint.trayin/Library/LaunchAgents, limited to the Aqua session, running/Applications/Verae NetPrint.app/Contents/MacOS/verae-print trayas the logged-in user
Receipts and job files go to /Users/Shared/Verae Receipts, not next to those binaries. The package from CI is not signed and not notarized. macOS blocks a normal double-click until the package is signed with a Developer ID Installer certificate and notarized. To install this unsigned package, right-click it in Finder and choose Open, then Open again. Or, in Terminal:
sudo installer -pkg VeraeNetPrint-macos-arm64-0.3.4.pkg -target /
postinstall checks that verae-print, verae-airdrop, and verae-menubar are in the app, then runs verae-print netprint install --owner standalone, which bootstraps the daemon into system and the menu-bar agent into the console user's gui domain. The agent is not the root daemon. AirDrop runs there.
verae-print tray loads AppKit and stays in NSApplication run on the main thread. If that run returns without Quit, or the status item cannot be created, it logs the reason to ~/Library/Logs/Verae/netprint-tray.log and execs verae-menubar in the same app (a small AppKit status item with status, Start, Stop, Open Receipts…, Open Settings…, Share receipts folder over SMB, and AirDrop again). A failure exits 1. It does not exit 0 when the menu bar cannot stay up. verae-print tray --smoke prints smoke ok or no window server and does not enter the run loop. Customize on the installer shows Share receipts folder over the network (SMB), unselected unless you check it. That choice is saved as shareReceiptsSMB. The first connection from iPhone Files needs a username and password from this Mac.
AirDrop on the Mac
Settings and the menu bar have AirDrop stamped PDF after each job. It is off until you turn it on. When a job completes, the daemon records it and tells the menu-bar app on GET http://127.0.0.1:8630/api/v1/events (an event stream on the loopback control API). The agent downloads the certificate and the receipt JSON through that API and opens the AirDrop share sheet with both files, using NSSharingService(named: .sendViaAirDrop). A notification shows the receipt ID and an AirDrop again action. The same action is on the menu. The root daemon never opens the sheet.
platform/macos/airdrop/main.swift is that share sheet as verae-airdrop. The macOS package build compiles it with swiftc and installs it inside Verae NetPrint.app, next to the tray executable. The menu-bar app launches that helper. macOS asks for notification permission the first time the agent posts AirDrop again. UNUserNotificationCenter is used only when the process is that app bundle (bundleIdentifier set and the bundle path ends in .app). A bare binary skips the call instead of crashing, because currentNotificationCenter throws when mainBundle is a directory.
The control API listens only on 127.0.0.1:8630. The receipts page is on the IPP port, not on the control port, and it stays on Private and Domain networks with the rest of the printer.
A silent Windows install (/S) does not wait on a dialog. Upgrades stop VeraeNetPrint, wait until it is stopped, and close verae-netprint-tray.exe before replacing those files. If a file is still locked, setup logs the error to %ProgramData%\Verae\logs\netprint-installer.log and exits with a failure instead of leaving the old binary in place. The service is started again after the new files are in place. verae-print netprint install starts the tray once, through Explorer (via a one-shot scheduled task when an interactive user is available). A second copy exits immediately on the Local\VeraeNetPrintTray mutex. The tray is not a Task Scheduler job and not a child of setup, so Start-Process -Wait returns and the icon stays up. Tray startup, mutex, and message-loop errors are appended to netprint.log. An unknown netprint subcommand does not start a second server. The service appends startup, mDNS, and job lines to %ProgramData%\Verae\logs\netprint.log and flushes each line, including when the process has no console. Job numbers continue from %ProgramData%\Verae\NetPrint\next-job and from existing job-N folders, so a restart does not write a new document into an old folder. http://127.0.0.1:8630/api/v1/status includes mdnsAdvertising, mdnsMode, mdnsDetail, mdnsError, receiptsUrl, receiptsDir, ippBind, emailEnabled, emailTo, emailError, smtpHost, smtpUser, smtpPasswordSet, receiptsPinSet, shareReceiptsSMB, and smbUrl. It does not include the SMTP password or the receipts PIN.
macOS upgrades run launchctl bootout on com.verae.netprint before the package copies the binary. Debian upgrades run systemctl stop verae-netprint from preinst when the unit is running that package's binary.
Troubleshooting
- The icon says stopped. Start it from the menu. On Linux,
systemctl status verae-netprint. On Windows,sc query VeraeNetPrint. On macOS,sudo launchctl print system/com.verae.netprint. - Other devices do not see it. Open
http://127.0.0.1:8630/api/v1/statusand readmdnsMode/mdnsError, and%ProgramData%\Verae\logs\netprint.logon Windows.mdnsModedns-sdmeans Windows DNS-SD accepted the printer. Confirm the host has a LAN address and the network is Private, or turn on Allow Public networks. On a Mac, CUPS keeps localhost port 631. This printer uses 631 on the LAN addresses (ippBindlan) or 8632 when that bind does not succeed (ippBindall,port8632). It does not fall back to 8631. Receipt files are inreceiptsDir. - Windows setup seemed to hang with
/S. Every installer dialog has a silent default. Read%ProgramData%\Verae\logs\netprint-installer.log. - Jobs fail with an authentication error. Open Settings and save a current
xVerae-key. The service reads the machine token (/etc/verae/xverae-token, the macOS Application Support file, or%ProgramData%\Verae\PrintStamp\xverae-token) and the usual per-user token. - Raster jobs (AirPrint
image/urf, Linuximage/pwg-raster) andimage/jpegare converted to PDF on this machine before they are hashed. PDF is accepted as-is.
Commands:
verae-print netprint # foreground, for debugging
verae-print netprint install --owner driver --allow-public=false
verae-print netprint install --owner standalone --allow-public=true --local-queue
verae-print netprint launch-tray # Windows: tray as the logged-in user
verae-print netprint uninstall --owner driver
verae-print tray