Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 42 additions & 10 deletions src-tauri/src/commands/url_watcher.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
use crate::service::user::UserService;
use crate::utils::{format_cookies, get_window_cookies};

use log::info;
use serde_json::json;
use std::time::{Duration, Instant};
use tauri::{AppHandle, Emitter, Manager};
use tokio::time::{self, MissedTickBehavior};
use url::Url;

#[tauri::command]
pub fn url_watcher(app: AppHandle, name: String, origin: String) {
tauri::async_runtime::spawn(async move {
info!("开始监听 url 变化");
log::info!("开始监听 url 变化");

let mut cookie_header: String = String::new();
let mut effective_origin = origin.clone();
let mut ticker = time::interval(Duration::from_secs(2));

let start = Instant::now();
Expand Down Expand Up @@ -50,30 +51,43 @@ pub fn url_watcher(app: AppHandle, name: String, origin: String) {
// - 尚未创建:在宽限期内继续等待;
// - 曾经存在后丢失:视为用户关闭,结束监听;
match app.get_webview_window(&name) {
Some(_) => {
Some(window) => {
seen_window = true;

if let Ok(current_url) = window.url() {
if let Some(updated_origin) = http_origin_from_url(&current_url) {
if updated_origin != effective_origin {
log::info!(
"检测到登录窗口跳转: {} -> 使用实际站点 {}",
current_url,
updated_origin
);
effective_origin = updated_origin;
}
}
}
}
None => {
if !seen_window {
if start.elapsed() < create_grace {
if !logged_waiting {
info!("等待登录窗口创建...");
log::info!("等待登录窗口创建...");
logged_waiting = true;
}
continue;
} else {
info!("登录窗口未创建或已被立即关闭,结束监听");
log::info!("登录窗口未创建或已被立即关闭,结束监听");
break;
}
} else {
info!("检测到登录窗口被关闭,结束监听");
log::info!("检测到登录窗口被关闭,结束监听");
break;
}
}
}

// 轮询获取 Cookies(第三方认证)
if let Ok(cookies) = get_window_cookies(&app, &name, &origin).await {
if let Ok(cookies) = get_window_cookies(&app, &name, &effective_origin).await {
let new_header = format_cookies(&cookies);
if !new_header.is_empty() && new_header != cookie_header {
cookie_header = new_header;
Expand All @@ -85,16 +99,16 @@ pub fn url_watcher(app: AppHandle, name: String, origin: String) {
}

// 轮询调用直到 status 为 200
let user_service = UserService::new(origin.clone(), cookie_header.clone());
let user_service = UserService::new(effective_origin.clone(), cookie_header.clone());
let profile = user_service.get_user_profile().await;

info!("profile: {:?}", profile);
log::info!("profile: {:?}", profile);

if profile.status != 401 && profile.success {
let user_data = user_service.init().await;
let version_message = user_service.get_version_message().await;

info!("version_message: {:?}", version_message);
log::info!("version_message: {:?}", version_message);

let version = if version_message.status == 200 && version_message.success {
version_message.data
Expand All @@ -113,6 +127,7 @@ pub fn url_watcher(app: AppHandle, name: String, origin: String) {
"current_org": user_data.current_org,
"cookies": cookie_header,
"version": version,
"resolved_site": effective_origin,
}),
);

Expand All @@ -124,3 +139,20 @@ pub fn url_watcher(app: AppHandle, name: String, origin: String) {
}
});
}

fn http_origin_from_url(url: &Url) -> Option<String> {
match url.scheme() {
"http" | "https" => {
let host = url.host_str()?;
let mut origin = format!("{}://{}", url.scheme(), host);

if let Some(port) = url.port() {
origin.push(':');
origin.push_str(&port.to_string());
}

Some(origin)
}
_ => None,
}
}
1 change: 1 addition & 0 deletions src-tauri/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ pub fn run() {
tauri::Builder::default()
.plugin(
tauri_plugin_log::Builder::new()
.level(log::LevelFilter::Info)
.max_file_size(500_000 /* bytes */)
.timezone_strategy(tauri_plugin_log::TimezoneStrategy::UseLocal)
.rotation_strategy(tauri_plugin_log::RotationStrategy::KeepSome(5))
Expand Down
17 changes: 13 additions & 4 deletions src-tauri/src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,19 +54,28 @@ pub async fn get_window_cookies(
let url = Url::parse(origin)
.or_else(|_| Url::parse(&format!("https://{}", origin)))
.map_err(|e| e.to_string())?;
let target_domain = url.host_str().unwrap_or("");
let target_domain = url.host_str().unwrap_or("").trim_start_matches('.').to_string();
let target_is_ip = target_domain.parse::<std::net::IpAddr>().is_ok();

sleep(Duration::from_millis(1000)).await;

let all_cookies = win.cookies().map_err(|e| e.to_string())?;
let cookies: Vec<_> = all_cookies
.into_iter()
.filter(|cookie| {
if target_is_ip {
return true;
}
let domain = cookie.domain().unwrap_or("");
// 更宽松的域名匹配:支持父子域
let cd = domain.trim_start_matches('.');
let td = target_domain.trim_start_matches('.');
cd == td || cd.ends_with(&format!(".{}", td)) || td.ends_with(&format!(".{}", cd))
let td = target_domain.as_str();

let exact_or_subdomain =
!cd.is_empty() && (cd == td || cd.ends_with(&format!(".{}", td)) || td.ends_with(&format!(".{}", cd)));

let ip_cookie_without_domain = cd.is_empty() && target_is_ip;

exact_or_subdomain || ip_cookie_without_domain
})
.collect();

Expand Down
8 changes: 5 additions & 3 deletions ui/components/SideBar/profile.vue
Original file line number Diff line number Diff line change
Expand Up @@ -445,7 +445,8 @@ onMounted(async () => {
});

unlistenLoginSuccessRef.value = await useTauriEventListen("login-success-detected", async (event) => {
const { status, profile, permission_orgs, current_org, cookies, version } = event.payload as UserIntiInfo;
const { status, profile, permission_orgs, current_org, cookies, version, resolved_site } =
event.payload as UserIntiInfo;
const appVersion = await useTauriAppGetVersion().catch(() => "");

let versionMessage: string | string[] = version ?? "";
Expand All @@ -468,6 +469,7 @@ onMounted(async () => {
const permissionOrgData = JSON.parse((permission_orgs as any).data) as PermissionOrgs;

const normalizedSite = normalizedInputSite.value;
const resolvedSite = resolved_site || normalizedSite;

if (status === "success" && profileData) {
const language = resolveLanguageFromCookies(cookies);
Expand All @@ -483,10 +485,10 @@ onMounted(async () => {

const availableOrgs = initSelectOrganization(permissionOrgData);

userInfoStore.setUserData(normalizedSite, {
userInfoStore.setUserData(resolvedSite, {
name: profileData.name,
headerJson: cookies,
site: normalizedSite,
site: resolvedSite,
org: currentOrgData,
system_roles: profileData.system_roles,
availableOrgs,
Expand Down
9 changes: 8 additions & 1 deletion ui/pages/setting/appearance.vue
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,14 @@ function applyFont(font: string) {

<div class="flex items-center justify-between">
<span class="text-sm font-medium">{{ t("Common.Fonts") }}</span>
<USelectMenu v-model="selectedFont" :items="fontsItems" value-key="id" option-attribute="label" class="w-56" />
<USelectMenu
v-model="selectedFont"
:items="fontsItems"
:search-input="{ placeholder: t('Operation.Search') }"
value-key="id"
option-attribute="label"
class="w-56"
/>
</div>
</div>
</template>
1 change: 1 addition & 0 deletions ui/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ export interface UserIntiInfo {
status: string;
cookies: string;
version?: string;
resolved_site?: string;
profile: {
data: string;
};
Expand Down