mirror of
https://github.com/fluxerapp/fluxer
synced 2026-10-17 13:05:32 +09:00
fix(config)!: validate and derive config, drop the unread keys (#2482)
This commit is contained in:
46 files changed
+1310
-199
No files matched your search
@@ -120,6 +120,10 @@ impl AdminConfig {
|
||||
pub fn is_production(&self) -> bool {
|
||||
self.env == RuntimeEnv::Production
|
||||
}
|
||||
|
||||
pub fn secure_cookies(&self) -> bool {
|
||||
self.admin_endpoint.starts_with("https://")
|
||||
}
|
||||
}
|
||||
|
||||
impl RuntimeEnv {
|
||||
|
||||
@@ -28,7 +28,7 @@ pub async fn csrf_protection(
|
||||
let config = state.config();
|
||||
let secret = config.secret_key_base.clone();
|
||||
let admin_endpoint = config.admin_endpoint.clone();
|
||||
let is_production = config.is_production();
|
||||
let secure_cookies = config.secure_cookies();
|
||||
|
||||
let user_id = request
|
||||
.extensions()
|
||||
@@ -76,17 +76,17 @@ pub async fn csrf_protection(
|
||||
|
||||
let mut response = next.run(request).await;
|
||||
|
||||
let cookie_name = if is_production {
|
||||
let cookie_name = if secure_cookies {
|
||||
HOST_CSRF_COOKIE_NAME
|
||||
} else {
|
||||
CSRF_COOKIE_NAME
|
||||
};
|
||||
let secure = if is_production { "; Secure" } else { "" };
|
||||
let secure = if secure_cookies { "; Secure" } else { "" };
|
||||
let cookie_value = format!("{cookie_name}={token}; Path=/; SameSite=Lax; HttpOnly{secure}");
|
||||
if let Ok(value) = HeaderValue::from_str(&cookie_value) {
|
||||
response.headers_mut().append(header::SET_COOKIE, value);
|
||||
}
|
||||
if is_production
|
||||
if secure_cookies
|
||||
&& let Ok(value) = HeaderValue::from_str(&format!(
|
||||
"{CSRF_COOKIE_NAME}=; Path=/; SameSite=Lax; HttpOnly; Max-Age=0"
|
||||
))
|
||||
@@ -199,6 +199,81 @@ pub fn get_csrf_token(request: &Request) -> String {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::config::{AdminConfig, ProxyConfig, RuntimeEnv};
|
||||
use crate::state::AppState;
|
||||
use axum::{Router, middleware::from_fn_with_state, routing::get};
|
||||
use tower::ServiceExt;
|
||||
|
||||
fn state_with_admin_endpoint(admin_endpoint: &str) -> AppState {
|
||||
AppState::new(AdminConfig {
|
||||
env: RuntimeEnv::Production,
|
||||
host: String::new(),
|
||||
port: 3020,
|
||||
secret_key_base: "test-secret".to_owned(),
|
||||
base_path: String::new(),
|
||||
api_endpoint: String::new(),
|
||||
media_endpoint: String::new(),
|
||||
static_cdn_endpoint: String::new(),
|
||||
admin_endpoint: admin_endpoint.to_owned(),
|
||||
web_app_endpoint: String::new(),
|
||||
kv_url: String::new(),
|
||||
oauth_client_id: String::new(),
|
||||
oauth_client_secret: String::new(),
|
||||
oauth_redirect_uri: String::new(),
|
||||
build_version: "test".to_owned(),
|
||||
release_channel: String::new(),
|
||||
self_hosted: false,
|
||||
proxy: ProxyConfig {
|
||||
trust_client_ip_header: false,
|
||||
client_ip_header_name: String::new(),
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
async fn csrf_cookies(admin_endpoint: &str) -> Vec<String> {
|
||||
let state = state_with_admin_endpoint(admin_endpoint);
|
||||
let app = Router::new()
|
||||
.route("/", get(|| async { "ok" }))
|
||||
.layer(from_fn_with_state(state, csrf_protection));
|
||||
let response = app
|
||||
.oneshot(Request::builder().uri("/").body(Body::empty()).unwrap())
|
||||
.await
|
||||
.expect("router responds");
|
||||
response
|
||||
.headers()
|
||||
.get_all(header::SET_COOKIE)
|
||||
.iter()
|
||||
.filter_map(|value| value.to_str().ok())
|
||||
.map(|value| value.to_owned())
|
||||
.collect()
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn https_admin_endpoint_sets_a_host_prefixed_secure_cookie() {
|
||||
let cookies = csrf_cookies("https://example.com/admin").await;
|
||||
assert!(
|
||||
cookies
|
||||
.iter()
|
||||
.any(|cookie| cookie.starts_with("__Host-csrf_token=")
|
||||
&& cookie.contains("; Secure")),
|
||||
"expected a secure __Host- cookie, got {cookies:?}"
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn http_admin_endpoint_sets_a_plain_cookie_without_secure() {
|
||||
let cookies = csrf_cookies("http://example.com/admin").await;
|
||||
assert!(
|
||||
cookies
|
||||
.iter()
|
||||
.any(|cookie| cookie.starts_with("csrf_token=") && !cookie.contains("Secure")),
|
||||
"expected a plain csrf_token cookie, got {cookies:?}"
|
||||
);
|
||||
assert!(
|
||||
!cookies.iter().any(|cookie| cookie.contains("__Host-")),
|
||||
"expected no __Host- cookie, got {cookies:?}"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn oauth2_callback_is_exempt() {
|
||||
|
||||
@@ -92,9 +92,9 @@ pub fn clear_flash_cookie(response: &mut Response) {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn redirect_with_flash(url: &str, flash: FlashData, is_production: bool) -> Response {
|
||||
pub fn redirect_with_flash(url: &str, flash: FlashData, secure: bool) -> Response {
|
||||
let encoded = serialize_flash(&flash);
|
||||
let secure_flag = if is_production { "; Secure" } else { "" };
|
||||
let secure_flag = if secure { "; Secure" } else { "" };
|
||||
let cookie_value = format!(
|
||||
"{FLASH_COOKIE_NAME}={encoded}; Path=/; HttpOnly; SameSite=Lax; Max-Age=60{secure_flag}"
|
||||
);
|
||||
|
||||
@@ -119,7 +119,7 @@ async fn admin_api_keys_post(
|
||||
return flash::redirect_with_flash(
|
||||
&format!("{base}/admin-api-keys"),
|
||||
flash,
|
||||
config.is_production(),
|
||||
config.secure_cookies(),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -128,7 +128,7 @@ async fn admin_api_keys_post(
|
||||
flash::redirect_with_flash(
|
||||
&format!("{base}/admin-api-keys"),
|
||||
FlashData::success(format!("API key action '{action}' completed.")),
|
||||
config.is_production(),
|
||||
config.secure_cookies(),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -143,7 +143,7 @@ fn admin_api_key_flash_response(
|
||||
flash::redirect_with_flash(
|
||||
&format!("{}/admin-api-keys", config.base_path),
|
||||
flash_data,
|
||||
config.is_production(),
|
||||
config.secure_cookies(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -151,7 +151,7 @@ async fn application_detail_post(
|
||||
return flash::redirect_with_flash(
|
||||
&format!("{base}/applications/{application_id}"),
|
||||
FlashData::error("Invalid form data"),
|
||||
config.is_production(),
|
||||
config.secure_cookies(),
|
||||
);
|
||||
}
|
||||
};
|
||||
@@ -178,6 +178,6 @@ async fn application_detail_post(
|
||||
flash::redirect_with_flash(
|
||||
&format!("{base}/applications/{application_id}"),
|
||||
flash,
|
||||
config.is_production(),
|
||||
config.secure_cookies(),
|
||||
)
|
||||
}
|
||||
@@ -187,7 +187,7 @@ async fn oauth2_callback_finish(
|
||||
|
||||
let session_cookie_value =
|
||||
session::create_session(&user.id, &token.access_token, &config.secret_key_base);
|
||||
let secure = if config.is_production() {
|
||||
let secure = if config.secure_cookies() {
|
||||
"; Secure"
|
||||
} else {
|
||||
""
|
||||
|
||||
@@ -82,7 +82,7 @@ async fn gift_codes_post(
|
||||
return flash::redirect_with_flash(
|
||||
&format!("{base}/gift-codes"),
|
||||
FlashData::error("Invalid form data"),
|
||||
config.is_production(),
|
||||
config.secure_cookies(),
|
||||
);
|
||||
}
|
||||
};
|
||||
@@ -99,14 +99,14 @@ async fn gift_codes_post(
|
||||
.and_then(|s| s.parse::<u32>().ok())
|
||||
.unwrap_or(1);
|
||||
let client = AdminApiClient::new(state.http_client(), config, &auth.0.session);
|
||||
let is_prod = config.is_production();
|
||||
let secure_cookies = config.secure_cookies();
|
||||
match client.generate_gift_codes(count, dur_type, dur_qty).await {
|
||||
Ok(result) => {
|
||||
let codes = result.codes.join(",");
|
||||
flash::redirect_with_flash(
|
||||
&format!("{base}/gift-codes?codes={codes}"),
|
||||
FlashData::success(format!("{} gift code(s) generated", result.codes.len())),
|
||||
is_prod,
|
||||
secure_cookies,
|
||||
)
|
||||
}
|
||||
Err(error) => {
|
||||
@@ -114,7 +114,7 @@ async fn gift_codes_post(
|
||||
flash::redirect_with_flash(
|
||||
&format!("{base}/gift-codes"),
|
||||
FlashData::error("Failed to generate gift codes"),
|
||||
is_prod,
|
||||
secure_cookies,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -105,7 +105,7 @@ async fn discovery_approve(
|
||||
return flash::redirect_with_flash(
|
||||
&format!("{base}/discovery"),
|
||||
FlashData::error("Invalid form data"),
|
||||
config.is_production(),
|
||||
config.secure_cookies(),
|
||||
);
|
||||
}
|
||||
};
|
||||
@@ -115,7 +115,7 @@ async fn discovery_approve(
|
||||
return flash::redirect_with_flash(
|
||||
&format!("{base}/discovery"),
|
||||
FlashData::error("Guild ID is required"),
|
||||
config.is_production(),
|
||||
config.secure_cookies(),
|
||||
);
|
||||
}
|
||||
};
|
||||
@@ -131,7 +131,7 @@ async fn discovery_approve(
|
||||
flash::redirect_with_flash(
|
||||
&format!("{base}/discovery?tab=pending"),
|
||||
flash,
|
||||
config.is_production(),
|
||||
config.secure_cookies(),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -149,7 +149,7 @@ async fn discovery_reject(
|
||||
return flash::redirect_with_flash(
|
||||
&format!("{base}/discovery"),
|
||||
FlashData::error("Invalid form data"),
|
||||
config.is_production(),
|
||||
config.secure_cookies(),
|
||||
);
|
||||
}
|
||||
};
|
||||
@@ -159,7 +159,7 @@ async fn discovery_reject(
|
||||
return flash::redirect_with_flash(
|
||||
&format!("{base}/discovery"),
|
||||
FlashData::error("Guild ID is required"),
|
||||
config.is_production(),
|
||||
config.secure_cookies(),
|
||||
);
|
||||
}
|
||||
};
|
||||
@@ -173,7 +173,7 @@ async fn discovery_reject(
|
||||
flash::redirect_with_flash(
|
||||
&format!("{base}/discovery?tab=pending"),
|
||||
flash,
|
||||
config.is_production(),
|
||||
config.secure_cookies(),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -191,7 +191,7 @@ async fn discovery_remove(
|
||||
return flash::redirect_with_flash(
|
||||
&format!("{base}/discovery"),
|
||||
FlashData::error("Invalid form data"),
|
||||
config.is_production(),
|
||||
config.secure_cookies(),
|
||||
);
|
||||
}
|
||||
};
|
||||
@@ -201,7 +201,7 @@ async fn discovery_remove(
|
||||
return flash::redirect_with_flash(
|
||||
&format!("{base}/discovery"),
|
||||
FlashData::error("Guild ID is required"),
|
||||
config.is_production(),
|
||||
config.secure_cookies(),
|
||||
);
|
||||
}
|
||||
};
|
||||
@@ -215,6 +215,6 @@ async fn discovery_remove(
|
||||
flash::redirect_with_flash(
|
||||
&format!("{base}/discovery?tab=listed"),
|
||||
flash,
|
||||
config.is_production(),
|
||||
config.secure_cookies(),
|
||||
)
|
||||
}
|
||||
@@ -191,7 +191,7 @@ async fn guild_detail_post(
|
||||
return flash::redirect_with_flash(
|
||||
&format!("{base}/guilds/{guild_id}"),
|
||||
FlashData::error("Invalid form data"),
|
||||
config.is_production(),
|
||||
config.secure_cookies(),
|
||||
);
|
||||
}
|
||||
};
|
||||
@@ -203,7 +203,7 @@ async fn guild_detail_post(
|
||||
} else {
|
||||
format!("{base}/guilds/{guild_id}?tab={tab}")
|
||||
};
|
||||
flash::redirect_with_flash(&redirect, flash, config.is_production())
|
||||
flash::redirect_with_flash(&redirect, flash, config.secure_cookies())
|
||||
}
|
||||
|
||||
async fn dispatch_guild_action(
|
||||
|
||||
@@ -187,7 +187,7 @@ async fn job_detail_post(
|
||||
return flash::redirect_with_flash(
|
||||
&format!("{base}/jobs/{job_id}"),
|
||||
FlashData::error("Invalid form data"),
|
||||
config.is_production(),
|
||||
config.secure_cookies(),
|
||||
);
|
||||
}
|
||||
};
|
||||
@@ -214,7 +214,7 @@ async fn job_detail_post(
|
||||
flash::redirect_with_flash(
|
||||
&format!("{base}/jobs/{job_id}"),
|
||||
flash,
|
||||
config.is_production(),
|
||||
config.secure_cookies(),
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ pub(crate) async fn messages_post(
|
||||
return flash::redirect_with_flash(
|
||||
&format!("{base}/messages"),
|
||||
FlashData::error("Invalid form data"),
|
||||
config.is_production(),
|
||||
config.secure_cookies(),
|
||||
);
|
||||
}
|
||||
};
|
||||
@@ -164,7 +164,7 @@ pub(crate) async fn system_dms_post(
|
||||
return flash::redirect_with_flash(
|
||||
&format!("{base}/system-dms"),
|
||||
FlashData::error("Invalid form data"),
|
||||
config.is_production(),
|
||||
config.secure_cookies(),
|
||||
);
|
||||
}
|
||||
};
|
||||
@@ -184,7 +184,11 @@ pub(crate) async fn system_dms_post(
|
||||
} else {
|
||||
FlashData::error("Recipients and content are required")
|
||||
};
|
||||
flash::redirect_with_flash(&format!("{base}/system-dms"), flash, config.is_production())
|
||||
flash::redirect_with_flash(
|
||||
&format!("{base}/system-dms"),
|
||||
flash,
|
||||
config.secure_cookies(),
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) async fn bulk_actions_post(
|
||||
@@ -201,7 +205,7 @@ pub(crate) async fn bulk_actions_post(
|
||||
return flash::redirect_with_flash(
|
||||
&format!("{base}/bulk-actions"),
|
||||
FlashData::error("Invalid form data"),
|
||||
config.is_production(),
|
||||
config.secure_cookies(),
|
||||
);
|
||||
}
|
||||
};
|
||||
@@ -278,7 +282,7 @@ pub(crate) async fn bulk_actions_post(
|
||||
return flash::redirect_with_flash(
|
||||
&format!("{base}/bulk-actions"),
|
||||
FlashData::error("Unknown bulk action"),
|
||||
config.is_production(),
|
||||
config.secure_cookies(),
|
||||
);
|
||||
}
|
||||
};
|
||||
@@ -290,7 +294,7 @@ pub(crate) async fn bulk_actions_post(
|
||||
flash::redirect_with_flash(
|
||||
&format!("{base}/bulk-actions"),
|
||||
FlashData::success("Bulk action submitted"),
|
||||
config.is_production(),
|
||||
config.secure_cookies(),
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -299,7 +303,7 @@ pub(crate) async fn bulk_actions_post(
|
||||
flash::redirect_with_flash(
|
||||
&format!("{base}/bulk-actions"),
|
||||
FlashData::error("Failed to submit bulk action"),
|
||||
config.is_production(),
|
||||
config.secure_cookies(),
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -405,14 +409,14 @@ pub(crate) async fn archives_download(
|
||||
Ok(_) => flash::redirect_with_flash(
|
||||
&format!("{base}/archives"),
|
||||
FlashData::error("Archive download URL was empty"),
|
||||
config.is_production(),
|
||||
config.secure_cookies(),
|
||||
),
|
||||
Err(error) => {
|
||||
tracing::warn!(%error, "admin API request failed: get archive download URL");
|
||||
flash::redirect_with_flash(
|
||||
&format!("{base}/archives"),
|
||||
FlashData::error("Failed to create archive download URL"),
|
||||
config.is_production(),
|
||||
config.secure_cookies(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -195,7 +195,7 @@ async fn report_resolve(
|
||||
return flash::redirect_with_flash(
|
||||
&format!("{base}/reports/{report_id}"),
|
||||
FlashData::error("Invalid form data"),
|
||||
config.is_production(),
|
||||
config.secure_cookies(),
|
||||
);
|
||||
}
|
||||
};
|
||||
@@ -212,7 +212,7 @@ async fn report_resolve(
|
||||
flash::redirect_with_flash(
|
||||
&format!("{base}/reports/{report_id}"),
|
||||
FlashData::success("Report resolved"),
|
||||
config.is_production(),
|
||||
config.secure_cookies(),
|
||||
)
|
||||
}
|
||||
Err(error) => {
|
||||
@@ -223,7 +223,7 @@ async fn report_resolve(
|
||||
flash::redirect_with_flash(
|
||||
&format!("{base}/reports/{report_id}"),
|
||||
FlashData::error("Failed to resolve report"),
|
||||
config.is_production(),
|
||||
config.secure_cookies(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,8 +44,8 @@ pub struct ActionQuery {
|
||||
pub rule: Option<String>,
|
||||
}
|
||||
|
||||
pub fn redirect_back_with_flash(base: &str, path: &str, fd: FlashData, prod: bool) -> Response {
|
||||
flash::redirect_with_flash(&format!("{base}{path}"), fd, prod)
|
||||
pub fn redirect_back_with_flash(base: &str, path: &str, fd: FlashData, secure: bool) -> Response {
|
||||
flash::redirect_with_flash(&format!("{base}{path}"), fd, secure)
|
||||
}
|
||||
|
||||
pub async fn gateway_post(
|
||||
@@ -63,7 +63,7 @@ pub async fn gateway_post(
|
||||
base,
|
||||
"/gateway",
|
||||
FlashData::error("Invalid form data"),
|
||||
config.is_production(),
|
||||
config.secure_cookies(),
|
||||
);
|
||||
}
|
||||
};
|
||||
@@ -80,7 +80,7 @@ pub async fn gateway_post(
|
||||
} else {
|
||||
FlashData::error("Unknown gateway action")
|
||||
};
|
||||
redirect_back_with_flash(base, "/gateway", flash, config.is_production())
|
||||
redirect_back_with_flash(base, "/gateway", flash, config.secure_cookies())
|
||||
}
|
||||
|
||||
pub async fn search_index_post(
|
||||
@@ -97,7 +97,7 @@ pub async fn search_index_post(
|
||||
base,
|
||||
"/search-index",
|
||||
FlashData::error("Invalid form data"),
|
||||
config.is_production(),
|
||||
config.secure_cookies(),
|
||||
);
|
||||
}
|
||||
};
|
||||
@@ -114,7 +114,7 @@ pub async fn search_index_post(
|
||||
flash::redirect_with_flash(
|
||||
&format!("{base}/search-index?job_id={job_id}"),
|
||||
FlashData::success("Search index refresh started"),
|
||||
config.is_production(),
|
||||
config.secure_cookies(),
|
||||
)
|
||||
}
|
||||
Err(error) => {
|
||||
@@ -123,7 +123,7 @@ pub async fn search_index_post(
|
||||
base,
|
||||
"/search-index",
|
||||
FlashData::error("Failed to start search index refresh"),
|
||||
config.is_production(),
|
||||
config.secure_cookies(),
|
||||
)
|
||||
}
|
||||
};
|
||||
@@ -132,7 +132,7 @@ pub async fn search_index_post(
|
||||
base,
|
||||
"/search-index",
|
||||
FlashData::error("Index type is required"),
|
||||
config.is_production(),
|
||||
config.secure_cookies(),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -157,7 +157,7 @@ pub async fn instance_config_post(
|
||||
base,
|
||||
"/instance-config",
|
||||
flash,
|
||||
config.is_production(),
|
||||
config.secure_cookies(),
|
||||
);
|
||||
}
|
||||
};
|
||||
@@ -320,7 +320,7 @@ pub async fn instance_config_post(
|
||||
if htmx::is_htmx_request(&headers) {
|
||||
return htmx::toast_response(&flash);
|
||||
}
|
||||
redirect_back_with_flash(base, "/instance-config", flash, config.is_production())
|
||||
redirect_back_with_flash(base, "/instance-config", flash, config.secure_cookies())
|
||||
}
|
||||
|
||||
fn render_registration_url_list_response(
|
||||
@@ -866,13 +866,13 @@ pub async fn limit_config_post(
|
||||
base,
|
||||
"/limit-config",
|
||||
FlashData::error("Invalid form data"),
|
||||
config.is_production(),
|
||||
config.secure_cookies(),
|
||||
);
|
||||
}
|
||||
};
|
||||
let client = AdminApiClient::new(state.http_client(), config, &auth.0.session);
|
||||
let action = aq.action.as_deref().unwrap_or("");
|
||||
let is_prod = config.is_production();
|
||||
let secure_cookies = config.secure_cookies();
|
||||
let current = match client.get_limit_config().await {
|
||||
Ok(current) => current,
|
||||
Err(error) => {
|
||||
@@ -881,7 +881,7 @@ pub async fn limit_config_post(
|
||||
base,
|
||||
"/limit-config",
|
||||
FlashData::error("Failed to fetch current limit configuration"),
|
||||
is_prod,
|
||||
secure_cookies,
|
||||
);
|
||||
}
|
||||
};
|
||||
@@ -895,7 +895,7 @@ pub async fn limit_config_post(
|
||||
base,
|
||||
"/limit-config",
|
||||
FlashData::error("Rule not found"),
|
||||
is_prod,
|
||||
secure_cookies,
|
||||
);
|
||||
}
|
||||
};
|
||||
@@ -908,7 +908,7 @@ pub async fn limit_config_post(
|
||||
base,
|
||||
"/limit-config",
|
||||
FlashData::error("Rule not found"),
|
||||
is_prod,
|
||||
secure_cookies,
|
||||
);
|
||||
};
|
||||
let fallback = current
|
||||
@@ -923,7 +923,7 @@ pub async fn limit_config_post(
|
||||
"Limit configuration updated",
|
||||
"Failed to update limit configuration",
|
||||
);
|
||||
return redirect_back_with_flash(base, "/limit-config", flash, is_prod);
|
||||
return redirect_back_with_flash(base, "/limit-config", flash, secure_cookies);
|
||||
}
|
||||
"delete" => {
|
||||
let rule_id = match aq.rule.as_deref().and_then(clean_string) {
|
||||
@@ -933,7 +933,7 @@ pub async fn limit_config_post(
|
||||
base,
|
||||
"/limit-config",
|
||||
FlashData::error("Rule not found"),
|
||||
is_prod,
|
||||
secure_cookies,
|
||||
);
|
||||
}
|
||||
};
|
||||
@@ -942,7 +942,7 @@ pub async fn limit_config_post(
|
||||
base,
|
||||
"/limit-config",
|
||||
FlashData::error("The default rule cannot be deleted"),
|
||||
is_prod,
|
||||
secure_cookies,
|
||||
);
|
||||
}
|
||||
let old_len = limit_config.rules.len();
|
||||
@@ -952,14 +952,14 @@ pub async fn limit_config_post(
|
||||
base,
|
||||
"/limit-config",
|
||||
FlashData::error("Rule not found"),
|
||||
is_prod,
|
||||
secure_cookies,
|
||||
);
|
||||
}
|
||||
let request = LimitConfigUpdateRequest { limit_config };
|
||||
let result = client.update_limit_config(&request).await;
|
||||
let flash =
|
||||
limit_config_result(result, "Limit rule deleted", "Failed to delete limit rule");
|
||||
return redirect_back_with_flash(base, "/limit-config", flash, is_prod);
|
||||
return redirect_back_with_flash(base, "/limit-config", flash, secure_cookies);
|
||||
}
|
||||
"create" => {
|
||||
let rule_id = match form.clean("rule_id") {
|
||||
@@ -969,7 +969,7 @@ pub async fn limit_config_post(
|
||||
base,
|
||||
"/limit-config",
|
||||
FlashData::error("Rule ID is required"),
|
||||
is_prod,
|
||||
secure_cookies,
|
||||
);
|
||||
}
|
||||
};
|
||||
@@ -978,7 +978,7 @@ pub async fn limit_config_post(
|
||||
base,
|
||||
"/limit-config",
|
||||
FlashData::error("The default rule ID is reserved"),
|
||||
is_prod,
|
||||
secure_cookies,
|
||||
);
|
||||
}
|
||||
if limit_config.rules.iter().any(|rule| rule.id == rule_id) {
|
||||
@@ -986,7 +986,7 @@ pub async fn limit_config_post(
|
||||
base,
|
||||
"/limit-config",
|
||||
FlashData::error("Rule ID already exists"),
|
||||
is_prod,
|
||||
secure_cookies,
|
||||
);
|
||||
}
|
||||
let limits = current.defaults.get("default").cloned().unwrap_or_default();
|
||||
@@ -1000,7 +1000,7 @@ pub async fn limit_config_post(
|
||||
let result = client.update_limit_config(&request).await;
|
||||
let flash =
|
||||
limit_config_result(result, "Limit rule created", "Failed to create limit rule");
|
||||
return redirect_back_with_flash(base, "/limit-config", flash, is_prod);
|
||||
return redirect_back_with_flash(base, "/limit-config", flash, secure_cookies);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
@@ -1008,7 +1008,7 @@ pub async fn limit_config_post(
|
||||
base,
|
||||
"/limit-config",
|
||||
FlashData::success("Limit config updated"),
|
||||
is_prod,
|
||||
secure_cookies,
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -189,7 +189,7 @@ async fn user_detail_post(
|
||||
return flash::redirect_with_flash(
|
||||
&format!("{base}/users/{user_id}"),
|
||||
flash,
|
||||
config.is_production(),
|
||||
config.secure_cookies(),
|
||||
);
|
||||
}
|
||||
};
|
||||
@@ -208,7 +208,7 @@ async fn user_detail_post(
|
||||
{
|
||||
return htmx::toast_response(&outcome.flash);
|
||||
}
|
||||
flash::redirect_with_flash(&redirect, outcome.flash, config.is_production())
|
||||
flash::redirect_with_flash(&redirect, outcome.flash, config.secure_cookies())
|
||||
}
|
||||
|
||||
async fn user_tab(
|
||||
|
||||
@@ -160,7 +160,7 @@ pub(crate) async fn voice_regions_post(
|
||||
flash::redirect_with_flash(
|
||||
&format!("{base}/voice-regions"),
|
||||
flash_from_level(level, &msg),
|
||||
config.is_production(),
|
||||
config.secure_cookies(),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -232,7 +232,7 @@ pub(crate) async fn voice_servers_post(
|
||||
flash::redirect_with_flash(
|
||||
&redirect_url,
|
||||
flash_from_level(level, &msg),
|
||||
config.is_production(),
|
||||
config.secure_cookies(),
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user