Create a basic API client
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing

This commit is contained in:
Pierre HUBERT 2024-04-10 21:03:05 +02:00
parent 23fc10bb60
commit b1937d42a2
2 changed files with 82 additions and 0 deletions

View File

@ -0,0 +1,66 @@
use clap::Parser;
use std::os::unix::prelude::CommandExt;
use std::process::Command;
use std::str::FromStr;
use virtweb_backend::api_tokens::TokenVerb;
use virtweb_backend::extractors::api_auth_extractor::TokenClaims;
use virtweb_backend::utils::jwt_utils::{sign_jwt, TokenPrivKey};
use virtweb_backend::utils::time_utils::time;
/// curl wrapper to query Virtweb backend API
#[derive(Parser, Debug)]
#[command(version, about, long_about = None)]
struct Args {
/// URL of VirtWeb
#[arg(short('u'), long, env, default_value = "http://localhost:8000")]
virtweb_url: String,
/// Token ID
#[arg(short('i'), long, env)]
token_id: String,
/// Token private key
#[arg(short('t'), long, env)]
token_key: String,
/// Request verb
#[arg(short('X'), long, default_value = "GET")]
verb: String,
/// Request URI
uri: String,
/// Command line arguments to pass to cURL
#[clap(trailing_var_arg = true, allow_hyphen_values = true)]
run: Vec<String>,
}
fn main() {
let args = Args::parse();
let full_url = format!("{}{}", args.virtweb_url, args.uri);
log::debug!("Full URL: {full_url}");
let key = TokenPrivKey::ES384 {
r#priv: args.token_key,
};
let claims = TokenClaims {
sub: args.token_id.to_string(),
iat: time() as usize,
exp: time() as usize + 50,
verb: TokenVerb::from_str(&args.verb).expect("Invalid request verb!"),
path: args.uri,
nonce: uuid::Uuid::new_v4().to_string(),
};
let jwt = sign_jwt(&key, &claims).expect("Failed to sign JWT!");
Command::new("curl")
.args(["-X", &args.verb])
.args(["-H", &format!("x-token-id: {}", args.token_id)])
.args(["-H", &format!("x-token-content: {jwt}")])
.args(args.run)
.arg(full_url)
.exec();
panic!("Failed to run curl!")
}

View File

@ -7,6 +7,7 @@ use crate::utils::jwt_utils::{TokenPrivKey, TokenPubKey};
use crate::utils::time_utils::time; use crate::utils::time_utils::time;
use actix_http::Method; use actix_http::Method;
use std::path::Path; use std::path::Path;
use std::str::FromStr;
#[derive(serde::Serialize, serde::Deserialize, Clone, Copy, Debug)] #[derive(serde::Serialize, serde::Deserialize, Clone, Copy, Debug)]
pub struct TokenID(pub uuid::Uuid); pub struct TokenID(pub uuid::Uuid);
@ -95,6 +96,21 @@ impl TokenVerb {
} }
} }
impl FromStr for TokenVerb {
type Err = ();
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"GET" => Ok(TokenVerb::GET),
"POST" => Ok(TokenVerb::POST),
"PUT" => Ok(TokenVerb::PUT),
"PATCH" => Ok(TokenVerb::PATCH),
"DELETE" => Ok(TokenVerb::DELETE),
_ => Err(()),
}
}
}
/// Structure used to create a token /// Structure used to create a token
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] #[derive(serde::Serialize, serde::Deserialize, Debug, Clone)]
pub struct NewToken { pub struct NewToken {