mirror of
https://github.com/yuezk/GlobalProtect-openconnect.git
synced 2025-04-30 14:46:27 -04:00
Compare commits
No commits in common. "c347f97b953b32f45d7e8ccb4dd3e70f55c0a875" and "e9f2dbf9eaa5bbb04f907e9e8d4944db70722c99" have entirely different histories.
c347f97b95
...
e9f2dbf9ea
14
.github/workflows/build.yaml
vendored
14
.github/workflows/build.yaml
vendored
@ -25,9 +25,9 @@ jobs:
|
|||||||
id: set-matrix
|
id: set-matrix
|
||||||
run: |
|
run: |
|
||||||
if [[ "${{ github.ref }}" == "refs/tags/"* ]]; then
|
if [[ "${{ github.ref }}" == "refs/tags/"* ]]; then
|
||||||
echo 'matrix=[{"runner": "ubuntu-latest", "arch": "amd64"}, {"runner": "arm64", "arch": "arm64"]' >> $GITHUB_OUTPUT
|
echo "matrix=[\"ubuntu-latest\", \"arm64\"]" >> $GITHUB_OUTPUT
|
||||||
else
|
else
|
||||||
echo 'matrix=[{"runner": "ubuntu-latest", "arch": "amd64"}]' >> $GITHUB_OUTPUT
|
echo "matrix=[\"ubuntu-latest\"]" >> $GITHUB_OUTPUT
|
||||||
fi
|
fi
|
||||||
|
|
||||||
tarball:
|
tarball:
|
||||||
@ -70,8 +70,7 @@ jobs:
|
|||||||
matrix:
|
matrix:
|
||||||
os: ${{fromJson(needs.setup-matrix.outputs.matrix)}}
|
os: ${{fromJson(needs.setup-matrix.outputs.matrix)}}
|
||||||
package: [deb, rpm, pkg, binary]
|
package: [deb, rpm, pkg, binary]
|
||||||
runs-on: ${{ matrix.os.runner }}
|
runs-on: ${{ matrix.os }}
|
||||||
name: build-gp (${{ matrix.package }}, ${{ matrix.os.arch }})
|
|
||||||
steps:
|
steps:
|
||||||
- name: Prepare workspace
|
- name: Prepare workspace
|
||||||
run: |
|
run: |
|
||||||
@ -99,7 +98,7 @@ jobs:
|
|||||||
- name: Upload ${{ matrix.package }} package
|
- name: Upload ${{ matrix.package }} package
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: artifact-gp-${{ matrix.package }}-${{ matrix.os.arch }}
|
name: artifact-gp-${{ matrix.os }}-${{ matrix.package }}
|
||||||
if-no-files-found: error
|
if-no-files-found: error
|
||||||
path: |
|
path: |
|
||||||
build-gp-${{ matrix.package }}/artifacts/*
|
build-gp-${{ matrix.package }}/artifacts/*
|
||||||
@ -110,8 +109,7 @@ jobs:
|
|||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
os: ${{fromJson(needs.setup-matrix.outputs.matrix)}}
|
os: ${{fromJson(needs.setup-matrix.outputs.matrix)}}
|
||||||
runs-on: ${{ matrix.os.runner }}
|
runs-on: ${{ matrix.os }}
|
||||||
name: build-gpgui (${{ matrix.os.arch }})
|
|
||||||
steps:
|
steps:
|
||||||
- uses: pnpm/action-setup@v2
|
- uses: pnpm/action-setup@v2
|
||||||
with:
|
with:
|
||||||
@ -150,7 +148,7 @@ jobs:
|
|||||||
- name: Upload gpgui
|
- name: Upload gpgui
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: artifact-gpgui-${{ matrix.os.arch }}
|
name: artifact-gpgui-${{ matrix.os }}
|
||||||
if-no-files-found: error
|
if-no-files-found: error
|
||||||
path: |
|
path: |
|
||||||
gpgui-source/*.bin.tar.xz
|
gpgui-source/*.bin.tar.xz
|
||||||
|
@ -185,10 +185,6 @@ impl<'a> AuthWindow<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
info!("Loaded uri: {}", redact_uri(&uri));
|
info!("Loaded uri: {}", redact_uri(&uri));
|
||||||
if uri.starts_with("globalprotectcallback:") {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
read_auth_data(&main_resource, auth_result_tx_clone.clone());
|
read_auth_data(&main_resource, auth_result_tx_clone.clone());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -207,9 +203,7 @@ impl<'a> AuthWindow<'a> {
|
|||||||
|
|
||||||
wv.connect_load_failed(move |_wv, _event, uri, err| {
|
wv.connect_load_failed(move |_wv, _event, uri, err| {
|
||||||
let redacted_uri = redact_uri(uri);
|
let redacted_uri = redact_uri(uri);
|
||||||
if !uri.starts_with("globalprotectcallback:") {
|
|
||||||
warn!("Failed to load uri: {} with error: {}", redacted_uri, err);
|
warn!("Failed to load uri: {} with error: {}", redacted_uri, err);
|
||||||
}
|
|
||||||
// NOTE: Don't send error here, since load_changed event will be triggered after this
|
// NOTE: Don't send error here, since load_changed event will be triggered after this
|
||||||
// send_auth_result(&auth_result_tx, Err(AuthDataError::Invalid));
|
// send_auth_result(&auth_result_tx, Err(AuthDataError::Invalid));
|
||||||
// true to stop other handlers from being invoked for the event. false to propagate the event further.
|
// true to stop other handlers from being invoked for the event. false to propagate the event further.
|
||||||
@ -346,7 +340,7 @@ fn read_auth_data_from_headers(response: &URIResponse) -> AuthResult {
|
|||||||
|
|
||||||
fn read_auth_data_from_body<F>(main_resource: &WebResource, callback: F)
|
fn read_auth_data_from_body<F>(main_resource: &WebResource, callback: F)
|
||||||
where
|
where
|
||||||
F: FnOnce(Result<SamlAuthData, AuthDataParseError>) + Send + 'static,
|
F: FnOnce(AuthResult) + Send + 'static,
|
||||||
{
|
{
|
||||||
main_resource.data(Cancellable::NONE, |data| match data {
|
main_resource.data(Cancellable::NONE, |data| match data {
|
||||||
Ok(data) => {
|
Ok(data) => {
|
||||||
@ -355,15 +349,15 @@ where
|
|||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
info!("Failed to read response body: {}", err);
|
info!("Failed to read response body: {}", err);
|
||||||
callback(Err(AuthDataParseError::Invalid))
|
callback(Err(AuthDataError::Invalid))
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_auth_data_from_html(html: &str) -> Result<SamlAuthData, AuthDataParseError> {
|
fn read_auth_data_from_html(html: &str) -> AuthResult {
|
||||||
if html.contains("Temporarily Unavailable") {
|
if html.contains("Temporarily Unavailable") {
|
||||||
info!("Found 'Temporarily Unavailable' in HTML, auth failed");
|
info!("Found 'Temporarily Unavailable' in HTML, auth failed");
|
||||||
return Err(AuthDataParseError::Invalid);
|
return Err(AuthDataError::Invalid);
|
||||||
}
|
}
|
||||||
|
|
||||||
let auth_data = match SamlAuthData::from_html(html) {
|
let auth_data = match SamlAuthData::from_html(html) {
|
||||||
@ -378,7 +372,10 @@ fn read_auth_data_from_html(html: &str) -> Result<SamlAuthData, AuthDataParseErr
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
auth_data
|
auth_data.map_err(|err| match err {
|
||||||
|
AuthDataParseError::NotFound => AuthDataError::NotFound,
|
||||||
|
AuthDataParseError::Invalid => AuthDataError::Invalid,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn extract_gpcallback(html: &str) -> Option<&str> {
|
fn extract_gpcallback(html: &str) -> Option<&str> {
|
||||||
@ -389,12 +386,13 @@ fn extract_gpcallback(html: &str) -> Option<&str> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn read_auth_data(main_resource: &WebResource, auth_result_tx: mpsc::UnboundedSender<AuthResult>) {
|
fn read_auth_data(main_resource: &WebResource, auth_result_tx: mpsc::UnboundedSender<AuthResult>) {
|
||||||
let Some(response) = main_resource.response() else {
|
if main_resource.response().is_none() {
|
||||||
info!("No response found in main resource");
|
info!("No response found in main resource");
|
||||||
send_auth_result(&auth_result_tx, Err(AuthDataError::Invalid));
|
send_auth_result(&auth_result_tx, Err(AuthDataError::Invalid));
|
||||||
return;
|
return;
|
||||||
};
|
}
|
||||||
|
|
||||||
|
let response = main_resource.response().unwrap();
|
||||||
info!("Trying to read auth data from response headers...");
|
info!("Trying to read auth data from response headers...");
|
||||||
|
|
||||||
match read_auth_data_from_headers(&response) {
|
match read_auth_data_from_headers(&response) {
|
||||||
@ -407,27 +405,22 @@ fn read_auth_data(main_resource: &WebResource, auth_result_tx: mpsc::UnboundedSe
|
|||||||
read_auth_data_from_body(main_resource, move |auth_result| {
|
read_auth_data_from_body(main_resource, move |auth_result| {
|
||||||
// Since we have already found invalid auth data in headers, which means this could be the `/SAML20/SP/ACS` endpoint
|
// Since we have already found invalid auth data in headers, which means this could be the `/SAML20/SP/ACS` endpoint
|
||||||
// any error result from body should be considered as invalid, and trigger a retry
|
// any error result from body should be considered as invalid, and trigger a retry
|
||||||
let auth_result = auth_result.map_err(|err| {
|
let auth_result = auth_result.map_err(|_| AuthDataError::Invalid);
|
||||||
info!("Failed to read auth data from body: {}", err);
|
|
||||||
AuthDataError::Invalid
|
|
||||||
});
|
|
||||||
send_auth_result(&auth_result_tx, auth_result);
|
send_auth_result(&auth_result_tx, auth_result);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
Err(AuthDataError::NotFound) => {
|
Err(AuthDataError::NotFound) => {
|
||||||
info!("No auth data found in headers, trying to read from body...");
|
info!("No auth data found in headers, trying to read from body...");
|
||||||
|
let url = main_resource.uri().unwrap_or("".into());
|
||||||
let is_acs_endpoint = main_resource.uri().map_or(false, |uri| uri.contains("/SAML20/SP/ACS"));
|
let is_acs_endpoint = url.contains("/SAML20/SP/ACS");
|
||||||
|
|
||||||
read_auth_data_from_body(main_resource, move |auth_result| {
|
read_auth_data_from_body(main_resource, move |auth_result| {
|
||||||
// If the endpoint is `/SAML20/SP/ACS` and no auth data found in body, it should be considered as invalid
|
// If the endpoint is `/SAML20/SP/ACS` and no auth data found in body, it should be considered as invalid
|
||||||
let auth_result = auth_result.map_err(|err| {
|
let auth_result = auth_result.map_err(|err| {
|
||||||
info!("Failed to read auth data from body: {}", err);
|
if matches!(err, AuthDataError::NotFound) && is_acs_endpoint {
|
||||||
|
|
||||||
if !is_acs_endpoint && matches!(err, AuthDataParseError::NotFound) {
|
|
||||||
AuthDataError::NotFound
|
|
||||||
} else {
|
|
||||||
AuthDataError::Invalid
|
AuthDataError::Invalid
|
||||||
|
} else {
|
||||||
|
err
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -499,10 +492,7 @@ mod tests {
|
|||||||
<meta http-equiv="refresh" content="0; URL=globalprotectcallback:PGh0bWw+PCEtLSA8c">
|
<meta http-equiv="refresh" content="0; URL=globalprotectcallback:PGh0bWw+PCEtLSA8c">
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(extract_gpcallback(html), Some("globalprotectcallback:PGh0bWw+PCEtLSA8c"));
|
||||||
extract_gpcallback(html),
|
|
||||||
Some("globalprotectcallback:PGh0bWw+PCEtLSA8c")
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -31,6 +31,6 @@
|
|||||||
"eslint-plugin-react-hooks": "^4.6.0",
|
"eslint-plugin-react-hooks": "^4.6.0",
|
||||||
"prettier": "3.1.0",
|
"prettier": "3.1.0",
|
||||||
"typescript": "^5.0.2",
|
"typescript": "^5.0.2",
|
||||||
"vite": "^4.5.3"
|
"vite": "^4.5.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
14
apps/gpgui-helper/pnpm-lock.yaml
generated
14
apps/gpgui-helper/pnpm-lock.yaml
generated
@ -48,7 +48,7 @@ devDependencies:
|
|||||||
version: 6.12.0(eslint@8.54.0)(typescript@5.0.2)
|
version: 6.12.0(eslint@8.54.0)(typescript@5.0.2)
|
||||||
'@vitejs/plugin-react':
|
'@vitejs/plugin-react':
|
||||||
specifier: ^4.0.3
|
specifier: ^4.0.3
|
||||||
version: 4.0.3(vite@4.5.3)
|
version: 4.0.3(vite@4.5.2)
|
||||||
eslint:
|
eslint:
|
||||||
specifier: ^8.54.0
|
specifier: ^8.54.0
|
||||||
version: 8.54.0
|
version: 8.54.0
|
||||||
@ -68,8 +68,8 @@ devDependencies:
|
|||||||
specifier: ^5.0.2
|
specifier: ^5.0.2
|
||||||
version: 5.0.2
|
version: 5.0.2
|
||||||
vite:
|
vite:
|
||||||
specifier: ^4.5.3
|
specifier: ^4.5.2
|
||||||
version: 4.5.3(@types/node@20.8.10)
|
version: 4.5.2(@types/node@20.8.10)
|
||||||
|
|
||||||
packages:
|
packages:
|
||||||
|
|
||||||
@ -1229,7 +1229,7 @@ packages:
|
|||||||
resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==}
|
resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/@vitejs/plugin-react@4.0.3(vite@4.5.3):
|
/@vitejs/plugin-react@4.0.3(vite@4.5.2):
|
||||||
resolution: {integrity: sha512-pwXDog5nwwvSIzwrvYYmA2Ljcd/ZNlcsSG2Q9CNDBwnsd55UGAyr2doXtB5j+2uymRCnCfExlznzzSFbBRcoCg==}
|
resolution: {integrity: sha512-pwXDog5nwwvSIzwrvYYmA2Ljcd/ZNlcsSG2Q9CNDBwnsd55UGAyr2doXtB5j+2uymRCnCfExlznzzSFbBRcoCg==}
|
||||||
engines: {node: ^14.18.0 || >=16.0.0}
|
engines: {node: ^14.18.0 || >=16.0.0}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@ -1239,7 +1239,7 @@ packages:
|
|||||||
'@babel/plugin-transform-react-jsx-self': 7.22.5(@babel/core@7.23.2)
|
'@babel/plugin-transform-react-jsx-self': 7.22.5(@babel/core@7.23.2)
|
||||||
'@babel/plugin-transform-react-jsx-source': 7.22.5(@babel/core@7.23.2)
|
'@babel/plugin-transform-react-jsx-source': 7.22.5(@babel/core@7.23.2)
|
||||||
react-refresh: 0.14.0
|
react-refresh: 0.14.0
|
||||||
vite: 4.5.3(@types/node@20.8.10)
|
vite: 4.5.2(@types/node@20.8.10)
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
dev: true
|
dev: true
|
||||||
@ -2979,8 +2979,8 @@ packages:
|
|||||||
punycode: 2.3.1
|
punycode: 2.3.1
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/vite@4.5.3(@types/node@20.8.10):
|
/vite@4.5.2(@types/node@20.8.10):
|
||||||
resolution: {integrity: sha512-kQL23kMeX92v3ph7IauVkXkikdDRsYMGTVl5KY2E9OY4ONLvkHf04MDTbnfo6NKxZiDLWzVpP5oTa8hQD8U3dg==}
|
resolution: {integrity: sha512-tBCZBNSBbHQkaGyhGCDUGqeo2ph8Fstyp6FMSvTtsXeZSPpSMGlviAOav2hxVTqFcx8Hj/twtWKsMJXNY0xI8w==}
|
||||||
engines: {node: ^14.18.0 || >=16.0.0}
|
engines: {node: ^14.18.0 || >=16.0.0}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
|
@ -68,12 +68,12 @@ impl SamlAuthData {
|
|||||||
if auth_data.starts_with("cas-as") {
|
if auth_data.starts_with("cas-as") {
|
||||||
info!("Got token auth data: {}", auth_data);
|
info!("Got token auth data: {}", auth_data);
|
||||||
|
|
||||||
let auth_data: SamlAuthData = serde_urlencoded::from_str(auth_data).map_err(|e| {
|
let token_cred: SamlAuthData = serde_urlencoded::from_str(auth_data).map_err(|e| {
|
||||||
warn!("Failed to parse token auth data: {}", e);
|
warn!("Failed to parse token auth data: {}", e);
|
||||||
AuthDataParseError::Invalid
|
AuthDataParseError::Invalid
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
Ok(auth_data)
|
Ok(token_cred)
|
||||||
} else {
|
} else {
|
||||||
info!("Parsing SAML auth data...");
|
info!("Parsing SAML auth data...");
|
||||||
|
|
||||||
|
@ -42,7 +42,7 @@ impl ClientOs {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, Type, Default)]
|
#[derive(Debug, Serialize, Deserialize, Type, Default, Clone)]
|
||||||
pub struct GpParams {
|
pub struct GpParams {
|
||||||
is_gateway: bool,
|
is_gateway: bool,
|
||||||
user_agent: String,
|
user_agent: String,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user