mirror of https://github.com/ospab/ostp.git
fix(server): return API token support for Relay servers sync
This commit is contained in:
parent
3b88359746
commit
5c39f24bee
|
|
@ -42,6 +42,7 @@ pub struct ApiState {
|
||||||
pub user_stats: Arc<RwLock<HashMap<String, Arc<UserStats>>>>,
|
pub user_stats: Arc<RwLock<HashMap<String, Arc<UserStats>>>>,
|
||||||
pub start_time: Instant,
|
pub start_time: Instant,
|
||||||
pub session_token: Arc<RwLock<Option<String>>>,
|
pub session_token: Arc<RwLock<Option<String>>>,
|
||||||
|
pub api_token: Option<String>,
|
||||||
pub webpath: String,
|
pub webpath: String,
|
||||||
pub username: String,
|
pub username: String,
|
||||||
pub password_hash: String,
|
pub password_hash: String,
|
||||||
|
|
@ -59,6 +60,7 @@ pub struct ApiState {
|
||||||
pub struct ApiConfig {
|
pub struct ApiConfig {
|
||||||
pub enabled: bool,
|
pub enabled: bool,
|
||||||
pub bind: String,
|
pub bind: String,
|
||||||
|
pub token: Option<String>,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub webpath: String,
|
pub webpath: String,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
|
|
@ -72,6 +74,7 @@ impl Default for ApiConfig {
|
||||||
Self {
|
Self {
|
||||||
enabled: false,
|
enabled: false,
|
||||||
bind: "127.0.0.1:9090".to_string(),
|
bind: "127.0.0.1:9090".to_string(),
|
||||||
|
token: None,
|
||||||
webpath: String::new(),
|
webpath: String::new(),
|
||||||
username: String::new(),
|
username: String::new(),
|
||||||
password_hash: String::new(),
|
password_hash: String::new(),
|
||||||
|
|
@ -257,6 +260,7 @@ pub async fn start_api_server(
|
||||||
user_stats,
|
user_stats,
|
||||||
start_time: Instant::now(),
|
start_time: Instant::now(),
|
||||||
session_token: Arc::new(RwLock::new(None)),
|
session_token: Arc::new(RwLock::new(None)),
|
||||||
|
api_token: config.token.clone(),
|
||||||
webpath: config.webpath.clone(),
|
webpath: config.webpath.clone(),
|
||||||
username: config.username.clone(),
|
username: config.username.clone(),
|
||||||
password_hash: config.password_hash.clone(),
|
password_hash: config.password_hash.clone(),
|
||||||
|
|
@ -287,26 +291,40 @@ pub async fn start_api_server(
|
||||||
// ── Middleware: token check ──────────────────────────────────────────────────
|
// ── Middleware: token check ──────────────────────────────────────────────────
|
||||||
|
|
||||||
fn check_token(state: &ApiState, headers: &axum::http::HeaderMap) -> bool {
|
fn check_token(state: &ApiState, headers: &axum::http::HeaderMap) -> bool {
|
||||||
|
// Both session token (for web UI) and static API token (for relays) are checked
|
||||||
|
let mut allowed = false;
|
||||||
|
|
||||||
// If no credentials configured, panel is open (unsafe but possible)
|
// If no credentials configured, panel is open (unsafe but possible)
|
||||||
if state.username.is_empty() && state.password_hash.is_empty() {
|
if state.username.is_empty() && state.password_hash.is_empty() && state.api_token.is_none() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
match headers.get("authorization") {
|
if let Some(value) = headers.get("authorization") {
|
||||||
Some(value) => {
|
if let Ok(val) = value.to_str() {
|
||||||
let val = value.to_str().unwrap_or("");
|
|
||||||
if let Some(token) = val.strip_prefix("Bearer ") {
|
if let Some(token) = val.strip_prefix("Bearer ") {
|
||||||
let current_session = state.session_token.read().unwrap().clone();
|
let current_session = state.session_token.read().unwrap().clone();
|
||||||
if let Some(session) = current_session {
|
if let Some(session) = current_session {
|
||||||
if token == session {
|
if token == session {
|
||||||
return true;
|
allowed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(ref api_tok) = state.api_token {
|
||||||
|
if token == api_tok {
|
||||||
|
allowed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if let Some(ref api_tok) = state.api_token {
|
||||||
|
if val == api_tok {
|
||||||
|
allowed = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
false
|
|
||||||
}
|
}
|
||||||
None => false,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
allowed
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn handle_login(
|
async fn handle_login(
|
||||||
|
|
@ -904,6 +922,7 @@ mod tests {
|
||||||
user_stats: Arc::new(RwLock::new(HashMap::new())),
|
user_stats: Arc::new(RwLock::new(HashMap::new())),
|
||||||
start_time: std::time::Instant::now(),
|
start_time: std::time::Instant::now(),
|
||||||
session_token: Arc::new(RwLock::new(None)),
|
session_token: Arc::new(RwLock::new(None)),
|
||||||
|
api_token: Some("test-token".to_string()),
|
||||||
webpath: webpath.to_string(),
|
webpath: webpath.to_string(),
|
||||||
username: "admin".to_string(),
|
username: "admin".to_string(),
|
||||||
password_hash: "hash".to_string(),
|
password_hash: "hash".to_string(),
|
||||||
|
|
|
||||||
|
|
@ -294,6 +294,7 @@ impl ListenConfig {
|
||||||
struct ApiConfig {
|
struct ApiConfig {
|
||||||
enabled: Option<bool>,
|
enabled: Option<bool>,
|
||||||
bind: Option<String>,
|
bind: Option<String>,
|
||||||
|
token: Option<String>,
|
||||||
webpath: Option<String>,
|
webpath: Option<String>,
|
||||||
username: Option<String>,
|
username: Option<String>,
|
||||||
password_hash: Option<String>,
|
password_hash: Option<String>,
|
||||||
|
|
@ -631,10 +632,12 @@ async fn run_app() -> Result<()> {
|
||||||
]
|
]
|
||||||
}},
|
}},
|
||||||
|
|
||||||
// Web control panel
|
// Web control panel & Management API
|
||||||
"api": {{
|
"api": {{
|
||||||
"enabled": false,
|
"enabled": false,
|
||||||
"bind": "0.0.0.0:9090",
|
"bind": "0.0.0.0:9090",
|
||||||
|
// Static API token for Relay servers (optional)
|
||||||
|
"token": "",
|
||||||
// Secret URL path to hide panel from scanners (e.g. "mySecret123")
|
// Secret URL path to hide panel from scanners (e.g. "mySecret123")
|
||||||
"webpath": "",
|
"webpath": "",
|
||||||
// Login credentials for web panel (password stored as SHA256 hash)
|
// Login credentials for web panel (password stored as SHA256 hash)
|
||||||
|
|
@ -904,6 +907,7 @@ async fn run_app() -> Result<()> {
|
||||||
let api_config = server_cfg.api.map(|a| ostp_server::ApiConfig {
|
let api_config = server_cfg.api.map(|a| ostp_server::ApiConfig {
|
||||||
enabled: a.enabled.unwrap_or(false),
|
enabled: a.enabled.unwrap_or(false),
|
||||||
bind: a.bind.unwrap_or_else(|| "127.0.0.1:9090".to_string()),
|
bind: a.bind.unwrap_or_else(|| "127.0.0.1:9090".to_string()),
|
||||||
|
token: a.token.clone(),
|
||||||
webpath: a.webpath.unwrap_or_default(),
|
webpath: a.webpath.unwrap_or_default(),
|
||||||
username: a.username.unwrap_or_default(),
|
username: a.username.unwrap_or_default(),
|
||||||
password_hash: a.password_hash.unwrap_or_default(),
|
password_hash: a.password_hash.unwrap_or_default(),
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue