Add API tokens support #9

Merged
pierre merged 40 commits from api into master 2024-04-23 17:04:45 +00:00
5 changed files with 20 additions and 8 deletions
Showing only changes of commit d60064fbaa - Show all commits

View File

@ -7,7 +7,7 @@ use virtweb_backend::api_tokens::TokenVerb;
use virtweb_backend::extractors::api_auth_extractor::TokenClaims; use virtweb_backend::extractors::api_auth_extractor::TokenClaims;
use virtweb_backend::utils::time_utils::time; use virtweb_backend::utils::time_utils::time;
/// curl wrapper to query Virtweb backend API /// cURL wrapper to query Virtweb backend API
#[derive(Parser, Debug)] #[derive(Parser, Debug)]
#[command(version, about, long_about = None)] #[command(version, about, long_about = None)]
struct Args { struct Args {

View File

@ -33,12 +33,16 @@ impl TokenRights {
if !r.path.starts_with("/api/") { if !r.path.starts_with("/api/") {
return Some("All API rights shall start with /api/"); return Some("All API rights shall start with /api/");
} }
if r.path.len() > constants::API_TOKEN_PATH_MAX_LENGTH {
return Some("An API path shall not exceed maximum URL size!");
}
} }
None None
} }
pub fn contains(&self, verb: TokenVerb, path: &str) -> bool { pub fn contains(&self, verb: TokenVerb, path: &str) -> bool {
let path_split = path.split('/').collect::<Vec<_>>(); let req_path_split = path.split('/').collect::<Vec<_>>();
'root: for r in &self.0 { 'root: for r in &self.0 {
if r.verb != verb { if r.verb != verb {
@ -47,11 +51,11 @@ impl TokenRights {
let mut last_idx = 0; let mut last_idx = 0;
for (idx, part) in r.path.split('/').enumerate() { for (idx, part) in r.path.split('/').enumerate() {
if idx >= path_split.len() { if idx >= req_path_split.len() {
continue 'root; continue 'root;
} }
if part != "*" && part != path_split[idx] { if part != "*" && part != req_path_split[idx] {
continue 'root; continue 'root;
} }
@ -59,7 +63,7 @@ impl TokenRights {
} }
// Check we visited the whole path // Check we visited the whole path
if last_idx + 1 == path_split.len() { if last_idx + 1 == req_path_split.len() {
return true; return true;
} }
} }
@ -283,6 +287,7 @@ mod test {
]); ]);
assert!(rights.contains(TokenVerb::GET, "/api/vm/ab")); assert!(rights.contains(TokenVerb::GET, "/api/vm/ab"));
assert!(!rights.contains(TokenVerb::GET, "/api/vm"));
assert!(!rights.contains(TokenVerb::GET, "/api/vm/ab/c")); assert!(!rights.contains(TokenVerb::GET, "/api/vm/ab/c"));
assert!(rights.contains(TokenVerb::PUT, "/api/vm/a")); assert!(rights.contains(TokenVerb::PUT, "/api/vm/a"));
assert!(!rights.contains(TokenVerb::PUT, "/api/vm/other")); assert!(!rights.contains(TokenVerb::PUT, "/api/vm/other"));

View File

@ -104,3 +104,6 @@ pub const API_TOKEN_DESCRIPTION_MIN_LENGTH: usize = 5;
/// API token description max length /// API token description max length
pub const API_TOKEN_DESCRIPTION_MAX_LENGTH: usize = 30; pub const API_TOKEN_DESCRIPTION_MAX_LENGTH: usize = 30;
/// API token path max length
pub const API_TOKEN_PATH_MAX_LENGTH: usize = 255;

View File

@ -112,7 +112,10 @@ pub async fn static_config(local_auth: LocalAuthEnabled) -> impl Responder {
max: constants::API_TOKEN_DESCRIPTION_MAX_LENGTH, max: constants::API_TOKEN_DESCRIPTION_MAX_LENGTH,
}, },
api_token_right_path_size: LenConstraints { min: 0, max: 255 }, api_token_right_path_size: LenConstraints {
min: 0,
max: constants::API_TOKEN_PATH_MAX_LENGTH,
},
}, },
}) })
} }

View File

@ -1,5 +1,6 @@
import { Tooltip } from "@mui/material"; import { Tooltip } from "@mui/material";
import date from "date-and-time"; import date from "date-and-time";
import { time } from "../utils/DateUtils";
export function formatDate(time: number): string { export function formatDate(time: number): string {
const t = new Date(); const t = new Date();
@ -50,8 +51,8 @@ export function timeDiff(a: number, b: number): string {
return `${diffYears} years`; return `${diffYears} years`;
} }
export function timeDiffFromNow(time: number): string { export function timeDiffFromNow(t: number): string {
return timeDiff(time, Math.floor(new Date().getTime() / 1000)); return timeDiff(t, time());
} }
export function TimeWidget(p: { time?: number }): React.ReactElement { export function TimeWidget(p: { time?: number }): React.ReactElement {