Managed to query VirtWeb API

This commit is contained in:
Pierre HUBERT 2024-04-25 18:51:42 +02:00
parent 38e69ea167
commit 48f24e6ca1
7 changed files with 117 additions and 2 deletions

View File

@ -1648,13 +1648,17 @@ version = "0.1.0"
dependencies = [ dependencies = [
"actix-remote-ip", "actix-remote-ip",
"actix-web", "actix-web",
"anyhow",
"basic-jwt", "basic-jwt",
"clap", "clap",
"env_logger", "env_logger",
"lazy_static", "lazy_static",
"light-openid", "light-openid",
"log", "log",
"reqwest",
"serde", "serde",
"thiserror",
"uuid",
] ]
[[package]] [[package]]
@ -2269,6 +2273,15 @@ version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
[[package]]
name = "uuid"
version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a183cf7feeba97b4dd1c0d46788634f6221d87fa961b305bed08c851829efcc0"
dependencies = [
"getrandom",
]
[[package]] [[package]]
name = "vcpkg" name = "vcpkg"
version = "0.2.15" version = "0.2.15"

View File

@ -15,3 +15,7 @@ basic-jwt = "0.2.0"
actix-remote-ip = "0.1.0" actix-remote-ip = "0.1.0"
lazy_static = "1.4.0" lazy_static = "1.4.0"
actix-web = "4.5.1" actix-web = "4.5.1"
anyhow = "1.0.82"
reqwest = { version = "0.12.4", features = ["json"] }
thiserror = "1.0.59"
uuid = { version = "1.8.0", features = ["v4"] }

View File

@ -1,3 +1,4 @@
use basic_jwt::JWTPrivateKey;
use clap::Parser; use clap::Parser;
/// VirtWeb backend API /// VirtWeb backend API
@ -58,7 +59,7 @@ pub struct AppConfig {
/// VirtWeb API token private key /// VirtWeb API token private key
#[arg(long, env)] #[arg(long, env)]
pub virtweb_token_private_key: String, virtweb_token_private_key: String,
} }
lazy_static::lazy_static! { lazy_static::lazy_static! {
@ -119,6 +120,13 @@ impl AppConfig {
self.oidc_redirect_url self.oidc_redirect_url
.replace("APP_ORIGIN", &self.website_origin) .replace("APP_ORIGIN", &self.website_origin)
} }
/// Get VirtWeb token private key
pub fn token_private_key(&self) -> JWTPrivateKey {
JWTPrivateKey::ES384 {
r#priv: self.virtweb_token_private_key.to_string(),
}
}
} }
#[derive(Debug, Clone, serde::Serialize)] #[derive(Debug, Clone, serde::Serialize)]

View File

@ -1 +1,3 @@
pub mod app_config; pub mod app_config;
pub mod utils;
pub mod virtweb_client;

View File

@ -4,6 +4,7 @@ use actix_web::web::Data;
use actix_web::{App, HttpServer}; use actix_web::{App, HttpServer};
use light_openid::basic_state_manager::BasicStateManager; use light_openid::basic_state_manager::BasicStateManager;
use remote_backend::app_config::AppConfig; use remote_backend::app_config::AppConfig;
use remote_backend::virtweb_client;
#[actix_web::main] #[actix_web::main]
async fn main() -> std::io::Result<()> { async fn main() -> std::io::Result<()> {
@ -11,6 +12,8 @@ async fn main() -> std::io::Result<()> {
let state_manager = Data::new(BasicStateManager::new()); let state_manager = Data::new(BasicStateManager::new());
println!("{:#?}", virtweb_client::get_token_rights().await.unwrap());
HttpServer::new(move || { HttpServer::new(move || {
App::new() App::new()
.wrap(Logger::default()) .wrap(Logger::default())

View File

@ -0,0 +1,14 @@
use std::time::{SystemTime, UNIX_EPOCH};
/// Get the current time since epoch
///
/// ```
/// use remote_backend::utils::time;
/// let time = time();
/// ```
pub fn time() -> u64 {
SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_secs()
}

View File

@ -0,0 +1,71 @@
use crate::app_config::AppConfig;
use crate::utils::time;
use std::fmt::Display;
use thiserror::Error;
use uuid::Uuid;
#[derive(Error, Debug)]
pub enum VirtWebClientError {
#[error("Invalid status code from VirtWeb: {0}")]
InvalidStatusCode(u16),
}
#[derive(serde::Serialize, Debug)]
pub struct TokenClaims {
pub sub: String,
pub iat: u64,
pub exp: u64,
pub verb: String,
pub path: String,
pub nonce: String,
}
#[derive(serde::Deserialize, Debug)]
pub struct TokenRight {
verb: String,
path: String,
}
pub type TokenRights = Vec<TokenRight>;
#[derive(serde::Deserialize)]
struct TokenInfo {
rights: TokenRights,
}
/// Perform a request on the API
async fn request<D: Display, E: serde::de::DeserializeOwned>(uri: D) -> anyhow::Result<E> {
let url = format!("{}{}", AppConfig::get().virtweb_base_url, uri);
log::debug!("Will query {uri}...");
let jwt = TokenClaims {
sub: AppConfig::get().virtweb_token_id.to_string(),
iat: time() - 60 * 2,
exp: time() + 60 * 3,
verb: "GET".to_string(),
path: uri.to_string(),
nonce: Uuid::new_v4().to_string(),
};
let jwt = AppConfig::get().token_private_key().sign_jwt(&jwt)?;
let res = reqwest::Client::new()
.get(url)
.header("x-token-id", &AppConfig::get().virtweb_token_id)
.header("x-token-content", jwt)
.send()
.await?;
if !res.status().is_success() {
return Err(VirtWebClientError::InvalidStatusCode(res.status().as_u16()).into());
}
Ok(res.json().await?)
}
/// Get current token rights
pub async fn get_token_rights() -> anyhow::Result<TokenRights> {
let res: TokenInfo =
request(format!("/api/token/{}", AppConfig::get().virtweb_token_id)).await?;
Ok(res.rights)
}