diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 9b87b52e..5fb7de96 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -168,22 +168,23 @@ jobs: steps: - name: Prepare workspace run: rm -rf gh-release && mkdir gh-release + + - name: Checkout GlobalProtect-openconnect + uses: actions/checkout@v3 + with: + token: ${{ secrets.GH_PAT }} + repository: yuezk/GlobalProtect-openconnect + ref: ${{ github.ref }} + path: gh-release/gp + - name: Download all artifacts uses: actions/download-artifact@v3 with: - path: gh-release + path: gh-release/gp/.build/artifacts + - name: Create GH release env: GH_TOKEN: ${{ secrets.GH_PAT }} RELEASE_TAG: ${{ github.ref == 'refs/heads/dev' && 'snapshot' || github.ref_name }} - REPO: ${{ github.repository }} - NOTES: ${{ github.ref == 'refs/heads/dev' && '**!!! DO NOT USE THIS RELEASE IN PRODUCTION !!!**' || format('Release {0}', github.ref_name) }} run: | - gh -R "$REPO" release delete $RELEASE_TAG --yes --cleanup-tag || true - gh -R "$REPO" release create $RELEASE_TAG \ - --title "$RELEASE_TAG" \ - --notes "$NOTES" \ - ${{ github.ref == 'refs/heads/dev' && '--target dev' || '' }} \ - ${{ github.ref == 'refs/heads/dev' && '--prerelease' || '' }} \ - gh-release/artifact-source/* \ - gh-release/artifact-gpgui-*/* + cd gp-release/gp/scripts && ./gh-release.sh "$RELEASE_TAG" diff --git a/crates/gpapi/src/auth.rs b/crates/gpapi/src/auth.rs index d77e1ebd..245c7d01 100644 --- a/crates/gpapi/src/auth.rs +++ b/crates/gpapi/src/auth.rs @@ -1,3 +1,5 @@ +use std::borrow::{Borrow, Cow}; + use log::{info, warn}; use regex::Regex; use serde::{Deserialize, Serialize}; @@ -68,24 +70,29 @@ impl SamlAuthData { if auth_data.starts_with("cas-as") { info!("Got CAS auth data from globalprotectcallback"); - let auth_data: SamlAuthData = serde_urlencoded::from_str(auth_data).map_err(|e| { + // Decode the auth data and use the original value if decoding fails + let auth_data = urlencoding::decode(auth_data).unwrap_or_else(|err| { + warn!("Failed to decode token auth data: {}", err); + Cow::Borrowed(auth_data) + }); + + let auth_data: SamlAuthData = serde_urlencoded::from_str(auth_data.borrow()).map_err(|e| { warn!("Failed to parse token auth data: {}", e); warn!("Auth data: {}", auth_data); AuthDataParseError::Invalid })?; - Ok(auth_data) - } else { - info!("Parsing SAML auth data..."); + return Ok(auth_data); + } - let auth_data = decode_to_string(auth_data).map_err(|e| { - warn!("Failed to decode SAML auth data: {}", e); - AuthDataParseError::Invalid - })?; - let auth_data = Self::from_html(&auth_data)?; + info!("Parsing SAML auth data..."); + let auth_data = decode_to_string(auth_data).map_err(|e| { + warn!("Failed to decode SAML auth data: {}", e); + AuthDataParseError::Invalid + })?; + let auth_data = Self::from_html(&auth_data)?; - Ok(auth_data) - } + Ok(auth_data) } pub fn username(&self) -> &str { @@ -143,6 +150,16 @@ mod tests { assert_eq!(auth_data.token(), Some("very_long_string")); } + #[test] + fn auth_data_from_gpcallback_cas_urlencoded() { + let auth_data = "globalprotectcallback:cas-as%3D1%26un%3Dxyz%40email.com%26token%3Dvery_long_string"; + + let auth_data = SamlAuthData::from_gpcallback(auth_data).unwrap(); + + assert_eq!(auth_data.username(), "xyz@email.com"); + assert_eq!(auth_data.token(), Some("very_long_string")); + } + #[test] fn auth_data_from_gpcallback_non_cas() { let auth_data = "PGh0bWw+PCEtLSA8c2FtbC1hdXRoLXN0YXR1cz4xPC9zYW1sLWF1dGgtc3RhdHVzPjxwcmVsb2dpbi1jb29raWU+cHJlbG9naW4tY29va2llPC9wcmVsb2dpbi1jb29raWU+PHNhbWwtdXNlcm5hbWU+eHl6QGVtYWlsLmNvbTwvc2FtbC11c2VybmFtZT48c2FtbC1zbG8+bm88L3NhbWwtc2xvPjxzYW1sLVNlc3Npb25Ob3RPbk9yQWZ0ZXI+PC9zYW1sLVNlc3Npb25Ob3RPbk9yQWZ0ZXI+IC0tPjwvaHRtbD4="; diff --git a/scripts/gh-release.sh b/scripts/gh-release.sh new file mode 100755 index 00000000..a862062e --- /dev/null +++ b/scripts/gh-release.sh @@ -0,0 +1,51 @@ +#!/bin/bash + +# Usage: ./scripts/gh-release.sh + +set -e + +REPO="yuezk/GlobalProtect-openconnect" +TAG=$1 + +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )" +PROJECT_DIR="$(dirname "$SCRIPT_DIR")" + +RELEASE_NOTES="Release $TAG" + +if [ -z "$TAG" ]; then + echo "Usage: ./scripts/gh-release.sh " + exit 1 +fi + +# For snapshot release, we don't create a release, just clear the existing assets and upload new ones. +# This is to avoid notification spam. +release_snapshot() { + RELEASE_NOTES='**!!! DO NOT USE THIS RELEASE IN PRODUCTION !!!**' + + # Get the existing assets + gh -R "$REPO" release view "$TAG" --json assets --jq '.assets[].name' \ + | xargs -I {} gh -R "$REPO" release delete-asset "$TAG" {} --yes + + echo "Uploading new assets..." + gh -R "$REPO" release upload "$TAG" \ + "$PROJECT_DIR"/.build/artifacts/artifact-source/* \ + "$PROJECT_DIR"/.build/artifacts/artifact-gpgui-*/* +} + +release_tag() { + echo "Removing existing release..." + gh -R "$REPO" release delete $TAG --yes --cleanup-tag || true + + echo "Creating release..." + gh -R "$REPO" release create $TAG \ + --title "$TAG" \ + --notes "$RELEASE_NOTES" \ + "$PROJECT_DIR"/.build/artifacts/artifact-source/* \ + "$PROJECT_DIR"/.build/artifacts/artifact-gpgui-*/* +} + +if [[ $TAG == *"snapshot" ]]; then + release_snapshot +else + release_tag +fi