Skip to content

Commit

Permalink
Merge pull request #41 from sentclose/reset-user
Browse files Browse the repository at this point in the history
Reset user
  • Loading branch information
joernheinemann authored May 24, 2024
2 parents 42634d8 + 1448aac commit 65f78e7
Show file tree
Hide file tree
Showing 6 changed files with 382 additions and 170 deletions.
199 changes: 100 additions & 99 deletions server_crates/server_api/routes.yml

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions server_crates/server_api/src/routes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,10 @@ pub(crate) fn routes(router: &mut Router)
"/api/v1/user/forced/delete",
r(crate::user::delete_user).add(server_api_common::middleware::app_token::app_token_transform),
);
router.put(
"/api/v1/user/forced/reset_user",
r(crate::user::reset_user).add(server_api_common::middleware::app_token::app_token_transform),
);
router.put(
"/api/v1/user/forced/disable_otp",
r(crate::user::disable_otp_forced).add(server_api_common::middleware::app_token::app_token_transform),
Expand Down
67 changes: 65 additions & 2 deletions server_crates/server_api/src/user/user_controller.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use rustgram::Request;
use rustgram_server_util::cache;
use rustgram_server_util::error::{ServerCoreError, ServerErrorConstructor};
use rustgram_server_util::input_helper::{bytes_to_json, get_raw_body};
use rustgram_server_util::res::{echo, echo_success, AppRes, JRes, ServerSuccessOutput};
Expand Down Expand Up @@ -35,13 +36,14 @@ use sentc_crypto_common::user::{
};
use sentc_crypto_common::AppId;
use server_api_common::customer_app::{check_endpoint_with_app_options, check_endpoint_with_req, get_app_data_from_req, Endpoint};
use server_api_common::group::GROUP_TYPE_USER;
use server_api_common::user::get_jwt_data_from_param;
use server_api_common::user::user_entity::UserJwtEntity;
use server_api_common::util::hash_token_to_string;
use server_api_common::util::{get_user_in_app_key, hash_token_to_string};

use crate::check_user_group_keys_set;
use crate::group::group_entities::{GroupKeyUpdate, GroupUserKeys};
use crate::group::{group_key_rotation_service, group_user_service};
use crate::group::{group_key_rotation_service, group_service, group_user_service};
use crate::sentc_user_entities::{DoneLoginServerOutput, DoneLoginServerReturn, LoginForcedOutput, VerifyLoginOutput};
use crate::user::auth::auth_service;
use crate::user::user_entities::{UserDeviceList, UserInitEntity, UserPublicKeyDataEntity, UserVerifyKeyDataEntity};
Expand Down Expand Up @@ -624,3 +626,64 @@ pub(crate) async fn disable_otp_forced(mut req: Request) -> JRes<ServerSuccessOu

echo_success()
}

pub(crate) async fn reset_user(mut req: Request) -> JRes<ServerSuccessOutput>
{
let body = get_raw_body(&mut req).await?;
let app_data = get_app_data_from_req(&req)?;
check_endpoint_with_app_options(app_data, Endpoint::ForceServer)?;
let app_id = &app_data.app_data.app_id;
let input: RegisterData = bytes_to_json(&body)?;

let jwt = prepare_user_forced_action(app_id, &input.device.device_identifier).await?;

//delete all devices and update the user group
let mut group_data = input.group;

check_user_group_keys_set!(
group_data.encrypted_sign_key,
group_data.verify_key,
group_data.public_key_sig,
group_data.keypair_sign_alg
);

let device_data = input.device;
let identifier = hash_token_to_string(device_data.device_identifier.as_bytes())?;

let device_id = user_model::reset_user(
app_id,
&jwt.id,
identifier,
device_data.master_key,
device_data.derived,
)
.await?;

group_data.creator_public_key_id = device_id.to_string();

//delete the old group
group_service::delete_user_group(app_id, &jwt.group_id).await?;

//create user group, insert the device not the user id because the devices are in the group not the user!
let group_id = group_service::create_group(
app_id,
&device_id,
group_data,
GROUP_TYPE_USER,
None,
None,
None,
false,
)
.await?
.0;

//delete the user in app check cache from the jwt mw
let cache_key = get_user_in_app_key(app_id, &jwt.id);
cache::delete(&cache_key).await?;

//now update the user group id
user_model::register_update_user_group_id(app_id, &jwt.id, group_id).await?;

echo_success()
}
36 changes: 36 additions & 0 deletions server_crates/server_api/src/user/user_model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,42 @@ pub(super) async fn register(
Ok((user_id, device_id))
}

