summaryrefslogtreecommitdiff
path: root/src/vapid/app.rs
diff options
context:
space:
mode:
authorOwen Jacobson <owen@grimoire.ca>2025-08-30 02:59:51 -0400
committerOwen Jacobson <owen@grimoire.ca>2025-08-30 02:59:51 -0400
commit96b62f1018641b3dc28cc189d314a1bff475b751 (patch)
tree1e10b660f2c68cb73d3c17703257ec0be51c36af /src/vapid/app.rs
parent3bd63e20777126216777b392615dc8144f21bb9a (diff)
Allow administrators to rotate VAPID keys immediately if needed.
In spite of my design preference away from CLI tools, this is a CLI tool: `pilcrow --database-url <URL> rotate-vapid-key`. This is something we can implement here and now, which does not require us to confront the long-avoided issue of how to handle the idea that some users are allowed to make server-operational changes and some aren't, by delegating the problem back to the OS. The implementation is a little half-baked to make it easier to rip out later. I would ordinarily prefer to push both `serve` (the default verb, not actually named in this change) and `rotate-vapid-key` into their own, separate CLI submodules, with their own argument structs, but that change is much more intrusive and would make this effectively permanent. This can be yanked out in a few minutes by deleting a few lines of `cli.rs` and inlining the `serve` function. Nonetheless, nothing is as permanent as a temporary solution, so I've written at least some bare-minimum operations documentation on how to use this and what it does.
Diffstat (limited to 'src/vapid/app.rs')
-rw-r--r--src/vapid/app.rs17
1 files changed, 16 insertions, 1 deletions
diff --git a/src/vapid/app.rs b/src/vapid/app.rs
index 8886c9f..ddb1f4d 100644
--- a/src/vapid/app.rs
+++ b/src/vapid/app.rs
@@ -1,4 +1,4 @@
-use chrono::TimeDelta;
+use chrono::{TimeDelta, Utc};
use sqlx::SqlitePool;
use super::{History, repo, repo::Provider as _};
@@ -18,6 +18,21 @@ impl<'a> Vapid<'a> {
Self { db, events }
}
+ pub async fn rotate_key(&self, rotate_at: &DateTime) -> Result<(), sqlx::Error> {
+ let mut tx = self.db.begin().await?;
+ // This is called from a separate CLI utility (see `cli.rs`), and we _can't_ deliver events
+ // to active clients from another process, so don't do anything that would require us to
+ // send events, like generating a new key.
+ //
+ // Instead, the server's next `refresh_key` call will generate a key and notify clients
+ // of the change. All we have to do is remove the existing key, so that the server can know
+ // to do so.
+ tx.vapid().clear().await?;
+ tx.commit().await?;
+
+ Ok(())
+ }
+
pub async fn refresh_key(&self, ensure_at: &DateTime) -> Result<(), Error> {
let mut tx = self.db.begin().await?;
let key = tx.vapid().current().await.optional()?;