Signed-off-by: Jason Volk <jason@zemos.net>
This commit is contained in:
@@ -34,7 +34,7 @@ use tuwunel_service::{
|
|||||||
oauth::{
|
oauth::{
|
||||||
CODE_VERIFIER_LENGTH, Provider, SESSION_ID_LENGTH, Session, UserInfo, unique_id_sub,
|
CODE_VERIFIER_LENGTH, Provider, SESSION_ID_LENGTH, Session, UserInfo, unique_id_sub,
|
||||||
},
|
},
|
||||||
users::Register,
|
users::{PASSWORD_SENTINEL, Register},
|
||||||
};
|
};
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
@@ -480,7 +480,7 @@ async fn register_user(
|
|||||||
.users
|
.users
|
||||||
.full_register(Register {
|
.full_register(Register {
|
||||||
user_id: Some(user_id),
|
user_id: Some(user_id),
|
||||||
password: Some("*"),
|
password: Some(PASSWORD_SENTINEL),
|
||||||
origin: Some("sso"),
|
origin: Some("sso"),
|
||||||
displayname: userinfo.name.as_deref(),
|
displayname: userinfo.name.as_deref(),
|
||||||
grant_first_user_admin: true,
|
grant_first_user_admin: true,
|
||||||
|
|||||||
@@ -9,10 +9,11 @@ use ruma::{
|
|||||||
push::Ruleset,
|
push::Ruleset,
|
||||||
};
|
};
|
||||||
use tuwunel_core::{
|
use tuwunel_core::{
|
||||||
Err, Result, debug, debug_info, debug_warn, error, info,
|
Err, Result, debug, debug_info, debug_warn, err, error, info,
|
||||||
itertools::Itertools,
|
itertools::Itertools,
|
||||||
matrix::PduCount,
|
matrix::PduCount,
|
||||||
result::NotFound,
|
result::NotFound,
|
||||||
|
utils,
|
||||||
utils::{
|
utils::{
|
||||||
IterStream, ReadyExt,
|
IterStream, ReadyExt,
|
||||||
stream::{TryExpect, TryIgnore},
|
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"retroactively_fix_bad_data_from_roomuserid_joined", []);
|
||||||
db["global"].insert(b"fix_referencedevents_missing_sep", []);
|
db["global"].insert(b"fix_referencedevents_missing_sep", []);
|
||||||
db["global"].insert(b"fix_readreceiptid_readreceipt_duplicates", []);
|
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
|
// Create the admin room and server user on first run
|
||||||
if services.config.create_admin_room {
|
if services.config.create_admin_room {
|
||||||
@@ -145,6 +147,14 @@ async fn migrate(services: &Services) -> Result {
|
|||||||
fix_readreceiptid_readreceipt_duplicates(services).await?;
|
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 {
|
if services.globals.db.database_version().await < 17 {
|
||||||
services.globals.db.bump_database_version(17);
|
services.globals.db.bump_database_version(17);
|
||||||
info!("Migration: Bumped database version to 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["global"].insert(b"fix_readreceiptid_readreceipt_duplicates", []);
|
||||||
db.engine.sort()
|
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()
|
||||||
|
}
|
||||||
|
|||||||
@@ -24,6 +24,9 @@ use tuwunel_database::{Deserialized, Json, Map};
|
|||||||
|
|
||||||
pub use self::{keys::parse_master_key, register::Register};
|
pub use self::{keys::parse_master_key, register::Register};
|
||||||
|
|
||||||
|
pub const PASSWORD_SENTINEL: &str = "*";
|
||||||
|
pub const PASSWORD_DISABLED: &str = "";
|
||||||
|
|
||||||
pub struct Service {
|
pub struct Service {
|
||||||
services: Arc<crate::services::OnceServices>,
|
services: Arc<crate::services::OnceServices>,
|
||||||
db: Data,
|
db: Data,
|
||||||
@@ -222,10 +225,7 @@ impl Service {
|
|||||||
// exception is made for that origin in the condition below. Note that users
|
// exception is made for that origin in the condition below. Note that users
|
||||||
// with no origin are also password-origin users.
|
// with no origin are also password-origin users.
|
||||||
let allowed_origins = ["password", "sso"];
|
let allowed_origins = ["password", "sso"];
|
||||||
|
if password.is_some() && password != Some(PASSWORD_SENTINEL) {
|
||||||
if let Some(password) = password
|
|
||||||
&& password != "*"
|
|
||||||
{
|
|
||||||
let origin = self.origin(user_id).await;
|
let origin = self.origin(user_id).await;
|
||||||
let origin = origin.as_deref().unwrap_or("password");
|
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) {
|
match password.map(utils::hash::password) {
|
||||||
| None => {
|
| 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)) => {
|
| Some(Ok(hash)) => {
|
||||||
self.db.userid_password.insert(user_id, 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)) => {
|
| Some(Err(e)) => {
|
||||||
return Err!(Request(InvalidParam(
|
return Err!(Request(InvalidParam(
|
||||||
|
|||||||
Reference in New Issue
Block a user