pub(super) async fn reset_user(
app_id: impl Into<AppId>,
user_id: impl Into<UserId>,
device_identifier: String,
master_key: MasterKey,
derived: KeyDerivedData,
) -> AppRes<DeviceId>
{
let app_id = app_id.into();
let user_id = user_id.into();

//first delete all devices from the user. the user group keys will be changed.
// the old are not valid anymore which means that old devices can't access the new keys either
//language=SQL
let sql = "DELETE FROM sentc_user_device WHERE user_id = ? AND app_id = ?";

exec(sql, set_params!(user_id.clone(), app_id.clone())).await?;

let device_id = create_id();
let time = get_time()?;
let (sql_keys, key_params) = prepare_register_device(
&device_id,
&user_id,
app_id,
time,
device_identifier,
master_key,
derived,
None,
);

exec(sql_keys, key_params).await?;

Ok(device_id)
}

pub(super) async fn register_device(
app_id: impl Into<AppId>,
device_identifier: String,
Expand Down
124 changes: 62 additions & 62 deletions server_crates/server_api_integration_tests/tests/test_fn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use sentc_crypto::entities::group::{GroupKeyData, GroupOutData};
use sentc_crypto::entities::keys::{HmacKeyFormatInt, PrivateKeyFormatInt, PublicKeyFormatInt, SortableKeyFormatInt, SymKeyFormatInt};
use sentc_crypto::entities::user::{UserDataInt, UserKeyDataInt};
use sentc_crypto::sdk_common::file::FileData;
use sentc_crypto::sdk_common::group::{GroupAcceptJoinReqServerOutput, GroupHmacData, GroupInviteServerOutput, GroupSortableData};
use sentc_crypto::sdk_common::group::{GroupHmacData, GroupSortableData};
use sentc_crypto::sdk_common::user::UserPublicKeyData;
use sentc_crypto::sdk_core::SymKey;
use sentc_crypto::sdk_utils::error::SdkUtilError;
Expand Down Expand Up @@ -436,7 +436,7 @@ pub async fn create_child_group_from_group_as_member(

pub fn decrypt_group_hmac_keys(first_group_key: &SymKeyFormatInt, hmac_keys: Vec<GroupHmacData>) -> Vec<HmacKeyFormatInt>
{
//its important to use the sdk common version here and not from the api
//it's important to use the sdk common version here and not from the api

let mut decrypted_hmac_keys = Vec::with_capacity(hmac_keys.len());

Expand All @@ -449,7 +449,7 @@ pub fn decrypt_group_hmac_keys(first_group_key: &SymKeyFormatInt, hmac_keys: Vec

pub fn decrypt_group_sortable_keys(first_group_key: &SymKeyFormatInt, keys: Vec<GroupSortableData>) -> Vec<SortableKeyFormatInt>
{
//its important to use the sdk common version here and not from the api
//it's important to use the sdk common version here and not from the api

let mut decrypted_keys = Vec::with_capacity(keys.len());

Expand Down Expand Up @@ -554,26 +554,28 @@ pub async fn add_user_by_invite(
group_keys_ref.push(&decrypted_group_key.group_key);
}

let invite = sentc_crypto::group::prepare_group_keys_for_new_member(user_to_add_public_key, &group_keys_ref, false, None).unwrap();

let url = get_url("api/v1/group/".to_owned() + group_id + "/invite_auto/" + user_to_invite_id);

let client = reqwest::Client::new();
let res = client
.put(url)
.header(AUTHORIZATION, auth_header(jwt))
.header("x-sentc-app-token", secret_token)
.body(invite)
.send()
.await
.unwrap();

let body = res.text().await.unwrap();
let join_res = sentc_crypto_full::group::invite_user(
get_base_url(),
secret_token,
jwt,
group_id,
user_to_invite_id,
1,
None,
1,
true,
false,
false,
user_to_add_public_key,
&group_keys_ref,
None,
)
.await
.unwrap();

let join_res: GroupAcceptJoinReqServerOutput = handle_server_response(body.as_str()).unwrap();
assert_eq!(join_res.session_id, None);
assert_eq!(join_res, None);

//accept the invite, no need to accept the invite -> we using auto invite here
//no need to accept the invite -> we're using auto invite here

let data = get_group(
secret_token,
Expand Down Expand Up @@ -608,27 +610,28 @@ pub async fn add_user_by_invite_as_group_as_member(
group_keys_ref.push(&decrypted_group_key.group_key);
}

let invite = sentc_crypto::group::prepare_group_keys_for_new_member(user_to_add_public_key, &group_keys_ref, false, None).unwrap();

let url = get_url("api/v1/group/".to_owned() + group_id + "/invite_auto/" + user_to_invite_id);

let client = reqwest::Client::new();
let res = client
.put(url)
.header(AUTHORIZATION, auth_header(jwt))
.header("x-sentc-app-token", secret_token)
.header("x-sentc-group-access-id", group_with_access)
.body(invite)
.send()
.await
.unwrap();

let body = res.text().await.unwrap();
let join_res = sentc_crypto_full::group::invite_user(
get_base_url(),
secret_token,
jwt,
group_id,
user_to_invite_id,
1,
None,
1,
true,
false,
false,
user_to_add_public_key,
&group_keys_ref,
Some(group_with_access),
)
.await
.unwrap();

let join_res: GroupAcceptJoinReqServerOutput = handle_server_response(body.as_str()).unwrap();
assert_eq!(join_res.session_id, None);
assert_eq!(join_res, None);

//accept the invite, no need to accept the invite -> we using auto invite here
//no need to accept the invite -> we're using auto invite here

let data = get_group(
secret_token,
Expand Down Expand Up @@ -663,29 +666,26 @@ pub async fn add_group_by_invite(
group_keys_ref.push(&decrypted_group_key.group_key);
}

let invite = sentc_crypto::group::prepare_group_keys_for_new_member(group_to_invite_exported_public_key, &group_keys_ref, false, None).unwrap();

let url = get_url("api/v1/group/".to_owned() + group_id + "/invite_group_auto/" + group_to_invite_id);

let client = reqwest::Client::new();
let res = client
.put(url)
.header(AUTHORIZATION, auth_header(jwt))
.header("x-sentc-app-token", secret_token)
.body(invite);

let res = match group_as_member_id {
Some(id) => res.header("x-sentc-group-access-id", id),
None => res,
};

let res = res.send().await.unwrap();

let body = res.text().await.unwrap();

let invite_res: GroupInviteServerOutput = handle_server_response(&body).unwrap();
let join_res = sentc_crypto_full::group::invite_user(
get_base_url(),
secret_token,
jwt,
group_id,
group_to_invite_id,
1,
None,
1,
true,
true,
false,
group_to_invite_exported_public_key,
&group_keys_ref,
group_as_member_id,
)
.await
.unwrap();

assert_eq!(invite_res.session_id, None);
assert_eq!(join_res, None);

get_group_from_group_as_member(
secret_token,
Expand Down
Loading

0 comments on commit 65f78e7

Please sign in to comment.