Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merge ClientIp with Headers. #3332

Merged
merged 1 commit into from Mar 15, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
37 changes: 19 additions & 18 deletions src/api/admin.rs
Expand Up @@ -369,7 +369,7 @@ async fn get_user_json(uuid: String, _token: AdminToken, mut conn: DbConn) -> Js
}

#[post("/users/<uuid>/delete")]
async fn delete_user(uuid: String, _token: AdminToken, mut conn: DbConn, ip: ClientIp) -> EmptyResult {
async fn delete_user(uuid: String, token: AdminToken, mut conn: DbConn) -> EmptyResult {
let user = get_user_or_404(&uuid, &mut conn).await?;

// Get the user_org records before deleting the actual user
Expand All @@ -383,7 +383,7 @@ async fn delete_user(uuid: String, _token: AdminToken, mut conn: DbConn, ip: Cli
user_org.org_uuid,
String::from(ACTING_ADMIN_USER),
14, // Use UnknownBrowser type
&ip.ip,
&token.ip.ip,
&mut conn,
)
.await;
Expand Down Expand Up @@ -443,12 +443,7 @@ struct UserOrgTypeData {
}

#[post("/users/org_type", data = "<data>")]
async fn update_user_org_type(
data: Json<UserOrgTypeData>,
_token: AdminToken,
mut conn: DbConn,
ip: ClientIp,
) -> EmptyResult {
async fn update_user_org_type(data: Json<UserOrgTypeData>, token: AdminToken, mut conn: DbConn) -> EmptyResult {
let data: UserOrgTypeData = data.into_inner();

let mut user_to_edit =
Expand Down Expand Up @@ -489,7 +484,7 @@ async fn update_user_org_type(
data.org_uuid,
String::from(ACTING_ADMIN_USER),
14, // Use UnknownBrowser type
&ip.ip,
&token.ip.ip,
&mut conn,
)
.await;
Expand Down Expand Up @@ -724,15 +719,24 @@ async fn backup_db(_token: AdminToken, mut conn: DbConn) -> EmptyResult {
}
}

pub struct AdminToken {}
pub struct AdminToken {
ip: ClientIp,
}

#[rocket::async_trait]
impl<'r> FromRequest<'r> for AdminToken {
type Error = &'static str;

async fn from_request(request: &'r Request<'_>) -> Outcome<Self, Self::Error> {
let ip = match ClientIp::from_request(request).await {
Outcome::Success(ip) => ip,
_ => err_handler!("Error getting Client IP"),
};

if CONFIG.disable_admin_token() {
Outcome::Success(Self {})
Outcome::Success(Self {
ip,
})
} else {
let cookies = request.cookies();

Expand All @@ -741,19 +745,16 @@ impl<'r> FromRequest<'r> for AdminToken {
None => return Outcome::Failure((Status::Unauthorized, "Unauthorized")),
};

let ip = match ClientIp::from_request(request).await {
Outcome::Success(ip) => ip.ip,
_ => err_handler!("Error getting Client IP"),
};

if decode_admin(access_token).is_err() {
// Remove admin cookie
cookies.remove(Cookie::build(COOKIE_NAME, "").path(admin_path()).finish());
error!("Invalid or expired admin JWT. IP: {}.", ip);
error!("Invalid or expired admin JWT. IP: {}.", &ip.ip);
return Outcome::Failure((Status::Unauthorized, "Session expired"));
}

Outcome::Success(Self {})
Outcome::Success(Self {
ip,
})
}
}
}
16 changes: 5 additions & 11 deletions src/api/core/accounts.rs
Expand Up @@ -6,7 +6,7 @@ use crate::{
api::{
core::log_user_event, EmptyResult, JsonResult, JsonUpcase, Notify, NumberOrString, PasswordData, UpdateType,
},
auth::{decode_delete, decode_invite, decode_verify_email, ClientIp, Headers},
auth::{decode_delete, decode_invite, decode_verify_email, Headers},
crypto,
db::{models::*, DbConn},
mail, CONFIG,
Expand Down Expand Up @@ -305,7 +305,6 @@ async fn post_password(
data: JsonUpcase<ChangePassData>,
headers: Headers,
mut conn: DbConn,
ip: ClientIp,
nt: Notify<'_>,
) -> EmptyResult {
let data: ChangePassData = data.into_inner().data;
Expand All @@ -318,7 +317,8 @@ async fn post_password(
user.password_hint = clean_password_hint(&data.MasterPasswordHint);
enforce_password_hint_setting(&user.password_hint)?;

log_user_event(EventType::UserChangedPassword as i32, &user.uuid, headers.device.atype, &ip.ip, &mut conn).await;
log_user_event(EventType::UserChangedPassword as i32, &user.uuid, headers.device.atype, &headers.ip.ip, &mut conn)
.await;

user.set_password(
&data.NewMasterPasswordHash,
Expand Down Expand Up @@ -414,13 +414,7 @@ struct KeyData {
}

#[post("/accounts/key", data = "<data>")]
async fn post_rotatekey(
data: JsonUpcase<KeyData>,
headers: Headers,
mut conn: DbConn,
ip: ClientIp,
nt: Notify<'_>,
) -> EmptyResult {
async fn post_rotatekey(data: JsonUpcase<KeyData>, headers: Headers, mut conn: DbConn, nt: Notify<'_>) -> EmptyResult {
let data: KeyData = data.into_inner().data;

if !headers.user.check_valid_password(&data.MasterPasswordHash) {
Expand Down Expand Up @@ -466,7 +460,7 @@ async fn post_rotatekey(
// Prevent triggering cipher updates via WebSockets by settings UpdateType::None
// The user sessions are invalidated because all the ciphers were re-encrypted and thus triggering an update could cause issues.
// We force the users to logout after the user has been saved to try and prevent these issues.
update_cipher_from_data(&mut saved_cipher, cipher_data, &headers, false, &mut conn, &ip, &nt, UpdateType::None)
update_cipher_from_data(&mut saved_cipher, cipher_data, &headers, false, &mut conn, &nt, UpdateType::None)
.await?
}

Expand Down