mirror of
https://github.com/yuezk/GlobalProtect-openconnect.git
synced 2025-05-20 07:26:58 -04:00
Compare commits
6 Commits
v2.4.2
...
gpauth_win
Author | SHA1 | Date | |
---|---|---|---|
|
3175d1083a | ||
|
fe3d3df662 | ||
|
2f90b73683 | ||
|
5186e80c6f | ||
|
4ff1c1dc1f | ||
|
c1427040f6 |
63
.github/workflows/build.yaml
vendored
63
.github/workflows/build.yaml
vendored
@@ -44,7 +44,8 @@ jobs:
|
||||
with:
|
||||
version: 9
|
||||
- name: Prepare workspace
|
||||
run: rm -rf source && mkdir source
|
||||
run: rm -rf source && mkdir -p source/artifacts
|
||||
|
||||
- name: Checkout GlobalProtect-openconnect
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
@@ -52,6 +53,7 @@ jobs:
|
||||
repository: yuezk/GlobalProtect-openconnect
|
||||
ref: ${{ github.ref }}
|
||||
path: source/gp
|
||||
|
||||
- name: Create tarball
|
||||
run: |
|
||||
cd source/gp
|
||||
@@ -60,13 +62,69 @@ jobs:
|
||||
touch SNAPSHOT
|
||||
fi
|
||||
make tarball
|
||||
|
||||
mv -v .build/tarball/*.tar.gz ../artifacts/
|
||||
|
||||
- name: Generate RPM spec file
|
||||
env:
|
||||
RELEASE_TAG: ${{ github.ref == 'refs/heads/dev' && 'snapshot' || github.ref_name }}
|
||||
run: |
|
||||
cd source/gp
|
||||
|
||||
make init-rpm \
|
||||
REVISION='1%{?dist}' \
|
||||
RPM_SOURCE=https://github.com/yuezk/GlobalProtect-openconnect/releases/download/${RELEASE_TAG}/%{name}-%{version}.tar.gz
|
||||
|
||||
mv -v .build/rpm/*.spec ../artifacts/
|
||||
|
||||
- name: Upload tarball
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: artifact-source
|
||||
if-no-files-found: error
|
||||
path: |
|
||||
source/gp/.build/tarball/*.tar.gz
|
||||
source/artifacts/*
|
||||
|
||||
tarball-offline:
|
||||
if: ${{ github.ref == 'refs/heads/dev' || startsWith(github.ref, 'refs/tags/') }}
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
- tarball
|
||||
steps:
|
||||
- uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: 9
|
||||
|
||||
- name: Prepare workspace
|
||||
run: rm -rf source-offline && mkdir source-offline
|
||||
|
||||
- name: Download tarball
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: artifact-source
|
||||
path: source-offline
|
||||
|
||||
- name: Create offline tarball
|
||||
run: |
|
||||
cd source-offline
|
||||
|
||||
offline_tarball=$(basename *.tar.gz .tar.gz).offline.tar.gz
|
||||
|
||||
# Extract the tarball
|
||||
tar -xzf *.tar.gz
|
||||
|
||||
cd */
|
||||
make tarball OFFLINE=1
|
||||
|
||||
# Rename the tarball to .offline.tar.gz
|
||||
mv -v .build/tarball/*.tar.gz ../$offline_tarball
|
||||
|
||||
- name: Upload offline tarball
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
path: source-offline/*.offline.tar.gz
|
||||
name: artifact-source-offline
|
||||
if-no-files-found: error
|
||||
|
||||
build-gp:
|
||||
needs:
|
||||
@@ -168,6 +226,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
- tarball
|
||||
- tarball-offline
|
||||
- build-gp
|
||||
- build-gpgui
|
||||
|
||||
|
33
.github/workflows/publish.yaml
vendored
33
.github/workflows/publish.yaml
vendored
@@ -52,22 +52,26 @@ jobs:
|
||||
version: 9
|
||||
- name: Prepare workspace
|
||||
run: rm -rf publish-ppa && mkdir publish-ppa
|
||||
- name: Download ${{ inputs.tag }} source code
|
||||
uses: robinraju/release-downloader@v1.9
|
||||
with:
|
||||
token: ${{ secrets.GH_PAT }}
|
||||
tag: ${{ inputs.tag }}
|
||||
fileName: globalprotect-openconnect-*.tar.gz
|
||||
tarBall: false
|
||||
zipBall: false
|
||||
out-file-path: publish-ppa
|
||||
- name: Make the offline tarball
|
||||
- name: Download ${{ inputs.tag }} offline source code
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GH_PAT }}
|
||||
run: |
|
||||
gh -R yuezk/GlobalProtect-openconnect \
|
||||
release download ${{ inputs.tag }} \
|
||||
--pattern '*.offline.tar.gz' \
|
||||
--dir publish-ppa
|
||||
- name: Patch the source code
|
||||
run: |
|
||||
cd publish-ppa
|
||||
tar -xf globalprotect-openconnect-*.tar.gz
|
||||
cd globalprotect-openconnect-*/
|
||||
|
||||
make tarball OFFLINE=1
|
||||
# Rename the source tarball without the offline suffix
|
||||
mv -v *.tar.gz $(basename *.tar.gz .offline.tar.gz).tar.gz
|
||||
|
||||
# Extract the source tarball
|
||||
tar -xzf *.tar.gz
|
||||
|
||||
# Prepare the debian directory with custom files
|
||||
cd globalprotect-openconnect-*/
|
||||
|
||||
# Prepare the debian directory with custom files
|
||||
mkdir -p .build/debian
|
||||
@@ -78,7 +82,6 @@ jobs:
|
||||
cp -v packaging/deb/postrm .build/debian/postrm
|
||||
|
||||
sed -i "s/@RUST@/cargo-1.80/g" .build/debian/control
|
||||
|
||||
sed -i "s/@OFFLINE@/1/g" .build/debian/rules
|
||||
sed -i "s/@BUILD_GUI@/1/g" .build/debian/rules
|
||||
sed -i "s/@RUST_VERSION@/1.80/g" .build/debian/rules
|
||||
@@ -89,7 +92,7 @@ jobs:
|
||||
repository: "yuezk/globalprotect-openconnect"
|
||||
gpg_private_key: ${{ secrets.PPA_GPG_PRIVATE_KEY }}
|
||||
gpg_passphrase: ${{ secrets.PPA_GPG_PASSPHRASE }}
|
||||
tarball: publish-ppa/globalprotect-openconnect-*/.build/tarball/*.tar.gz
|
||||
tarball: publish-ppa/globalprotect-openconnect-*.tar.gz
|
||||
debian_dir: publish-ppa/globalprotect-openconnect-*/.build/debian
|
||||
deb_email: "k3vinyue@gmail.com"
|
||||
deb_fullname: "Kevin Yue"
|
||||
|
17
.github/workflows/release.yaml
vendored
17
.github/workflows/release.yaml
vendored
@@ -96,15 +96,16 @@ jobs:
|
||||
steps:
|
||||
- name: Prepare workspace
|
||||
run: rm -rf build-${{ matrix.package }} && mkdir -p build-${{ matrix.package }}
|
||||
|
||||
- name: Download ${{ inputs.tag }} source code
|
||||
uses: robinraju/release-downloader@v1.9
|
||||
with:
|
||||
token: ${{ secrets.GH_PAT }}
|
||||
tag: ${{ inputs.tag }}
|
||||
fileName: globalprotect-openconnect-*.tar.gz
|
||||
tarBall: false
|
||||
zipBall: false
|
||||
out-file-path: build-${{ matrix.package }}
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GH_PAT }}
|
||||
run: |
|
||||
gh -R yuezk/GlobalProtect-openconnect \
|
||||
release download ${{ inputs.tag }} \
|
||||
--pattern '*[^offline].tar.gz' \
|
||||
--dir build-${{ matrix.package }}
|
||||
|
||||
- name: Docker Login
|
||||
run: echo ${{ secrets.DOCKER_HUB_TOKEN }} | docker login -u ${{ secrets.DOCKER_HUB_USERNAME }} --password-stdin
|
||||
- name: Build ${{ matrix.package }} package in Docker
|
||||
|
20
Cargo.lock
generated
20
Cargo.lock
generated
@@ -176,7 +176,7 @@ checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0"
|
||||
|
||||
[[package]]
|
||||
name = "auth"
|
||||
version = "2.4.2"
|
||||
version = "2.4.3"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"block2",
|
||||
@@ -188,6 +188,7 @@ dependencies = [
|
||||
"objc2-web-kit",
|
||||
"open",
|
||||
"regex",
|
||||
"serde_json",
|
||||
"tauri",
|
||||
"tiny_http",
|
||||
"tokio",
|
||||
@@ -195,7 +196,10 @@ dependencies = [
|
||||
"uuid",
|
||||
"webbrowser",
|
||||
"webkit2gtk",
|
||||
"webview2-com",
|
||||
"which",
|
||||
"windows 0.58.0",
|
||||
"windows-core 0.58.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -642,7 +646,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "common"
|
||||
version = "2.4.2"
|
||||
version = "2.4.3"
|
||||
dependencies = [
|
||||
"is_executable",
|
||||
]
|
||||
@@ -1590,7 +1594,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "gpapi"
|
||||
version = "2.4.2"
|
||||
version = "2.4.3"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"base64 0.22.1",
|
||||
@@ -1626,7 +1630,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "gpauth"
|
||||
version = "2.4.2"
|
||||
version = "2.4.3"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"auth",
|
||||
@@ -1645,7 +1649,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "gpclient"
|
||||
version = "2.4.2"
|
||||
version = "2.4.3"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap",
|
||||
@@ -1667,7 +1671,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "gpgui-helper"
|
||||
version = "2.4.2"
|
||||
version = "2.4.3"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap",
|
||||
@@ -1685,7 +1689,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "gpservice"
|
||||
version = "2.4.2"
|
||||
version = "2.4.3"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"axum",
|
||||
@@ -2951,7 +2955,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "openconnect"
|
||||
version = "2.4.2"
|
||||
version = "2.4.3"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"common",
|
||||
|
@@ -11,7 +11,7 @@ members = [
|
||||
|
||||
[workspace.package]
|
||||
rust-version = "1.80"
|
||||
version = "2.4.2"
|
||||
version = "2.4.3"
|
||||
authors = ["Kevin Yue <k3vinyue@gmail.com>"]
|
||||
homepage = "https://github.com/yuezk/GlobalProtect-openconnect"
|
||||
edition = "2021"
|
||||
|
3
Makefile
3
Makefile
@@ -8,6 +8,8 @@ RUST_VERSION = 1.80
|
||||
|
||||
VERSION = $(shell $(CARGO) metadata --no-deps --format-version 1 | jq -r '.packages[0].version')
|
||||
REVISION ?= 1
|
||||
RPM_SOURCE ?= %{name}.tar.gz
|
||||
|
||||
PPA_REVISION ?= 1
|
||||
PKG_NAME = globalprotect-openconnect
|
||||
PKG = $(PKG_NAME)-$(VERSION)
|
||||
@@ -234,6 +236,7 @@ init-rpm: clean-rpm
|
||||
|
||||
sed -i "s/@VERSION@/$(VERSION)/g" .build/rpm/globalprotect-openconnect.spec
|
||||
sed -i "s/@REVISION@/$(REVISION)/g" .build/rpm/globalprotect-openconnect.spec
|
||||
sed -i "s|@SOURCE@|$(RPM_SOURCE)|g" .build/rpm/globalprotect-openconnect.spec
|
||||
sed -i "s/@OFFLINE@/$(OFFLINE)/g" .build/rpm/globalprotect-openconnect.spec
|
||||
sed -i "s/@DATE@/$(shell LC_ALL=en.US date "+%a %b %d %Y")/g" .build/rpm/globalprotect-openconnect.spec
|
||||
|
||||
|
@@ -70,7 +70,7 @@ The GUI version is also available after you installed it. You can launch it from
|
||||
|
||||
### Debian/Ubuntu based distributions
|
||||
|
||||
#### Install from PPA (Ubuntu > 18.04)
|
||||
#### Install from PPA
|
||||
|
||||
```
|
||||
sudo add-apt-repository ppa:yuezk/globalprotect-openconnect
|
||||
@@ -81,10 +81,6 @@ sudo apt-get install globalprotect-openconnect
|
||||
>
|
||||
> For Linux Mint, you might need to import the GPG key with: `sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 7937C393082992E5D6E4A60453FC26B43838D761` if you encountered an error `gpg: keyserver receive failed: General error`.
|
||||
|
||||
#### **Ubuntu 18.04**
|
||||
|
||||
The latest package is not available in the PPA, but you still needs to add the `ppa:yuezk/globalprotect-openconnect` repo beforehand to use the required `openconnect` package. Then you can follow the [Install from deb package](#install-from-deb-package) section to install the latest package.
|
||||
|
||||
#### Install from deb package
|
||||
|
||||
Download the latest deb package from [releases](https://github.com/yuezk/GlobalProtect-openconnect/releases) page. Then install it with `apt`:
|
||||
|
@@ -1,17 +1,21 @@
|
||||
use std::{env::temp_dir, fs::File};
|
||||
use std::{env::temp_dir, fs::File, str::FromStr};
|
||||
|
||||
use anyhow::bail;
|
||||
use clap::{Parser, Subcommand};
|
||||
use gpapi::{
|
||||
clap::{handle_error, Args, InfoLevelVerbosity},
|
||||
utils::openssl,
|
||||
};
|
||||
use log::info;
|
||||
use sysinfo::{Pid, System};
|
||||
use tempfile::NamedTempFile;
|
||||
use tokio::fs;
|
||||
|
||||
use crate::{
|
||||
connect::{ConnectArgs, ConnectHandler},
|
||||
disconnect::{DisconnectArgs, DisconnectHandler},
|
||||
launch_gui::{LaunchGuiArgs, LaunchGuiHandler},
|
||||
GP_CLIENT_LOCK_FILE,
|
||||
};
|
||||
|
||||
const VERSION: &str = concat!(env!("CARGO_PKG_VERSION"), " (", compile_time::date_str!(), ")");
|
||||
@@ -77,6 +81,25 @@ impl Args for Cli {
|
||||
}
|
||||
|
||||
impl Cli {
|
||||
async fn is_running(&self) -> bool {
|
||||
let Ok(c) = fs::read_to_string(GP_CLIENT_LOCK_FILE).await else {
|
||||
return false;
|
||||
};
|
||||
|
||||
let Ok(pid) = Pid::from_str(c.trim()) else {
|
||||
return false;
|
||||
};
|
||||
|
||||
let s = System::new_all();
|
||||
let Some(p) = s.process(pid) else {
|
||||
return false;
|
||||
};
|
||||
|
||||
p.exe()
|
||||
.map(|exe| exe.to_string_lossy().contains("gpclient"))
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
fn fix_openssl(&self) -> anyhow::Result<Option<NamedTempFile>> {
|
||||
if self.fix_openssl {
|
||||
let file = openssl::fix_openssl_env()?;
|
||||
@@ -87,6 +110,11 @@ impl Cli {
|
||||
}
|
||||
|
||||
async fn run(&self) -> anyhow::Result<()> {
|
||||
// check if an instance is running
|
||||
if self.is_running().await {
|
||||
bail!("Another instance of the client is already running");
|
||||
}
|
||||
|
||||
// The temp file will be dropped automatically when the file handle is dropped
|
||||
// So, declare it here to ensure it's not dropped
|
||||
let _file = self.fix_openssl()?;
|
||||
|
@@ -87,8 +87,8 @@ pub(crate) struct ConnectArgs {
|
||||
#[arg(long, value_enum, default_value_t = ConnectArgs::default_os())]
|
||||
os: Os,
|
||||
|
||||
#[arg(long, default_value_t = ConnectArgs::default_os_version())]
|
||||
os_version: String,
|
||||
#[arg(long, help = "If not specified, it will be computed based on the --os option")]
|
||||
os_version: Option<String>,
|
||||
|
||||
#[arg(long, help = "Disable DTLS and ESP")]
|
||||
no_dtls: bool,
|
||||
@@ -121,8 +121,12 @@ impl ConnectArgs {
|
||||
}
|
||||
}
|
||||
|
||||
fn default_os_version() -> String {
|
||||
match ConnectArgs::default_os() {
|
||||
fn os_version(&self) -> String {
|
||||
if let Some(os_version) = self.os_version.as_deref() {
|
||||
return os_version.to_string();
|
||||
}
|
||||
|
||||
match self.os {
|
||||
Os::Linux => format!("Linux {}", whoami::distro()),
|
||||
Os::Windows => String::from("Microsoft Windows 11 Pro , 64-bit"),
|
||||
Os::Mac => String::from("Apple Mac OS X 13.4.0"),
|
||||
@@ -149,7 +153,7 @@ impl<'a> ConnectHandler<'a> {
|
||||
GpParams::builder()
|
||||
.user_agent(&self.args.user_agent)
|
||||
.client_os(ClientOs::from(&self.args.os))
|
||||
.os_version(self.args.os_version.clone())
|
||||
.os_version(self.args.os_version())
|
||||
.ignore_tls_errors(self.shared_args.ignore_tls_errors)
|
||||
.certificate(self.args.certificate.clone())
|
||||
.sslkey(self.args.sslkey.clone())
|
||||
@@ -359,7 +363,7 @@ impl<'a> ConnectHandler<'a> {
|
||||
None
|
||||
};
|
||||
|
||||
let os_version = self.args.os_version.clone();
|
||||
let os_version = self.args.os_version();
|
||||
let verbose = self.shared_args.verbose.to_verbose_arg();
|
||||
let auth_launcher = SamlAuthLauncher::new(&self.args.server)
|
||||
.gateway(is_gateway)
|
||||
|
@@ -1,5 +1,9 @@
|
||||
# Changelog
|
||||
|
||||
## 2.4.3 - 2025-01-21
|
||||
|
||||
- Do not use static default value for `--os-version` option.
|
||||
|
||||
## 2.4.2 - 2025-01-20
|
||||
|
||||
- Disconnect the VPN when sleep (fix [#166](https://github.com/yuezk/GlobalProtect-openconnect/issues/166), [#267](https://github.com/yuezk/GlobalProtect-openconnect/issues/267))
|
||||
|
@@ -28,15 +28,21 @@ regex = { workspace = true, optional = true }
|
||||
tokio-util = { workspace = true, optional = true }
|
||||
html-escape = { version = "0.2.13", optional = true }
|
||||
|
||||
[target.'cfg(not(target_os = "macos"))'.dependencies]
|
||||
[target.'cfg(not(any(target_os="macos", target_os="windows")))'.dependencies]
|
||||
webkit2gtk = { version = "2", optional = true }
|
||||
|
||||
[target.'cfg(target_os = "macos")'.dependencies]
|
||||
[target.'cfg(target_os="macos")'.dependencies]
|
||||
block2 = { version = "0.5", optional = true }
|
||||
objc2 = { version = "0.5", optional = true }
|
||||
objc2-foundation = { 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]
|
||||
browser-auth = [
|
||||
"dep:webbrowser",
|
||||
@@ -56,4 +62,8 @@ webview-auth = [
|
||||
"dep:objc2",
|
||||
"dep:objc2-foundation",
|
||||
"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, os::unix::fs::PermissionsExt};
|
||||
use std::{env::temp_dir, fs};
|
||||
|
||||
use gpapi::{auth::SamlAuthData, GP_CALLBACK_PORT_FILENAME};
|
||||
use log::info;
|
||||
@@ -96,7 +96,11 @@ async fn wait_auth_data() -> anyhow::Result<SamlAuthData> {
|
||||
|
||||
// Write the port to a file
|
||||
fs::write(&port_file, port.to_string())?;
|
||||
fs::set_permissions(&port_file, fs::Permissions::from_mode(0o600))?;
|
||||
#[cfg(unix)]
|
||||
{
|
||||
use os::unix::fs::PermissionsExt;
|
||||
fs::set_permissions(&port_file, fs::Permissions::from_mode(0o600))?;
|
||||
}
|
||||
|
||||
// Remove the previous log file
|
||||
let callback_log = temp_dir().join("gpcallback.log");
|
||||
|
@@ -1,8 +1,9 @@
|
||||
mod auth_messenger;
|
||||
mod webview_auth;
|
||||
|
||||
#[cfg_attr(not(target_os = "macos"), path = "webview/unix.rs")]
|
||||
#[cfg_attr(not(any(target_os = "macos", target_os = "windows")), path = "webview/unix.rs")]
|
||||
#[cfg_attr(target_os = "macos", path = "webview/macos.rs")]
|
||||
#[cfg_attr(windows, path = "webview/windows.rs")]
|
||||
mod platform_impl;
|
||||
|
||||
pub use webview_auth::WebviewAuthenticator;
|
||||
|
@@ -15,7 +15,7 @@ pub(crate) enum AuthDataLocation {
|
||||
#[derive(Debug)]
|
||||
pub(crate) enum AuthError {
|
||||
/// Failed to load page due to TLS error
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
#[cfg(not(any(target_os = "macos", target_os = "windows")))]
|
||||
TlsError,
|
||||
/// 1. Found auth data in headers/body but it's invalid
|
||||
/// 2. Loaded an empty page, failed to load page. etc.
|
||||
|
@@ -115,7 +115,7 @@ impl<'a> WebviewAuthenticator<'a> {
|
||||
match auth_messenger.subscribe().await? {
|
||||
AuthEvent::Close => bail!("Authentication cancelled"),
|
||||
AuthEvent::RaiseWindow => self.raise_window(&auth_window),
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
#[cfg(not(any(target_os = "macos", target_os = "windows")))]
|
||||
AuthEvent::Error(AuthError::TlsError) => bail!(gpapi::error::PortalError::TlsError),
|
||||
AuthEvent::Error(AuthError::NotFound(location)) => {
|
||||
info!(
|
||||
@@ -261,10 +261,10 @@ impl<'a> WebviewAuthenticator<'a> {
|
||||
|
||||
info!("Raising auth window...");
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
#[cfg(any(target_os = "macos", target_os = "windows"))]
|
||||
let result = auth_window.show();
|
||||
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
#[cfg(not(any(target_os = "macos", target_os = "windows")))]
|
||||
let result = {
|
||||
use gpapi::utils::window::WindowExt;
|
||||
auth_window.raise()
|
||||
|
142
crates/auth/src/webview/windows.rs
Normal file
142
crates/auth/src/webview/windows.rs
Normal file
@@ -0,0 +1,142 @@
|
||||
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
|
||||
url.workspace = true
|
||||
regex.workspace = true
|
||||
uzers.workspace = true
|
||||
|
||||
serde_urlencoded.workspace = true
|
||||
md5.workspace = true
|
||||
sha256.workspace = true
|
||||
@@ -39,6 +39,9 @@ clap-verbosity-flag = { workspace = true, optional = true }
|
||||
env_logger = { workspace = true, optional = true }
|
||||
log-reload = { version = "0.1", optional = true }
|
||||
|
||||
[target.'cfg(target_family="unix")'.dependencies]
|
||||
uzers.workspace = true
|
||||
|
||||
[features]
|
||||
tauri = ["dep:tauri"]
|
||||
clap = ["dep:clap", "dep:clap-verbosity-flag"]
|
||||
|
@@ -104,7 +104,7 @@ impl SamlAuthData {
|
||||
}
|
||||
|
||||
let auth_data = decode_to_string(auth_data).map_err(|e| {
|
||||
warn!("Failed to decode SAML auth data: {}", e);
|
||||
warn!("Failed to decode SAML auth data: {}", auth_data);
|
||||
AuthDataParseError::Invalid(anyhow::anyhow!(e))
|
||||
})?;
|
||||
let auth_data = Self::from_html(&auth_data)?;
|
||||
|
@@ -1,5 +1,7 @@
|
||||
mod login;
|
||||
mod parse_gateways;
|
||||
|
||||
#[cfg(unix)]
|
||||
pub mod hip;
|
||||
|
||||
pub use login::*;
|
||||
|
@@ -4,7 +4,10 @@ pub mod error;
|
||||
pub mod gateway;
|
||||
pub mod gp_params;
|
||||
pub mod portal;
|
||||
|
||||
#[cfg(unix)]
|
||||
pub mod process;
|
||||
|
||||
pub mod service;
|
||||
pub mod utils;
|
||||
|
||||
|
@@ -1,8 +1,11 @@
|
||||
pub(crate) mod command_traits;
|
||||
|
||||
pub(crate) mod gui_helper_launcher;
|
||||
|
||||
pub mod auth_launcher;
|
||||
pub mod gui_launcher;
|
||||
pub mod hip_launcher;
|
||||
pub mod service_launcher;
|
||||
|
||||
#[cfg(unix)]
|
||||
pub mod users;
|
||||
|
@@ -9,7 +9,7 @@ pub mod lock_file;
|
||||
pub mod openssl;
|
||||
pub mod redact;
|
||||
pub mod request;
|
||||
#[cfg(feature = "tauri")]
|
||||
#[cfg(all(feature = "tauri", not(any(target_os = "macos", target_os = "windows"))))]
|
||||
pub mod window;
|
||||
|
||||
mod shutdown_signal;
|
||||
|
@@ -6,15 +6,21 @@ pub async fn shutdown_signal() {
|
||||
};
|
||||
|
||||
#[cfg(unix)]
|
||||
let terminate = async {
|
||||
signal::unix::signal(signal::unix::SignalKind::terminate())
|
||||
.expect("failed to install signal handler")
|
||||
.recv()
|
||||
.await;
|
||||
};
|
||||
{
|
||||
let terminate = async {
|
||||
signal::unix::signal(signal::unix::SignalKind::terminate())
|
||||
.expect("failed to install signal handler")
|
||||
.recv()
|
||||
.await;
|
||||
};
|
||||
tokio::select! {
|
||||
_ = ctrl_c => {},
|
||||
_ = terminate => {},
|
||||
}
|
||||
}
|
||||
|
||||
tokio::select! {
|
||||
_ = ctrl_c => {},
|
||||
_ = terminate => {},
|
||||
#[cfg(not(unix))]
|
||||
{
|
||||
ctrl_c.await;
|
||||
}
|
||||
}
|
||||
|
@@ -6,7 +6,7 @@ Group: Productivity/Networking/PPP
|
||||
|
||||
License: GPL-3.0
|
||||
URL: https://github.com/yuezk/GlobalProtect-openconnect
|
||||
Source: %{name}.tar.gz
|
||||
Source: @SOURCE@
|
||||
|
||||
BuildRequires: make
|
||||
BuildRequires: rust
|
||||
|
@@ -28,7 +28,7 @@ release_snapshot() {
|
||||
|
||||
echo "Uploading new assets..."
|
||||
gh -R "$REPO" release upload "$TAG" \
|
||||
"$PROJECT_DIR"/.build/artifacts/artifact-source/* \
|
||||
"$PROJECT_DIR"/.build/artifacts/artifact-source*/* \
|
||||
"$PROJECT_DIR"/.build/artifacts/artifact-gpgui-*/*
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ release_tag() {
|
||||
gh -R "$REPO" release create $TAG \
|
||||
--title "$TAG" \
|
||||
--notes "$RELEASE_NOTES" \
|
||||
"$PROJECT_DIR"/.build/artifacts/artifact-source/* \
|
||||
"$PROJECT_DIR"/.build/artifacts/artifact-source*/* \
|
||||
"$PROJECT_DIR"/.build/artifacts/artifact-gpgui-*/*
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user