See parent: pwsafe | See also: transport plugin architecture | Branch: webdav
Design for WebDAV read/write support. The user passes a WebDAV URL instead of a local file path. Credentials are read from ~/.netrc (libcurl native support via CURLOPT_NETRC). No changes are needed to the crypto, record-parsing, or UI layers.
Note on scope: This note describes the WebDAV-specific concerns (Part 2 — the plugin). The dispatch layer, plugin interface, cache management, and offline fallback that sit beneath it (Part 1) are described in transport plugin architecture. The "Layer Intercept Point" section below predates that design and is retained for context, but the transport note is now authoritative for Part 1.
The fundamental design decision: the local cache copy is the working file. The WebDAV store is treated as the authoritative remote, but the application operates entirely against a local cached copy.
Cache location: ~/.pwsafe/cache/<sha256_of_url>.psafe3 (deterministic path derived from the URL, so the same URL always maps to the same cache file). Managed by the transport dispatch layer, not the plugin.
On open:
1. GET the file from WebDAV into the local cache path (overwriting any previous cache). 2. If the GET fails (server unreachable, network down): warn the user and offer to open the local cache if it exists — the session continues in offline mode. 3. Open the cache file as a normal local file. Everything above this layer is unchanged.
On save:
1. Write to the local cache file (normal pwsafe save path, unchanged). 2. PUT the cache file to the WebDAV URL. 3. If the PUT fails: warn the user. The local cache is still saved and consistent. The user can retry or copy manually later.
Backups (incremental .ibak files) are taken against the local cache path, exactly as for a local database. No changes needed to BackupCurFile().
Offline-only use: If WebDAV is never available, the user can work entirely from the local cache, then copy it to the WebDAV store by other means (e.g., a WebDAV client, rclone) at any time.
*(Predates the transport plugin design — see transport for the current authoritative design of this layer.)*
All file I/O funnels through pws_os::FOpen / pws_os::FClose / pws_os::FileExists / pws_os::LockFile. These are intercepted by the transport dispatch layer; the WebDAV plugin never sees a FILE* directly — it only handles URLs and local paths. Everything else — PWSfileV3, PWSfileV4, PWScore, all crypto — is unchanged.
On open, send an HTTP OPTIONS request and inspect the response:
• DAV: 2 in response headers — server supports WebDAV Class 2 (RFC 4918), which mandates LOCK/UNLOCK. Use it.
• Allow: LOCK also works as a fallback indicator.
• If neither present: warn the user once ("WebDAV server does not support locking; concurrent access is not protected") and continue without locking. Result cached per-host for the session.
When locking is available: send LOCK (exclusive, write) before GET; send UNLOCK after PUT or on close without save. Store the lock token from the server's Lock-Token response header. Honour the lock timeout — refresh if the session is long.
The WebDAV plugin registers for schemes http and https. URL detection ("does this path start with a known scheme?") is handled by the transport dispatch layer. The rest of the codebase passes m_currfile through unchanged — no structural changes to PWScore or the UI are needed.
libcurl reads ~/.netrc automatically when CURLOPT_NETRC is set to CURL_NETRC_OPTIONAL. No credential management code is needed in pwsafe itself. The user populates ~/.netrc with the WebDAV server hostname, login, and password in the standard format.
• GET fails, no cache: fatal error — cannot open database • GET fails, cache exists: warn + offer offline mode • PUT fails after save: warn user; local cache is consistent; no data loss • LOCK fails (network): treat as if server doesn't support locking — warn, continue • UNLOCK fails: log, do not block close
With the transport architecture, the WebDAV plugin is a standalone pwsafe-transport-webdav.so (~300 lines) implementing the PWSTransport interface:
• fetch — libcurl GET to local path
• store — libcurl PUT from local path
• exists — libcurl HEAD
• lock / unlock — libcurl LOCK/UNLOCK (after OPTIONS probe)
• pws_plugin_init — registers for http and https schemes
The plugin links libcurl. The main pwsafe binary has no libcurl dependency.