mirror of
https://github.com/fawney19/Aether.git
synced 2026-09-01 17:00:21 +08:00
Normalize management token prefixes
This commit is contained in:
@@ -84,6 +84,8 @@ const LOCAL_EXECUTION_LOOP_DETECTED_DETAIL: &str =
|
||||
const AUTH_API_KEY_CONCURRENCY_LIMIT_REACHED_DETAIL: &str =
|
||||
"当前 API Key 并发请求数已达上限,请稍后重试";
|
||||
const EXECUTION_PATH_TUNNEL_AFFINITY_FORWARD: &str = "tunnel_affinity_forward";
|
||||
const MANAGEMENT_TOKEN_PREFIX: &str = "ae-";
|
||||
const LEGACY_MANAGEMENT_TOKEN_PREFIX: &str = "ae_";
|
||||
|
||||
fn local_execution_outcome_label(outcome: &LocalExecutionRequestOutcome) -> &'static str {
|
||||
match outcome {
|
||||
@@ -113,7 +115,10 @@ fn extract_management_token_bearer(headers: &http::HeaderMap) -> Option<String>
|
||||
.or_else(|| header.strip_prefix("bearer "))?
|
||||
.trim()
|
||||
.to_string();
|
||||
(!token.is_empty() && token.starts_with("ae_")).then_some(token)
|
||||
(!token.is_empty()
|
||||
&& (token.starts_with(MANAGEMENT_TOKEN_PREFIX)
|
||||
|| token.starts_with(LEGACY_MANAGEMENT_TOKEN_PREFIX)))
|
||||
.then_some(token)
|
||||
}
|
||||
|
||||
fn hash_management_token(value: &str) -> String {
|
||||
|
||||
@@ -19,11 +19,12 @@ use super::{
|
||||
query_param_value, resolve_authenticated_local_user, AppState, AuthenticatedLocalUserContext,
|
||||
GatewayPublicRequestContext,
|
||||
};
|
||||
use crate::handlers::shared::generate_gateway_secret_plaintext;
|
||||
use crate::LocalMutationOutcome;
|
||||
|
||||
const USERS_ME_MANAGEMENT_TOKEN_PREFIX: &str = "ae_";
|
||||
const USERS_ME_MANAGEMENT_TOKEN_RANDOM_LENGTH: usize = 40;
|
||||
const USERS_ME_MANAGEMENT_TOKEN_DISPLAY_PREFIX_LEN: usize = 7;
|
||||
const USERS_ME_MANAGEMENT_TOKEN_PREFIX: &str = "ae";
|
||||
const USERS_ME_MANAGEMENT_TOKEN_SEPARATOR: &str = "-";
|
||||
const USERS_ME_MANAGEMENT_TOKEN_DISPLAY_PREFIX_LEN: usize = 10;
|
||||
const USERS_ME_MANAGEMENT_TOKEN_FETCH_LIMIT: usize = 10_000;
|
||||
const USERS_ME_MANAGEMENT_TOKEN_DEFAULT_MAX_PER_USER: usize = 20;
|
||||
const USERS_ME_MANAGEMENT_TOKEN_MAX_PER_USER_ENV: &str = "MANAGEMENT_TOKEN_MAX_PER_USER";
|
||||
@@ -122,13 +123,10 @@ fn users_me_management_token_max_per_user() -> usize {
|
||||
}
|
||||
|
||||
fn generate_users_me_management_token_plaintext() -> String {
|
||||
let first = Uuid::new_v4().simple().to_string();
|
||||
let second = Uuid::new_v4().simple().to_string();
|
||||
let mut random_part = String::with_capacity(USERS_ME_MANAGEMENT_TOKEN_RANDOM_LENGTH);
|
||||
random_part.push_str(&first);
|
||||
random_part.push_str(&second);
|
||||
random_part.truncate(USERS_ME_MANAGEMENT_TOKEN_RANDOM_LENGTH);
|
||||
format!("{USERS_ME_MANAGEMENT_TOKEN_PREFIX}{random_part}")
|
||||
generate_gateway_secret_plaintext(
|
||||
USERS_ME_MANAGEMENT_TOKEN_PREFIX,
|
||||
USERS_ME_MANAGEMENT_TOKEN_SEPARATOR,
|
||||
)
|
||||
}
|
||||
|
||||
fn hash_users_me_management_token(value: &str) -> String {
|
||||
|
||||
@@ -26,7 +26,7 @@ fn api_key_placeholder_display_with_prefix(prefix: &str) -> String {
|
||||
format!("{prefix}-****")
|
||||
}
|
||||
|
||||
fn generate_gateway_api_key_plaintext_with_prefix(prefix: &str) -> String {
|
||||
fn generate_gateway_secret_random_part() -> String {
|
||||
let mut random = String::with_capacity(API_KEY_RANDOM_LEN);
|
||||
while random.len() < API_KEY_RANDOM_LEN {
|
||||
for byte in uuid::Uuid::new_v4().as_bytes() {
|
||||
@@ -37,7 +37,18 @@ fn generate_gateway_api_key_plaintext_with_prefix(prefix: &str) -> String {
|
||||
}
|
||||
}
|
||||
}
|
||||
format!("{prefix}-{random}")
|
||||
random
|
||||
}
|
||||
|
||||
pub(crate) fn generate_gateway_secret_plaintext(prefix: &str, separator: &str) -> String {
|
||||
format!(
|
||||
"{prefix}{separator}{}",
|
||||
generate_gateway_secret_random_part()
|
||||
)
|
||||
}
|
||||
|
||||
fn generate_gateway_api_key_plaintext_with_prefix(prefix: &str) -> String {
|
||||
generate_gateway_secret_plaintext(prefix, "-")
|
||||
}
|
||||
|
||||
pub(crate) fn configured_api_key_prefix() -> String {
|
||||
@@ -84,7 +95,8 @@ pub(crate) fn normalize_optional_api_key_concurrent_limit(
|
||||
mod tests {
|
||||
use super::{
|
||||
api_key_placeholder_display_with_prefix, configured_api_key_prefix_from_lookup,
|
||||
generate_gateway_api_key_plaintext_with_prefix, masked_gateway_api_key_display,
|
||||
generate_gateway_api_key_plaintext_with_prefix, generate_gateway_secret_plaintext,
|
||||
masked_gateway_api_key_display,
|
||||
};
|
||||
|
||||
#[test]
|
||||
@@ -114,6 +126,17 @@ mod tests {
|
||||
.all(|ch| ch.is_ascii_alphanumeric()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn generates_plaintext_secret_with_custom_separator() {
|
||||
let value = generate_gateway_secret_plaintext("ae", "-");
|
||||
assert!(value.starts_with("ae-"));
|
||||
assert_eq!(value.len(), 3 + 32);
|
||||
assert!(value
|
||||
.trim_start_matches("ae-")
|
||||
.chars()
|
||||
.all(|ch| ch.is_ascii_alphanumeric()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn uses_configured_prefix_in_placeholder_display() {
|
||||
assert_eq!(
|
||||
|
||||
@@ -16,7 +16,8 @@ pub(crate) use self::admin_proxy::{
|
||||
};
|
||||
pub(crate) use self::api_keys::{
|
||||
api_key_placeholder_display, configured_api_key_prefix, generate_gateway_api_key_plaintext,
|
||||
masked_gateway_api_key_display, normalize_optional_api_key_concurrent_limit,
|
||||
generate_gateway_secret_plaintext, masked_gateway_api_key_display,
|
||||
normalize_optional_api_key_concurrent_limit,
|
||||
};
|
||||
pub(crate) use self::catalog::{
|
||||
build_admin_provider_key_response, decrypt_catalog_secret_with_fallbacks,
|
||||
|
||||
@@ -663,7 +663,7 @@ async fn gateway_registers_and_unregisters_proxy_nodes_locally_with_management_t
|
||||
}),
|
||||
);
|
||||
|
||||
let raw_token = "ae_proxy_register_test";
|
||||
let raw_token = "ae-proxy-register-test";
|
||||
let proxy_node_repository = Arc::new(InMemoryProxyNodeRepository::default());
|
||||
let state = AppState::new().expect("gateway should build");
|
||||
let admin_user = state
|
||||
|
||||
@@ -6825,10 +6825,12 @@ async fn gateway_handles_users_me_management_token_writes_locally_without_proxyi
|
||||
.to_string();
|
||||
assert_eq!(create_payload["message"], "Management Token 创建成功");
|
||||
assert_eq!(create_payload["data"]["name"], "writer-token");
|
||||
assert!(create_payload["token"]
|
||||
.as_str()
|
||||
.unwrap_or_default()
|
||||
.starts_with("ae_"));
|
||||
let created_token = create_payload["token"].as_str().unwrap_or_default();
|
||||
let created_token_random = created_token.strip_prefix("ae-").unwrap_or_default();
|
||||
assert_eq!(created_token_random.len(), 32);
|
||||
assert!(created_token_random
|
||||
.chars()
|
||||
.all(|ch| ch.is_ascii_alphanumeric()));
|
||||
|
||||
let update_response = client
|
||||
.put(format!(
|
||||
@@ -6901,10 +6903,12 @@ async fn gateway_handles_users_me_management_token_writes_locally_without_proxyi
|
||||
.await
|
||||
.expect("json body should parse");
|
||||
assert_eq!(regenerate_payload["message"], "Token 已重新生成");
|
||||
assert!(regenerate_payload["token"]
|
||||
.as_str()
|
||||
.unwrap_or_default()
|
||||
.starts_with("ae_"));
|
||||
let regenerated_token = regenerate_payload["token"].as_str().unwrap_or_default();
|
||||
let regenerated_token_random = regenerated_token.strip_prefix("ae-").unwrap_or_default();
|
||||
assert_eq!(regenerated_token_random.len(), 32);
|
||||
assert!(regenerated_token_random
|
||||
.chars()
|
||||
.all(|ch| ch.is_ascii_alphanumeric()));
|
||||
|
||||
let delete_response = client
|
||||
.delete(format!(
|
||||
|
||||
@@ -132,7 +132,7 @@ impl StoredManagementToken {
|
||||
self.token_prefix
|
||||
.as_deref()
|
||||
.map(|prefix| format!("{prefix}...****"))
|
||||
.unwrap_or_else(|| "ae_****".to_string())
|
||||
.unwrap_or_else(|| "ae-****".to_string())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user