implement deprecated user field for login requests

Signed-off-by: strawberry <strawberry@puppygock.gay>
This commit is contained in:
strawberry 2024-02-15 20:47:12 -05:00 committed by June
parent 5f007d8117
commit a0205cd41d
6 changed files with 73 additions and 33 deletions

View file

@ -71,11 +71,11 @@ pub async fn get_register_available_route(
Ok(get_username_availability::v3::Response { available: true })
}
/// # `POST /_matrix/client/r0/register`
/// # `POST /_matrix/client/v3/register`
///
/// Register an account on this homeserver.
///
/// You can use [`GET /_matrix/client/r0/register/available`](fn.get_register_available_route.html)
/// You can use [`GET /_matrix/client/v3/register/available`](fn.get_register_available_route.html)
/// to check if the user id is valid and available.
///
/// - Only works if registration is enabled

View file

@ -17,7 +17,7 @@ use ruma::{
UserId,
};
use serde::Deserialize;
use tracing::{error, info, warn};
use tracing::{debug, error, info, warn};
#[derive(Debug, Deserialize)]
struct Claims {
@ -53,21 +53,32 @@ pub async fn login_route(body: Ruma<login::v3::Request>) -> Result<login::v3::Re
// Validate login method
// TODO: Other login methods
let user_id = match &body.login_info {
#[allow(deprecated)]
login::v3::LoginInfo::Password(login::v3::Password {
identifier,
password,
user,
..
}) => {
let username = if let UserIdentifier::UserIdOrLocalpart(user_id) = identifier {
debug!("Got password login type");
let username = if let Some(UserIdentifier::UserIdOrLocalpart(user_id)) = identifier {
debug!("Using username from identifier field");
user_id.to_lowercase()
} else if let Some(user_id) = user {
warn!("User \"{}\" is attempting to login with the deprecated \"user\" field at \"/_matrix/client/v3/login\". conduwuit implements this deprecated behaviour, but this is destined to be removed in a future Matrix release.", user_id);
user_id.to_lowercase()
} else {
warn!("Bad login type: {:?}", &body.login_info);
return Err(Error::BadRequest(ErrorKind::Forbidden, "Bad login type."));
};
let user_id =
UserId::parse_with_server_name(username, services().globals.server_name())
.map_err(|_| {
.map_err(|e| {
warn!("Failed to parse username from user logging in: {}", e);
Error::BadRequest(ErrorKind::InvalidUsername, "Username is invalid.")
})?;
let hash = services()
.users
.password_hash(&user_id)?
@ -82,15 +93,18 @@ pub async fn login_route(body: Ruma<login::v3::Request>) -> Result<login::v3::Re
"The user has been deactivated",
));
}
let Ok(parsed_hash) = PasswordHash::new(&hash) else {
error!("error while hashing user {}", user_id);
return Err(Error::BadServerResponse("could not hash"));
};
let hash_matches = services()
.globals
.argon
.verify_password(password.as_bytes(), &parsed_hash)
.is_ok();
if !hash_matches {
return Err(Error::BadRequest(
ErrorKind::Forbidden,
@ -101,16 +115,25 @@ pub async fn login_route(body: Ruma<login::v3::Request>) -> Result<login::v3::Re
user_id
}
login::v3::LoginInfo::Token(login::v3::Token { token }) => {
debug!("Got token login type");
if let Some(jwt_decoding_key) = services().globals.jwt_decoding_key() {
let token = jsonwebtoken::decode::<Claims>(
token,
jwt_decoding_key,
&jsonwebtoken::Validation::default(),
)
.map_err(|_| Error::BadRequest(ErrorKind::InvalidUsername, "Token is invalid."))?;
.map_err(|e| {
warn!("Failed to parse JWT token from user logging in: {}", e);
Error::BadRequest(ErrorKind::InvalidUsername, "Token is invalid.")
})?;
let username = token.claims.sub.to_lowercase();
UserId::parse_with_server_name(username, services().globals.server_name()).map_err(
|_| Error::BadRequest(ErrorKind::InvalidUsername, "Username is invalid."),
|e| {
warn!("Failed to parse username from user logging in: {}", e);
Error::BadRequest(ErrorKind::InvalidUsername, "Username is invalid.")
},
)?
} else {
return Err(Error::BadRequest(
@ -119,28 +142,41 @@ pub async fn login_route(body: Ruma<login::v3::Request>) -> Result<login::v3::Re
));
}
}
login::v3::LoginInfo::ApplicationService(login::v3::ApplicationService { identifier }) => {
#[allow(deprecated)]
login::v3::LoginInfo::ApplicationService(login::v3::ApplicationService {
identifier,
user,
}) => {
debug!("Got appservice login type");
if !body.from_appservice {
info!("User tried logging in as an appservice, but request body is not from a known/registered appservice");
return Err(Error::BadRequest(
ErrorKind::Forbidden,
"Forbidden login type.",
));
};
let username = if let UserIdentifier::UserIdOrLocalpart(user_id) = identifier {
let username = if let Some(UserIdentifier::UserIdOrLocalpart(user_id)) = identifier {
user_id.to_lowercase()
} else if let Some(user_id) = user {
warn!("Appservice \"{}\" is attempting to login with the deprecated \"user\" field at \"/_matrix/client/v3/login\". conduwuit implements this deprecated behaviour, but this is destined to be removed in a future Matrix release.", user_id);
user_id.to_lowercase()
} else {
return Err(Error::BadRequest(ErrorKind::Forbidden, "Bad login type."));
};
UserId::parse_with_server_name(username, services().globals.server_name()).map_err(
|_| Error::BadRequest(ErrorKind::InvalidUsername, "Username is invalid."),
|e| {
warn!("Failed to parse username from appservice logging in: {}", e);
Error::BadRequest(ErrorKind::InvalidUsername, "Username is invalid.")
},
)?
}
_ => {
warn!("Unsupported or unknown login type: {:?}", &body.login_info);
debug!("JSON body: {:?}", &body.json_body);
return Err(Error::BadRequest(
ErrorKind::Unknown,
"Unsupported login type.",
"Unsupported or unknown login type.",
));
}
};

View file

@ -12,7 +12,7 @@ use ruma::{
serde::Raw,
EventId, RoomId, UserId,
};
use tracing::log::warn;
use tracing::{error, log::warn};
/// # `PUT /_matrix/client/r0/rooms/{roomId}/state/{eventType}/{stateKey}`
///
@ -105,7 +105,7 @@ pub async fn get_state_events_route(
})
}
/// # `GET /_matrix/client/r0/rooms/{roomid}/state/{eventType}/{stateKey}`
/// # `GET /_matrix/client/v3/rooms/{roomid}/state/{eventType}/{stateKey}`
///
/// Get single state event of a room.
///
@ -139,12 +139,14 @@ pub async fn get_state_events_for_key_route(
})?;
Ok(get_state_events_for_key::v3::Response {
content: serde_json::from_str(event.content.get())
.map_err(|_| Error::bad_database("Invalid event content in database"))?,
content: serde_json::from_str(event.content.get()).map_err(|e| {
error!("Invalid event content in database: {}", e);
Error::bad_database("Invalid event content in database")
})?,
})
}
/// # `GET /_matrix/client/r0/rooms/{roomid}/state/{eventType}`
/// # `GET /_matrix/client/v3/rooms/{roomid}/state/{eventType}`
///
/// Get single state event of a room.
///
@ -178,8 +180,10 @@ pub async fn get_state_events_for_empty_key_route(
})?;
Ok(get_state_events_for_key::v3::Response {
content: serde_json::from_str(event.content.get())
.map_err(|_| Error::bad_database("Invalid event content in database"))?,
content: serde_json::from_str(event.content.get()).map_err(|e| {
error!("Invalid event content in database: {}", e);
Error::bad_database("Invalid event content in database")
})?,
}
.into())
}

View file

@ -318,7 +318,7 @@ async fn run_server() -> io::Result<()> {
let socket_perms = config.unix_socket_perms.to_string();
let octal_perms = u32::from_str_radix(&socket_perms, 8).unwrap();
let listener = UnixListener::bind(path.clone()).unwrap();
let listener = UnixListener::bind(path.clone())?;
tokio::fs::set_permissions(path, Permissions::from_mode(octal_perms))
.await
.unwrap();