Add db migration and further origin-overwrite rectifications. (6bed0d38f) (#313)

Signed-off-by: Jason Volk <jason@zemos.net>
This commit is contained in:
Jason Volk
2026-03-03 01:02:34 +00:00
parent d00cfcb85a
commit 59791db213
3 changed files with 75 additions and 13 deletions

View File

@@ -34,7 +34,7 @@ use tuwunel_service::{
oauth::{
CODE_VERIFIER_LENGTH, Provider, SESSION_ID_LENGTH, Session, UserInfo, unique_id_sub,
},
users::Register,
users::{PASSWORD_SENTINEL, Register},
};
use url::Url;
@@ -480,7 +480,7 @@ async fn register_user(
.users
.full_register(Register {
user_id: Some(user_id),
password: Some("*"),
password: Some(PASSWORD_SENTINEL),
origin: Some("sso"),
displayname: userinfo.name.as_deref(),
grant_first_user_admin: true,

View File

@@ -9,10 +9,11 @@ use ruma::{
push::Ruleset,
};
use tuwunel_core::{
Err, Result, debug, debug_info, debug_warn, error, info,
Err, Result, debug, debug_info, debug_warn, err, error, info,
itertools::Itertools,
matrix::PduCount,
result::NotFound,
utils,
utils::{
IterStream, ReadyExt,
stream::{TryExpect, TryIgnore},
@@ -66,6 +67,7 @@ async fn fresh(services: &Services) -> Result {
db["global"].insert(b"retroactively_fix_bad_data_from_roomuserid_joined", []);
db["global"].insert(b"fix_referencedevents_missing_sep", []);
db["global"].insert(b"fix_readreceiptid_readreceipt_duplicates", []);
db["global"].insert(b"fix_hashed_sentinel_passwords", []);
// Create the admin room and server user on first run
if services.config.create_admin_room {
@@ -145,6 +147,14 @@ async fn migrate(services: &Services) -> Result {
fix_readreceiptid_readreceipt_duplicates(services).await?;
}
if db["global"]
.get(b"fix_hashed_sentinel_passwords")
.await
.is_not_found()
{
fix_hashed_sentinel_passwords(services).await?;
}
if services.globals.db.database_version().await < 17 {
services.globals.db.bump_database_version(17);
info!("Migration: Bumped database version to 17");
@@ -582,3 +592,52 @@ async fn fix_readreceiptid_readreceipt_duplicates(services: &Services) -> Result
db["global"].insert(b"fix_readreceiptid_readreceipt_duplicates", []);
db.engine.sort()
}
async fn fix_hashed_sentinel_passwords(services: &Services) -> Result {
use tuwunel_core::utils::hash::verify_password;
const PASSWORD_SENTINEL: &str = "*";
let db = &services.db;
let cork = db.cork_and_sync();
let userid_password = db["userid_password"].clone();
let hashed_sentinel = utils::hash::password(PASSWORD_SENTINEL).map_err(|e| {
err!("Could not apply migration: failed to hash sentinel password: {e:?}")
})?;
warn!(
"Fixing occurrences of password-hash {hashed_sentinel:?} generated from \
{PASSWORD_SENTINEL:?}"
);
let (checked, good, bad) = userid_password
.stream()
.expect_ok()
.ready_fold(
(0, 0, 0),
|(mut checked, mut good, mut bad): (usize, usize, usize),
(key, val): (&str, &str)| {
let good_sentinel = val == PASSWORD_SENTINEL;
let bad_sentinel = !val.is_empty()
&& !good_sentinel
&& verify_password(PASSWORD_SENTINEL, val).is_ok();
checked = checked.saturating_add(usize::from(true));
good = good.saturating_add(usize::from(good_sentinel));
bad = bad.saturating_add(usize::from(bad_sentinel));
if bad_sentinel {
userid_password.insert(key, PASSWORD_SENTINEL);
}
(checked, good, bad)
},
)
.await;
drop(cork);
info!(?checked, ?good, ?bad, "Fixed any occurrences of hashed sentinel passwords");
db["global"].insert(b"fix_hashed_sentinel_passwords", []);
db.engine.sort()
}

View File

@@ -24,6 +24,9 @@ use tuwunel_database::{Deserialized, Json, Map};
pub use self::{keys::parse_master_key, register::Register};
pub const PASSWORD_SENTINEL: &str = "*";
pub const PASSWORD_DISABLED: &str = "";
pub struct Service {
services: Arc<crate::services::OnceServices>,
db: Data,
@@ -222,10 +225,7 @@ impl Service {
// exception is made for that origin in the condition below. Note that users
// with no origin are also password-origin users.
let allowed_origins = ["password", "sso"];
if let Some(password) = password
&& password != "*"
{
if password.is_some() && password != Some(PASSWORD_SENTINEL) {
let origin = self.origin(user_id).await;
let origin = origin.as_deref().unwrap_or("password");
@@ -236,17 +236,20 @@ impl Service {
}
}
let is_sentinel = password.is_some_and(|p| p == "*");
match password.map(utils::hash::password) {
| None => {
self.db.userid_password.insert(user_id, b"");
self.db
.userid_password
.insert(user_id, PASSWORD_DISABLED);
},
| Some(Ok(_)) if password == Some(PASSWORD_SENTINEL) => {
self.db
.userid_password
.insert(user_id, PASSWORD_SENTINEL);
},
| Some(Ok(hash)) => {
self.db.userid_password.insert(user_id, hash);
if !is_sentinel {
self.db.userid_origin.insert(user_id, "password");
}
self.db.userid_origin.insert(user_id, "password");
},
| Some(Err(e)) => {
return Err!(Request(InvalidParam(