From b1937d42a2781840b3565f73370a12e2529f8d88 Mon Sep 17 00:00:00 2001 From: Pierre HUBERT Date: Wed, 10 Apr 2024 21:03:05 +0200 Subject: [PATCH] Create a basic API client --- virtweb_backend/examples/api_curl.rs | 66 ++++++++++++++++++++++++++++ virtweb_backend/src/api_tokens.rs | 16 +++++++ 2 files changed, 82 insertions(+) create mode 100644 virtweb_backend/examples/api_curl.rs diff --git a/virtweb_backend/examples/api_curl.rs b/virtweb_backend/examples/api_curl.rs new file mode 100644 index 0000000..cf363b8 --- /dev/null +++ b/virtweb_backend/examples/api_curl.rs @@ -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, +} + +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!") +} diff --git a/virtweb_backend/src/api_tokens.rs b/virtweb_backend/src/api_tokens.rs index f71342d..31dacdc 100644 --- a/virtweb_backend/src/api_tokens.rs +++ b/virtweb_backend/src/api_tokens.rs @@ -7,6 +7,7 @@ use crate::utils::jwt_utils::{TokenPrivKey, TokenPubKey}; use crate::utils::time_utils::time; use actix_http::Method; use std::path::Path; +use std::str::FromStr; #[derive(serde::Serialize, serde::Deserialize, Clone, Copy, Debug)] pub struct TokenID(pub uuid::Uuid); @@ -95,6 +96,21 @@ impl TokenVerb { } } +impl FromStr for TokenVerb { + type Err = (); + + fn from_str(s: &str) -> Result { + 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 #[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] pub struct NewToken {