handle addresses consistently

This commit is contained in:
Bryan Stitt 2023-06-24 10:20:24 -07:00
parent 39a505c0ff
commit 9115419ec0
10 changed files with 27 additions and 67 deletions

@ -26,7 +26,7 @@ pub async fn query_admin_modify_usertier<'a>(
params: &'a HashMap<String, String>, params: &'a HashMap<String, String>,
) -> Web3ProxyResponse { ) -> Web3ProxyResponse {
// Quickly return if any of the input tokens are bad // Quickly return if any of the input tokens are bad
let user_address: Vec<u8> = params let user_address = params
.get("user_address") .get("user_address")
.ok_or_else(|| { .ok_or_else(|| {
Web3ProxyError::BadRequest("Unable to find user_address key in request".into()) Web3ProxyError::BadRequest("Unable to find user_address key in request".into())
@ -34,9 +34,7 @@ pub async fn query_admin_modify_usertier<'a>(
.parse::<Address>() .parse::<Address>()
.map_err(|_| { .map_err(|_| {
Web3ProxyError::BadRequest("Unable to parse user_address as an Address".into()) Web3ProxyError::BadRequest("Unable to parse user_address as an Address".into())
})? })?;
.to_fixed_bytes()
.into();
let user_tier_title = params.get("user_tier_title").ok_or_else(|| { let user_tier_title = params.get("user_tier_title").ok_or_else(|| {
Web3ProxyError::BadRequest("Unable to get the user_tier_title key from the request".into()) Web3ProxyError::BadRequest("Unable to get the user_tier_title key from the request".into())
})?; })?;
@ -78,7 +76,7 @@ pub async fn query_admin_modify_usertier<'a>(
// Fetch the admin, and the user // Fetch the admin, and the user
let user: user::Model = user::Entity::find() let user: user::Model = user::Entity::find()
.filter(user::Column::Address.eq(user_address)) .filter(user::Column::Address.eq(user_address.as_bytes()))
.one(&db_conn) .one(&db_conn)
.await? .await?
.ok_or(Web3ProxyError::BadRequest( .ok_or(Web3ProxyError::BadRequest(

@ -26,15 +26,12 @@ impl ChangeAdminStatusSubCommand {
let address: Address = self.address.parse()?; let address: Address = self.address.parse()?;
let should_be_admin: bool = self.should_be_admin; let should_be_admin: bool = self.should_be_admin;
// we keep "address" around for use in logs
let address_vec: Vec<u8> = address.to_fixed_bytes().into();
// Find user in database // Find user in database
let user = user::Entity::find() let user = user::Entity::find()
.filter(user::Column::Address.eq(address_vec)) .filter(user::Column::Address.eq(address.as_bytes()))
.one(db_conn) .one(db_conn)
.await? .await?
.context(format!("No user with this id found {:?}", address))?; .context(format!("No user with this address found {:?}", address))?;
debug!("user: {:#}", json!(&user)); debug!("user: {:#}", json!(&user));
@ -59,7 +56,7 @@ impl ChangeAdminStatusSubCommand {
info!("granted admin status"); info!("granted admin status");
} }
_ => { _ => {
info!("no change needed for: {:#?}", user); info!("no change needed for: {:#}", json!(user));
// Since no change happened, we do not want to delete active logins. Return now. // Since no change happened, we do not want to delete active logins. Return now.
return Ok(()); return Ok(());
} }

@ -27,29 +27,24 @@ impl ChangeUserAddressSubCommand {
let old_address: Address = self.old_address.parse()?; let old_address: Address = self.old_address.parse()?;
let new_address: Address = self.new_address.parse()?; let new_address: Address = self.new_address.parse()?;
let old_address: Vec<u8> = old_address.to_fixed_bytes().into();
let new_address: Vec<u8> = new_address.to_fixed_bytes().into();
let u = user::Entity::find() let u = user::Entity::find()
.filter(user::Column::Address.eq(old_address)) .filter(user::Column::Address.eq(old_address.as_bytes()))
.one(db_conn) .one(db_conn)
.await? .await?
.context("No user found with that address")?; .context("No user found with that address")?;
debug!("initial user: {:#}", json!(&u)); debug!("initial user: {:#}", json!(&u));
if u.address == new_address { if u.address == new_address.as_bytes() {
info!("user already has this address"); info!("user already has this address");
} else { } else {
let mut u = u.into_active_model(); let mut u = u.into_active_model();
u.address = sea_orm::Set(new_address); u.address = sea_orm::Set(new_address.as_bytes().to_vec());
let u = u.save(db_conn).await?; let u = u.save(db_conn).await?;
info!("changed user address"); info!("updated user: {:#?}", u);
debug!("updated user: {:#?}", u);
} }
Ok(()) Ok(())

@ -24,11 +24,9 @@ pub struct ChangeUserTierByAddressSubCommand {
impl ChangeUserTierByAddressSubCommand { impl ChangeUserTierByAddressSubCommand {
pub async fn main(self, db_conn: &DatabaseConnection) -> anyhow::Result<()> { pub async fn main(self, db_conn: &DatabaseConnection) -> anyhow::Result<()> {
let address: Vec<u8> = self.user_address.to_fixed_bytes().into();
// use the address to get the user // use the address to get the user
let user = user::Entity::find() let user = user::Entity::find()
.filter(user::Column::Address.eq(address)) .filter(user::Column::Address.eq(self.user_address.as_bytes()))
.one(db_conn) .one(db_conn)
.await? .await?
.context("No user found with that key")?; .context("No user found with that key")?;

@ -16,7 +16,7 @@ pub struct CreateKeySubCommand {
/// If a string is given, it will be converted to hex and potentially truncated. /// If a string is given, it will be converted to hex and potentially truncated.
/// Users from strings are only for testing since they won't be able to log in. /// Users from strings are only for testing since they won't be able to log in.
#[argh(positional)] #[argh(positional)]
address: String, address: Address,
/// the user's api ULID or UUID key. /// the user's api ULID or UUID key.
/// If none given, one will be created. /// If none given, one will be created.
@ -30,27 +30,9 @@ pub struct CreateKeySubCommand {
impl CreateKeySubCommand { impl CreateKeySubCommand {
pub async fn main(self, db: &sea_orm::DatabaseConnection) -> anyhow::Result<()> { pub async fn main(self, db: &sea_orm::DatabaseConnection) -> anyhow::Result<()> {
// TODO: would be nice to use the fixed array instead of a Vec in the entities
// take a simple String. If it starts with 0x, parse as address. otherwise convert ascii to hex
let address: Vec<u8> = if self.address.starts_with("0x") {
let address = self.address.parse::<Address>()?;
address.to_fixed_bytes().into()
} else {
// TODO: allow ENS
// left pad and truncate the string
let address = &format!("{:\x00>20}", self.address)[0..20];
// convert the string to bytes
let bytes = address.as_bytes();
// convert the slice to a Vec
bytes.try_into().expect("Bytes can always be a Vec<u8>")
};
// TODO: get existing or create a new one // TODO: get existing or create a new one
let u = user::Entity::find() let u = user::Entity::find()
.filter(user::Column::Address.eq(address)) .filter(user::Column::Address.eq(self.address.as_bytes()))
.one(db) .one(db)
.await? .await?
.context("No user found with that address")?; .context("No user found with that address")?;

@ -93,11 +93,11 @@ impl RpcAccountingSubCommand {
// TODO: do this with add_option? try operator is harder to use then // TODO: do this with add_option? try operator is harder to use then
if let Some(address) = self.address { if let Some(address) = self.address {
let address: Vec<u8> = address.parse::<Address>()?.to_fixed_bytes().into(); let address = address.parse::<Address>()?;
// TODO: find_with_related // TODO: find_with_related
let u = user::Entity::find() let u = user::Entity::find()
.filter(user::Column::Address.eq(address)) .filter(user::Column::Address.eq(address.as_bytes()))
.one(db_conn) .one(db_conn)
.await? .await?
.context("no user found")?; .context("no user found")?;

@ -29,8 +29,6 @@ impl TransferKeySubCommand {
let new_address: Address = self.new_address.parse()?; let new_address: Address = self.new_address.parse()?;
let new_address: Vec<u8> = new_address.to_fixed_bytes().into();
let uk = rpc_key::Entity::find() let uk = rpc_key::Entity::find()
.filter(rpc_key::Column::SecretKey.eq(rpc_secret_key)) .filter(rpc_key::Column::SecretKey.eq(rpc_secret_key))
.one(db_conn) .one(db_conn)
@ -40,7 +38,7 @@ impl TransferKeySubCommand {
debug!("user key: {}", serde_json::to_string(&uk)?); debug!("user key: {}", serde_json::to_string(&uk)?);
let new_u = user::Entity::find() let new_u = user::Entity::find()
.filter(user::Column::Address.eq(new_address)) .filter(user::Column::Address.eq(new_address.as_bytes()))
.one(db_conn) .one(db_conn)
.await? .await?
.context("No user found with that key")?; .context("No user found with that key")?;

@ -125,7 +125,7 @@ impl UserImportSubCommand {
for import_u in us.into_iter() { for import_u in us.into_iter() {
// first, check if a user already exists with this address // first, check if a user already exists with this address
if let Some(existing_u) = user::Entity::find() if let Some(existing_u) = user::Entity::find()
.filter(user::Column::Address.eq(import_u.address.clone())) .filter(user::Column::Address.eq(import_u.address))
.one(db_conn) .one(db_conn)
.await? .await?
{ {

@ -7,7 +7,6 @@ use crate::errors::Web3ProxyResponse;
use crate::errors::{Web3ProxyError, Web3ProxyErrorContext}; use crate::errors::{Web3ProxyError, Web3ProxyErrorContext};
use crate::user_token::UserBearerToken; use crate::user_token::UserBearerToken;
use crate::PostLogin; use crate::PostLogin;
use anyhow::Context;
use axum::{ use axum::{
extract::{Path, Query}, extract::{Path, Query},
headers::{authorization::Bearer, Authorization}, headers::{authorization::Bearer, Authorization},
@ -73,8 +72,6 @@ pub async fn admin_increase_balance(
Web3ProxyError::BadRequest("Unable to parse user_address as an Address".into()) Web3ProxyError::BadRequest("Unable to parse user_address as an Address".into())
})?; })?;
let user_address_bytes: Vec<u8> = user_address.to_fixed_bytes().into();
let note: String = params let note: String = params
.get("note") .get("note")
.ok_or_else(|| Web3ProxyError::BadRequest("Unable to find 'note' key in request".into()))? .ok_or_else(|| Web3ProxyError::BadRequest("Unable to find 'note' key in request".into()))?
@ -95,11 +92,11 @@ pub async fn admin_increase_balance(
})?; })?;
let user_entry: user::Model = user::Entity::find() let user_entry: user::Model = user::Entity::find()
.filter(user::Column::Address.eq(user_address_bytes.clone())) .filter(user::Column::Address.eq(user_address.as_bytes()))
.one(&txn) .one(&txn)
.await? .await?
.ok_or(Web3ProxyError::BadRequest( .ok_or(Web3ProxyError::BadRequest(
"No user with this id found".into(), format!("No user found with {:?}", user_address).into(),
))?; ))?;
let increase_balance_receipt = admin_increase_balance_receipt::ActiveModel { let increase_balance_receipt = admin_increase_balance_receipt::ActiveModel {
@ -200,7 +197,7 @@ pub async fn admin_login_get(
})?; })?;
// Fetch the user_address parameter from the login string ... (as who we want to be logging in ...) // Fetch the user_address parameter from the login string ... (as who we want to be logging in ...)
let user_address: Vec<u8> = params let user_address: Address = params
.get("user_address") .get("user_address")
.ok_or_else(|| { .ok_or_else(|| {
Web3ProxyError::BadRequest("Unable to find user_address key in request".into()) Web3ProxyError::BadRequest("Unable to find user_address key in request".into())
@ -208,9 +205,7 @@ pub async fn admin_login_get(
.parse::<Address>() .parse::<Address>()
.map_err(|_err| { .map_err(|_err| {
Web3ProxyError::BadRequest("Unable to parse user_address as an Address".into()) Web3ProxyError::BadRequest("Unable to parse user_address as an Address".into())
})? })?;
.to_fixed_bytes()
.into();
// We want to login to llamanodes.com // We want to login to llamanodes.com
let login_domain = app let login_domain = app
@ -228,8 +223,8 @@ pub async fn admin_login_get(
// TODO: don't unwrap // TODO: don't unwrap
// TODO: accept a login_domain from the request? // TODO: accept a login_domain from the request?
domain: login_domain.parse().unwrap(), domain: login_domain.parse().unwrap(),
// In the case of the admin, the admin needs to sign the message, so we include this logic ... // the admin needs to sign the message, not the imitated user
address: admin_address.to_fixed_bytes(), // user_address.to_fixed_bytes(), address: admin_address.to_fixed_bytes(),
// TODO: config for statement // TODO: config for statement
statement: Some("🦙🦙🦙🦙🦙".to_string()), statement: Some("🦙🦙🦙🦙🦙".to_string()),
// TODO: don't unwrap // TODO: don't unwrap
@ -244,8 +239,6 @@ pub async fn admin_login_get(
resources: vec![], resources: vec![],
}; };
let admin_address: Vec<u8> = admin_address.to_fixed_bytes().into();
let db_conn = app.db_conn().web3_context("login requires a database")?; let db_conn = app.db_conn().web3_context("login requires a database")?;
let db_replica = app let db_replica = app
.db_replica() .db_replica()
@ -264,7 +257,7 @@ pub async fn admin_login_get(
// Get the user that we want to imitate from the read-only database (their id ...) // Get the user that we want to imitate from the read-only database (their id ...)
// TODO: Only get the id, not the whole user object ... // TODO: Only get the id, not the whole user object ...
let user = user::Entity::find() let user = user::Entity::find()
.filter(user::Column::Address.eq(user_address)) .filter(user::Column::Address.eq(user_address.as_bytes()))
.one(db_replica.as_ref()) .one(db_replica.as_ref())
.await? .await?
.ok_or(Web3ProxyError::BadRequest( .ok_or(Web3ProxyError::BadRequest(
@ -273,9 +266,8 @@ pub async fn admin_login_get(
// TODO: Gotta check if encoding messes up things maybe ... // TODO: Gotta check if encoding messes up things maybe ...
info!("Admin address is: {:?}", admin_address); info!("Admin address is: {:?}", admin_address);
info!("Encoded admin address is: {:?}", admin_address);
let admin = user::Entity::find() let admin = user::Entity::find()
.filter(user::Column::Address.eq(admin_address)) .filter(user::Column::Address.eq(admin_address.as_bytes()))
.one(db_replica.as_ref()) .one(db_replica.as_ref())
.await? .await?
.ok_or(Web3ProxyError::BadRequest( .ok_or(Web3ProxyError::BadRequest(
@ -287,7 +279,7 @@ pub async fn admin_login_get(
caller: sea_orm::Set(admin.id), caller: sea_orm::Set(admin.id),
imitating_user: sea_orm::Set(Some(user.id)), imitating_user: sea_orm::Set(Some(user.id)),
endpoint: sea_orm::Set("admin_login_get".to_string()), endpoint: sea_orm::Set("admin_login_get".to_string()),
payload: sea_orm::Set(format!("{:?}", params)), payload: sea_orm::Set(format!("{}", json!(params))),
..Default::default() ..Default::default()
}; };
trail trail

@ -282,7 +282,7 @@ pub async fn user_balance_post(
); );
let recipient = match user::Entity::find() let recipient = match user::Entity::find()
.filter(user::Column::Address.eq(recipient_account.to_fixed_bytes().as_slice())) .filter(user::Column::Address.eq(recipient_account.as_bytes()))
.one(&txn) .one(&txn)
.await? .await?
{ {