mirror of
https://github.com/yuezk/GlobalProtect-openconnect.git
synced 2025-05-20 07:26:58 -04:00
Compare commits
3 Commits
gpauth_win
...
dev
Author | SHA1 | Date | |
---|---|---|---|
|
dc9480fd71 | ||
|
fa2849a080 | ||
|
c70c7ee5b9 |
10
.github/workflows/build.yaml
vendored
10
.github/workflows/build.yaml
vendored
@@ -152,11 +152,13 @@ jobs:
|
|||||||
- name: Build ${{ matrix.package }} package in Docker
|
- name: Build ${{ matrix.package }} package in Docker
|
||||||
run: |
|
run: |
|
||||||
docker run --pull=always --rm \
|
docker run --pull=always --rm \
|
||||||
|
-e COREPACK_INTEGRITY_KEYS=0 \
|
||||||
-v $(pwd)/build-gp-${{ matrix.package }}:/${{ matrix.package }} \
|
-v $(pwd)/build-gp-${{ matrix.package }}:/${{ matrix.package }} \
|
||||||
yuezk/gpdev:${{ matrix.package }}-builder-tauri2
|
yuezk/gpdev:${{ matrix.package }}-builder-tauri2
|
||||||
- name: Install ${{ matrix.package }} package in Docker
|
- name: Install ${{ matrix.package }} package in Docker
|
||||||
run: |
|
run: |
|
||||||
docker run --pull=always --rm \
|
docker run --pull=always --rm \
|
||||||
|
-e COREPACK_INTEGRITY_KEYS=0 \
|
||||||
-e GPGUI_INSTALLED=0 \
|
-e GPGUI_INSTALLED=0 \
|
||||||
-v $(pwd)/build-gp-${{ matrix.package }}:/${{ matrix.package }} \
|
-v $(pwd)/build-gp-${{ matrix.package }}:/${{ matrix.package }} \
|
||||||
yuezk/gpdev:${{ matrix.package }}-builder-tauri2 \
|
yuezk/gpdev:${{ matrix.package }}-builder-tauri2 \
|
||||||
@@ -205,12 +207,16 @@ jobs:
|
|||||||
run: echo ${{ secrets.DOCKER_HUB_TOKEN }} | docker login -u ${{ secrets.DOCKER_HUB_USERNAME }} --password-stdin
|
run: echo ${{ secrets.DOCKER_HUB_TOKEN }} | docker login -u ${{ secrets.DOCKER_HUB_USERNAME }} --password-stdin
|
||||||
- name: Build gpgui in Docker
|
- name: Build gpgui in Docker
|
||||||
run: |
|
run: |
|
||||||
docker run --pull=always --rm -v $(pwd)/gpgui-source:/gpgui yuezk/gpdev:gpgui-builder-tauri2
|
docker run --pull=always --rm \
|
||||||
|
-e COREPACK_INTEGRITY_KEYS=0 \
|
||||||
|
-v $(pwd)/gpgui-source:/gpgui yuezk/gpdev:gpgui-builder-tauri2
|
||||||
- name: Install gpgui in Docker
|
- name: Install gpgui in Docker
|
||||||
run: |
|
run: |
|
||||||
cd gpgui-source
|
cd gpgui-source
|
||||||
tar -xJf *.bin.tar.xz
|
tar -xJf *.bin.tar.xz
|
||||||
docker run --pull=always --rm -v $(pwd):/gpgui yuezk/gpdev:gpgui-builder-tauri2 \
|
docker run --pull=always --rm \
|
||||||
|
-e COREPACK_INTEGRITY_KEYS=0 \
|
||||||
|
-v $(pwd):/gpgui yuezk/gpdev:gpgui-builder-tauri2 \
|
||||||
bash -c "cd /gpgui/gpgui_*/ && ./gpgui --version"
|
bash -c "cd /gpgui/gpgui_*/ && ./gpgui --version"
|
||||||
- name: Upload gpgui
|
- name: Upload gpgui
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v4
|
||||||
|
2
.github/workflows/release.yaml
vendored
2
.github/workflows/release.yaml
vendored
@@ -112,12 +112,14 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
docker run --pull=always --rm \
|
docker run --pull=always --rm \
|
||||||
-v $(pwd)/build-${{ matrix.package }}:/${{ matrix.package }} \
|
-v $(pwd)/build-${{ matrix.package }}:/${{ matrix.package }} \
|
||||||
|
-e COREPACK_INTEGRITY_KEYS=0 \
|
||||||
-e INCLUDE_GUI=1 \
|
-e INCLUDE_GUI=1 \
|
||||||
yuezk/gpdev:${{ matrix.package }}-builder-tauri2
|
yuezk/gpdev:${{ matrix.package }}-builder-tauri2
|
||||||
|
|
||||||
- name: Install ${{ matrix.package }} package in Docker
|
- name: Install ${{ matrix.package }} package in Docker
|
||||||
run: |
|
run: |
|
||||||
docker run --pull=always --rm \
|
docker run --pull=always --rm \
|
||||||
|
-e COREPACK_INTEGRITY_KEYS=0 \
|
||||||
-v $(pwd)/build-${{ matrix.package }}:/${{ matrix.package }} \
|
-v $(pwd)/build-${{ matrix.package }}:/${{ matrix.package }} \
|
||||||
yuezk/gpdev:${{ matrix.package }}-builder-tauri2 \
|
yuezk/gpdev:${{ matrix.package }}-builder-tauri2 \
|
||||||
bash install.sh
|
bash install.sh
|
||||||
|
457
Cargo.lock
generated
457
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -11,7 +11,7 @@ members = [
|
|||||||
|
|
||||||
[workspace.package]
|
[workspace.package]
|
||||||
rust-version = "1.80"
|
rust-version = "1.80"
|
||||||
version = "2.4.3"
|
version = "2.4.4"
|
||||||
authors = ["Kevin Yue <k3vinyue@gmail.com>"]
|
authors = ["Kevin Yue <k3vinyue@gmail.com>"]
|
||||||
homepage = "https://github.com/yuezk/GlobalProtect-openconnect"
|
homepage = "https://github.com/yuezk/GlobalProtect-openconnect"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
193
apps/gpgui-helper/dist/assets/main-CQPVXkdn.js
vendored
193
apps/gpgui-helper/dist/assets/main-CQPVXkdn.js
vendored
File diff suppressed because one or more lines are too long
228
apps/gpgui-helper/dist/assets/main-sEPcTvJX.js
vendored
Normal file
228
apps/gpgui-helper/dist/assets/main-sEPcTvJX.js
vendored
Normal file
File diff suppressed because one or more lines are too long
2
apps/gpgui-helper/dist/index.html
vendored
2
apps/gpgui-helper/dist/index.html
vendored
@@ -5,7 +5,7 @@
|
|||||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
<title>GlobalProtect</title>
|
<title>GlobalProtect</title>
|
||||||
<script type="module" crossorigin src="/assets/main-CQPVXkdn.js"></script>
|
<script type="module" crossorigin src="/assets/main-sEPcTvJX.js"></script>
|
||||||
<link rel="stylesheet" crossorigin href="/assets/main-B3YRsHQ2.css">
|
<link rel="stylesheet" crossorigin href="/assets/main-B3YRsHQ2.css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
@@ -11,27 +11,27 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@emotion/react": "^11.14.0",
|
"@emotion/react": "^11.14.0",
|
||||||
"@emotion/styled": "^11.14.0",
|
"@emotion/styled": "^11.14.0",
|
||||||
"@mui/icons-material": "^6.3.0",
|
"@mui/icons-material": "^6.4.3",
|
||||||
"@mui/material": "^6.3.0",
|
"@mui/material": "^6.4.3",
|
||||||
"@tauri-apps/api": "^2.1.1",
|
"@tauri-apps/api": "^2.2.0",
|
||||||
"react": "^19.0.0",
|
"react": "^19.0.0",
|
||||||
"react-dom": "^19.0.0"
|
"react-dom": "^19.0.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@tauri-apps/cli": "^2.1.0",
|
"@tauri-apps/cli": "^2.2.7",
|
||||||
"@types/node": "^22.10.2",
|
"@types/node": "^22.13.1",
|
||||||
"@types/react": "^19.0.2",
|
"@types/react": "^19.0.8",
|
||||||
"@types/react-dom": "^19.0.2",
|
"@types/react-dom": "^19.0.3",
|
||||||
"@typescript-eslint/eslint-plugin": "^8.18.2",
|
"@typescript-eslint/eslint-plugin": "^8.23.0",
|
||||||
"@typescript-eslint/parser": "^8.18.2",
|
"@typescript-eslint/parser": "^8.23.0",
|
||||||
"@vitejs/plugin-react": "^4.3.4",
|
"@vitejs/plugin-react": "^4.3.4",
|
||||||
"eslint": "^9.17.0",
|
"eslint": "^9.20.0",
|
||||||
"eslint-config-prettier": "^9.1.0",
|
"eslint-config-prettier": "^9.1.0",
|
||||||
"eslint-plugin-react": "^7.37.3",
|
"eslint-plugin-react": "^7.37.4",
|
||||||
"eslint-plugin-react-hooks": "^5.1.0",
|
"eslint-plugin-react-hooks": "^5.1.0",
|
||||||
"prettier": "3.4.2",
|
"prettier": "3.4.2",
|
||||||
"typescript": "^5.7.2",
|
"typescript": "^5.7.3",
|
||||||
"vite": "^6.0.5"
|
"vite": "^6.1.0"
|
||||||
},
|
},
|
||||||
"packageManager": "pnpm@9.15.1"
|
"packageManager": "pnpm@9.15.1"
|
||||||
}
|
}
|
||||||
|
1412
apps/gpgui-helper/pnpm-lock.yaml
generated
1412
apps/gpgui-helper/pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,10 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## 2.4.4 - 2025-02-09
|
||||||
|
|
||||||
|
- GUI: fix multiple tray icons issue (fix [#464](https://github.com/yuezk/GlobalProtect-openconnect/issues/464))
|
||||||
|
- CLI: check the cli running state before running the `gpclient` command (fix [#447](https://github.com/yuezk/GlobalProtect-openconnect/issues/447))
|
||||||
|
|
||||||
## 2.4.3 - 2025-01-21
|
## 2.4.3 - 2025-01-21
|
||||||
|
|
||||||
- Do not use static default value for `--os-version` option.
|
- Do not use static default value for `--os-version` option.
|
||||||
|
@@ -28,21 +28,15 @@ regex = { workspace = true, optional = true }
|
|||||||
tokio-util = { workspace = true, optional = true }
|
tokio-util = { workspace = true, optional = true }
|
||||||
html-escape = { version = "0.2.13", optional = true }
|
html-escape = { version = "0.2.13", optional = true }
|
||||||
|
|
||||||
[target.'cfg(not(any(target_os="macos", target_os="windows")))'.dependencies]
|
[target.'cfg(not(target_os = "macos"))'.dependencies]
|
||||||
webkit2gtk = { version = "2", optional = true }
|
webkit2gtk = { version = "2", optional = true }
|
||||||
|
|
||||||
[target.'cfg(target_os="macos")'.dependencies]
|
[target.'cfg(target_os = "macos")'.dependencies]
|
||||||
block2 = { version = "0.5", optional = true }
|
block2 = { version = "0.5", optional = true }
|
||||||
objc2 = { version = "0.5", optional = true }
|
objc2 = { version = "0.5", optional = true }
|
||||||
objc2-foundation = { version = "0.2", optional = true }
|
objc2-foundation = { version = "0.2", optional = true }
|
||||||
objc2-web-kit = { version = "0.2", optional = true }
|
objc2-web-kit = { version = "0.2", optional = true }
|
||||||
|
|
||||||
[target.'cfg(target_os="windows")'.dependencies]
|
|
||||||
webview2-com = { version = "0.34", optional = true }
|
|
||||||
windows-core = { version = "0.58", optional = true }
|
|
||||||
windows = { version = "0.58", optional = true }
|
|
||||||
serde_json = { workspace = true, optional = true }
|
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
browser-auth = [
|
browser-auth = [
|
||||||
"dep:webbrowser",
|
"dep:webbrowser",
|
||||||
@@ -62,8 +56,4 @@ webview-auth = [
|
|||||||
"dep:objc2",
|
"dep:objc2",
|
||||||
"dep:objc2-foundation",
|
"dep:objc2-foundation",
|
||||||
"dep:objc2-web-kit",
|
"dep:objc2-web-kit",
|
||||||
"dep:webview2-com",
|
|
||||||
"dep:windows-core",
|
|
||||||
"dep:windows",
|
|
||||||
"dep:serde_json",
|
|
||||||
]
|
]
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
use std::{env::temp_dir, fs};
|
use std::{env::temp_dir, fs, os::unix::fs::PermissionsExt};
|
||||||
|
|
||||||
use gpapi::{auth::SamlAuthData, GP_CALLBACK_PORT_FILENAME};
|
use gpapi::{auth::SamlAuthData, GP_CALLBACK_PORT_FILENAME};
|
||||||
use log::info;
|
use log::info;
|
||||||
@@ -96,11 +96,7 @@ async fn wait_auth_data() -> anyhow::Result<SamlAuthData> {
|
|||||||
|
|
||||||
// Write the port to a file
|
// Write the port to a file
|
||||||
fs::write(&port_file, port.to_string())?;
|
fs::write(&port_file, port.to_string())?;
|
||||||
#[cfg(unix)]
|
fs::set_permissions(&port_file, fs::Permissions::from_mode(0o600))?;
|
||||||
{
|
|
||||||
use os::unix::fs::PermissionsExt;
|
|
||||||
fs::set_permissions(&port_file, fs::Permissions::from_mode(0o600))?;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove the previous log file
|
// Remove the previous log file
|
||||||
let callback_log = temp_dir().join("gpcallback.log");
|
let callback_log = temp_dir().join("gpcallback.log");
|
||||||
|
@@ -1,9 +1,8 @@
|
|||||||
mod auth_messenger;
|
mod auth_messenger;
|
||||||
mod webview_auth;
|
mod webview_auth;
|
||||||
|
|
||||||
#[cfg_attr(not(any(target_os = "macos", target_os = "windows")), path = "webview/unix.rs")]
|
#[cfg_attr(not(target_os = "macos"), path = "webview/unix.rs")]
|
||||||
#[cfg_attr(target_os = "macos", path = "webview/macos.rs")]
|
#[cfg_attr(target_os = "macos", path = "webview/macos.rs")]
|
||||||
#[cfg_attr(windows, path = "webview/windows.rs")]
|
|
||||||
mod platform_impl;
|
mod platform_impl;
|
||||||
|
|
||||||
pub use webview_auth::WebviewAuthenticator;
|
pub use webview_auth::WebviewAuthenticator;
|
||||||
|
@@ -15,7 +15,7 @@ pub(crate) enum AuthDataLocation {
|
|||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(crate) enum AuthError {
|
pub(crate) enum AuthError {
|
||||||
/// Failed to load page due to TLS error
|
/// Failed to load page due to TLS error
|
||||||
#[cfg(not(any(target_os = "macos", target_os = "windows")))]
|
#[cfg(not(target_os = "macos"))]
|
||||||
TlsError,
|
TlsError,
|
||||||
/// 1. Found auth data in headers/body but it's invalid
|
/// 1. Found auth data in headers/body but it's invalid
|
||||||
/// 2. Loaded an empty page, failed to load page. etc.
|
/// 2. Loaded an empty page, failed to load page. etc.
|
||||||
|
@@ -115,7 +115,7 @@ impl<'a> WebviewAuthenticator<'a> {
|
|||||||
match auth_messenger.subscribe().await? {
|
match auth_messenger.subscribe().await? {
|
||||||
AuthEvent::Close => bail!("Authentication cancelled"),
|
AuthEvent::Close => bail!("Authentication cancelled"),
|
||||||
AuthEvent::RaiseWindow => self.raise_window(&auth_window),
|
AuthEvent::RaiseWindow => self.raise_window(&auth_window),
|
||||||
#[cfg(not(any(target_os = "macos", target_os = "windows")))]
|
#[cfg(not(target_os = "macos"))]
|
||||||
AuthEvent::Error(AuthError::TlsError) => bail!(gpapi::error::PortalError::TlsError),
|
AuthEvent::Error(AuthError::TlsError) => bail!(gpapi::error::PortalError::TlsError),
|
||||||
AuthEvent::Error(AuthError::NotFound(location)) => {
|
AuthEvent::Error(AuthError::NotFound(location)) => {
|
||||||
info!(
|
info!(
|
||||||
@@ -261,10 +261,10 @@ impl<'a> WebviewAuthenticator<'a> {
|
|||||||
|
|
||||||
info!("Raising auth window...");
|
info!("Raising auth window...");
|
||||||
|
|
||||||
#[cfg(any(target_os = "macos", target_os = "windows"))]
|
#[cfg(target_os = "macos")]
|
||||||
let result = auth_window.show();
|
let result = auth_window.show();
|
||||||
|
|
||||||
#[cfg(not(any(target_os = "macos", target_os = "windows")))]
|
#[cfg(not(target_os = "macos"))]
|
||||||
let result = {
|
let result = {
|
||||||
use gpapi::utils::window::WindowExt;
|
use gpapi::utils::window::WindowExt;
|
||||||
auth_window.raise()
|
auth_window.raise()
|
||||||
|
@@ -1,142 +0,0 @@
|
|||||||
use log::warn;
|
|
||||||
use tauri::webview::PlatformWebview;
|
|
||||||
use webview2_com::{
|
|
||||||
pwstr_from_str, take_pwstr, ExecuteScriptCompletedHandler,
|
|
||||||
Microsoft::Web::WebView2::Win32::{
|
|
||||||
ICoreWebView2WebResourceResponseView, ICoreWebView2_14, ICoreWebView2_2,
|
|
||||||
COREWEBVIEW2_SERVER_CERTIFICATE_ERROR_ACTION_ALWAYS_ALLOW,
|
|
||||||
},
|
|
||||||
ServerCertificateErrorDetectedEventHandler, WebResourceResponseReceivedEventHandler,
|
|
||||||
};
|
|
||||||
use windows_core::{Interface, PWSTR};
|
|
||||||
|
|
||||||
use super::{
|
|
||||||
auth_messenger::AuthError,
|
|
||||||
webview_auth::{GetHeader, PlatformWebviewExt},
|
|
||||||
};
|
|
||||||
|
|
||||||
impl PlatformWebviewExt for PlatformWebview {
|
|
||||||
fn ignore_tls_errors(&self) -> anyhow::Result<()> {
|
|
||||||
unsafe {
|
|
||||||
let wv = self.controller().CoreWebView2()?.cast::<ICoreWebView2_14>()?;
|
|
||||||
let handler = ServerCertificateErrorDetectedEventHandler::create(Box::new(|_, e| {
|
|
||||||
if let Some(e) = e {
|
|
||||||
let _ = e.SetAction(COREWEBVIEW2_SERVER_CERTIFICATE_ERROR_ACTION_ALWAYS_ALLOW);
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}));
|
|
||||||
|
|
||||||
wv.add_ServerCertificateErrorDetected(&handler, &mut Default::default())?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn load_url(&self, url: &str) -> anyhow::Result<()> {
|
|
||||||
let url = pwstr_from_str(url);
|
|
||||||
|
|
||||||
unsafe { self.controller().CoreWebView2()?.Navigate(url)? }
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn load_html(&self, html: &str) -> anyhow::Result<()> {
|
|
||||||
let html = pwstr_from_str(html);
|
|
||||||
|
|
||||||
unsafe { self.controller().CoreWebView2()?.NavigateToString(html)? }
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_html(&self, callback: Box<dyn Fn(anyhow::Result<String>) + 'static>) {
|
|
||||||
unsafe {
|
|
||||||
match self.controller().CoreWebView2() {
|
|
||||||
Ok(wv) => {
|
|
||||||
let js = "document.documentElement.outerHTML";
|
|
||||||
let js = pwstr_from_str(js);
|
|
||||||
|
|
||||||
let handler = ExecuteScriptCompletedHandler::create(Box::new(move |err, html| {
|
|
||||||
if let Err(err) = err {
|
|
||||||
callback(Err(anyhow::anyhow!(err)));
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
|
|
||||||
// The returned HTML is JSON.stringify'd string, so we need to parse it
|
|
||||||
let res = match serde_json::from_str(&html) {
|
|
||||||
Ok(Some(html)) => Ok(html),
|
|
||||||
Ok(None) => Err(anyhow::anyhow!("No HTML returned")),
|
|
||||||
Err(err) => Err(anyhow::anyhow!(err)),
|
|
||||||
};
|
|
||||||
callback(res);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}));
|
|
||||||
|
|
||||||
if let Err(err) = wv.ExecuteScript(js, &handler) {
|
|
||||||
warn!("Failed to execute script: {}", err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(err) => callback(Err(anyhow::anyhow!(err))),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl GetHeader for ICoreWebView2WebResourceResponseView {
|
|
||||||
fn get_header(&self, key: &str) -> Option<String> {
|
|
||||||
unsafe {
|
|
||||||
let headers = self.Headers().ok()?;
|
|
||||||
let key = pwstr_from_str(key);
|
|
||||||
|
|
||||||
let mut contains = Default::default();
|
|
||||||
headers.Contains(key, &mut contains).ok()?;
|
|
||||||
|
|
||||||
if contains.as_bool() {
|
|
||||||
let mut value = PWSTR::null();
|
|
||||||
headers.GetHeader(key, &mut value).ok()?;
|
|
||||||
let value = take_pwstr(value);
|
|
||||||
|
|
||||||
Some(value)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait PlatformWebviewOnResponse {
|
|
||||||
fn on_response(
|
|
||||||
&self,
|
|
||||||
callback: Box<dyn Fn(anyhow::Result<ICoreWebView2WebResourceResponseView, AuthError>) + 'static>,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PlatformWebviewOnResponse for PlatformWebview {
|
|
||||||
fn on_response(
|
|
||||||
&self,
|
|
||||||
callback: Box<dyn Fn(anyhow::Result<ICoreWebView2WebResourceResponseView, AuthError>) + 'static>,
|
|
||||||
) {
|
|
||||||
unsafe {
|
|
||||||
let _ = self
|
|
||||||
.controller()
|
|
||||||
.CoreWebView2()
|
|
||||||
.and_then(|wv| wv.cast::<ICoreWebView2_2>())
|
|
||||||
.map(|wv| {
|
|
||||||
let handler = WebResourceResponseReceivedEventHandler::create(Box::new(move |_, e| {
|
|
||||||
let Some(e) = e else {
|
|
||||||
return Ok(());
|
|
||||||
};
|
|
||||||
|
|
||||||
match e.Response() {
|
|
||||||
Ok(res) => callback(Ok(res)),
|
|
||||||
Err(err) => warn!("Failed to get response: {}", err),
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}));
|
|
||||||
|
|
||||||
let _ = wv.add_WebResourceResponseReceived(&handler, &mut Default::default());
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -27,7 +27,7 @@ chacha20poly1305 = { version = "0.10", features = ["std"] }
|
|||||||
redact-engine.workspace = true
|
redact-engine.workspace = true
|
||||||
url.workspace = true
|
url.workspace = true
|
||||||
regex.workspace = true
|
regex.workspace = true
|
||||||
|
uzers.workspace = true
|
||||||
serde_urlencoded.workspace = true
|
serde_urlencoded.workspace = true
|
||||||
md5.workspace = true
|
md5.workspace = true
|
||||||
sha256.workspace = true
|
sha256.workspace = true
|
||||||
@@ -39,8 +39,8 @@ clap-verbosity-flag = { workspace = true, optional = true }
|
|||||||
env_logger = { workspace = true, optional = true }
|
env_logger = { workspace = true, optional = true }
|
||||||
log-reload = { version = "0.1", optional = true }
|
log-reload = { version = "0.1", optional = true }
|
||||||
|
|
||||||
[target.'cfg(target_family="unix")'.dependencies]
|
[target.'cfg(not(any(target_os="macos", target_os="windows")))'.dependencies]
|
||||||
uzers.workspace = true
|
gtk = "0.18"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
tauri = ["dep:tauri"]
|
tauri = ["dep:tauri"]
|
||||||
|
@@ -104,7 +104,7 @@ impl SamlAuthData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let auth_data = decode_to_string(auth_data).map_err(|e| {
|
let auth_data = decode_to_string(auth_data).map_err(|e| {
|
||||||
warn!("Failed to decode SAML auth data: {}", auth_data);
|
warn!("Failed to decode SAML auth data: {}", e);
|
||||||
AuthDataParseError::Invalid(anyhow::anyhow!(e))
|
AuthDataParseError::Invalid(anyhow::anyhow!(e))
|
||||||
})?;
|
})?;
|
||||||
let auth_data = Self::from_html(&auth_data)?;
|
let auth_data = Self::from_html(&auth_data)?;
|
||||||
|
@@ -1,7 +1,5 @@
|
|||||||
mod login;
|
mod login;
|
||||||
mod parse_gateways;
|
mod parse_gateways;
|
||||||
|
|
||||||
#[cfg(unix)]
|
|
||||||
pub mod hip;
|
pub mod hip;
|
||||||
|
|
||||||
pub use login::*;
|
pub use login::*;
|
||||||
|
@@ -4,10 +4,7 @@ pub mod error;
|
|||||||
pub mod gateway;
|
pub mod gateway;
|
||||||
pub mod gp_params;
|
pub mod gp_params;
|
||||||
pub mod portal;
|
pub mod portal;
|
||||||
|
|
||||||
#[cfg(unix)]
|
|
||||||
pub mod process;
|
pub mod process;
|
||||||
|
|
||||||
pub mod service;
|
pub mod service;
|
||||||
pub mod utils;
|
pub mod utils;
|
||||||
|
|
||||||
|
@@ -1,11 +1,8 @@
|
|||||||
pub(crate) mod command_traits;
|
pub(crate) mod command_traits;
|
||||||
|
|
||||||
pub(crate) mod gui_helper_launcher;
|
pub(crate) mod gui_helper_launcher;
|
||||||
|
|
||||||
pub mod auth_launcher;
|
pub mod auth_launcher;
|
||||||
pub mod gui_launcher;
|
pub mod gui_launcher;
|
||||||
pub mod hip_launcher;
|
pub mod hip_launcher;
|
||||||
pub mod service_launcher;
|
pub mod service_launcher;
|
||||||
|
|
||||||
#[cfg(unix)]
|
|
||||||
pub mod users;
|
pub mod users;
|
||||||
|
@@ -41,12 +41,6 @@ pub fn patch_gui_runtime_env(hidpi: bool) {
|
|||||||
// This is to avoid blank screen on some systems
|
// This is to avoid blank screen on some systems
|
||||||
std::env::set_var("WEBKIT_DISABLE_COMPOSITING_MODE", "1");
|
std::env::set_var("WEBKIT_DISABLE_COMPOSITING_MODE", "1");
|
||||||
|
|
||||||
// Workaround for https://github.com/tauri-apps/tao/issues/929
|
|
||||||
let is_wayland = std::env::var("XDG_SESSION_TYPE").unwrap_or_default() == "wayland";
|
|
||||||
if is_wayland {
|
|
||||||
env::set_var("GDK_BACKEND", "x11");
|
|
||||||
}
|
|
||||||
|
|
||||||
if hidpi {
|
if hidpi {
|
||||||
info!("Setting GDK_SCALE=2 and GDK_DPI_SCALE=0.5");
|
info!("Setting GDK_SCALE=2 and GDK_DPI_SCALE=0.5");
|
||||||
std::env::set_var("GDK_SCALE", "2");
|
std::env::set_var("GDK_SCALE", "2");
|
||||||
|
@@ -9,7 +9,7 @@ pub mod lock_file;
|
|||||||
pub mod openssl;
|
pub mod openssl;
|
||||||
pub mod redact;
|
pub mod redact;
|
||||||
pub mod request;
|
pub mod request;
|
||||||
#[cfg(all(feature = "tauri", not(any(target_os = "macos", target_os = "windows"))))]
|
#[cfg(feature = "tauri")]
|
||||||
pub mod window;
|
pub mod window;
|
||||||
|
|
||||||
mod shutdown_signal;
|
mod shutdown_signal;
|
||||||
|
@@ -6,21 +6,15 @@ pub async fn shutdown_signal() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
{
|
let terminate = async {
|
||||||
let terminate = async {
|
signal::unix::signal(signal::unix::SignalKind::terminate())
|
||||||
signal::unix::signal(signal::unix::SignalKind::terminate())
|
.expect("failed to install signal handler")
|
||||||
.expect("failed to install signal handler")
|
.recv()
|
||||||
.recv()
|
.await;
|
||||||
.await;
|
};
|
||||||
};
|
|
||||||
tokio::select! {
|
|
||||||
_ = ctrl_c => {},
|
|
||||||
_ = terminate => {},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(not(unix))]
|
tokio::select! {
|
||||||
{
|
_ = ctrl_c => {},
|
||||||
ctrl_c.await;
|
_ = terminate => {},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,73 +1,97 @@
|
|||||||
use std::{process::ExitStatus, time::Duration};
|
|
||||||
|
|
||||||
use anyhow::bail;
|
|
||||||
use log::info;
|
|
||||||
use tauri::WebviewWindow;
|
use tauri::WebviewWindow;
|
||||||
use tokio::process::Command;
|
|
||||||
|
|
||||||
pub trait WindowExt {
|
pub trait WindowExt {
|
||||||
fn raise(&self) -> anyhow::Result<()>;
|
fn raise(&self) -> anyhow::Result<()>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WindowExt for WebviewWindow {
|
impl WindowExt for WebviewWindow {
|
||||||
|
#[cfg(any(target_os = "macos", target_os = "windows"))]
|
||||||
fn raise(&self) -> anyhow::Result<()> {
|
fn raise(&self) -> anyhow::Result<()> {
|
||||||
raise_window(self)
|
self.show()?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(any(target_os = "macos", target_os = "windows")))]
|
||||||
|
fn raise(&self) -> anyhow::Result<()> {
|
||||||
|
unix::raise_window(self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn raise_window(win: &WebviewWindow) -> anyhow::Result<()> {
|
#[cfg(not(any(target_os = "macos", target_os = "windows")))]
|
||||||
let is_wayland = std::env::var("XDG_SESSION_TYPE").unwrap_or_default() == "wayland";
|
mod unix {
|
||||||
|
use std::{process::ExitStatus, time::Duration};
|
||||||
|
|
||||||
if is_wayland {
|
use anyhow::bail;
|
||||||
win.hide()?;
|
use gtk::{
|
||||||
win.show()?;
|
glib::Cast,
|
||||||
} else {
|
traits::{EventBoxExt, GtkWindowExt, WidgetExt},
|
||||||
if !win.is_visible()? {
|
EventBox,
|
||||||
win.show()?;
|
};
|
||||||
}
|
use log::info;
|
||||||
let title = win.title()?;
|
use tauri::WebviewWindow;
|
||||||
tokio::spawn(async move {
|
use tokio::process::Command;
|
||||||
if let Err(err) = wmctrl_raise_window(&title).await {
|
|
||||||
info!("Window not raised: {}", err);
|
pub fn raise_window(win: &WebviewWindow) -> anyhow::Result<()> {
|
||||||
|
let is_wayland = std::env::var("XDG_SESSION_TYPE").unwrap_or_default() == "wayland";
|
||||||
|
|
||||||
|
if is_wayland {
|
||||||
|
let gtk_win = win.gtk_window()?;
|
||||||
|
if let Some(header) = gtk_win.titlebar() {
|
||||||
|
let _ = header.downcast::<EventBox>().map(|event_box| {
|
||||||
|
event_box.set_above_child(false);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Calling window.show() on Windows will cause the menu to be shown.
|
gtk_win.hide();
|
||||||
// We need to hide it again.
|
gtk_win.show_all();
|
||||||
win.hide_menu()?;
|
} else {
|
||||||
|
if !win.is_visible()? {
|
||||||
Ok(())
|
win.show()?;
|
||||||
}
|
|
||||||
|
|
||||||
async fn wmctrl_raise_window(title: &str) -> anyhow::Result<()> {
|
|
||||||
let mut counter = 0;
|
|
||||||
|
|
||||||
loop {
|
|
||||||
if let Ok(exit_status) = wmctrl_try_raise_window(title).await {
|
|
||||||
if exit_status.success() {
|
|
||||||
info!("Window raised after {} attempts", counter + 1);
|
|
||||||
return Ok(());
|
|
||||||
}
|
}
|
||||||
|
let title = win.title()?;
|
||||||
|
tokio::spawn(async move {
|
||||||
|
if let Err(err) = wmctrl_raise_window(&title).await {
|
||||||
|
info!("Window not raised: {}", err);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if counter >= 10 {
|
// Calling window.show() on window object will cause the menu to be shown.
|
||||||
bail!("Failed to raise window: {}", title)
|
// We need to hide it again.
|
||||||
}
|
win.hide_menu()?;
|
||||||
|
|
||||||
counter += 1;
|
Ok(())
|
||||||
tokio::time::sleep(Duration::from_millis(100)).await;
|
}
|
||||||
|
|
||||||
|
async fn wmctrl_raise_window(title: &str) -> anyhow::Result<()> {
|
||||||
|
let mut counter = 0;
|
||||||
|
|
||||||
|
loop {
|
||||||
|
if let Ok(exit_status) = wmctrl_try_raise_window(title).await {
|
||||||
|
if exit_status.success() {
|
||||||
|
info!("Window raised after {} attempts", counter + 1);
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if counter >= 10 {
|
||||||
|
bail!("Failed to raise window: {}", title)
|
||||||
|
}
|
||||||
|
|
||||||
|
counter += 1;
|
||||||
|
tokio::time::sleep(Duration::from_millis(100)).await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn wmctrl_try_raise_window(title: &str) -> anyhow::Result<ExitStatus> {
|
||||||
|
let exit_status = Command::new("wmctrl")
|
||||||
|
.arg("-F")
|
||||||
|
.arg("-a")
|
||||||
|
.arg(title)
|
||||||
|
.spawn()?
|
||||||
|
.wait()
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
Ok(exit_status)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn wmctrl_try_raise_window(title: &str) -> anyhow::Result<ExitStatus> {
|
|
||||||
let exit_status = Command::new("wmctrl")
|
|
||||||
.arg("-F")
|
|
||||||
.arg("-a")
|
|
||||||
.arg(title)
|
|
||||||
.spawn()?
|
|
||||||
.wait()
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
Ok(exit_status)
|
|
||||||
}
|
|
||||||
|
Reference in New Issue
Block a user