Can update and delete API tokens
This commit is contained in:
		@@ -10,6 +10,15 @@ use std::path::Path;
 | 
			
		||||
#[derive(serde::Serialize, serde::Deserialize, Clone, Copy, Debug)]
 | 
			
		||||
pub struct TokenID(pub uuid::Uuid);
 | 
			
		||||
 | 
			
		||||
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)]
 | 
			
		||||
pub struct TokenRight {
 | 
			
		||||
    verb: TokenVerb,
 | 
			
		||||
    uri: String,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)]
 | 
			
		||||
pub struct TokenRights(Vec<TokenRight>);
 | 
			
		||||
 | 
			
		||||
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)]
 | 
			
		||||
pub struct Token {
 | 
			
		||||
    pub id: TokenID,
 | 
			
		||||
@@ -19,7 +28,7 @@ pub struct Token {
 | 
			
		||||
    updated: u64,
 | 
			
		||||
    #[serde(skip_serializing_if = "TokenPubKey::is_invalid")]
 | 
			
		||||
    pub pub_key: TokenPubKey,
 | 
			
		||||
    pub rights: Vec<TokenRights>,
 | 
			
		||||
    pub rights: TokenRights,
 | 
			
		||||
    pub last_used: Option<u64>,
 | 
			
		||||
    pub ip_restriction: Option<ipnetwork::IpNetwork>,
 | 
			
		||||
    pub delete_after_inactivity: Option<u64>,
 | 
			
		||||
@@ -27,8 +36,12 @@ pub struct Token {
 | 
			
		||||
 | 
			
		||||
impl Token {
 | 
			
		||||
    /// Turn the token into a JSON string
 | 
			
		||||
    pub fn to_json(&self) -> String {
 | 
			
		||||
        serde_json::to_string(self).expect("Failed to serialize an API token!")
 | 
			
		||||
    fn save(&self) -> anyhow::Result<()> {
 | 
			
		||||
        let json = serde_json::to_string(self)?;
 | 
			
		||||
 | 
			
		||||
        std::fs::write(AppConfig::get().api_token_definition_path(self.id), json)?;
 | 
			
		||||
 | 
			
		||||
        Ok(())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Load token information from a file
 | 
			
		||||
@@ -46,22 +59,27 @@ pub enum TokenVerb {
 | 
			
		||||
    DELETE,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)]
 | 
			
		||||
pub struct TokenRights {
 | 
			
		||||
    verb: TokenVerb,
 | 
			
		||||
    uri: String,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Structure used to create a token
 | 
			
		||||
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)]
 | 
			
		||||
pub struct NewToken {
 | 
			
		||||
    pub name: String,
 | 
			
		||||
    pub description: String,
 | 
			
		||||
    pub rights: Vec<TokenRights>,
 | 
			
		||||
    pub rights: TokenRights,
 | 
			
		||||
    pub ip_restriction: Option<ipnetwork::IpNetwork>,
 | 
			
		||||
    pub delete_after_inactivity: Option<u64>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl TokenRights {
 | 
			
		||||
    pub fn check_error(&self) -> Option<&'static str> {
 | 
			
		||||
        for r in &self.0 {
 | 
			
		||||
            if !r.uri.starts_with("/api/") {
 | 
			
		||||
                return Some("All API rights shall start with /api/");
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        None
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl NewToken {
 | 
			
		||||
    /// Check for error in token
 | 
			
		||||
    pub fn check_error(&self) -> Option<&'static str> {
 | 
			
		||||
@@ -81,10 +99,8 @@ impl NewToken {
 | 
			
		||||
            return Some("Description is too long!");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        for r in &self.rights {
 | 
			
		||||
            if !r.uri.starts_with("/api/") {
 | 
			
		||||
                return Some("All API rights shall start with /api/");
 | 
			
		||||
            }
 | 
			
		||||
        if let Some(err) = self.rights.check_error() {
 | 
			
		||||
            return Some(err);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if let Some(t) = self.delete_after_inactivity {
 | 
			
		||||
@@ -114,11 +130,6 @@ pub async fn create(t: &NewToken) -> anyhow::Result<(Token, TokenPrivKey)> {
 | 
			
		||||
        delete_after_inactivity: t.delete_after_inactivity,
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    std::fs::write(
 | 
			
		||||
        AppConfig::get().api_token_definition_path(token.id),
 | 
			
		||||
        token.to_json(),
 | 
			
		||||
    )?;
 | 
			
		||||
 | 
			
		||||
    Ok((token, priv_key))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -135,3 +146,21 @@ pub async fn full_list() -> anyhow::Result<Vec<Token>> {
 | 
			
		||||
pub async fn get_single(id: TokenID) -> anyhow::Result<Token> {
 | 
			
		||||
    Token::load_from_file(&AppConfig::get().api_token_definition_path(id))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Update API tokens rights
 | 
			
		||||
pub async fn update_rights(id: TokenID, rights: TokenRights) -> anyhow::Result<()> {
 | 
			
		||||
    let mut token = get_single(id).await?;
 | 
			
		||||
    token.rights = rights;
 | 
			
		||||
    token.updated = time();
 | 
			
		||||
    token.save()?;
 | 
			
		||||
    Ok(())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Delete an API token
 | 
			
		||||
pub async fn delete(id: TokenID) -> anyhow::Result<()> {
 | 
			
		||||
    let path = AppConfig::get().api_token_definition_path(id);
 | 
			
		||||
    if path.exists() {
 | 
			
		||||
        std::fs::remove_file(path)?;
 | 
			
		||||
    }
 | 
			
		||||
    Ok(())
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,7 @@
 | 
			
		||||
//! # API tokens management
 | 
			
		||||
 | 
			
		||||
use crate::api_tokens;
 | 
			
		||||
use crate::api_tokens::{NewToken, TokenID};
 | 
			
		||||
use crate::api_tokens::{NewToken, TokenID, TokenRights};
 | 
			
		||||
use crate::controllers::api_tokens_controller::rest_token::RestToken;
 | 
			
		||||
use crate::controllers::HttpResult;
 | 
			
		||||
use crate::utils::jwt_utils::TokenPrivKey;
 | 
			
		||||
@@ -70,3 +70,31 @@ pub async fn get_single(path: web::Path<TokenIDInPath>) -> HttpResult {
 | 
			
		||||
 | 
			
		||||
    Ok(HttpResponse::Ok().json(RestToken::new(token)))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(serde::Deserialize)]
 | 
			
		||||
pub struct UpdateTokenBody {
 | 
			
		||||
    rights: TokenRights,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Update a token
 | 
			
		||||
pub async fn update(
 | 
			
		||||
    path: web::Path<TokenIDInPath>,
 | 
			
		||||
    body: web::Json<UpdateTokenBody>,
 | 
			
		||||
) -> HttpResult {
 | 
			
		||||
    if let Some(err) = body.rights.check_error() {
 | 
			
		||||
        log::error!("Failed to validate updated API token information! {err}");
 | 
			
		||||
        return Ok(HttpResponse::BadRequest()
 | 
			
		||||
            .json(format!("Failed to validate API token information! {err}")));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    api_tokens::update_rights(path.uid, body.0.rights).await?;
 | 
			
		||||
 | 
			
		||||
    Ok(HttpResponse::Accepted().finish())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Delete a token
 | 
			
		||||
pub async fn delete(path: web::Path<TokenIDInPath>) -> HttpResult {
 | 
			
		||||
    api_tokens::delete(path.uid).await?;
 | 
			
		||||
 | 
			
		||||
    Ok(HttpResponse::Accepted().finish())
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -290,14 +290,14 @@ async fn main() -> std::io::Result<()> {
 | 
			
		||||
                "/api/tokens/{uid}",
 | 
			
		||||
                web::get().to(api_tokens_controller::get_single),
 | 
			
		||||
            )
 | 
			
		||||
            /* TODO .route(
 | 
			
		||||
            .route(
 | 
			
		||||
                "/api/tokens/{uid}",
 | 
			
		||||
                web::put().to(api_tokens_controller::update),
 | 
			
		||||
                web::patch().to(api_tokens_controller::update),
 | 
			
		||||
            )
 | 
			
		||||
            .route(
 | 
			
		||||
                "/api/tokens/{uid}",
 | 
			
		||||
                web::delete().to(api_tokens_controller::delete),
 | 
			
		||||
            )*/
 | 
			
		||||
            )
 | 
			
		||||
            // Static assets
 | 
			
		||||
            .route("/", web::get().to(static_controller::root_index))
 | 
			
		||||
            .route(
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user