web3-proxy/web3_proxy/src/sub_commands/create_user.rs

92 lines
2.9 KiB
Rust
Raw Normal View History

use crate::frontend::authorization::RpcSecretKey;
use anyhow::Context;
use argh::FromArgs;
2022-11-01 21:54:39 +03:00
use entities::{rpc_key, user};
2022-08-15 20:50:14 +03:00
use ethers::prelude::Address;
2022-11-14 21:24:52 +03:00
use migration::sea_orm::{self, ActiveModelTrait, TransactionTrait};
use tracing::info;
2022-09-24 08:53:45 +03:00
use ulid::Ulid;
2022-08-15 20:50:14 +03:00
use uuid::Uuid;
2022-08-15 20:50:14 +03:00
#[derive(FromArgs, PartialEq, Debug, Eq)]
2022-08-06 09:17:49 +03:00
/// Create a new user and api key
#[argh(subcommand, name = "create_user")]
pub struct CreateUserSubCommand {
2022-09-24 10:03:42 +03:00
/// the user's ethereum address or descriptive string.
/// 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.
2022-10-26 00:10:05 +03:00
#[argh(option)]
2022-09-24 10:03:42 +03:00
address: String,
2022-09-24 08:53:45 +03:00
/// the user's optional email.
2022-10-26 00:10:05 +03:00
#[argh(option)]
email: Option<String>,
2022-08-15 20:50:14 +03:00
2022-09-24 08:53:45 +03:00
/// the user's first api ULID or UUID key.
/// If none given, one will be created.
2022-10-26 00:10:05 +03:00
#[argh(option)]
2022-11-08 02:00:08 +03:00
rpc_secret_key: Option<RpcSecretKey>,
2022-10-10 07:15:07 +03:00
2022-10-26 00:10:05 +03:00
/// an optional short description of the key's purpose.
2022-10-10 07:15:07 +03:00
#[argh(option)]
description: Option<String>,
}
impl CreateUserSubCommand {
pub async fn main(self, db: &sea_orm::DatabaseConnection) -> anyhow::Result<()> {
2022-08-16 20:47:04 +03:00
let txn = db.begin().await?;
2022-08-06 09:57:29 +03:00
// TODO: would be nice to use the fixed array instead of a Vec in the entities
2022-09-24 10:03:42 +03:00
// take a simple String. If it starts with 0x, parse as address. otherwise convert ascii to hex
let address = if self.address.starts_with("0x") {
let address = self.address.parse::<Address>()?;
address.to_fixed_bytes().into()
} else {
2022-09-24 10:18:33 +03:00
// left pad and truncate the string
let address = &format!("{:\x00>20}", self.address)[0..20];
2022-09-24 10:03:42 +03:00
2022-09-24 10:18:33 +03:00
// convert the string to bytes
let bytes = address.as_bytes();
2022-09-24 10:03:42 +03:00
2022-09-24 10:18:33 +03:00
// convert the slice to a Vec
2022-09-30 07:18:18 +03:00
bytes.try_into().expect("Bytes can always be a Vec<u8>")
2022-09-24 10:03:42 +03:00
};
2022-09-24 08:53:45 +03:00
// TODO: get existing or create a new one
let u = user::ActiveModel {
address: sea_orm::Set(address),
email: sea_orm::Set(self.email),
..Default::default()
};
2022-08-16 20:47:04 +03:00
let u = u.save(&txn).await.context("Failed saving new user")?;
2022-08-16 20:47:04 +03:00
info!(
"user #{}: {:?}",
u.id.as_ref(),
Address::from_slice(u.address.as_ref())
);
2022-11-08 02:00:08 +03:00
let rpc_secret_key = self.rpc_secret_key.unwrap_or_else(RpcSecretKey::new);
// create a key for the new user
2022-11-01 21:54:39 +03:00
let uk = rpc_key::ActiveModel {
2022-08-16 20:47:04 +03:00
user_id: u.id,
2022-11-08 02:00:08 +03:00
secret_key: sea_orm::Set(rpc_secret_key.into()),
2022-10-10 07:15:07 +03:00
description: sea_orm::Set(self.description),
..Default::default()
};
2022-08-15 22:28:15 +03:00
// TODO: if this fails, rever adding the user, too
2022-10-10 07:15:07 +03:00
let _uk = uk.save(&txn).await.context("Failed saving new user key")?;
2022-08-16 20:47:04 +03:00
txn.commit().await?;
2022-11-08 02:00:08 +03:00
info!("user key as ULID: {}", Ulid::from(rpc_secret_key));
info!("user key as UUID: {}", Uuid::from(rpc_secret_key));
Ok(())
}
}