fix(oauth): fix login failures and add provider icon_url config

- Fix FIND_OAUTH_LINKED_USER_SQL missing allowed_providers_mode columns
- Fix TOUCH_OAUTH_LINK_SQL json/jsonb type mismatch in COALESCE
- Add icon_url field to OAuth provider config (DB, API, frontend)
- Fix admin OAuth test: accept 404 as reachable, use system proxy
This commit is contained in:
dalamudx
2026-05-17 21:22:20 +08:00
parent 3a23eaa572
commit 48deff15c4
18 changed files with 91 additions and 16 deletions

View File

@@ -28,6 +28,8 @@ pub(crate) struct AdminOAuthProviderUpsertRequest {
#[serde(default)]
pub(super) extra_config: Option<serde_json::Value>,
#[serde(default)]
pub(super) icon_url: Option<String>,
#[serde(default)]
pub(super) is_enabled: bool,
#[serde(default)]
pub(super) force: bool,
@@ -70,6 +72,7 @@ pub(super) fn build_admin_oauth_provider_payload(
"frontend_callback_url": provider.frontend_callback_url,
"attribute_mapping": provider.attribute_mapping,
"extra_config": provider.extra_config,
"icon_url": provider.icon_url,
"is_enabled": provider.is_enabled,
})
}
@@ -364,6 +367,10 @@ pub(super) fn build_admin_oauth_upsert_record(
frontend_callback_url: frontend_callback_url.to_string(),
attribute_mapping: payload.attribute_mapping,
extra_config: payload.extra_config,
icon_url: payload.icon_url.and_then(|value| {
let value = value.trim().to_string();
(!value.is_empty()).then_some(value)
}),
is_enabled: payload.is_enabled,
})
}

View File

@@ -16,7 +16,7 @@ use axum::{
use serde_json::json;
use std::time::Duration;
const ADMIN_OAUTH_TEST_TIMEOUT_SECS: u64 = 5;
const ADMIN_OAUTH_TEST_TIMEOUT_SECS: u64 = 10;
const LINUXDO_AUTHORIZATION_URL: &str = "https://connect.linux.do/oauth2/authorize";
const LINUXDO_TOKEN_URL: &str = "https://connect.linux.do/oauth2/token";
@@ -54,10 +54,7 @@ async fn admin_oauth_endpoint_reachable(client: &reqwest::Client, url: &str) ->
.send()
.await
{
Ok(response) => {
let status = response.status();
status != reqwest::StatusCode::NOT_FOUND && status.as_u16() < 500
}
Ok(response) => response.status().as_u16() < 500,
Err(_) => false,
}
}
@@ -120,10 +117,16 @@ async fn build_admin_oauth_test_payload(
}));
};
let client = reqwest::Client::builder()
let proxy_snapshot = state.app().resolve_system_proxy_snapshot().await;
let mut client_builder = reqwest::Client::builder()
.timeout(Duration::from_secs(ADMIN_OAUTH_TEST_TIMEOUT_SECS))
.redirect(reqwest::redirect::Policy::limited(3))
.build();
.redirect(reqwest::redirect::Policy::limited(3));
if let Some(proxy_url) = proxy_snapshot.as_ref().and_then(|p| p.url.as_deref()) {
if let Ok(proxy) = reqwest::Proxy::all(proxy_url) {
client_builder = client_builder.proxy(proxy);
}
}
let client = client_builder.build();
let Ok(client) = client else {
return Ok(json!({
"authorization_url_reachable": false,

View File

@@ -1885,6 +1885,7 @@ impl<'a> AdminAppState<'a> {
oauth_provider.extra_config,
"extra_config",
)),
icon_url: None,
is_enabled: oauth_provider.is_enabled,
};
invalid!(record.validate().map_err(|err| err.to_string()));

View File

@@ -16,6 +16,8 @@ const LINUXDO_USERINFO_URL: &str = "https://connect.linux.do/api/user";
pub(crate) struct IdentityOAuthProviderSummary {
pub(crate) provider_type: String,
pub(crate) display_name: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub(crate) icon_url: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Serialize)]
@@ -77,6 +79,7 @@ pub(crate) async fn list_enabled_identity_oauth_providers(
.map(|provider| IdentityOAuthProviderSummary {
provider_type: provider.provider_type,
display_name: provider.display_name,
icon_url: provider.icon_url,
})
.collect::<Vec<_>>();
providers.sort_by(|left, right| left.provider_type.cmp(&right.provider_type));