htyproc: dynamic sudo token via loginWithCert → sudo, drop PROC_SUDOER_TOKEN
This commit is contained in:
@@ -53,6 +53,14 @@ pub fn proc_port() -> u16 {
|
|||||||
.unwrap_or(3004)
|
.unwrap_or(3004)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn priv_key() -> anyhow::Result<String> {
|
||||||
|
env::var("PRIV_KEY").map_err(|_| anyhow::anyhow!("PRIV_KEY not set"))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pub_key() -> anyhow::Result<String> {
|
||||||
|
env::var("PUB_KEY").map_err(|_| anyhow::anyhow!("PUB_KEY not set"))
|
||||||
|
}
|
||||||
|
|
||||||
pub fn http_timeout() -> Duration {
|
pub fn http_timeout() -> Duration {
|
||||||
Duration::from_secs(120)
|
Duration::from_secs(120)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,22 @@
|
|||||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
|
use htycommons::cert::encrypt_text_with_private_key;
|
||||||
use htyts_models::{ReqTask, TaskStatus, TaskType};
|
use htyts_models::{ReqTask, TaskStatus, TaskType};
|
||||||
|
use serde::Deserialize;
|
||||||
|
use serde_json::json;
|
||||||
|
|
||||||
use crate::clients::{merge_row_status, ngx_combine_image, ngx_convert_audio, TsClient};
|
use crate::clients::{merge_row_status, ngx_combine_image, ngx_convert_audio, TsClient};
|
||||||
use crate::config;
|
use crate::config;
|
||||||
use crate::redis_task::RedisTask;
|
use crate::redis_task::RedisTask;
|
||||||
use crate::tasks;
|
use crate::tasks;
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
struct HtyResp {
|
||||||
|
r: bool,
|
||||||
|
d: Option<serde_json::Value>,
|
||||||
|
}
|
||||||
|
|
||||||
pub static PROCESSING: AtomicUsize = AtomicUsize::new(0);
|
pub static PROCESSING: AtomicUsize = AtomicUsize::new(0);
|
||||||
|
|
||||||
/// Mirrors Java `ProcessorHelper.Status`.
|
/// Mirrors Java `ProcessorHelper.Status`.
|
||||||
@@ -59,11 +68,11 @@ impl ProcessorRuntime {
|
|||||||
let http = reqwest::Client::builder()
|
let http = reqwest::Client::builder()
|
||||||
.timeout(config::http_timeout())
|
.timeout(config::http_timeout())
|
||||||
.build()?;
|
.build()?;
|
||||||
Ok(Arc::new(Self {
|
let rt = Arc::new(Self {
|
||||||
machine_status: Mutex::new(ProcMachineStatus::Pending),
|
machine_status: Mutex::new(ProcMachineStatus::Pending),
|
||||||
ts,
|
ts,
|
||||||
redis,
|
redis,
|
||||||
sudo_token: tokio::sync::Mutex::new(std::env::var("PROC_SUDOER_TOKEN").ok()),
|
sudo_token: tokio::sync::Mutex::new(None),
|
||||||
ts_domain,
|
ts_domain,
|
||||||
ngx_url,
|
ngx_url,
|
||||||
http,
|
http,
|
||||||
@@ -71,16 +80,79 @@ impl ProcessorRuntime {
|
|||||||
htyws_url,
|
htyws_url,
|
||||||
htyuc_url,
|
htyuc_url,
|
||||||
ts_url,
|
ts_url,
|
||||||
}))
|
});
|
||||||
|
// eagerly fetch token at startup so processor_loop can start immediately
|
||||||
|
if let Err(e) = rt.refresh_sudo_token().await {
|
||||||
|
tracing::warn!("initial sudo token refresh failed (will retry in loop): {e:?}");
|
||||||
|
}
|
||||||
|
Ok(rt)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn proc_status(&self) -> ProcMachineStatus {
|
pub fn proc_status(&self) -> ProcMachineStatus {
|
||||||
*self.machine_status.lock().expect("proc status mutex poisoned")
|
*self.machine_status.lock().expect("proc status mutex poisoned")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the cached sudoer token, or tries to refresh on the fly.
|
||||||
pub async fn sudo_token(&self) -> Option<String> {
|
pub async fn sudo_token(&self) -> Option<String> {
|
||||||
|
let cached = self.sudo_token.lock().await.clone();
|
||||||
|
if cached.is_some() {
|
||||||
|
return cached;
|
||||||
|
}
|
||||||
|
// token missing — try to obtain one
|
||||||
|
if let Err(e) = self.refresh_sudo_token().await {
|
||||||
|
tracing::warn!("sudo_token refresh on demand failed: {e:?}");
|
||||||
|
}
|
||||||
self.sudo_token.lock().await.clone()
|
self.sudo_token.lock().await.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Obtain a fresh sudoer token from UC via loginWithCert → sudo.
|
||||||
|
///
|
||||||
|
/// Mirrors Java `HtyucUtil.refreshRootTokenWithLoginWithCertAndThenSudo`.
|
||||||
|
async fn refresh_sudo_token(&self) -> anyhow::Result<()> {
|
||||||
|
// 1. Read keys
|
||||||
|
let priv_key = config::priv_key()?;
|
||||||
|
let pub_key = config::pub_key()?;
|
||||||
|
|
||||||
|
// 2. Sign pub_key with priv_key using Ed25519
|
||||||
|
let encrypted = encrypt_text_with_private_key(priv_key, pub_key.clone())?;
|
||||||
|
|
||||||
|
// 3. POST loginWithCert → returns JWT
|
||||||
|
let cert_url = format!("{}/api/v1/uc/login_with_cert", self.htyuc_url.trim_end_matches('/'));
|
||||||
|
let login_resp = self
|
||||||
|
.http
|
||||||
|
.post(&cert_url)
|
||||||
|
.header("HtyHost", &self.ts_domain)
|
||||||
|
.json(&json!({"encrypted_data": encrypted}))
|
||||||
|
.send()
|
||||||
|
.await?;
|
||||||
|
let login_body: HtyResp = login_resp.json().await?;
|
||||||
|
let login_jwt = login_body
|
||||||
|
.d
|
||||||
|
.and_then(|v| v.as_str().map(String::from))
|
||||||
|
.ok_or_else(|| anyhow::anyhow!("loginWithCert: r=false or missing d"))?;
|
||||||
|
|
||||||
|
tracing::debug!("loginWithCert succeeded, got JWT");
|
||||||
|
|
||||||
|
// 4. POST sudo → returns sudoer token (NO "Bearer " prefix)
|
||||||
|
let sudo_url = format!("{}/api/v1/uc/sudo", self.htyuc_url.trim_end_matches('/'));
|
||||||
|
let sudo_resp = self
|
||||||
|
.http
|
||||||
|
.post(&sudo_url)
|
||||||
|
.header("Authorization", &login_jwt)
|
||||||
|
.send()
|
||||||
|
.await?;
|
||||||
|
let sudo_body: HtyResp = sudo_resp.json().await?;
|
||||||
|
let sudoer_token = sudo_body
|
||||||
|
.d
|
||||||
|
.and_then(|v| v.as_str().map(String::from))
|
||||||
|
.ok_or_else(|| anyhow::anyhow!("sudo: r=false or missing d"))?;
|
||||||
|
|
||||||
|
tracing::info!("obtained new sudoer token");
|
||||||
|
|
||||||
|
// 5. Cache in-memory
|
||||||
|
*self.sudo_token.lock().await = Some(sudoer_token);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn processor_loop(rt: Arc<ProcessorRuntime>) {
|
pub async fn processor_loop(rt: Arc<ProcessorRuntime>) {
|
||||||
|
|||||||
Reference in New Issue
Block a user