|
|
|
|
@ -1,15 +1,17 @@
@@ -1,15 +1,17 @@
|
|
|
|
|
use crate::{Error, Result}; |
|
|
|
|
use crate::{client_server::SESSION_ID_LENGTH, utils, Error, Result}; |
|
|
|
|
use ruma::{ |
|
|
|
|
api::client::{ |
|
|
|
|
error::ErrorKind, |
|
|
|
|
r0::uiaa::{IncomingAuthData, UiaaInfo}, |
|
|
|
|
}, |
|
|
|
|
signatures::CanonicalJsonValue, |
|
|
|
|
DeviceId, UserId, |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
#[derive(Clone)] |
|
|
|
|
pub struct Uiaa { |
|
|
|
|
pub(super) userdeviceid_uiaainfo: sled::Tree, // User-interactive authentication
|
|
|
|
|
pub(super) userdevicesessionid_uiaainfo: sled::Tree, // User-interactive authentication
|
|
|
|
|
pub(super) userdevicesessionid_uiaarequest: sled::Tree, // UiaaRequest = canonical json value
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
impl Uiaa { |
|
|
|
|
@ -19,8 +21,20 @@ impl Uiaa {
@@ -19,8 +21,20 @@ impl Uiaa {
|
|
|
|
|
user_id: &UserId, |
|
|
|
|
device_id: &DeviceId, |
|
|
|
|
uiaainfo: &UiaaInfo, |
|
|
|
|
json_body: &CanonicalJsonValue, |
|
|
|
|
) -> Result<()> { |
|
|
|
|
self.update_uiaa_session(user_id, device_id, Some(uiaainfo)) |
|
|
|
|
self.set_uiaa_request( |
|
|
|
|
user_id, |
|
|
|
|
device_id, |
|
|
|
|
uiaainfo.session.as_ref().expect("session should be set"), // TODO: better session error handling (why is it optional in ruma?)
|
|
|
|
|
json_body, |
|
|
|
|
)?; |
|
|
|
|
self.update_uiaa_session( |
|
|
|
|
user_id, |
|
|
|
|
device_id, |
|
|
|
|
uiaainfo.session.as_ref().expect("session should be set"), |
|
|
|
|
Some(uiaainfo), |
|
|
|
|
) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
pub fn try_auth( |
|
|
|
|
@ -45,6 +59,10 @@ impl Uiaa {
@@ -45,6 +59,10 @@ impl Uiaa {
|
|
|
|
|
}) |
|
|
|
|
.unwrap_or_else(|| Ok(uiaainfo.clone()))?; |
|
|
|
|
|
|
|
|
|
if uiaainfo.session.is_none() { |
|
|
|
|
uiaainfo.session = Some(utils::random_string(SESSION_ID_LENGTH)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Find out what the user completed
|
|
|
|
|
match &**kind { |
|
|
|
|
"m.login.password" => { |
|
|
|
|
@ -130,35 +148,96 @@ impl Uiaa {
@@ -130,35 +148,96 @@ impl Uiaa {
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if !completed { |
|
|
|
|
self.update_uiaa_session(user_id, device_id, Some(&uiaainfo))?; |
|
|
|
|
self.update_uiaa_session( |
|
|
|
|
user_id, |
|
|
|
|
device_id, |
|
|
|
|
uiaainfo.session.as_ref().expect("session is always set"), |
|
|
|
|
Some(&uiaainfo), |
|
|
|
|
)?; |
|
|
|
|
return Ok((false, uiaainfo)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// UIAA was successful! Remove this session and return true
|
|
|
|
|
self.update_uiaa_session(user_id, device_id, None)?; |
|
|
|
|
self.update_uiaa_session( |
|
|
|
|
user_id, |
|
|
|
|
device_id, |
|
|
|
|
uiaainfo.session.as_ref().expect("session is always set"), |
|
|
|
|
None, |
|
|
|
|
)?; |
|
|
|
|
Ok((true, uiaainfo)) |
|
|
|
|
} else { |
|
|
|
|
panic!("FallbackAcknowledgement is not supported yet"); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
fn set_uiaa_request( |
|
|
|
|
&self, |
|
|
|
|
user_id: &UserId, |
|
|
|
|
device_id: &DeviceId, |
|
|
|
|
session: &str, |
|
|
|
|
request: &CanonicalJsonValue, |
|
|
|
|
) -> Result<()> { |
|
|
|
|
let mut userdevicesessionid = user_id.as_bytes().to_vec(); |
|
|
|
|
userdevicesessionid.push(0xff); |
|
|
|
|
userdevicesessionid.extend_from_slice(device_id.as_bytes()); |
|
|
|
|
userdevicesessionid.push(0xff); |
|
|
|
|
userdevicesessionid.extend_from_slice(session.as_bytes()); |
|
|
|
|
|
|
|
|
|
self.userdevicesessionid_uiaarequest.insert( |
|
|
|
|
&userdevicesessionid, |
|
|
|
|
&*serde_json::to_string(request).expect("json value to string always works"), |
|
|
|
|
)?; |
|
|
|
|
|
|
|
|
|
Ok(()) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
pub fn get_uiaa_request( |
|
|
|
|
&self, |
|
|
|
|
user_id: &UserId, |
|
|
|
|
device_id: &DeviceId, |
|
|
|
|
session: &str, |
|
|
|
|
) -> Result<Option<CanonicalJsonValue>> { |
|
|
|
|
let mut userdevicesessionid = user_id.as_bytes().to_vec(); |
|
|
|
|
userdevicesessionid.push(0xff); |
|
|
|
|
userdevicesessionid.extend_from_slice(device_id.as_bytes()); |
|
|
|
|
userdevicesessionid.push(0xff); |
|
|
|
|
userdevicesessionid.extend_from_slice(session.as_bytes()); |
|
|
|
|
|
|
|
|
|
self.userdevicesessionid_uiaarequest |
|
|
|
|
.get(&userdevicesessionid)? |
|
|
|
|
.map_or(Ok(None), |bytes| { |
|
|
|
|
Ok::<_, Error>(Some( |
|
|
|
|
serde_json::from_str::<CanonicalJsonValue>( |
|
|
|
|
&utils::string_from_bytes(&bytes).map_err(|_| { |
|
|
|
|
Error::bad_database("Invalid uiaa request bytes in db.") |
|
|
|
|
})?, |
|
|
|
|
) |
|
|
|
|
.map_err(|_| Error::bad_database("Invalid uiaa request in db."))?, |
|
|
|
|
)) |
|
|
|
|
}) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
fn update_uiaa_session( |
|
|
|
|
&self, |
|
|
|
|
user_id: &UserId, |
|
|
|
|
device_id: &DeviceId, |
|
|
|
|
session: &str, |
|
|
|
|
uiaainfo: Option<&UiaaInfo>, |
|
|
|
|
) -> Result<()> { |
|
|
|
|
let mut userdeviceid = user_id.as_bytes().to_vec(); |
|
|
|
|
userdeviceid.push(0xff); |
|
|
|
|
userdeviceid.extend_from_slice(device_id.as_bytes()); |
|
|
|
|
let mut userdevicesessionid = user_id.as_bytes().to_vec(); |
|
|
|
|
userdevicesessionid.push(0xff); |
|
|
|
|
userdevicesessionid.extend_from_slice(device_id.as_bytes()); |
|
|
|
|
userdevicesessionid.push(0xff); |
|
|
|
|
userdevicesessionid.extend_from_slice(session.as_bytes()); |
|
|
|
|
|
|
|
|
|
if let Some(uiaainfo) = uiaainfo { |
|
|
|
|
self.userdeviceid_uiaainfo.insert( |
|
|
|
|
&userdeviceid, |
|
|
|
|
self.userdevicesessionid_uiaainfo.insert( |
|
|
|
|
&userdevicesessionid, |
|
|
|
|
&*serde_json::to_string(&uiaainfo).expect("UiaaInfo::to_string always works"), |
|
|
|
|
)?; |
|
|
|
|
} else { |
|
|
|
|
self.userdeviceid_uiaainfo.remove(&userdeviceid)?; |
|
|
|
|
self.userdevicesessionid_uiaainfo |
|
|
|
|
.remove(&userdevicesessionid)?; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
Ok(()) |
|
|
|
|
@ -170,14 +249,16 @@ impl Uiaa {
@@ -170,14 +249,16 @@ impl Uiaa {
|
|
|
|
|
device_id: &DeviceId, |
|
|
|
|
session: &str, |
|
|
|
|
) -> Result<UiaaInfo> { |
|
|
|
|
let mut userdeviceid = user_id.as_bytes().to_vec(); |
|
|
|
|
userdeviceid.push(0xff); |
|
|
|
|
userdeviceid.extend_from_slice(device_id.as_bytes()); |
|
|
|
|
let mut userdevicesessionid = user_id.as_bytes().to_vec(); |
|
|
|
|
userdevicesessionid.push(0xff); |
|
|
|
|
userdevicesessionid.extend_from_slice(device_id.as_bytes()); |
|
|
|
|
userdevicesessionid.push(0xff); |
|
|
|
|
userdevicesessionid.extend_from_slice(session.as_bytes()); |
|
|
|
|
|
|
|
|
|
let uiaainfo = serde_json::from_slice::<UiaaInfo>( |
|
|
|
|
&self |
|
|
|
|
.userdeviceid_uiaainfo |
|
|
|
|
.get(&userdeviceid)? |
|
|
|
|
.userdevicesessionid_uiaainfo |
|
|
|
|
.get(&userdevicesessionid)? |
|
|
|
|
.ok_or(Error::BadRequest( |
|
|
|
|
ErrorKind::Forbidden, |
|
|
|
|
"UIAA session does not exist.", |
|
|
|
|
@ -185,18 +266,6 @@ impl Uiaa {
@@ -185,18 +266,6 @@ impl Uiaa {
|
|
|
|
|
) |
|
|
|
|
.map_err(|_| Error::bad_database("UiaaInfo in userdeviceid_uiaainfo is invalid."))?; |
|
|
|
|
|
|
|
|
|
if uiaainfo |
|
|
|
|
.session |
|
|
|
|
.as_ref() |
|
|
|
|
.filter(|&s| s == session) |
|
|
|
|
.is_none() |
|
|
|
|
{ |
|
|
|
|
return Err(Error::BadRequest( |
|
|
|
|
ErrorKind::Forbidden, |
|
|
|
|
"UIAA session token invalid.", |
|
|
|
|
)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
Ok(uiaainfo) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|