feat: Implement !admin oidc unlink

This commit is contained in:
Ginger committed 2026-07-02 16:34:38 -04:00
1 parent c0cb4afd8a
commit 58a6e1232c
5 files changed
+49 -39

No files matched your search

+11 -10
View File
@@ -19,47 +19,48 @@ use crate::{
#[derive(Debug, Parser)]
#[command(name = conduwuit_core::BRANDING, version = conduwuit_core::version())]
pub enum AdminCommand {
#[command(subcommand)]
/// Commands for managing appservices
#[command(subcommand)]
Appservices(AppserviceCommand),
#[command(subcommand)]
/// Commands for managing local users
#[command(subcommand)]
Users(UserCommand),
#[command(subcommand)]
/// Commands for managing registration tokens
#[command(subcommand)]
Token(TokenCommand),
/// Commands for managing OIDC
#[command(subcommand)]
Oidc(OidcCommand),
#[command(subcommand)]
/// Commands for managing rooms
#[command(subcommand)]
Rooms(RoomCommand),
#[command(subcommand)]
/// Commands for managing federation
#[command(subcommand)]
Federation(FederationCommand),
#[command(subcommand)]
/// Commands for managing the server
#[command(subcommand)]
Server(ServerCommand),
#[command(subcommand)]
/// Commands for managing media
#[command(subcommand)]
Media(MediaCommand),
#[command(subcommand)]
/// Commands for checking integrity
#[command(subcommand)]
Check(CheckCommand),
#[command(subcommand)]
/// Commands for debugging things
#[command(subcommand)]
Debug(DebugCommand),
#[command(subcommand)]
/// Low-level queries for database getters and iterators
#[command(subcommand)]
Query(QueryCommand),
}
+11 -3
View File
@@ -6,12 +6,20 @@ impl crate::Context<'_> {
pub(super) async fn oidc_link(&self, user_id: String, subject: String) -> Result {
let user_id = parse_active_local_user_id(self.services, &user_id).await?;
self.services.oidc.link_user(&user_id, &subject).await;
self.services.oidc.link_user(&user_id, &subject);
self.write_str("Account linked successfully").await?;
self.write_str(&format!("Subject `{subject}` linked to account `{user_id}`."))
.await?;
Ok(())
}
pub(super) async fn oidc_unlink(&self, _user_id: String) -> Result { todo!() }
pub(super) async fn oidc_unlink(&self, subject: String) -> Result {
self.services.oidc.unlink_user(&subject);
self.write_str(&format!("Subject `{subject}` unlinked."))
.await?;
Ok(())
}
}
+2 -1
View File
@@ -14,8 +14,9 @@ pub enum OidcCommand {
subject: String,
},
/// Unlink the given subject claim from its associated user ID.
#[clap(name = "unlink")]
OidcUnlink {
user_id: String,
subject: String,
},
}
+4 -2
View File
@@ -263,7 +263,7 @@ impl Service {
Self::SERVER_MISCONFIGURED
})?;
self.link_user(&user_id, subject).await;
self.link_user(&user_id, subject);
info!(?subject, ?user_id, "Shadow user created for {user_id}");
},
@@ -275,9 +275,11 @@ impl Service {
Ok(SessionCompletionStatus::Complete(user_id))
}
pub async fn link_user(&self, user_id: &UserId, subject: &str) {
pub fn link_user(&self, user_id: &UserId, subject: &str) {
self.db
.openidsubject_localpart
.insert(subject, user_id.localpart());
}
pub fn unlink_user(&self, subject: &str) { self.db.openidsubject_localpart.remove(subject); }
}
+21 -23
View File
@@ -298,28 +298,7 @@ impl super::Service {
&supplied_username,
self.services.globals.server_name(),
) {
| Ok(user_id) => {
if let Err(e) = user_id.validate_strict() {
// Unless we are in emergency mode, we should follow synapse's behaviour
// on not allowing things like spaces and UTF-8 characters in
// usernames
if !emergency_mode_enabled {
return Err!(Request(InvalidUsername(debug_warn!(
"Username {supplied_username} contains disallowed characters or \
spaces: {e}"
))));
}
}
// Don't allow registration with user IDs that aren't local
if !self.services.globals.user_is_local(&user_id) {
return Err!(Request(InvalidUsername(
"Username {supplied_username} is not local to this server"
)));
}
user_id
},
| Ok(user_id) => user_id,
| Err(e) => {
return Err!(Request(InvalidUsername(debug_warn!(
"Username {supplied_username} is not valid: {e}"
@@ -327,8 +306,27 @@ impl super::Service {
},
};
if let Err(e) = user_id.validate_strict() {
// Unless we are in emergency mode, we should follow synapse's behaviour
// on not allowing things like spaces and UTF-8 characters in
// usernames
if !emergency_mode_enabled {
return Err!(Request(InvalidUsername(debug_warn!(
"Username {supplied_username} contains disallowed characters or spaces: \
{e}"
))));
}
}
// Don't allow registration with user IDs that aren't local
if !self.services.globals.user_is_local(&user_id) {
return Err!(Request(InvalidUsername(
"Username {supplied_username} is not local to this server"
)));
}
if self.status(&user_id).await.is_found() {
return Err!(Request(UserInUse("User ID is not available.")));
return Err!(Request(UserInUse("Username is not available.")));
}
// Check that the user ID is/is not in an appservice's namespace