ipx user rename: give an account the name the proxy signs it in as

An account made by hand before the proxy was set up is called what it was
given ('rays'), while Cloudflare Access vouches for an email address. With
auto_create_users on, the first visit through the tunnel would make a
second, empty account. Renaming keeps the id, so feeds, read state and
admin rights go with it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TAC7sLVqfKmY6rsTLXzNgk
This commit is contained in:
2026-09-12 13:54:29 +00:00
parent 2ba83c3aed
commit 586d2c07a1
3 changed files with 44 additions and 0 deletions

View File

@@ -1069,6 +1069,15 @@ impl Db {
Ok(())
}
/// The proxy signs people in by the name it vouches for, so an account made before the proxy
/// was set up has to take that name to be found by it. The name is UNIQUE, so a taken one is
/// refused here as well as by the caller.
pub fn rename_user(&self, id: i64, name: &str) -> Result<()> {
let conn = self.conn.lock().unwrap();
conn.execute("UPDATE users SET name = ?2 WHERE id = ?1", params![id, name])?;
Ok(())
}
/// Records a sign-in, to the hour: the proxy vouches for every request, and writing each one
/// would buy nothing.
pub fn signed_in(&self, id: i64) -> Result<()> {
@@ -1571,6 +1580,20 @@ mod tests {
assert_eq!(kept, 1);
}
#[test]
fn a_renamed_account_keeps_everything_but_its_name() {
let db = Db::memory().unwrap();
let ray = db.create_user("rays", None, true).unwrap();
db.create_user("sam", None, false).unwrap();
db.subscribe(ray, "f").unwrap();
db.rename_user(ray, "rays@sdf1.net").unwrap();
assert!(db.user_by_name("rays").unwrap().is_none());
let renamed = db.user_by_name("RAYS@sdf1.net").unwrap().unwrap();
assert_eq!((renamed.id, renamed.is_admin), (ray, true), "same account, still the admin");
assert_eq!(db.subscriptions_for(ray).unwrap().len(), 1, "and still subscribed");
assert!(db.rename_user(ray, "sam").is_err(), "a taken name is refused");
}
#[test]
fn an_account_knows_when_it_was_made_and_last_signed_in() {
let db = Db::memory().unwrap();