admin keys from env test operator inspection test vm creation timeout extensive tests on airdrop refactor db module imports fix register vm_node creates operator account in db modularised test into its module and reusable method fix test brain message add ssh port on mock daemon while new vm improved error handling on tests unwraping only on top level method test utils methods accepts refs to remove clone() on top level methods
178 lines
6.2 KiB
Rust
178 lines
6.2 KiB
Rust
pub mod app;
|
|
pub mod general;
|
|
pub mod types;
|
|
pub mod vm;
|
|
|
|
use crate::constants::ADMIN_ACCOUNTS;
|
|
use detee_shared::common_proto::{Empty, Pubkey};
|
|
use detee_shared::general_proto::{
|
|
AirdropReq, BanUserReq, KickReq, RegOperatorReq, ReportNodeReq, SlashReq,
|
|
};
|
|
use detee_shared::vm_proto::{ListVmContractsReq, *};
|
|
use tonic::{Request, Status};
|
|
|
|
pub trait PubkeyGetter {
|
|
fn get_pubkey(&self) -> Option<String>;
|
|
}
|
|
|
|
macro_rules! impl_pubkey_getter {
|
|
($t:ty, $field:ident) => {
|
|
impl PubkeyGetter for $t {
|
|
fn get_pubkey(&self) -> Option<String> {
|
|
Some(self.$field.clone())
|
|
}
|
|
}
|
|
};
|
|
($t:ty) => {
|
|
impl PubkeyGetter for $t {
|
|
fn get_pubkey(&self) -> Option<String> {
|
|
None
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
impl_pubkey_getter!(Pubkey, pubkey);
|
|
impl_pubkey_getter!(NewVmReq, admin_pubkey);
|
|
impl_pubkey_getter!(DeleteVmReq, admin_pubkey);
|
|
impl_pubkey_getter!(UpdateVmReq, admin_pubkey);
|
|
impl_pubkey_getter!(ExtendVmReq, admin_pubkey);
|
|
impl_pubkey_getter!(ReportNodeReq, admin_pubkey);
|
|
impl_pubkey_getter!(ListVmContractsReq, wallet);
|
|
impl_pubkey_getter!(RegisterVmNodeReq, node_pubkey);
|
|
impl_pubkey_getter!(RegOperatorReq, pubkey);
|
|
impl_pubkey_getter!(KickReq, operator_wallet);
|
|
impl_pubkey_getter!(BanUserReq, operator_wallet);
|
|
|
|
impl_pubkey_getter!(VmNodeFilters);
|
|
impl_pubkey_getter!(Empty);
|
|
impl_pubkey_getter!(AirdropReq);
|
|
impl_pubkey_getter!(SlashReq);
|
|
|
|
// impl_pubkey_getter!(NewAppReq, admin_pubkey);
|
|
// impl_pubkey_getter!(DelAppReq, admin_pubkey);
|
|
// impl_pubkey_getter!(ListAppContractsReq, admin_pubkey);
|
|
//
|
|
// impl_pubkey_getter!(RegisterAppNodeReq);
|
|
// impl_pubkey_getter!(AppNodeFilters);
|
|
|
|
pub fn check_sig_from_req<T: std::fmt::Debug + PubkeyGetter>(req: Request<T>) -> Result<T, Status> {
|
|
let time = match req.metadata().get("timestamp") {
|
|
Some(t) => t.clone(),
|
|
None => return Err(Status::unauthenticated("Timestamp not found in metadata.")),
|
|
};
|
|
let time = time
|
|
.to_str()
|
|
.map_err(|_| Status::unauthenticated("Timestamp in metadata is not a string"))?;
|
|
|
|
let now = chrono::Utc::now();
|
|
let parsed_time = chrono::DateTime::parse_from_rfc3339(time)
|
|
.map_err(|_| Status::unauthenticated("Coult not parse timestamp"))?;
|
|
let seconds_elapsed = now.signed_duration_since(parsed_time).num_seconds();
|
|
if !(-4..=4).contains(&seconds_elapsed) {
|
|
return Err(Status::unauthenticated(format!(
|
|
"Date is not within 4 sec of the time of the server: CLI {} vs Server {}",
|
|
parsed_time, now
|
|
)));
|
|
}
|
|
|
|
let signature = match req.metadata().get("request-signature") {
|
|
Some(t) => t,
|
|
None => return Err(Status::unauthenticated("signature not found in metadata.")),
|
|
};
|
|
let signature = bs58::decode(signature)
|
|
.into_vec()
|
|
.map_err(|_| Status::unauthenticated("signature is not a bs58 string"))?;
|
|
let signature = ed25519_dalek::Signature::from_bytes(
|
|
signature
|
|
.as_slice()
|
|
.try_into()
|
|
.map_err(|_| Status::unauthenticated("could not parse ed25519 signature"))?,
|
|
);
|
|
|
|
let pubkey_value = match req.metadata().get("pubkey") {
|
|
Some(p) => p.clone(),
|
|
None => return Err(Status::unauthenticated("pubkey not found in metadata.")),
|
|
};
|
|
let pubkey = ed25519_dalek::VerifyingKey::from_bytes(
|
|
&bs58::decode(&pubkey_value)
|
|
.into_vec()
|
|
.map_err(|_| Status::unauthenticated("pubkey is not a bs58 string"))?
|
|
.try_into()
|
|
.map_err(|_| Status::unauthenticated("pubkey does not have the correct size."))?,
|
|
)
|
|
.map_err(|_| Status::unauthenticated("could not parse ed25519 pubkey"))?;
|
|
|
|
let req = req.into_inner();
|
|
let message = format!("{time}{req:?}");
|
|
use ed25519_dalek::Verifier;
|
|
pubkey
|
|
.verify(message.as_bytes(), &signature)
|
|
.map_err(|_| Status::unauthenticated("the signature is not valid"))?;
|
|
if let Some(req_pubkey) = req.get_pubkey() {
|
|
if *pubkey_value.to_str().unwrap() != req_pubkey {
|
|
return Err(Status::unauthenticated(
|
|
"pubkey of signature does not match pubkey of request",
|
|
));
|
|
}
|
|
}
|
|
Ok(req)
|
|
}
|
|
|
|
pub fn check_sig_from_parts(pubkey: &str, time: &str, msg: &str, sig: &str) -> Result<(), Status> {
|
|
let now = chrono::Utc::now();
|
|
let parsed_time = chrono::DateTime::parse_from_rfc3339(time)
|
|
.map_err(|_| Status::unauthenticated("Coult not parse timestamp"))?;
|
|
let seconds_elapsed = now.signed_duration_since(parsed_time).num_seconds();
|
|
if !(-4..=4).contains(&seconds_elapsed) {
|
|
return Err(Status::unauthenticated(format!(
|
|
"Date is not within 4 sec of the time of the server: CLI {} vs Server {}",
|
|
parsed_time, now
|
|
)));
|
|
}
|
|
|
|
let signature = bs58::decode(sig)
|
|
.into_vec()
|
|
.map_err(|_| Status::unauthenticated("signature is not a bs58 string"))?;
|
|
let signature = ed25519_dalek::Signature::from_bytes(
|
|
signature
|
|
.as_slice()
|
|
.try_into()
|
|
.map_err(|_| Status::unauthenticated("could not parse ed25519 signature"))?,
|
|
);
|
|
|
|
let pubkey = ed25519_dalek::VerifyingKey::from_bytes(
|
|
&bs58::decode(&pubkey)
|
|
.into_vec()
|
|
.map_err(|_| Status::unauthenticated("pubkey is not a bs58 string"))?
|
|
.try_into()
|
|
.map_err(|_| Status::unauthenticated("pubkey does not have the correct size."))?,
|
|
)
|
|
.map_err(|_| Status::unauthenticated("could not parse ed25519 pubkey"))?;
|
|
|
|
let msg = time.to_string() + msg;
|
|
use ed25519_dalek::Verifier;
|
|
pubkey
|
|
.verify(msg.as_bytes(), &signature)
|
|
.map_err(|_| Status::unauthenticated("the signature is not valid"))?;
|
|
|
|
Ok(())
|
|
}
|
|
|
|
pub fn check_admin_key<T>(req: &Request<T>) -> Result<(), Status> {
|
|
let pubkey = match req.metadata().get("pubkey") {
|
|
Some(p) => p.clone(),
|
|
None => return Err(Status::unauthenticated("pubkey not found in metadata.")),
|
|
};
|
|
let pubkey = pubkey
|
|
.to_str()
|
|
.map_err(|_| Status::unauthenticated("could not parse pubkey metadata to str"))?
|
|
.to_owned();
|
|
|
|
if !ADMIN_ACCOUNTS.contains(&pubkey) {
|
|
return Err(Status::unauthenticated("This operation is reserved to admin accounts"));
|
|
}
|
|
|
|
Ok(())
|
|
}
|