Compare commits

..

4 Commits

Author SHA1 Message Date
theS1LV3R 081f865705 chore: Use CARGO_LOG=debug for cargo build 2026-07-11 01:31:07 +00:00
theS1LV3R 0d6608a2f8 fix: Ensure docker builds stop on failed compilation 2026-07-11 01:31:07 +00:00
renovate abf96140b2 chore(Nix): Updated flake hashes 2026-07-11 01:30:41 +00:00
Renovate Bot 35fb56aafd chore(deps): update rust to v1.97.0 2026-07-11 01:30:41 +00:00
6 changed files with 52 additions and 81 deletions
-1
View File
@@ -1 +0,0 @@
Fixed existing accounts failing to link when logging in with OIDC if `prompt_for_localpart` was `false`.
+3 -1
View File
@@ -171,6 +171,7 @@ RUN --mount=type=cache,target=/usr/local/cargo/registry \
--mount=type=cache,target=/usr/local/cargo/git/db \
--mount=type=cache,target=/app/target,id=continuwuity-cargo-target-${TARGET_CPU}-${TARGETPLATFORM}-${RUST_PROFILE} \
bash <<'EOF'
set -euo pipefail
set -o allexport
set -o xtrace
. /etc/environment
@@ -191,7 +192,7 @@ RUN --mount=type=cache,target=/usr/local/cargo/registry \
jq -r ".target_directory"))
mkdir /out/sbin
PACKAGE=conduwuit
xx-cargo build --locked --profile ${RUST_PROFILE} \
CARGO_LOG=debug xx-cargo build --locked --profile ${RUST_PROFILE} \
--no-default-features --features ${CARGO_FEATURES} \
-p $PACKAGE;
BINARIES=($(cargo metadata --no-deps --format-version 1 | \
@@ -207,6 +208,7 @@ EOF
RUN --mount=type=cache,target=/usr/local/cargo/registry \
--mount=type=cache,target=/usr/local/cargo/git/db \
bash <<'EOF'
set -euo pipefail
set -o xtrace
mkdir /out/sbom
typeset -A PACKAGES
+1 -1
View File
@@ -12,7 +12,7 @@
target:
target.fromToolchainName {
name = (lib.importTOML "${inputs.self}/rust-toolchain.toml").toolchain.channel;
sha256 = "sha256-h+t2xTBz5yt2YIO+1VMIIGlCU7gyp2LYOFvaV1nwOXU=";
sha256 = "sha256-OATSZm98Es5kIFuqaba+UvkQtFsVgJEBMmS+t6od5/U=";
};
in
{
+1 -1
View File
@@ -10,7 +10,7 @@
[toolchain]
profile = "minimal"
channel = "1.96.1"
channel = "1.97.0"
components = [
# For rust-analyzer
"rust-src",
+6 -38
View File
@@ -115,21 +115,6 @@ pub enum SessionCompletionStatus {
Complete(OwnedUserId),
}
pub enum ClaimedLocalUser {
/// The claim refers to an existing user.
Existing(OwnedUserId),
/// The claim refers to a new user ID which should be registered.
New(OwnedUserId),
}
impl ClaimedLocalUser {
fn into_user_id(self) -> OwnedUserId {
match self {
| Self::Existing(user_id) | Self::New(user_id) => user_id,
}
}
}
#[async_trait]
impl crate::Service for Service {
fn build(args: crate::Args<'_>) -> Result<Arc<Self>> {
@@ -318,7 +303,7 @@ pub async fn complete_session(
.expect("claims should be an object")
.to_owned();
debug!(?all_claims, "Got claims from the identity provider");
debug!(?all_claims);
let subject = claims.subject().as_str();
@@ -341,13 +326,14 @@ pub async fn complete_session(
.get(&config.preferred_username_claim)
.and_then(|claim| claim.as_str())
{
self.identify_claimed_local_user(preferred_username)
self.services
.users
.determine_registration_user_id(Some(preferred_username.to_owned()), None, None)
.await
.map(ClaimedLocalUser::into_user_id)
.map_err(|err| {
error!("Preferred username claim is not a valid localpart: {err}");
"Your preferred username could not be converted to a valid Matrix user ID. \
Contact your homeserver's administrator."
"Your preferred username is not a valid Matrix user ID localpart. Contact \
your homeserver's administrator."
})?
} else {
error!("Preferred username claim was not present or was not a string");
@@ -496,22 +482,4 @@ pub fn link_user(&self, user_id: &UserId, subject: &str) {
}
pub fn unlink_user(&self, subject: &str) { self.db.openidsubject_localpart.remove(subject); }
/// Determine what user ID a localpart claim refers to.
pub async fn identify_claimed_local_user(&self, claim: &str) -> Result<ClaimedLocalUser> {
if let Ok(user_id) =
UserId::parse(format!("@{}:{}", claim, self.services.globals.server_name()))
&& self.services.users.status(&user_id).await.is_active()
{
Ok(ClaimedLocalUser::Existing(user_id))
} else {
let user_id = self
.services
.users
.determine_registration_user_id(Some(claim.to_owned()), None, None)
.await?;
Ok(ClaimedLocalUser::New(user_id))
}
}
}
+41 -39
View File
@@ -6,12 +6,9 @@
response::Redirect,
routing::on,
};
use conduwuit_service::{
oauth::grant::AuthorizationCodeResponse,
oidc::{ClaimedLocalUser, SessionCompletionStatus},
};
use conduwuit_service::{oauth::grant::AuthorizationCodeResponse, oidc::SessionCompletionStatus};
use futures::FutureExt;
use ruma::OwnedServerName;
use ruma::{OwnedServerName, UserId};
use serde::{Deserialize, de::IgnoredAny};
use tower_sessions::Session;
@@ -102,60 +99,65 @@ async fn route_complete(
state: OidcSessionState::Authorized { claims: Box::new(claims.clone()) },
})
.await
.expect("should be able to serialize oidc session");
.expect("Should be able to serialize oidc session");
services.oidc.complete_session(&claims, None).await
},
| OidcSessionState::Authorized { claims } => {
let supplied_user_id = if let Some(form) = form {
match services
.oidc
.identify_claimed_local_user(&form.username)
.await
if let Ok(user_id) = UserId::parse(format!(
"@{}:{}",
&form.username,
services.globals.server_name()
)) && services.users.status(&user_id).await.is_active()
{
| Ok(ClaimedLocalUser::Existing(user_id)) => {
let user_card =
UserCard::for_local_user(&services, user_id.clone()).await;
let user_card = UserCard::for_local_user(&services, user_id.clone()).await;
if let Some(password) = form.password {
if services
.users
.check_password(&user_id, &password)
.await
.is_ok()
{
Some(user_id)
} else {
return response!(OidcComplete::new(
context,
OidcCompleteBody::PasswordPrompt {
username: form.username,
user_card,
password_error: true
}
));
}
if let Some(password) = form.password {
if services
.users
.check_password(&user_id, &password)
.await
.is_ok()
{
Some(user_id)
} else {
return response!(OidcComplete::new(
context,
OidcCompleteBody::PasswordPrompt {
username: form.username,
user_card,
password_error: false,
password_error: true
}
));
}
},
| Ok(ClaimedLocalUser::New(user_id)) => Some(user_id),
| Err(err) => {
} else {
return response!(OidcComplete::new(
context,
OidcCompleteBody::UsernamePrompt {
server_name: services.globals.server_name().to_owned(),
username_error: Some(err.message()),
OidcCompleteBody::PasswordPrompt {
username: form.username,
user_card,
password_error: false,
}
));
},
}
} else {
match services
.users
.determine_registration_user_id(Some(form.username), None, None)
.await
{
| Ok(user_id) => Some(user_id),
| Err(err) => {
return response!(OidcComplete::new(
context,
OidcCompleteBody::UsernamePrompt {
server_name: services.globals.server_name().to_owned(),
username_error: Some(err.message()),
}
));
},
}
}
} else {
None