Add API tokens support #9
@ -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 {
|
||||||
|
@ -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"));
|
||||||
|
@ -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;
|
||||||
|
@ -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,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -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 {
|
||||||
|
Loading…
Reference in New Issue
Block a user