Skip to content

Use user_uid over user_email ubiquitously #3386

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

Merged
merged 5 commits into from
Apr 14, 2025
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions common/primitives/core/src/identity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -577,6 +577,9 @@ impl Identity {
Web2IdentityType::Google => {
Identity::Google(IdentityString::new(handle.as_bytes().to_vec()))
}
Web2IdentityType::Pumpx => {
Identity::Pumpx(IdentityString::new(handle.as_bytes().to_vec()))
}
}
}
}
Expand All @@ -588,6 +591,7 @@ pub enum Web2IdentityType {
Github,
Email,
Google,
Pumpx,
}

impl From<ed25519::Public> for Identity {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,13 @@ export default {
__Unused17: "Null",
__Unused18: "Null",
__Unused19: "Null",
PumpxRequestJwt: "(Identity, Option<String>, Option<String>, Option<String>)",
PumpxRequestJwt: "(Identity, String, Option<String>, Option<String>, Option<String>)",
},
},
OmniAuth: {
_enum: {
Web3: "(HeimaMultiSignature)",
Email: "(Text)",
Email: "(Text, Text)",
AuthToken: "(Text)",
OAuth2: "(OAuth2Data)",
},
Expand Down
2 changes: 1 addition & 1 deletion tee-worker/omni-executor/executor-core/src/native_task.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ pub enum NativeTask {

// pumpx specific, starting from index 20
#[codec(index = 20)]
PumpxRequestJwt(Identity, Option<String>, GoogleCode, Option<String>),
PumpxRequestJwt(Identity, String, Option<String>, GoogleCode, Option<String>),
#[codec(index = 21)]
PumpxExportWallet(Identity, GoogleCode, PumpxChainId, PumxWalletIndex, String),
#[codec(index = 22)]
Expand Down
4 changes: 2 additions & 2 deletions tee-worker/omni-executor/executor-primitives/src/auth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ pub type VerificationCode = String;
#[derive(Encode, Decode, Clone, Debug, PartialEq, Eq)]
pub enum OmniAuth {
Web3(HeimaMultiSignature),
Email(VerificationCode),
Email(String, VerificationCode),
AuthToken(String),
OAuth2(OAuth2Data),
}
Expand All @@ -15,7 +15,7 @@ impl From<OmniAuth> for OmniAccountAuthType {
fn from(value: OmniAuth) -> Self {
match value {
OmniAuth::Web3(_) => Self::Web3,
OmniAuth::Email(_) => Self::Email,
OmniAuth::Email(..) => Self::Email,
OmniAuth::OAuth2(_) => Self::OAuth2,
OmniAuth::AuthToken(_) => Self::AuthToken,
}
Expand Down
12 changes: 6 additions & 6 deletions tee-worker/omni-executor/heima/authentication/src/auth_token.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,8 +105,8 @@ mod tests {
.expect("Failed to calculate expiration")
.timestamp();

let email_identity = Identity::from_web2_account("test@test.com", Web2IdentityType::Email);
let omni_account = email_identity.to_omni_account();
let uid = Identity::from_web2_account("012345", Web2IdentityType::Pumpx);
let omni_account = uid.to_omni_account();

let claims = AuthTokenClaims::new(
omni_account.to_hex(),
Expand All @@ -128,8 +128,8 @@ mod tests {
RsaPrivateKey::new(&mut rng, 2048).expect("Failed to generate private key");
let private_key = rsa_private_key.to_pkcs1_der().unwrap();

let email_identity = Identity::from_web2_account("test@test.com", Web2IdentityType::Email);
let omni_account = email_identity.to_omni_account();
let uid = Identity::from_web2_account("012345", Web2IdentityType::Pumpx);
let omni_account = uid.to_omni_account();

let claims = AuthTokenClaims::new(
omni_account.to_hex(),
Expand All @@ -156,8 +156,8 @@ mod tests {
.expect("Failed to calculate expiration")
.timestamp();

let email_identity = Identity::from_web2_account("test@test.com", Web2IdentityType::Email);
let omni_account = email_identity.to_omni_account();
let uid = Identity::from_web2_account("012345", Web2IdentityType::Pumpx);
let omni_account = uid.to_omni_account();

let claims = AuthTokenClaims::new(
omni_account.to_hex(),
Expand Down
60 changes: 29 additions & 31 deletions tee-worker/omni-executor/native-task-handler/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ use executor_crypto::{
jwt,
};
use executor_primitives::{
utils::hex::ToHexPrefixed, Identity, Intent, MemberAccount, OmniAccountAuthType, ValidationData,
utils::hex::ToHexPrefixed, Identity, Intent, MemberAccount, OmniAccountAuthType,
ValidationData, Web2IdentityType,
};
use executor_storage::{MemberOmniAccountStorage, PumpxJwtStorage, Storage, StorageDB};
use heima_authentication::auth_token::*;
Expand Down Expand Up @@ -559,36 +560,29 @@ async fn handle_native_task<
let tx = ctx.transaction_signer.sign(dispatch_as_omni_account_call).await;
(response_sender, tx)
},
NativeTask::PumpxRequestJwt(sender, invite_code, google_code, language) => {
let email = match sender {
Identity::Email(ref identity_string) => {
let Ok(email) = std::str::from_utf8(identity_string.inner_ref()) else {
send_error(
"Invalid email identity".to_string(),
response_sender,
NativeTaskError::InvalidMemberIdentity,
);
return;
};
email.to_string()
},
_ => {
send_error(
"Unsupported identity type".to_string(),
response_sender,
NativeTaskError::UnsupportedIdentityType,
);
return;
},
};
NativeTask::PumpxRequestJwt(_sender, email, invite_code, google_code, language) => {
let expires_at = Utc::now()
.checked_add_days(Days::new(AUTH_TOKEN_EXPIRATION_DAYS))
.expect("Failed to calculate expiration")
.timestamp();
let auth_options = AuthOptions { expires_at };

let Ok(res) = ctx.pumpx_api.get_account_user_id(email.clone()).await else {
send_error(
"Failed to get_account_user_id".to_string(),
response_sender,
NativeTaskError::PumpxApiError(PumpxApiError::GetAccountUserIdFailed),
);
return;
};

let user_id = res.user_id;
log::debug!("get_account_user_id ok, email: {}, user_id: {}", email, user_id);
let omni_account =
Identity::from_web2_account(&user_id, Web2IdentityType::Pumpx).to_omni_account();

let access_token_claims = AuthTokenClaims::new(
sender.to_omni_account().to_hex(),
omni_account.to_hex(),
AUTH_TOKEN_ACCESS_TYPE.to_string(),
auth_options.clone(),
);
Expand All @@ -604,7 +598,7 @@ async fn handle_native_task<

let storage = PumpxJwtStorage::new(ctx.storage_db.clone());
if storage
.insert((sender.to_omni_account(), AUTH_TOKEN_ACCESS_TYPE), access_token.clone())
.insert((omni_account.clone(), AUTH_TOKEN_ACCESS_TYPE), access_token.clone())
.is_err()
{
log::error!(
Expand All @@ -615,7 +609,14 @@ async fn handle_native_task<

let Ok(backend_response) = ctx
.pumpx_api
.user_connect(&access_token, email.clone(), invite_code, google_code, language)
.user_connect(
&access_token,
user_id.clone(),
email.clone(),
invite_code,
google_code,
language,
)
.await
else {
send_error(
Expand All @@ -626,7 +627,7 @@ async fn handle_native_task<
return;
};
let id_token_claims = AuthTokenClaims::new(
sender.to_omni_account().to_hex(),
omni_account.to_hex(),
AUTH_TOKEN_ID_TYPE.to_string(),
auth_options,
);
Expand All @@ -639,10 +640,7 @@ async fn handle_native_task<
return;
};

if storage
.insert((sender.to_omni_account(), AUTH_TOKEN_ID_TYPE), id_token.clone())
.is_err()
{
if storage.insert((omni_account, AUTH_TOKEN_ID_TYPE), id_token.clone()).is_err() {
log::error!("Failed to insert pumpx_{}_jwt_token into storage", AUTH_TOKEN_ID_TYPE);
};

Expand Down
1 change: 1 addition & 0 deletions tee-worker/omni-executor/native-task-handler/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ pub enum PumpxApiError {
CreateTransferUnsignedTxFailed,
SendTransferTxFailed,
CreateTransferTxFailed,
GetAccountUserIdFailed,
}

#[derive(Encode, Decode, Clone, Debug, PartialEq, Eq)]
Expand Down
21 changes: 16 additions & 5 deletions tee-worker/omni-executor/pumpx/src/pumpx_api/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,11 @@ use types::{
AddWalletResponse, CreateCrossOrderBody, CreateLimitOrderBody, CreateMarketOrderTxBody,
CreateMarketOrderTxResponse, CreateMarketOrderUnsignedTxBody,
CreateMarketOrderUnsignedTxResponse, CreateTransferTxBody, CreateTransferTxResponse,
CreateTransferUnsignedTxBody, CreateTransferUnsignedTxResponse, CrossFailBody, GetGasInfoBody,
GetGasInfoResponse, GoogleCode, OrderInfoResponse, SendOrderTxBody, SendOrderTxResponse,
SendTransferTxBody, SendTransferTxResponse, UserConnectBody, UserConnectResponse,
UserTradeInfoResponse, VerifyGoogleCodeResponse,
CreateTransferUnsignedTxBody, CreateTransferUnsignedTxResponse, CrossFailBody,
GetAccountUserIdBody, GetAccountUserIdResponseData, GetGasInfoBody, GetGasInfoResponse,
GoogleCode, OrderInfoResponse, SendOrderTxBody, SendOrderTxResponse, SendTransferTxBody,
SendTransferTxResponse, UserConnectBody, UserConnectResponse, UserTradeInfoResponse,
VerifyGoogleCodeResponse,
};
use url::Url;

Expand Down Expand Up @@ -37,13 +38,14 @@ impl PumpxApi {
pub async fn user_connect(
&self,
access_token: &str,
user_id: String,
email: String,
invite_code: Option<String>,
google_code: String,
language: Option<String>,
) -> Result<UserConnectResponse, Error> {
let endpoint = format!("{}/v3/account/user_connect", self.base_url);
let body = UserConnectBody { email: email.clone(), invite_code, google_code };
let body = UserConnectBody { email, invite_code, google_code, user_id };

let response = self
.http_client
Expand Down Expand Up @@ -426,4 +428,13 @@ impl PumpxApi {
.json()
.await
}

pub async fn get_account_user_id(
&self,
email: String,
) -> Result<GetAccountUserIdResponseData, Error> {
let endpoint = format!("{}/v3/account/get_account_user_id", self.base_url);
let body = GetAccountUserIdBody { email };
self.http_client.get(&endpoint).json(&body).send().await?.json().await
}
}
14 changes: 14 additions & 0 deletions tee-worker/omni-executor/pumpx/src/pumpx_api/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ pub struct UserConnectBody {
pub email: String,
pub invite_code: Option<String>,
pub google_code: String,
pub user_id: String,
}

#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Eq, Clone)]
Expand Down Expand Up @@ -333,3 +334,16 @@ pub struct GasInfo {
pub fast_price: String,
pub super_fast_price: String,
}

// /v3/account/get_account_user_id
#[derive(Serialize, Debug)]
#[serde(rename_all = "camelCase")]
pub struct GetAccountUserIdBody {
pub email: String,
}

#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Eq, Clone)]
#[serde(rename_all = "camelCase")]
pub struct GetAccountUserIdResponseData {
pub user_id: String,
}
3 changes: 3 additions & 0 deletions tee-worker/omni-executor/rpc-server/src/error_code.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ const AUTH_TOKEN_CREATION_FAILED_CODE: i32 = -32007;
const INVALID_MEMBER_IDENTITY_CODE: i32 = -32008;
const VALIDATION_DATA_VERIFICATION_FAILED_CODE: i32 = -32009;
const UNSUPPORTED_IDENTITY_TYPE_CODE: i32 = -32010;
pub const USER_EMAIL_ID_MISMATCH_CODE: i32 = -32011;

const PUMPX_API_GOOGLE_CODE_VERIFICATION_FAILED_CODE: i32 = -32031;
const PUMPX_API_USER_CONNECTION_FAILED_CODE: i32 = -32032;
Expand All @@ -24,6 +25,7 @@ const PUMPX_API_CREATE_TRANSFER_UNSIGNED_TX_FAILED_CODE: i32 = -32035;
const PUMPX_API_SEND_TRANSFER_TX_FAILED_CODE: i32 = -32036;
const PUMPX_API_INVALID_INPUT_FAILED_CODE: i32 = -32037;
const PUMPX_API_CREATE_TRANSFER_TX_FAILED_CODE: i32 = -32038;
pub const PUMPX_API_GET_ACCOUNT_USER_ID_FAILED_CODE: i32 = -32039;

const PUMPX_SIGNER_REQUEST_SIGNATURE_FAILED_CODE: i32 = -32050;

Expand Down Expand Up @@ -51,6 +53,7 @@ pub fn get_native_task_error_code(error: &NativeTaskError) -> i32 {
PumpxApiError::SendTransferTxFailed => PUMPX_API_SEND_TRANSFER_TX_FAILED_CODE,
PumpxApiError::InvalidInput => PUMPX_API_INVALID_INPUT_FAILED_CODE,
PumpxApiError::CreateTransferTxFailed => PUMPX_API_CREATE_TRANSFER_TX_FAILED_CODE,
PumpxApiError::GetAccountUserIdFailed => PUMPX_API_GET_ACCOUNT_USER_ID_FAILED_CODE,
},
NativeTaskError::PumpxSignerError(signer_error) => match signer_error {
PumpxSignerError::RequestSignatureFailed => PUMPX_SIGNER_REQUEST_SIGNATURE_FAILED_CODE,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ pub fn register_request_email_verification_code(module: &mut RpcModule<RpcContex
module
.register_async_method("omni_requestEmailVerificationCode", |params, ctx, _| async move {
let params = params.parse::<RequestEmailVerificationCodeParams>()?;
// please note here we still use `email_identity` as key
let email_identity =
Identity::from_web2_account(&params.user_email, Web2IdentityType::Email);
let verification_code_storage = VerificationCodeStorage::new(ctx.storage_db.clone());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use serde::Serialize;

#[derive(Debug, Deserialize)]
pub struct AddWalletParams {
pub user_email: String,
pub user_id: String,
pub auth_token: String,
}

Expand All @@ -25,8 +25,8 @@ impl From<AddWalletParams> for NativeTaskWrapper<NativeTask> {
fn from(p: AddWalletParams) -> Self {
Self {
task: NativeTask::PumpxAddWallet(Identity::from_web2_account(
p.user_email.as_str(),
Web2IdentityType::Email,
p.user_id.as_str(),
Web2IdentityType::Pumpx,
)),
nonce: None,
auth: Some(OmniAuth::AuthToken(p.auth_token)),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ use sha2::Sha256;

#[derive(Debug, Deserialize)]
pub struct ExportWalletParams {
pub user_id: String,
pub user_email: String,
pub key: Bytes, // RSA-encrypted AES key to encrypt the wallet private key, in 0x-hex-string
pub google_code: String,
Expand All @@ -27,14 +28,14 @@ impl From<ExportWalletParams> for NativeTaskWrapper<NativeTask> {
fn from(p: ExportWalletParams) -> Self {
Self {
task: NativeTask::PumpxExportWallet(
Identity::from_web2_account(p.user_email.as_str(), Web2IdentityType::Email),
Identity::from_web2_account(p.user_id.as_str(), Web2IdentityType::Pumpx),
p.google_code,
p.chain_id,
p.wallet_index,
p.wallet_address,
),
nonce: None,
auth: Some(OmniAuth::Email(p.email_code)),
auth: Some(OmniAuth::Email(p.user_email, p.email_code)),
}
}
}
Expand All @@ -59,6 +60,24 @@ pub fn register_export_wallet(module: &mut RpcModule<RpcContext>) {
ErrorObject::owned::<()>(AES_KEY_CONVERT_FAILED_CODE, "AesKey convert failed", None)
})?;

// verify user_id and user_email matches
let Ok(res) = ctx.pumpx_api.get_account_user_id(params.user_email.clone()).await else {
log::error!("Failed to call get_account_user_id");
return Err(
ErrorCode::ServerError(PUMPX_API_GET_ACCOUNT_USER_ID_FAILED_CODE).into()
);
};

if res.user_id != params.user_id {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we query it from backend anyway can we simply not accept it from frontend ?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it gives us extra chance to tell F/E something goes wrong early.
If F/E doesn't pass in user_email - it could still give the wrong/arbitrary user_id. Now at least they need to pass in matching pairs.

log::error!(
"Parameter mismatch: user_id {} and user_email {}, expected user_id {}",
params.user_id,
params.user_email,
res.user_id
);
return Err(ErrorCode::ServerError(USER_EMAIL_ID_MISMATCH_CODE).into());
}

let wrapper: NativeTaskWrapper<NativeTask> = params.into();

if wrapper.task.require_auth() && verify_auth(ctx.clone(), &wrapper).await.is_err() {
Expand Down
Loading
Loading