At first glance, the feature sounds simple: let users open a password database from a URL instead of a local file path.
In reality, that request cuts straight through the heart of an application that has assumed for two decades that every database lives on a local filesystem.
pwsafe’s core logic is deliberately conservative. It opens files through two well-defined entry points — effectively ‘open’ and ‘close’. Everything else in the application builds on top of that assumption. There is no concept of ‘network storage’ anywhere in the core.
That constraint became the design opportunity.
Rather than rewriting large parts of the codebase to understand WebDAV, I asked a different question: what if the application never needed to know it was talking to a server at all?
The solution was to intercept those two file entry points and insert a transport layer underneath them. If the path looks like a normal file, nothing changes. If it looks like a URL, the transport layer quietly downloads the file to a secure local cache, hands it to the application as if it were local, and later uploads it back to the server when the user saves.
From the point of view of the rest of the codebase, nothing happened. It still thinks it opened a file on disk.
To make this extensible, the transport layer loads plugins dynamically. WebDAV is just one plugin — implemented as a separate shared library. In theory, someone could write an S3 or SFTP plugin later without touching the main application at all.
That architectural decision — keep the core untouched, push complexity to the edges — made the change feasible. It also made it safer. The cryptography layer, the database model, and the UI logic remain exactly as they were.
Downloading and uploading a file is the easy part. The hard part is correctness.
Password Safe already has a locking model to prevent two processes from editing the same file at once. On a local filesystem, that’s straightforward. On a WebDAV server, it involves explicit LOCK and UNLOCK operations over HTTP.
And there was a deeper problem: parts of the application can trigger unlock operations during shutdown, inside destructors, or even in signal handlers. The networking library used for WebDAV (libcurl) is not safe to call from those contexts.
If the application crashed at the wrong moment, the server-side lock could remain held. The next time anyone tried to open the database, they would get a ‘423 Locked’ error. Not a great user experience.
The solution was counterintuitive: don’t handle locks in the main process at all.
Instead, the first time a lock is acquired, the application forks a small child process — a dedicated ‘lock daemon’. That child process owns the WebDAV lock token and is responsible for all lock, unlock, and store operations. The parent process communicates with it over a tiny binary protocol through a Unix socket.
If the main application exits cleanly, the daemon unlocks everything and shuts down. If the application crashes or is killed, the operating system closes the socket automatically. The daemon detects this and releases the server lock before exiting.
In other words, correctness is enforced by process boundaries and the kernel itself, not by hoping every code path behaves perfectly.
One of the quiet goals of this architecture was to make the final user experience boring.
The feature now appears as ‘File → Open URL…’. You paste https://…/mydb.psafe3, enter your password, and work as usual. No special mount points. No fragile login-time scripts. No hidden server-side .plk files. Just a URL.
Behind that simplicity sits a plugin loader, a local encrypted cache, a lock registry, a forked daemon process, and a hardened IPC protocol. But the user never sees any of it.
That contrast — simple surface, careful machinery underneath — is what made the project satisfying. And it’s also where AI collaboration became unexpectedly powerful.