mirror of
https://github.com/yuezk/GlobalProtect-openconnect.git
synced 2025-04-02 18:31:50 -04:00
refactor: encrypt the sensitive data
This commit is contained in:
parent
bf96a88e21
commit
601f422863
5
.vscode/settings.json
vendored
5
.vscode/settings.json
vendored
@ -5,11 +5,13 @@
|
||||
"clickaway",
|
||||
"clientgpversion",
|
||||
"clientos",
|
||||
"consts",
|
||||
"devicename",
|
||||
"distro",
|
||||
"gpcommon",
|
||||
"gpgui",
|
||||
"gpservice",
|
||||
"humantime",
|
||||
"Immer",
|
||||
"jnlp",
|
||||
"oneshot",
|
||||
@ -17,7 +19,10 @@
|
||||
"prelogin",
|
||||
"prelogon",
|
||||
"prelogonuserauthcookie",
|
||||
"repr",
|
||||
"rustc",
|
||||
"tauri",
|
||||
"thiserror",
|
||||
"unlisten",
|
||||
"userauthcookie",
|
||||
"vpnc",
|
||||
|
695
Cargo.lock
generated
695
Cargo.lock
generated
@ -8,6 +8,53 @@ version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
|
||||
|
||||
[[package]]
|
||||
name = "aead"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0"
|
||||
dependencies = [
|
||||
"crypto-common",
|
||||
"generic-array",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "aes"
|
||||
version = "0.7.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9e8b47f52ea9bae42228d07ec09eb676433d7c4ed1ebdf0f1d1c29ed446f1ab8"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cipher 0.3.0",
|
||||
"cpufeatures",
|
||||
"opaque-debug",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "aes"
|
||||
version = "0.8.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac1f845298e95f983ff1944b728ae08b8cebab80d684f0a832ed0fc74dfa27e2"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cipher 0.4.4",
|
||||
"cpufeatures",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "aes-gcm"
|
||||
version = "0.10.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "209b47e8954a928e1d72e86eca7000ebb6655fe1436d33eefc2201cad027e237"
|
||||
dependencies = [
|
||||
"aead",
|
||||
"aes 0.8.3",
|
||||
"cipher 0.4.4",
|
||||
"ctr",
|
||||
"ghash",
|
||||
"subtle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "0.7.20"
|
||||
@ -51,8 +98,11 @@ checksum = "224afbd727c3d6e4b90103ece64b8d1b67fbb1973b1046c2281eed3f3803f800"
|
||||
name = "app"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"env_logger",
|
||||
"aes-gcm",
|
||||
"anyhow",
|
||||
"gpcommon",
|
||||
"hex",
|
||||
"keyring",
|
||||
"log",
|
||||
"openssl",
|
||||
"regex",
|
||||
@ -69,6 +119,117 @@ dependencies = [
|
||||
"whoami",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-broadcast"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7c48ccdbf6ca6b121e0f586cbc0e73ae440e56c67c30fa0873b4e110d9c26d2b"
|
||||
dependencies = [
|
||||
"event-listener",
|
||||
"futures-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-channel"
|
||||
version = "1.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "81953c529336010edd6d8e358f886d9581267795c61b19475b71314bffa46d35"
|
||||
dependencies = [
|
||||
"concurrent-queue",
|
||||
"event-listener",
|
||||
"futures-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-executor"
|
||||
version = "1.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6fa3dc5f2a8564f07759c008b9109dc0d39de92a88d5588b8a5036d286383afb"
|
||||
dependencies = [
|
||||
"async-lock",
|
||||
"async-task",
|
||||
"concurrent-queue",
|
||||
"fastrand",
|
||||
"futures-lite",
|
||||
"slab",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-fs"
|
||||
version = "1.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "279cf904654eeebfa37ac9bb1598880884924aab82e290aa65c9e77a0e142e06"
|
||||
dependencies = [
|
||||
"async-lock",
|
||||
"autocfg",
|
||||
"blocking",
|
||||
"futures-lite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-io"
|
||||
version = "1.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0fc5b45d93ef0529756f812ca52e44c221b35341892d3dcc34132ac02f3dd2af"
|
||||
dependencies = [
|
||||
"async-lock",
|
||||
"autocfg",
|
||||
"cfg-if",
|
||||
"concurrent-queue",
|
||||
"futures-lite",
|
||||
"log",
|
||||
"parking",
|
||||
"polling",
|
||||
"rustix",
|
||||
"slab",
|
||||
"socket2",
|
||||
"waker-fn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-lock"
|
||||
version = "2.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fa24f727524730b077666307f2734b4a1a1c57acb79193127dcc8914d5242dd7"
|
||||
dependencies = [
|
||||
"event-listener",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-process"
|
||||
version = "1.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7a9d28b1d97e08915212e2e45310d47854eafa69600756fc735fb788f75199c9"
|
||||
dependencies = [
|
||||
"async-io",
|
||||
"async-lock",
|
||||
"autocfg",
|
||||
"blocking",
|
||||
"cfg-if",
|
||||
"event-listener",
|
||||
"futures-lite",
|
||||
"rustix",
|
||||
"signal-hook",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-recursion"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0e97ce7de6cf12de5d7226c73f5ba9811622f4db3a5b91b55c53e987e5f91cba"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.16",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-task"
|
||||
version = "4.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ecc7ab41815b3c653ccd2978ec3255c81349336702dfdf62ee6f7069b12a3aae"
|
||||
|
||||
[[package]]
|
||||
name = "async-trait"
|
||||
version = "0.1.66"
|
||||
@ -104,6 +265,12 @@ dependencies = [
|
||||
"system-deps 6.0.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "atomic-waker"
|
||||
version = "1.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1181e1e0d1fce796a03db1ae795d67167da795f9cf4a39c37589e85ef57f26d3"
|
||||
|
||||
[[package]]
|
||||
name = "attohttpc"
|
||||
version = "0.22.0"
|
||||
@ -170,6 +337,37 @@ dependencies = [
|
||||
"generic-array",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "block-modes"
|
||||
version = "0.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2cb03d1bed155d89dce0f845b7899b18a9a163e148fd004e1c28421a783e2d8e"
|
||||
dependencies = [
|
||||
"block-padding",
|
||||
"cipher 0.3.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "block-padding"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8d696c370c750c948ada61c69a0ee2cbbb9c50b1019ddb86d9317157a99c2cae"
|
||||
|
||||
[[package]]
|
||||
name = "blocking"
|
||||
version = "1.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "77231a1c8f801696fc0123ec6150ce92cffb8e164a02afb9c8ddee0e9b65ad65"
|
||||
dependencies = [
|
||||
"async-channel",
|
||||
"async-lock",
|
||||
"async-task",
|
||||
"atomic-waker",
|
||||
"fastrand",
|
||||
"futures-lite",
|
||||
"log",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "brotli"
|
||||
version = "3.3.4"
|
||||
@ -329,6 +527,25 @@ dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cipher"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7ee52072ec15386f770805afd189a01c8841be8696bed250fa2f13c4c0d6dfb7"
|
||||
dependencies = [
|
||||
"generic-array",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cipher"
|
||||
version = "0.4.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad"
|
||||
dependencies = [
|
||||
"crypto-common",
|
||||
"inout",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cocoa"
|
||||
version = "0.24.1"
|
||||
@ -387,6 +604,15 @@ dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "concurrent-queue"
|
||||
version = "2.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "62ec6771ecfa0762d24683ee5a32ad78487a3d3afdc0fb8cae19d2c5deb50b7c"
|
||||
dependencies = [
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "convert_case"
|
||||
version = "0.4.0"
|
||||
@ -478,6 +704,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
|
||||
dependencies = [
|
||||
"generic-array",
|
||||
"rand_core 0.6.4",
|
||||
"typenum",
|
||||
]
|
||||
|
||||
@ -518,6 +745,15 @@ dependencies = [
|
||||
"syn 1.0.107",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ctr"
|
||||
version = "0.9.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835"
|
||||
dependencies = [
|
||||
"cipher 0.4.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cty"
|
||||
version = "0.2.2"
|
||||
@ -571,6 +807,17 @@ version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8d7439c3735f405729d52c3fbbe4de140eaf938a1fe47d227c27f8254d4302a5"
|
||||
|
||||
[[package]]
|
||||
name = "derivative"
|
||||
version = "2.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 1.0.107",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "derive_more"
|
||||
version = "0.99.17"
|
||||
@ -592,6 +839,7 @@ checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f"
|
||||
dependencies = [
|
||||
"block-buffer",
|
||||
"crypto-common",
|
||||
"subtle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -671,16 +919,24 @@ dependencies = [
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "env_logger"
|
||||
version = "0.10.0"
|
||||
name = "enumflags2"
|
||||
version = "0.7.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "85cdab6a89accf66733ad5a1693a4dcced6aeff64602b634530dd73c1f3ee9f0"
|
||||
checksum = "c041f5090df68b32bcd905365fd51769c8b9d553fe87fde0b683534f10c01bd2"
|
||||
dependencies = [
|
||||
"humantime",
|
||||
"is-terminal",
|
||||
"log",
|
||||
"regex",
|
||||
"termcolor",
|
||||
"enumflags2_derive",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "enumflags2_derive"
|
||||
version = "0.7.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5e9a1f9f7d83e59740248a6e14ecf93929ade55027844dfcea78beafccc15745"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.16",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -704,6 +960,12 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "event-listener"
|
||||
version = "2.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0"
|
||||
|
||||
[[package]]
|
||||
name = "fastrand"
|
||||
version = "1.8.0"
|
||||
@ -729,7 +991,7 @@ version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e1c54951450cbd39f3dbcf1005ac413b49487dabf18a720ad2383eccfeffb92"
|
||||
dependencies = [
|
||||
"memoffset",
|
||||
"memoffset 0.6.5",
|
||||
"rustc_version 0.3.3",
|
||||
]
|
||||
|
||||
@ -827,6 +1089,21 @@ version = "0.3.26"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bfb8371b6fb2aeb2d280374607aeabfc99d95c72edfe51692e42d3d7f0d08531"
|
||||
|
||||
[[package]]
|
||||
name = "futures-lite"
|
||||
version = "1.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49a9d51ce47660b1e808d3c990b4709f2f415d928835a17dfd16991515c46bce"
|
||||
dependencies = [
|
||||
"fastrand",
|
||||
"futures-core",
|
||||
"futures-io",
|
||||
"memchr",
|
||||
"parking",
|
||||
"pin-project-lite",
|
||||
"waker-fn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-macro"
|
||||
version = "0.3.26"
|
||||
@ -857,8 +1134,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c1d6de3acfef38d2be4b1f543f553131788603495be83da675e180c8d6b7bd1"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-io",
|
||||
"futures-macro",
|
||||
"futures-sink",
|
||||
"futures-task",
|
||||
"memchr",
|
||||
"pin-project-lite",
|
||||
"pin-utils",
|
||||
"slab",
|
||||
@ -1004,6 +1284,16 @@ dependencies = [
|
||||
"wasi 0.11.0+wasi-snapshot-preview1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ghash"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d930750de5717d2dd0b8c0d42c076c0e884c81a73e6cab859bbd2339c71e3e40"
|
||||
dependencies = [
|
||||
"opaque-debug",
|
||||
"polyval",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gio"
|
||||
version = "0.15.12"
|
||||
@ -1139,8 +1429,9 @@ dependencies = [
|
||||
name = "gpservice"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"env_logger",
|
||||
"fern",
|
||||
"gpcommon",
|
||||
"humantime",
|
||||
"log",
|
||||
"tokio",
|
||||
]
|
||||
@ -1251,6 +1542,24 @@ version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
|
||||
|
||||
[[package]]
|
||||
name = "hkdf"
|
||||
version = "0.12.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "791a029f6b9fc27657f6f188ec6e5e43f6911f6f878e0dc5501396e09809d437"
|
||||
dependencies = [
|
||||
"hmac",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hmac"
|
||||
version = "0.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e"
|
||||
dependencies = [
|
||||
"digest",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "html5ever"
|
||||
version = "0.25.2"
|
||||
@ -1388,6 +1697,15 @@ dependencies = [
|
||||
"cfb",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "inout"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5"
|
||||
dependencies = [
|
||||
"generic-array",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "instant"
|
||||
version = "0.1.12"
|
||||
@ -1408,18 +1726,6 @@ dependencies = [
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "is-terminal"
|
||||
version = "0.4.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "adcf93614601c8129ddf72e2d5633df827ba6551541c6d8c59520a371475be1f"
|
||||
dependencies = [
|
||||
"hermit-abi 0.3.1",
|
||||
"io-lifetimes",
|
||||
"rustix",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "is_executable"
|
||||
version = "1.0.1"
|
||||
@ -1505,6 +1811,20 @@ dependencies = [
|
||||
"treediff",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "keyring"
|
||||
version = "2.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "04ac4b8b0884cdf23c4619d139acf43839eac4f0739b92980c2a6d460d9c84f5"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"lazy_static",
|
||||
"linux-keyutils",
|
||||
"secret-service",
|
||||
"security-framework",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "kuchiki"
|
||||
version = "0.8.1"
|
||||
@ -1538,6 +1858,16 @@ dependencies = [
|
||||
"safemem",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "linux-keyutils"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3f27bb67f6dd1d0bb5ab582868e4f65052e58da6401188a08f0da09cf512b84b"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "linux-raw-sys"
|
||||
version = "0.3.7"
|
||||
@ -1638,6 +1968,15 @@ dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memoffset"
|
||||
version = "0.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.6.2"
|
||||
@ -1711,6 +2050,19 @@ version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54"
|
||||
|
||||
[[package]]
|
||||
name = "nix"
|
||||
version = "0.26.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bfdda3d196821d6af13126e40375cdf7da646a96114af134d5f417a9a1dc8e1a"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"memoffset 0.7.1",
|
||||
"static_assertions",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nodrop"
|
||||
version = "0.1.14"
|
||||
@ -1727,6 +2079,40 @@ dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b05180d69e3da0e530ba2a1dae5110317e49e3b7f3d41be227dc5f92e49ee7af"
|
||||
dependencies = [
|
||||
"num-bigint",
|
||||
"num-complex",
|
||||
"num-integer",
|
||||
"num-iter",
|
||||
"num-rational",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-bigint"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-complex"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "02e0d21255c828d6f128a1e41534206671e8c3ea0c62f32291e808dc82cff17d"
|
||||
dependencies = [
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-integer"
|
||||
version = "0.1.45"
|
||||
@ -1737,6 +2123,17 @@ dependencies = [
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-iter"
|
||||
version = "0.1.43"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-rational"
|
||||
version = "0.4.1"
|
||||
@ -1744,6 +2141,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"num-bigint",
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
]
|
||||
@ -1831,6 +2229,12 @@ version = "1.17.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6f61fba1741ea2b3d6a1e3178721804bb716a68a6aeba1149b5d52e3d464ea66"
|
||||
|
||||
[[package]]
|
||||
name = "opaque-debug"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
|
||||
|
||||
[[package]]
|
||||
name = "open"
|
||||
version = "3.2.0"
|
||||
@ -1886,6 +2290,16 @@ dependencies = [
|
||||
"vcpkg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ordered-stream"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9aa2b01e1d916879f73a53d01d1d6cee68adbb31d6d9177a8cfce093cced1d50"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"pin-project-lite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "overload"
|
||||
version = "0.1.1"
|
||||
@ -1917,6 +2331,12 @@ dependencies = [
|
||||
"system-deps 6.0.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking"
|
||||
version = "2.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "14f2252c834a40ed9bb5422029649578e63aa341ac401f74e719dd1afda8394e"
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot"
|
||||
version = "0.12.1"
|
||||
@ -2104,6 +2524,34 @@ dependencies = [
|
||||
"miniz_oxide",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "polling"
|
||||
version = "2.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4b2d323e8ca7996b3e23126511a523f7e62924d93ecd5ae73b333815b0eb3dce"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"bitflags",
|
||||
"cfg-if",
|
||||
"concurrent-queue",
|
||||
"libc",
|
||||
"log",
|
||||
"pin-project-lite",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "polyval"
|
||||
version = "0.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d52cff9d1d4dee5fe6d03729099f4a310a41179e0a10dbf542039873f2e826fb"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cpufeatures",
|
||||
"opaque-debug",
|
||||
"universal-hash",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ppv-lite86"
|
||||
version = "0.2.17"
|
||||
@ -2423,6 +2871,25 @@ version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
|
||||
|
||||
[[package]]
|
||||
name = "secret-service"
|
||||
version = "3.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5da1a5ad4d28c03536f82f77d9f36603f5e37d8869ac98f0a750d5b5686d8d95"
|
||||
dependencies = [
|
||||
"aes 0.7.5",
|
||||
"block-modes",
|
||||
"futures-util",
|
||||
"generic-array",
|
||||
"hkdf",
|
||||
"num",
|
||||
"once_cell",
|
||||
"rand 0.8.5",
|
||||
"serde",
|
||||
"sha2",
|
||||
"zbus",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "security-framework"
|
||||
version = "2.8.2"
|
||||
@ -2616,6 +3083,17 @@ dependencies = [
|
||||
"stable_deref_trait",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sha1"
|
||||
version = "0.10.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cpufeatures",
|
||||
"digest",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sha2"
|
||||
version = "0.10.6"
|
||||
@ -2636,6 +3114,16 @@ dependencies = [
|
||||
"lazy_static",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "signal-hook"
|
||||
version = "0.3.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b824b6e687aff278cdbf3b36f07aa52d4bd4099699324d5da86a2ebce3aa00b3"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"signal-hook-registry",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "signal-hook-registry"
|
||||
version = "1.4.0"
|
||||
@ -2725,6 +3213,12 @@ dependencies = [
|
||||
"loom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "static_assertions"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
|
||||
|
||||
[[package]]
|
||||
name = "string_cache"
|
||||
version = "0.8.4"
|
||||
@ -2757,6 +3251,12 @@ version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
||||
|
||||
[[package]]
|
||||
name = "subtle"
|
||||
version = "2.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.107"
|
||||
@ -3112,15 +3612,6 @@ dependencies = [
|
||||
"utf-8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "termcolor"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6"
|
||||
dependencies = [
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thin-slice"
|
||||
version = "0.1.1"
|
||||
@ -3354,6 +3845,16 @@ version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9e79c4d996edb816c91e4308506774452e55e95c3c9de07b6729e17e15a5ef81"
|
||||
|
||||
[[package]]
|
||||
name = "uds_windows"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ce65604324d3cce9b966701489fbd0cf318cb1f7bd9dd07ac9a4ee6fb791930d"
|
||||
dependencies = [
|
||||
"tempfile",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-bidi"
|
||||
version = "0.3.10"
|
||||
@ -3381,6 +3882,16 @@ version = "1.10.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36"
|
||||
|
||||
[[package]]
|
||||
name = "universal-hash"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea"
|
||||
dependencies = [
|
||||
"crypto-common",
|
||||
"subtle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "untrusted"
|
||||
version = "0.7.1"
|
||||
@ -3501,6 +4012,12 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "waker-fn"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9d5b2c62b4012a3e1eca5a7e077d13b3bf498c4073e33ccd58626607748ceeca"
|
||||
|
||||
[[package]]
|
||||
name = "walkdir"
|
||||
version = "2.3.2"
|
||||
@ -4041,3 +4558,117 @@ checksum = "6d1526bbe5aaeb5eb06885f4d987bcdfa5e23187055de9b83fe00156a821fabc"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "xdg-home"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2769203cd13a0c6015d515be729c526d041e9cf2c0cc478d57faee85f40c6dcd"
|
||||
dependencies = [
|
||||
"nix",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zbus"
|
||||
version = "3.14.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "31de390a2d872e4cd04edd71b425e29853f786dc99317ed72d73d6fcf5ebb948"
|
||||
dependencies = [
|
||||
"async-broadcast",
|
||||
"async-executor",
|
||||
"async-fs",
|
||||
"async-io",
|
||||
"async-lock",
|
||||
"async-process",
|
||||
"async-recursion",
|
||||
"async-task",
|
||||
"async-trait",
|
||||
"blocking",
|
||||
"byteorder",
|
||||
"derivative",
|
||||
"enumflags2",
|
||||
"event-listener",
|
||||
"futures-core",
|
||||
"futures-sink",
|
||||
"futures-util",
|
||||
"hex",
|
||||
"nix",
|
||||
"once_cell",
|
||||
"ordered-stream",
|
||||
"rand 0.8.5",
|
||||
"serde",
|
||||
"serde_repr",
|
||||
"sha1",
|
||||
"static_assertions",
|
||||
"tracing",
|
||||
"uds_windows",
|
||||
"winapi",
|
||||
"xdg-home",
|
||||
"zbus_macros",
|
||||
"zbus_names",
|
||||
"zvariant",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zbus_macros"
|
||||
version = "3.14.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "41d1794a946878c0e807f55a397187c11fc7a038ba5d868e7db4f3bd7760bc9d"
|
||||
dependencies = [
|
||||
"proc-macro-crate",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"regex",
|
||||
"syn 1.0.107",
|
||||
"zvariant_utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zbus_names"
|
||||
version = "2.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fb80bb776dbda6e23d705cf0123c3b95df99c4ebeaec6c2599d4a5419902b4a9"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"static_assertions",
|
||||
"zvariant",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zvariant"
|
||||
version = "3.15.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "44b291bee0d960c53170780af148dca5fa260a63cdd24f1962fa82e03e53338c"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"enumflags2",
|
||||
"libc",
|
||||
"serde",
|
||||
"static_assertions",
|
||||
"zvariant_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zvariant_derive"
|
||||
version = "3.15.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "934d7a7dfc310d6ee06c87ffe88ef4eca7d3e37bb251dece2ef93da8f17d8ecd"
|
||||
dependencies = [
|
||||
"proc-macro-crate",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 1.0.107",
|
||||
"zvariant_utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zvariant_utils"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7234f0d811589db492d16893e3f21e8e2fd282e6d01b0cddee310322062cc200"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 1.0.107",
|
||||
]
|
||||
|
@ -201,8 +201,14 @@ impl Client {
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn connect(&self, server: String, cookie: String) -> Result<(), ServerApiError> {
|
||||
self.send_command(Connect::new(server, cookie).into()).await
|
||||
pub async fn connect(
|
||||
&self,
|
||||
server: String,
|
||||
cookie: String,
|
||||
user_agent: String,
|
||||
) -> Result<(), ServerApiError> {
|
||||
self.send_command(Connect::new(server, cookie, user_agent).into())
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn disconnect(&self) -> Result<(), ServerApiError> {
|
||||
|
@ -7,11 +7,16 @@ use serde::{Deserialize, Serialize};
|
||||
pub struct Connect {
|
||||
server: String,
|
||||
cookie: String,
|
||||
user_agent: String,
|
||||
}
|
||||
|
||||
impl Connect {
|
||||
pub fn new(server: String, cookie: String) -> Self {
|
||||
Self { server, cookie }
|
||||
pub fn new(server: String, cookie: String, user_agent: String) -> Self {
|
||||
Self {
|
||||
server,
|
||||
cookie,
|
||||
user_agent,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -25,7 +30,7 @@ impl Command for Connect {
|
||||
return Err(format!("VPN is already in state: {:?}", status).into());
|
||||
}
|
||||
|
||||
if let Err(err) = vpn.connect(&self.server, &self.cookie).await {
|
||||
if let Err(err) = vpn.connect(&self.server, &self.cookie, &self.user_agent).await {
|
||||
return Err(err.to_string().into());
|
||||
}
|
||||
|
||||
|
@ -5,16 +5,17 @@ use tokio::sync::mpsc;
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub(crate) struct Options {
|
||||
pub server: *const ::std::os::raw::c_char,
|
||||
pub cookie: *const ::std::os::raw::c_char,
|
||||
pub script: *const ::std::os::raw::c_char,
|
||||
pub server: *const std::os::raw::c_char,
|
||||
pub cookie: *const std::os::raw::c_char,
|
||||
pub script: *const std::os::raw::c_char,
|
||||
pub user_agent: *const std::os::raw::c_char,
|
||||
pub user_data: *mut c_void,
|
||||
}
|
||||
|
||||
#[link(name = "vpn")]
|
||||
extern "C" {
|
||||
#[link_name = "vpn_connect"]
|
||||
pub(crate) fn connect(options: *const Options) -> ::std::os::raw::c_int;
|
||||
pub(crate) fn connect(options: *const Options) -> std::os::raw::c_int;
|
||||
|
||||
#[link_name = "vpn_disconnect"]
|
||||
pub(crate) fn disconnect();
|
||||
@ -32,7 +33,7 @@ extern "C" fn on_vpn_connected(value: i32, sender: *mut c_void) {
|
||||
// level: 0 = error, 1 = info, 2 = debug, 3 = trace
|
||||
// map the error level log in openconnect to the warning level
|
||||
#[no_mangle]
|
||||
extern "C" fn vpn_log(level: i32, message: *const ::std::os::raw::c_char) {
|
||||
extern "C" fn vpn_log(level: i32, message: *const std::os::raw::c_char) {
|
||||
let message = unsafe { std::ffi::CStr::from_ptr(message) };
|
||||
let message = message.to_str().unwrap_or("Invalid log message");
|
||||
// Strip the trailing newline
|
||||
|
@ -56,6 +56,7 @@ pub(crate) struct VpnOptions {
|
||||
server: CString,
|
||||
cookie: CString,
|
||||
script: CString,
|
||||
user_agent: CString,
|
||||
}
|
||||
|
||||
impl VpnOptions {
|
||||
@ -64,6 +65,7 @@ impl VpnOptions {
|
||||
server: self.server.as_ptr(),
|
||||
cookie: self.cookie.as_ptr(),
|
||||
script: self.script.as_ptr(),
|
||||
user_agent: self.user_agent.as_ptr(),
|
||||
user_data,
|
||||
}
|
||||
}
|
||||
@ -88,6 +90,7 @@ impl Vpn {
|
||||
&self,
|
||||
server: &str,
|
||||
cookie: &str,
|
||||
user_agent: &str,
|
||||
) -> Result<(), Box<dyn std::error::Error>> {
|
||||
let script = match find_default_vpnc_script() {
|
||||
Some(script) => {
|
||||
@ -104,6 +107,7 @@ impl Vpn {
|
||||
server: VpnOptions::to_cstr(server),
|
||||
cookie: VpnOptions::to_cstr(cookie),
|
||||
script: VpnOptions::to_cstr(script),
|
||||
user_agent: VpnOptions::to_cstr(user_agent),
|
||||
});
|
||||
|
||||
let vpn_options = self.vpn_options.clone();
|
||||
|
@ -53,7 +53,7 @@ int vpn_connect(const vpn_options *options)
|
||||
g_user_data = options->user_data;
|
||||
g_vpnc_script = options->script;
|
||||
|
||||
vpninfo = openconnect_vpninfo_new("PAN GlobalProtect", validate_peer_cert, NULL, NULL, print_progress, NULL);
|
||||
vpninfo = openconnect_vpninfo_new(options->user_agent, validate_peer_cert, NULL, NULL, print_progress, NULL);
|
||||
|
||||
if (!vpninfo)
|
||||
{
|
||||
|
@ -8,6 +8,7 @@ typedef struct vpn_options
|
||||
const char *server;
|
||||
const char *cookie;
|
||||
const char *script;
|
||||
const char *user_agent;
|
||||
void *user_data;
|
||||
} vpn_options;
|
||||
|
||||
|
@ -23,8 +23,7 @@
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-spinners": "^0.13.8",
|
||||
"tauri-plugin-log-api": "github:tauri-apps/tauri-plugin-log",
|
||||
"tauri-plugin-store-api": "github:tauri-apps/tauri-plugin-store#v1"
|
||||
"tauri-plugin-log-api": "github:tauri-apps/tauri-plugin-log#v1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tauri-apps/cli": "^1.3.1",
|
||||
|
28
gpgui/pnpm-lock.yaml
generated
28
gpgui/pnpm-lock.yaml
generated
@ -1,4 +1,4 @@
|
||||
lockfileVersion: '6.1'
|
||||
lockfileVersion: '6.0'
|
||||
|
||||
settings:
|
||||
autoInstallPeers: true
|
||||
@ -48,11 +48,8 @@ dependencies:
|
||||
specifier: ^0.13.8
|
||||
version: 0.13.8(react-dom@18.2.0)(react@18.2.0)
|
||||
tauri-plugin-log-api:
|
||||
specifier: github:tauri-apps/tauri-plugin-log
|
||||
version: github.com/tauri-apps/tauri-plugin-log/21921031d74f871180381317a338559f588ad8e9
|
||||
tauri-plugin-store-api:
|
||||
specifier: github:tauri-apps/tauri-plugin-store#v1
|
||||
version: github.com/tauri-apps/tauri-plugin-store/1467ba770623ab1d41d825841c3d9435d9eaa0f1
|
||||
specifier: github:tauri-apps/tauri-plugin-log#v1
|
||||
version: github.com/tauri-apps/tauri-plugin-log/fbbb126e6d7fba7a7e6772d33f99c0fb689f32b6
|
||||
|
||||
devDependencies:
|
||||
'@tauri-apps/cli':
|
||||
@ -878,6 +875,11 @@ packages:
|
||||
engines: {node: '>= 14.6.0', npm: '>= 6.6.0', yarn: '>= 1.19.1'}
|
||||
dev: false
|
||||
|
||||
/@tauri-apps/api@1.4.0:
|
||||
resolution: {integrity: sha512-Jd6HPoTM1PZSFIzq7FB8VmMu3qSSyo/3lSwLpoapW+lQ41CL5Dow2KryLg+gyazA/58DRWI9vu/XpEeHK4uMdw==}
|
||||
engines: {node: '>= 14.6.0', npm: '>= 6.6.0', yarn: '>= 1.19.1'}
|
||||
dev: false
|
||||
|
||||
/@tauri-apps/cli-darwin-arm64@1.3.1:
|
||||
resolution: {integrity: sha512-QlepYVPgOgspcwA/u4kGG4ZUijlXfdRtno00zEy+LxinN/IRXtk+6ErVtsmoLi1ZC9WbuMwzAcsRvqsD+RtNAg==}
|
||||
engines: {node: '>= 10'}
|
||||
@ -1465,18 +1467,10 @@ packages:
|
||||
engines: {node: '>= 6'}
|
||||
dev: false
|
||||
|
||||
github.com/tauri-apps/tauri-plugin-log/21921031d74f871180381317a338559f588ad8e9:
|
||||
resolution: {tarball: https://codeload.github.com/tauri-apps/tauri-plugin-log/tar.gz/21921031d74f871180381317a338559f588ad8e9}
|
||||
github.com/tauri-apps/tauri-plugin-log/fbbb126e6d7fba7a7e6772d33f99c0fb689f32b6:
|
||||
resolution: {tarball: https://codeload.github.com/tauri-apps/tauri-plugin-log/tar.gz/fbbb126e6d7fba7a7e6772d33f99c0fb689f32b6}
|
||||
name: tauri-plugin-log-api
|
||||
version: 0.0.0
|
||||
dependencies:
|
||||
'@tauri-apps/api': 1.3.0
|
||||
dev: false
|
||||
|
||||
github.com/tauri-apps/tauri-plugin-store/1467ba770623ab1d41d825841c3d9435d9eaa0f1:
|
||||
resolution: {tarball: https://codeload.github.com/tauri-apps/tauri-plugin-store/tar.gz/1467ba770623ab1d41d825841c3d9435d9eaa0f1}
|
||||
name: tauri-plugin-store-api
|
||||
version: 0.0.0
|
||||
dependencies:
|
||||
'@tauri-apps/api': 1.3.0
|
||||
'@tauri-apps/api': 1.4.0
|
||||
dev: false
|
||||
|
@ -23,7 +23,6 @@ tauri-plugin-log = { git = "https://github.com/tauri-apps/plugins-workspace", br
|
||||
serde_json = "1.0"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
log = "0.4"
|
||||
env_logger = "0.10"
|
||||
webkit2gtk = "0.18.2"
|
||||
regex = "1"
|
||||
url = "2.3"
|
||||
@ -32,6 +31,10 @@ veil = "0.1.6"
|
||||
whoami = "1.4.1"
|
||||
tauri-plugin-store = { git = "https://github.com/tauri-apps/plugins-workspace", branch = "v1" }
|
||||
openssl = "0.10"
|
||||
keyring = "2"
|
||||
aes-gcm = { version = "0.10", features = ["std"] }
|
||||
hex = "0.4"
|
||||
anyhow = "1.0"
|
||||
|
||||
[features]
|
||||
# by default Tauri runs in production mode
|
||||
|
@ -133,7 +133,7 @@ fn build_window(app_handle: &AppHandle, ua: &str) -> tauri::Result<Window> {
|
||||
Window::builder(app_handle, AUTH_WINDOW_LABEL, url)
|
||||
.visible(false)
|
||||
.title("GlobalProtect Login")
|
||||
.inner_size(400.0, 647.0)
|
||||
.inner_size(600.0, 500.0)
|
||||
.min_inner_size(370.0, 600.0)
|
||||
.user_agent(ua)
|
||||
.always_on_top(true)
|
||||
|
@ -1,9 +1,11 @@
|
||||
use crate::{
|
||||
auth::{self, AuthData, AuthRequest, SamlBinding, SamlLoginParams},
|
||||
storage::{AppStorage, KeyHint},
|
||||
utils::get_openssl_conf,
|
||||
utils::get_openssl_conf_path,
|
||||
};
|
||||
use gpcommon::{Client, ServerApiError, VpnStatus};
|
||||
use serde_json::Value;
|
||||
use std::sync::Arc;
|
||||
use tauri::{AppHandle, State};
|
||||
use tokio::fs;
|
||||
@ -24,9 +26,10 @@ pub(crate) async fn vpn_status<'a>(
|
||||
pub(crate) async fn vpn_connect<'a>(
|
||||
server: String,
|
||||
cookie: String,
|
||||
user_agent: String,
|
||||
client: State<'a, Arc<Client>>,
|
||||
) -> Result<(), ServerApiError> {
|
||||
client.connect(server, cookie).await
|
||||
client.connect(server, cookie, user_agent).await
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
@ -40,10 +43,10 @@ pub(crate) async fn vpn_disconnect<'a>(
|
||||
pub(crate) async fn saml_login(
|
||||
binding: SamlBinding,
|
||||
request: String,
|
||||
user_agent: String,
|
||||
clear_cookies: bool,
|
||||
app_handle: AppHandle,
|
||||
) -> tauri::Result<Option<AuthData>> {
|
||||
let user_agent = String::from("PAN GlobalProtect");
|
||||
let params = SamlLoginParams {
|
||||
auth_request: AuthRequest::new(binding, request),
|
||||
user_agent,
|
||||
@ -71,3 +74,29 @@ pub(crate) async fn update_openssl_config(app_handle: AppHandle) -> tauri::Resul
|
||||
fs::write(openssl_conf_path, openssl_conf).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub(crate) async fn store_get<'a>(
|
||||
hint: KeyHint<'_>,
|
||||
app_storage: State<'_, AppStorage<'_>>,
|
||||
) -> Result<Option<Value>, ()> {
|
||||
Ok(app_storage.get(hint))
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub(crate) fn store_set(
|
||||
hint: KeyHint,
|
||||
value: Value,
|
||||
app_storage: State<'_, AppStorage>,
|
||||
) -> Result<(), tauri_plugin_store::Error> {
|
||||
app_storage.set(hint, &value)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub(crate) fn store_save(
|
||||
app_storage: State<'_, AppStorage>,
|
||||
) -> Result<(), tauri_plugin_store::Error> {
|
||||
app_storage.save()?;
|
||||
Ok(())
|
||||
}
|
||||
|
46
gpgui/src-tauri/src/crypto.rs
Normal file
46
gpgui/src-tauri/src/crypto.rs
Normal file
@ -0,0 +1,46 @@
|
||||
use aes_gcm::{
|
||||
aead::{consts::U12, Aead, OsRng},
|
||||
AeadCore, Aes256Gcm, Key, KeyInit, Nonce,
|
||||
};
|
||||
use keyring::Entry;
|
||||
|
||||
const SERVICE_NAME: &str = "GlobalProtect-openconnect";
|
||||
const ENTRY_KEY: &str = "master-key";
|
||||
|
||||
fn get_master_key() -> Result<Key<Aes256Gcm>, anyhow::Error> {
|
||||
let key_entry = Entry::new(SERVICE_NAME, ENTRY_KEY)?;
|
||||
|
||||
if let Ok(key) = key_entry.get_password() {
|
||||
let key = hex::decode(key)?;
|
||||
return Ok(Key::<Aes256Gcm>::clone_from_slice(&key));
|
||||
}
|
||||
|
||||
let key = Aes256Gcm::generate_key(OsRng);
|
||||
let encoded_key = hex::encode(key);
|
||||
|
||||
key_entry.set_password(&encoded_key)?;
|
||||
|
||||
Ok(key)
|
||||
}
|
||||
|
||||
pub(crate) fn encrypt(data: &str) -> Result<String, anyhow::Error> {
|
||||
let master_key = get_master_key()?;
|
||||
let cipher = Aes256Gcm::new(&master_key);
|
||||
let nonce = Aes256Gcm::generate_nonce(&mut OsRng);
|
||||
let cipher_text = cipher.encrypt(&nonce, data.as_bytes())?;
|
||||
|
||||
let mut encrypted = nonce.to_vec();
|
||||
encrypted.extend_from_slice(&cipher_text);
|
||||
Ok(hex::encode(encrypted))
|
||||
}
|
||||
|
||||
pub(crate) fn decrypt(encrypted: &str) -> Result<String, anyhow::Error> {
|
||||
let master_key = get_master_key()?;
|
||||
let encrypted = hex::decode(encrypted)?;
|
||||
let nonce = Nonce::<U12>::from_slice(&encrypted[..12]);
|
||||
let cipher_text = &encrypted[12..];
|
||||
let cipher = Aes256Gcm::new(&master_key);
|
||||
let plain_text = cipher.decrypt(nonce, cipher_text)?;
|
||||
|
||||
String::from_utf8(plain_text).map_err(|err| err.into())
|
||||
}
|
@ -2,93 +2,26 @@
|
||||
all(not(debug_assertions), target_os = "windows"),
|
||||
windows_subsystem = "windows"
|
||||
)]
|
||||
|
||||
use crate::utils::get_openssl_conf_path;
|
||||
use env_logger::Env;
|
||||
use gpcommon::{Client, ClientStatus, VpnStatus};
|
||||
use log::{info, warn};
|
||||
use serde::Serialize;
|
||||
use std::{path::PathBuf, sync::Arc};
|
||||
use tauri::{Manager, Wry};
|
||||
use tauri_plugin_log::LogTarget;
|
||||
use tauri_plugin_store::{with_store, StoreCollection};
|
||||
|
||||
mod auth;
|
||||
mod commands;
|
||||
mod crypto;
|
||||
mod settings;
|
||||
mod setup;
|
||||
mod storage;
|
||||
mod utils;
|
||||
|
||||
#[derive(Debug, Clone, Serialize)]
|
||||
struct VpnStatusPayload {
|
||||
status: VpnStatus,
|
||||
}
|
||||
|
||||
fn setup(app: &mut tauri::App) -> Result<(), Box<dyn std::error::Error>> {
|
||||
let client = Arc::new(Client::default());
|
||||
let client_clone = client.clone();
|
||||
let app_handle = app.handle();
|
||||
|
||||
let stores = app.state::<StoreCollection<Wry>>();
|
||||
let path = PathBuf::from(".settings.dat");
|
||||
let _ = with_store(app_handle.clone(), stores, path, |store| {
|
||||
let settings_data = store.get("SETTINGS_DATA");
|
||||
let custom_openssl = settings_data.map_or(false, |data| {
|
||||
data["customOpenSSL"].as_bool().unwrap_or(false)
|
||||
});
|
||||
|
||||
if custom_openssl {
|
||||
info!("Using custom OpenSSL config");
|
||||
let openssl_conf = get_openssl_conf_path(&app_handle).into_os_string();
|
||||
std::env::set_var("OPENSSL_CONF", openssl_conf);
|
||||
}
|
||||
Ok(())
|
||||
});
|
||||
|
||||
tauri::async_runtime::spawn(async move {
|
||||
client_clone.subscribe_status(move |client_status| match client_status {
|
||||
ClientStatus::Vpn(vpn_status) => {
|
||||
let payload = VpnStatusPayload { status: vpn_status };
|
||||
if let Err(err) = app_handle.emit_all("vpn-status-received", payload) {
|
||||
warn!("Error emitting event: {}", err);
|
||||
}
|
||||
}
|
||||
ClientStatus::Service(is_online) => {
|
||||
if let Err(err) = app_handle.emit_all("service-status-changed", is_online) {
|
||||
warn!("Error emitting event: {}", err);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
let _ = client_clone.run().await;
|
||||
});
|
||||
|
||||
app.manage(client);
|
||||
|
||||
if let Ok(desktop) = std::env::var("XDG_CURRENT_DESKTOP") {
|
||||
if desktop == "KDE" {
|
||||
if let Some(main_window) = app.get_window("main") {
|
||||
let _ = main_window.set_decorations(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn main() {
|
||||
// env_logger::Builder::from_env(Env::default().default_filter_or("info")).init();
|
||||
tauri::Builder::default()
|
||||
.plugin(
|
||||
tauri_plugin_log::Builder::default()
|
||||
.targets([
|
||||
LogTarget::LogDir,
|
||||
LogTarget::Stdout, /*LogTarget::Webview*/
|
||||
])
|
||||
.targets([LogTarget::LogDir, LogTarget::Stdout])
|
||||
.level(log::LevelFilter::Info)
|
||||
.with_colors(Default::default())
|
||||
.build(),
|
||||
)
|
||||
.plugin(tauri_plugin_store::Builder::default().build())
|
||||
.setup(setup)
|
||||
.setup(setup::setup)
|
||||
.invoke_handler(tauri::generate_handler![
|
||||
commands::service_online,
|
||||
commands::vpn_status,
|
||||
@ -98,6 +31,9 @@ fn main() {
|
||||
commands::os_version,
|
||||
commands::openssl_config,
|
||||
commands::update_openssl_config,
|
||||
commands::store_get,
|
||||
commands::store_set,
|
||||
commands::store_save,
|
||||
])
|
||||
.run(tauri::generate_context!())
|
||||
.expect("error while running tauri application");
|
||||
|
19
gpgui/src-tauri/src/settings.rs
Normal file
19
gpgui/src-tauri/src/settings.rs
Normal file
@ -0,0 +1,19 @@
|
||||
use crate::storage::{AppStorage, KeyHint};
|
||||
use serde::Deserialize;
|
||||
use tauri::{AppHandle, Manager};
|
||||
|
||||
const STORAGE_KEY: &str = "SETTINGS_DATA";
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
struct Settings {
|
||||
#[serde(rename = "customOpenSSL")]
|
||||
custom_openssl: bool,
|
||||
}
|
||||
|
||||
pub(crate) fn is_custom_openssl_enabled(app_handle: &AppHandle) -> bool {
|
||||
let app_storage = app_handle.state::<AppStorage>();
|
||||
let hint = KeyHint::new(STORAGE_KEY, false);
|
||||
let settings = app_storage.get::<Settings>(hint);
|
||||
|
||||
settings.map_or(false, |settings| settings.custom_openssl)
|
||||
}
|
81
gpgui/src-tauri/src/setup.rs
Normal file
81
gpgui/src-tauri/src/setup.rs
Normal file
@ -0,0 +1,81 @@
|
||||
use crate::{settings, storage::AppStorage, utils::get_openssl_conf_path};
|
||||
use gpcommon::{Client, ClientStatus, VpnStatus};
|
||||
use log::{info, warn};
|
||||
use serde::Serialize;
|
||||
use std::sync::Arc;
|
||||
use tauri::Manager;
|
||||
|
||||
#[derive(Debug, Clone, Serialize)]
|
||||
struct VpnStatusPayload {
|
||||
status: VpnStatus,
|
||||
}
|
||||
|
||||
fn setup_window(app: &mut tauri::App) -> Result<(), Box<dyn std::error::Error>> {
|
||||
let desktop = std::env::var("XDG_CURRENT_DESKTOP")?;
|
||||
if desktop == "KDE" {
|
||||
if let Some(main_window) = app.get_window("main") {
|
||||
let _ = main_window.set_decorations(false);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn setup_app_storage(app: &mut tauri::App) -> Result<(), Box<dyn std::error::Error>> {
|
||||
let app_handle = app.app_handle();
|
||||
let app_storage = AppStorage::new(app_handle);
|
||||
|
||||
app.manage(app_storage);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn setup_app_env(app: &mut tauri::App) -> Result<(), Box<dyn std::error::Error>> {
|
||||
let app_handle = app.app_handle();
|
||||
let use_custom_openssl = settings::is_custom_openssl_enabled(&app_handle);
|
||||
|
||||
if use_custom_openssl {
|
||||
info!("Using custom OpenSSL config");
|
||||
|
||||
let openssl_conf = get_openssl_conf_path(&app_handle).into_os_string();
|
||||
std::env::set_var("OPENSSL_CONF", openssl_conf);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn setup_vpn_client(app: &mut tauri::App) -> Result<(), Box<dyn std::error::Error>> {
|
||||
let app_handle = app.handle();
|
||||
let client = Arc::new(Client::default());
|
||||
let client_clone = client.clone();
|
||||
|
||||
app.manage(client_clone);
|
||||
|
||||
tauri::async_runtime::spawn(async move {
|
||||
client.subscribe_status(move |client_status| match client_status {
|
||||
ClientStatus::Vpn(vpn_status) => {
|
||||
let payload = VpnStatusPayload { status: vpn_status };
|
||||
if let Err(err) = app_handle.emit_all("vpn-status-received", payload) {
|
||||
warn!("Error emitting event: {}", err);
|
||||
}
|
||||
}
|
||||
ClientStatus::Service(is_online) => {
|
||||
if let Err(err) = app_handle.emit_all("service-status-changed", is_online) {
|
||||
warn!("Error emitting event: {}", err);
|
||||
}
|
||||
}
|
||||
});
|
||||
let _ = client.run().await;
|
||||
});
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn setup(app: &mut tauri::App) -> Result<(), Box<dyn std::error::Error>> {
|
||||
setup_window(app)?;
|
||||
setup_app_storage(app)?;
|
||||
setup_app_env(app)?;
|
||||
setup_vpn_client(app)?;
|
||||
|
||||
Ok(())
|
||||
}
|
87
gpgui/src-tauri/src/storage.rs
Normal file
87
gpgui/src-tauri/src/storage.rs
Normal file
@ -0,0 +1,87 @@
|
||||
use crate::crypto::{decrypt, encrypt};
|
||||
use log::warn;
|
||||
use serde::{de::DeserializeOwned, Deserialize};
|
||||
use std::fmt::Debug;
|
||||
use tauri::{AppHandle, Manager, Wry};
|
||||
use tauri_plugin_store::{with_store, Error, StoreCollection};
|
||||
|
||||
const STORE_PATH: &str = ".data.json";
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub(crate) struct KeyHint<'a> {
|
||||
key: &'a str,
|
||||
encrypted: bool,
|
||||
}
|
||||
|
||||
impl<'a> KeyHint<'a> {
|
||||
pub(crate) fn new(key: &'a str, encrypted: bool) -> Self {
|
||||
Self { key, encrypted }
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct AppStorage<'a> {
|
||||
path: &'a str,
|
||||
app_handle: AppHandle<Wry>,
|
||||
}
|
||||
|
||||
impl AppStorage<'_> {
|
||||
pub(crate) fn new(app_handle: AppHandle<Wry>) -> Self {
|
||||
Self {
|
||||
path: STORE_PATH,
|
||||
app_handle,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get<T: DeserializeOwned + Debug>(&self, hint: KeyHint) -> Option<T> {
|
||||
let stores = self.app_handle.state::<StoreCollection<Wry>>();
|
||||
with_store(self.app_handle.clone(), stores, self.path, |store| {
|
||||
store
|
||||
.get(hint.key)
|
||||
.ok_or_else(|| Error::Deserialize("Value not found".into()))
|
||||
.and_then(|value| {
|
||||
if !hint.encrypted {
|
||||
return Ok(serde_json::from_value::<T>(value.clone())?);
|
||||
}
|
||||
|
||||
let value = value
|
||||
.as_str()
|
||||
.ok_or_else(|| Error::Deserialize("Value is not a string".into()))?;
|
||||
let value = decrypt(value).map_err(|err| {
|
||||
Error::Deserialize(format!("Failed to decrypt value: {}", err).into())
|
||||
})?;
|
||||
|
||||
Ok(serde_json::from_str::<T>(&value)?)
|
||||
})
|
||||
})
|
||||
.map_err(|err| warn!("Error getting value: {:?}", err))
|
||||
.ok()
|
||||
}
|
||||
|
||||
pub fn set<T: serde::Serialize>(&self, hint: KeyHint, value: &T) -> Result<(), Error> {
|
||||
let stores = self.app_handle.state::<StoreCollection<Wry>>();
|
||||
|
||||
with_store(self.app_handle.clone(), stores, self.path, |store| {
|
||||
let value = if hint.encrypted {
|
||||
let json_str = serde_json::to_string(value)?;
|
||||
let encrypted = encrypt(&json_str).map_err(|err| {
|
||||
Error::Serialize(format!("Failed to encrypt value: {}", err).into())
|
||||
})?;
|
||||
serde_json::to_value(encrypted)?
|
||||
} else {
|
||||
serde_json::to_value(value)?
|
||||
};
|
||||
|
||||
store.insert(hint.key.to_string(), value)?;
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
pub fn save(&self) -> Result<(), Error> {
|
||||
let stores = self.app_handle.state::<StoreCollection<Wry>>();
|
||||
|
||||
with_store(self.app_handle.clone(), stores, self.path, |store| {
|
||||
store.save()?;
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
}
|
@ -14,7 +14,11 @@ export const portalGatewaysAtom = atom<GatewayData[]>((get) => {
|
||||
});
|
||||
|
||||
export const selectedGatewayAtom = atom(
|
||||
(get) => get(currentPortalDataAtom).selectedGateway,
|
||||
(get) => {
|
||||
const { selectedGateway } = get(currentPortalDataAtom);
|
||||
const gateways = get(portalGatewaysAtom);
|
||||
return gateways.find(({ name }) => name === selectedGateway);
|
||||
},
|
||||
async (get, set, update: string) => {
|
||||
const portalData = get(currentPortalDataAtom);
|
||||
await set(updatePortalDataAtom, { ...portalData, selectedGateway: update });
|
||||
|
@ -62,7 +62,7 @@ export const loginPortalAtom = atom(
|
||||
}
|
||||
|
||||
// Here, we have got the portal config successfully, refresh the cached portal data
|
||||
const previousSelectedGateway = get(selectedGatewayAtom);
|
||||
const previousSelectedGateway = get(selectedGatewayAtom)?.name;
|
||||
const selectedGateway = gateways.find(
|
||||
({ name }) => name === previousSelectedGateway
|
||||
);
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { atom } from "jotai";
|
||||
import { atomWithDefault } from "jotai/utils";
|
||||
import { PortalCredential } from "../services/portalService";
|
||||
import { atomWithTauriStorage } from "../services/storeService";
|
||||
import { atomWithTauriStorage } from "../services/storageService";
|
||||
import { unwrap } from "./unwrap";
|
||||
|
||||
export type GatewayData = {
|
||||
@ -31,7 +31,11 @@ const DEFAULT_APP_DATA: AppData = {
|
||||
clearCookies: true,
|
||||
};
|
||||
|
||||
export const appDataAtom = atomWithTauriStorage("APP_DATA", DEFAULT_APP_DATA);
|
||||
const keyHint = {
|
||||
key: "APP_DATA",
|
||||
encrypted: true,
|
||||
};
|
||||
export const appDataAtom = atomWithTauriStorage(keyHint, DEFAULT_APP_DATA);
|
||||
const unwrappedAppDataAtom = atom(
|
||||
(get) => get(unwrap(appDataAtom)) || DEFAULT_APP_DATA
|
||||
);
|
||||
@ -51,6 +55,11 @@ export const currentPortalDataAtom = atom<PortalData>((get) => {
|
||||
return portalData || { address: portalAddress, gateways: [] };
|
||||
});
|
||||
|
||||
export const allPortalsAtom = atom((get) => {
|
||||
const { portals } = get(unwrappedAppDataAtom);
|
||||
return portals.map(({ address }) => address);
|
||||
});
|
||||
|
||||
export const updatePortalDataAtom = atom(
|
||||
null,
|
||||
async (get, set, update: PortalData) => {
|
||||
|
@ -5,7 +5,7 @@ import settingsService, {
|
||||
DEFAULT_SETTINGS_DATA,
|
||||
SETTINGS_DATA,
|
||||
} from "../services/settingsService";
|
||||
import { atomWithTauriStorage } from "../services/storeService";
|
||||
import { atomWithTauriStorage } from "../services/storageService";
|
||||
import { unwrap } from "./unwrap";
|
||||
|
||||
const settingsDataAtom = atomWithTauriStorage(
|
||||
|
@ -4,6 +4,7 @@ import vpnService from "../services/vpnService";
|
||||
import { selectedGatewayAtom, switchGatewayAtom } from "./gateway";
|
||||
import { notifyErrorAtom, notifySuccessAtom } from "./notification";
|
||||
import { unwrap } from "./unwrap";
|
||||
import { portalAddressAtom } from "./portal";
|
||||
|
||||
export type Status =
|
||||
| "disconnected"
|
||||
@ -75,14 +76,16 @@ export const statusTextAtom = atom<string>((get) => {
|
||||
|
||||
if (status === "connected") {
|
||||
const selectedGateway = get(selectedGatewayAtom);
|
||||
return selectedGateway
|
||||
? `Gateway: ${selectedGateway}`
|
||||
: statusTextMap[status];
|
||||
const portalAddress = get(portalAddressAtom);
|
||||
|
||||
return selectedGateway?.address === portalAddress
|
||||
? statusTextMap[status]
|
||||
: selectedGateway?.address!;
|
||||
}
|
||||
|
||||
if (switchingGateway) {
|
||||
const selectedGateway = get(selectedGatewayAtom);
|
||||
return `Switching to ${selectedGateway}`;
|
||||
return `Switching to ${selectedGateway?.name}`;
|
||||
}
|
||||
|
||||
return statusTextMap[status];
|
||||
|
@ -1,13 +1,8 @@
|
||||
import {
|
||||
Box,
|
||||
CssBaseline,
|
||||
ThemeProvider,
|
||||
createTheme,
|
||||
useMediaQuery,
|
||||
} from "@mui/material";
|
||||
import React, { Suspense, useMemo } from "react";
|
||||
import { Box, CssBaseline, ThemeProvider } from "@mui/material";
|
||||
import React, { Suspense } from "react";
|
||||
import { createRoot } from "react-dom/client";
|
||||
import "./styles.css";
|
||||
import useGlobalTheme from "./useGlobalTheme";
|
||||
|
||||
function Loading() {
|
||||
console.warn("Loading rendered");
|
||||
@ -27,16 +22,7 @@ function Loading() {
|
||||
}
|
||||
|
||||
function AppShell({ children }: { children: React.ReactNode }) {
|
||||
const prefersDarkMode = useMediaQuery("(prefers-color-scheme: dark)");
|
||||
const theme = useMemo(
|
||||
() =>
|
||||
createTheme({
|
||||
palette: {
|
||||
mode: prefersDarkMode ? "dark" : "light",
|
||||
},
|
||||
}),
|
||||
[prefersDarkMode]
|
||||
);
|
||||
const theme = useGlobalTheme();
|
||||
|
||||
return (
|
||||
<React.StrictMode>
|
||||
|
31
gpgui/src/components/AppShell/useGlobalTheme.ts
Normal file
31
gpgui/src/components/AppShell/useGlobalTheme.ts
Normal file
@ -0,0 +1,31 @@
|
||||
import { createTheme, useMediaQuery } from "@mui/material";
|
||||
import { useMemo } from "react";
|
||||
|
||||
export default function useGlobalTheme() {
|
||||
const prefersDarkMode = useMediaQuery("(prefers-color-scheme: dark)");
|
||||
return useMemo(
|
||||
() =>
|
||||
createTheme({
|
||||
palette: {
|
||||
mode: prefersDarkMode ? "dark" : "light",
|
||||
},
|
||||
components: {
|
||||
MuiButton: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
textTransform: "none",
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiTab: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
textTransform: "none",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
[prefersDarkMode]
|
||||
);
|
||||
}
|
@ -57,7 +57,7 @@ export default function PasswordAuth() {
|
||||
<Button
|
||||
variant="outlined"
|
||||
onClick={cancelPasswordAuth}
|
||||
sx={{ flex: 1, textTransform: "none" }}
|
||||
sx={{ flex: 1 }}
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
@ -66,7 +66,6 @@ export default function PasswordAuth() {
|
||||
type="submit"
|
||||
loading={loading}
|
||||
disabled={loading}
|
||||
sx={{ flex: 1, textTransform: "none" }}
|
||||
>
|
||||
Login
|
||||
</LoadingButton>
|
||||
|
@ -1,12 +1,12 @@
|
||||
import { Button, TextField } from "@mui/material";
|
||||
import { Autocomplete, Button, TextField } from "@mui/material";
|
||||
import { useAtom, useAtomValue, useSetAtom } from "jotai";
|
||||
import { ChangeEvent } from "react";
|
||||
import { ChangeEvent, useState } from "react";
|
||||
import {
|
||||
cancelConnectPortalAtom,
|
||||
connectPortalAtom,
|
||||
} from "../../atoms/connectPortal";
|
||||
import { switchGatewayAtom } from "../../atoms/gateway";
|
||||
import { portalAddressAtom } from "../../atoms/portal";
|
||||
import { allPortalsAtom, portalAddressAtom } from "../../atoms/portal";
|
||||
import {
|
||||
backgroundServiceStartedAtom,
|
||||
isProcessingAtom,
|
||||
@ -26,6 +26,7 @@ function normalizePortalAddress(input: string) {
|
||||
|
||||
export default function PortalForm() {
|
||||
const backgroundServiceStarted = useAtomValue(backgroundServiceStartedAtom);
|
||||
const allPortals = useAtomValue(allPortalsAtom);
|
||||
const [portalAddress, setPortalAddress] = useAtom(portalAddressAtom);
|
||||
// Use useAtom instead of useSetAtom, otherwise the onMount of the atom is not triggered
|
||||
const [, connectPortal] = useAtom(connectPortalAtom);
|
||||
@ -35,8 +36,10 @@ export default function PortalForm() {
|
||||
const disconnectVpn = useSetAtom(disconnectVpnAtom);
|
||||
const switchingGateway = useAtomValue(switchGatewayAtom);
|
||||
|
||||
function handlePortalAddressChange(e: ChangeEvent<HTMLInputElement>) {
|
||||
setPortalAddress(normalizePortalAddress(e.target.value));
|
||||
const readOnly = status !== "disconnected" || switchingGateway;
|
||||
|
||||
function handlePortalAddressChange(e: unknown, value: string) {
|
||||
setPortalAddress(normalizePortalAddress(value));
|
||||
}
|
||||
|
||||
function handleSubmit(e: ChangeEvent<HTMLFormElement>) {
|
||||
@ -46,16 +49,35 @@ export default function PortalForm() {
|
||||
|
||||
return (
|
||||
<form onSubmit={handleSubmit} data-tauri-drag-region>
|
||||
<TextField
|
||||
autoFocus
|
||||
label="Portal address"
|
||||
placeholder="Hostname or IP address"
|
||||
fullWidth
|
||||
<Autocomplete
|
||||
freeSolo
|
||||
options={allPortals}
|
||||
inputValue={portalAddress}
|
||||
onInputChange={handlePortalAddressChange}
|
||||
readOnly={readOnly}
|
||||
forcePopupIcon={!readOnly}
|
||||
disableClearable
|
||||
size="small"
|
||||
value={portalAddress}
|
||||
onChange={handlePortalAddressChange}
|
||||
InputProps={{ readOnly: status !== "disconnected" || switchingGateway }}
|
||||
sx={{ mb: 1 }}
|
||||
sx={{
|
||||
mb: 1,
|
||||
}}
|
||||
componentsProps={{
|
||||
paper: {
|
||||
sx: {
|
||||
"& .MuiAutocomplete-listbox .MuiAutocomplete-option": {
|
||||
minHeight: "auto",
|
||||
},
|
||||
},
|
||||
},
|
||||
}}
|
||||
renderInput={(params) => (
|
||||
<TextField
|
||||
{...params}
|
||||
autoFocus
|
||||
label="Portal address"
|
||||
placeholder="Hostname or IP address"
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
|
||||
{status === "disconnected" && !switchingGateway && (
|
||||
@ -64,7 +86,6 @@ export default function PortalForm() {
|
||||
type="submit"
|
||||
variant="contained"
|
||||
disabled={!backgroundServiceStarted}
|
||||
sx={{ textTransform: "none" }}
|
||||
>
|
||||
Connect
|
||||
</Button>
|
||||
@ -81,19 +102,13 @@ export default function PortalForm() {
|
||||
switchingGateway
|
||||
}
|
||||
onClick={cancelConnectPortal}
|
||||
sx={{ textTransform: "none" }}
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
)}
|
||||
|
||||
{status === "connected" && (
|
||||
<Button
|
||||
fullWidth
|
||||
variant="contained"
|
||||
onClick={disconnectVpn}
|
||||
sx={{ textTransform: "none" }}
|
||||
>
|
||||
<Button fullWidth variant="contained" onClick={disconnectVpn}>
|
||||
Disconnect
|
||||
</Button>
|
||||
)}
|
||||
|
@ -1,7 +1,18 @@
|
||||
import { GppBad, VerifiedUser as VerifiedIcon } from "@mui/icons-material";
|
||||
import { Box, CircularProgress, styled, useTheme } from "@mui/material";
|
||||
import { useAtomValue } from "jotai";
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
CircularProgress,
|
||||
Tooltip,
|
||||
styled,
|
||||
useTheme,
|
||||
} from "@mui/material";
|
||||
import { useAtomValue, useSetAtom } from "jotai";
|
||||
import { BeatLoader } from "react-spinners";
|
||||
import {
|
||||
openGatewaySwitcherAtom,
|
||||
selectedGatewayAtom,
|
||||
} from "../../atoms/gateway";
|
||||
import { isProcessingAtom, statusAtom } from "../../atoms/status";
|
||||
|
||||
function useStatusColor() {
|
||||
@ -59,11 +70,48 @@ function ProcessingIcon() {
|
||||
return <BeatLoader color={theme.palette.info.main} />;
|
||||
}
|
||||
|
||||
const ConnectedIcon = styled(VerifiedIcon)(({ theme }) => ({
|
||||
position: "relative",
|
||||
fontSize: 80,
|
||||
color: theme.palette.success.main,
|
||||
}));
|
||||
const ConnectedIcon = () => {
|
||||
const selectedGateway = useAtomValue(selectedGatewayAtom);
|
||||
const openGatewaySwitcher = useSetAtom(openGatewaySwitcherAtom);
|
||||
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
alignItems: "center",
|
||||
}}
|
||||
>
|
||||
<VerifiedIcon
|
||||
sx={{
|
||||
fontSize: 70,
|
||||
color: (theme) => theme.palette.success.main,
|
||||
}}
|
||||
/>
|
||||
<Tooltip title={`Connected to ${selectedGateway?.name}`}>
|
||||
<Button
|
||||
sx={{
|
||||
position: "relative",
|
||||
zIndex: 1,
|
||||
fontSize: "0.75rem",
|
||||
fontWeight: "bold",
|
||||
display: "block",
|
||||
width: 100,
|
||||
mt: 0.2,
|
||||
padding: 0.2,
|
||||
overflow: "hidden",
|
||||
textOverflow: "ellipsis",
|
||||
}}
|
||||
size="small"
|
||||
color="success"
|
||||
onClick={openGatewaySwitcher}
|
||||
>
|
||||
{selectedGateway?.name}
|
||||
</Button>
|
||||
</Tooltip>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
const IconContainer = styled(Box)(({ theme }) =>
|
||||
theme.unstable_sx({
|
||||
|
@ -20,7 +20,7 @@ export default function GatewaySwitcher() {
|
||||
gatewaySwitcherVisibleAtom
|
||||
);
|
||||
const gateways = useAtomValue(portalGatewaysAtom);
|
||||
const selectedGateway = useAtomValue(selectedGatewayAtom);
|
||||
const selectedGateway = useAtomValue(selectedGatewayAtom)?.name;
|
||||
const switchGateway = useSetAtom(switchGatewayAtom);
|
||||
|
||||
const handleClose = () => {
|
||||
|
@ -43,14 +43,12 @@ export default function SettingsPanel() {
|
||||
value="simulation"
|
||||
icon={<Devices />}
|
||||
iconPosition="start"
|
||||
sx={{ textTransform: "none" }}
|
||||
/>
|
||||
<Tab
|
||||
label="OpenSSL"
|
||||
value="openssl"
|
||||
icon={<Https />}
|
||||
iconPosition="start"
|
||||
sx={{ textTransform: "none" }}
|
||||
/>
|
||||
</TabList>
|
||||
<Box sx={{ flex: 1 }}>
|
||||
@ -61,12 +59,8 @@ export default function SettingsPanel() {
|
||||
</Box>
|
||||
<Box sx={{ flexShrink: 0, borderTop: 1, borderColor: "divider" }}>
|
||||
<DialogActions>
|
||||
<Button sx={{ textTransform: "none" }} onClick={closeWindow}>
|
||||
Cancel
|
||||
</Button>
|
||||
<Button sx={{ textTransform: "none" }} onClick={save}>
|
||||
Save
|
||||
</Button>
|
||||
<Button onClick={closeWindow}>Cancel</Button>
|
||||
<Button onClick={save}>Save</Button>
|
||||
</DialogActions>
|
||||
</Box>
|
||||
</Box>
|
||||
|
@ -1,4 +1,6 @@
|
||||
import { Box } from "@mui/material";
|
||||
import { useAtomValue } from "jotai";
|
||||
import { appDataAtom } from "../atoms/portal";
|
||||
import { renderToRoot } from "../components/AppShell";
|
||||
import ConnectForm from "../components/ConnectForm";
|
||||
import ConnectionStatus from "../components/ConnectionStatus";
|
||||
@ -8,6 +10,10 @@ import MainMenu from "../components/MainMenu";
|
||||
import Notification from "../components/Notification";
|
||||
|
||||
export default function App() {
|
||||
// Use the this atom to trigger loading data from the storage
|
||||
// And render the loading indicator
|
||||
useAtomValue(appDataAtom);
|
||||
|
||||
return (
|
||||
<Box data-tauri-drag-region padding={2} paddingBottom={0}>
|
||||
<MainMenu />
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { emit, listen } from "@tauri-apps/api/event";
|
||||
import invokeCommand from "../utils/invokeCommand";
|
||||
import settingsService from "./settingsService";
|
||||
|
||||
export type AuthData = {
|
||||
username: string;
|
||||
@ -30,9 +31,12 @@ class AuthService {
|
||||
|
||||
// binding: "POST" | "REDIRECT"
|
||||
async samlLogin(binding: string, request: string, clearCookies: boolean) {
|
||||
const { userAgent } = await settingsService.getSimulation();
|
||||
|
||||
return invokeCommand<AuthData>("saml_login", {
|
||||
binding,
|
||||
request,
|
||||
userAgent: `${userAgent} ${navigator.userAgent}`,
|
||||
clearCookies,
|
||||
});
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { Body, ResponseType, fetch } from "@tauri-apps/api/http";
|
||||
import { parseXml } from "../utils/parseXml";
|
||||
import settingsService from "./settingsService";
|
||||
|
||||
type LoginParams = {
|
||||
user: string;
|
||||
@ -15,6 +16,9 @@ class GatewayService {
|
||||
throw new Error("Gateway address is required");
|
||||
}
|
||||
|
||||
const { userAgent, clientOS, osVersion } =
|
||||
await settingsService.getSimulation();
|
||||
|
||||
const loginUrl = `https://${gateway}/ssl-vpn/login.esp`;
|
||||
const body = Body.form({
|
||||
prot: "https:",
|
||||
@ -25,8 +29,8 @@ class GatewayService {
|
||||
direct: "yes",
|
||||
"ipv6-support": "yes",
|
||||
clientVer: "4100",
|
||||
clientos: "Linux",
|
||||
"os-version": "Linux",
|
||||
clientos: clientOS,
|
||||
"os-version": osVersion,
|
||||
server: gateway,
|
||||
user,
|
||||
passwd: passwd || "",
|
||||
@ -38,7 +42,7 @@ class GatewayService {
|
||||
const response = await fetch<string>(loginUrl, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"User-Agent": "PAN GlobalProtect",
|
||||
"User-Agent": userAgent,
|
||||
},
|
||||
responseType: ResponseType.Text,
|
||||
body,
|
||||
|
@ -2,6 +2,7 @@ import { Body, ResponseType, fetch } from "@tauri-apps/api/http";
|
||||
import ErrorWithTitle from "../utils/ErrorWithTitle";
|
||||
import { parseXml } from "../utils/parseXml";
|
||||
import { Gateway } from "./types";
|
||||
import settingsService from "./settingsService";
|
||||
|
||||
export type SamlPrelogin = {
|
||||
isSamlAuth: true;
|
||||
@ -37,12 +38,15 @@ export type PortalCredential = {
|
||||
class PortalService {
|
||||
async prelogin(portal: string): Promise<Prelogin> {
|
||||
const preloginUrl = `https://${portal}/global-protect/prelogin.esp`;
|
||||
const { userAgent, clientOS, osVersion } =
|
||||
await settingsService.getSimulation();
|
||||
|
||||
let response;
|
||||
try {
|
||||
response = await fetch<string>(preloginUrl, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"User-Agent": "PAN GlobalProtect",
|
||||
"User-Agent": userAgent,
|
||||
},
|
||||
responseType: ResponseType.Text,
|
||||
query: {
|
||||
@ -51,8 +55,8 @@ class PortalService {
|
||||
body: Body.form({
|
||||
tmp: "tmp",
|
||||
clientVer: "4100",
|
||||
clientos: "Linux",
|
||||
"os-version": "Linux",
|
||||
clientos: clientOS,
|
||||
"os-version": osVersion,
|
||||
"ipv6-support": "yes",
|
||||
"default-browser": "0",
|
||||
"cas-support": "yes",
|
||||
@ -118,6 +122,9 @@ class PortalService {
|
||||
}
|
||||
|
||||
async fetchConfig(portal: string, params: PortalCredential) {
|
||||
const { userAgent, clientOS, osVersion, clientVersion } =
|
||||
await settingsService.getSimulation();
|
||||
|
||||
const {
|
||||
user,
|
||||
passwd,
|
||||
@ -132,12 +139,12 @@ class PortalService {
|
||||
inputStr: "",
|
||||
jnlpReady: "jnlpReady",
|
||||
computer: "Linux", // TODO
|
||||
clientos: "Linux",
|
||||
clientos: clientOS,
|
||||
ok: "Login",
|
||||
direct: "yes",
|
||||
clientVer: "4100",
|
||||
"os-version": "Linux",
|
||||
clientgpversion: "6.0.1-19",
|
||||
"os-version": osVersion,
|
||||
clientgpversion: clientVersion,
|
||||
"ipv6-support": "yes",
|
||||
server: portal,
|
||||
host: portal,
|
||||
@ -151,7 +158,7 @@ class PortalService {
|
||||
const response = await fetch<string>(configUrl, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"User-Agent": "PAN GlobalProtect",
|
||||
"User-Agent": userAgent,
|
||||
},
|
||||
responseType: ResponseType.Text,
|
||||
body,
|
||||
@ -166,8 +173,6 @@ class PortalService {
|
||||
}
|
||||
|
||||
private parsePortalConfigResponse(response: string): PortalConfig {
|
||||
// console.log(response);
|
||||
|
||||
const result = parseXml(response);
|
||||
const gateways = result.all("gateways list > entry").map((entry) => {
|
||||
const address = entry.attr("name");
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { UserAttentionType, WebviewWindow } from "@tauri-apps/api/window";
|
||||
import invokeCommand from "../utils/invokeCommand";
|
||||
import { appStore } from "./storeService";
|
||||
import { appStorage } from "./storageService";
|
||||
|
||||
export type TabValue = "simulation" | "openssl";
|
||||
const SETTINGS_WINDOW_LABEL = "settings";
|
||||
@ -68,9 +68,10 @@ export const DEFAULT_SETTINGS_DATA: SettingsData = {
|
||||
customOpenSSL: false,
|
||||
};
|
||||
|
||||
async function getSimulationSettings(): Promise<SimulationSettings> {
|
||||
async function getSimulation(): Promise<SimulationSettings> {
|
||||
const { clientOS, osVersion, clientVersion } =
|
||||
(await appStore.get<SettingsData>(SETTINGS_DATA)) || DEFAULT_SETTINGS_DATA;
|
||||
(await appStorage.get<SettingsData>(SETTINGS_DATA)) ||
|
||||
DEFAULT_SETTINGS_DATA;
|
||||
const currentOsVersion = await getCurrentOsVersion();
|
||||
|
||||
return {
|
||||
@ -81,8 +82,8 @@ async function getSimulationSettings(): Promise<SimulationSettings> {
|
||||
clientVersion
|
||||
),
|
||||
clientOS,
|
||||
osVersion,
|
||||
clientVersion,
|
||||
osVersion: determineOsVersion(clientOS, osVersion, currentOsVersion),
|
||||
clientVersion: clientVersion || DEFAULT_CLIENT_VERSION,
|
||||
};
|
||||
}
|
||||
|
||||
@ -131,7 +132,7 @@ export default {
|
||||
openSettings,
|
||||
closeSettings,
|
||||
getCurrentOsVersion,
|
||||
getSimulationSettings,
|
||||
getSimulation,
|
||||
buildUserAgent,
|
||||
determineOsVersion,
|
||||
getOpenSSLConfig,
|
||||
|
70
gpgui/src/services/storageService.ts
Normal file
70
gpgui/src/services/storageService.ts
Normal file
@ -0,0 +1,70 @@
|
||||
import { atom } from "jotai";
|
||||
import { RESET, atomWithDefault } from "jotai/utils";
|
||||
import invokeCommand from "../utils/invokeCommand";
|
||||
|
||||
type SetStateActionWithReset<T> =
|
||||
| T
|
||||
| typeof RESET
|
||||
| ((prev: T) => T | typeof RESET);
|
||||
|
||||
type KeyHint =
|
||||
| {
|
||||
key: string;
|
||||
encrypted: boolean;
|
||||
}
|
||||
| string;
|
||||
|
||||
type AppStorage = {
|
||||
get: <T>(key: KeyHint) => Promise<T | undefined>;
|
||||
set: <T>(key: KeyHint, value: T) => Promise<void>;
|
||||
save: () => Promise<void>;
|
||||
};
|
||||
|
||||
export const appStorage: AppStorage = {
|
||||
get: async (key) => {
|
||||
const hint = typeof key === "string" ? { key, encrypted: false } : key;
|
||||
return invokeCommand("store_get", { hint });
|
||||
},
|
||||
set: async (key, value) => {
|
||||
const hint = typeof key === "string" ? { key, encrypted: false } : key;
|
||||
return invokeCommand("store_set", { hint, value });
|
||||
},
|
||||
save: async () => {
|
||||
return invokeCommand("store_save");
|
||||
},
|
||||
};
|
||||
|
||||
export function atomWithTauriStorage<T>(key: KeyHint, initialValue: T) {
|
||||
const baseAtom = atomWithDefault<T | Promise<T>>(async () => {
|
||||
const storedValue = await appStorage.get<T>(key);
|
||||
if (!storedValue) {
|
||||
return initialValue;
|
||||
}
|
||||
return storedValue;
|
||||
});
|
||||
|
||||
const anAtom = atom(
|
||||
(get) => get(baseAtom),
|
||||
async (get, set, update: SetStateActionWithReset<T>) => {
|
||||
const value = await get(baseAtom);
|
||||
let newValue: T | typeof RESET;
|
||||
if (typeof update === "function") {
|
||||
newValue = (update as (prev: T) => T | typeof RESET)(value);
|
||||
} else {
|
||||
newValue = update as T | typeof RESET;
|
||||
}
|
||||
|
||||
if (newValue === RESET) {
|
||||
set(baseAtom, initialValue);
|
||||
await appStorage.set(key, initialValue);
|
||||
} else {
|
||||
set(baseAtom, newValue);
|
||||
await appStorage.set(key, newValue);
|
||||
}
|
||||
|
||||
await appStorage.save();
|
||||
}
|
||||
);
|
||||
|
||||
return anAtom;
|
||||
}
|
@ -1,45 +0,0 @@
|
||||
import { atom } from "jotai";
|
||||
import { RESET, atomWithDefault } from "jotai/utils";
|
||||
import { Store } from "tauri-plugin-store-api";
|
||||
|
||||
type SetStateActionWithReset<T> =
|
||||
| T
|
||||
| typeof RESET
|
||||
| ((prev: T) => T | typeof RESET);
|
||||
|
||||
export const appStore = new Store(".settings.dat");
|
||||
|
||||
export function atomWithTauriStorage<T>(key: string, initialValue: T) {
|
||||
const baseAtom = atomWithDefault<T | Promise<T>>(async () => {
|
||||
const storedValue = await appStore.get<T>(key);
|
||||
if (!storedValue) {
|
||||
return initialValue;
|
||||
}
|
||||
return storedValue;
|
||||
});
|
||||
|
||||
const anAtom = atom(
|
||||
(get) => get(baseAtom),
|
||||
async (get, set, update: SetStateActionWithReset<T>) => {
|
||||
const value = await get(baseAtom);
|
||||
let newValue: T | typeof RESET;
|
||||
if (typeof update === "function") {
|
||||
newValue = (update as (prev: T) => T | typeof RESET)(value);
|
||||
} else {
|
||||
newValue = update as T | typeof RESET;
|
||||
}
|
||||
|
||||
if (newValue === RESET) {
|
||||
set(baseAtom, initialValue);
|
||||
await appStore.set(key, initialValue);
|
||||
} else {
|
||||
set(baseAtom, newValue);
|
||||
await appStore.set(key, newValue);
|
||||
}
|
||||
|
||||
await appStore.save();
|
||||
}
|
||||
);
|
||||
|
||||
return anAtom;
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
import { Event, listen } from "@tauri-apps/api/event";
|
||||
import invokeCommand from "../utils/invokeCommand";
|
||||
import settingsService from "./settingsService";
|
||||
|
||||
type VpnStatus = "disconnected" | "connecting" | "connected" | "disconnecting";
|
||||
type VpnStatusCallback = (status: VpnStatus) => void;
|
||||
@ -64,7 +65,8 @@ class VpnService {
|
||||
}
|
||||
|
||||
async connect(server: string, cookie: string) {
|
||||
return invokeCommand("vpn_connect", { server, cookie });
|
||||
const { userAgent } = await settingsService.getSimulation();
|
||||
return invokeCommand("vpn_connect", { server, cookie, userAgent });
|
||||
}
|
||||
|
||||
async disconnect() {
|
||||
|
@ -8,8 +8,9 @@ edition = "2021"
|
||||
[dependencies]
|
||||
gpcommon = { path = "../gpcommon" }
|
||||
tokio = { version = "1", features = ["full"] }
|
||||
env_logger = "0.10"
|
||||
log = "0.4"
|
||||
fern = "0.6"
|
||||
humantime = "2.1"
|
||||
# warp = "0.3"
|
||||
# aes-gcm = "0.10"
|
||||
# procfs = "0.15"
|
||||
|
@ -1,9 +1,8 @@
|
||||
include!(concat!(env!("OUT_DIR"), "/client_hash.rs"));
|
||||
|
||||
// use aes_gcm::{aead::OsRng, Aes256Gcm, KeyInit};
|
||||
use gpcommon::{server, SOCKET_PATH};
|
||||
use env_logger::Env;
|
||||
use log::error;
|
||||
use std::fs::File;
|
||||
use tokio::signal;
|
||||
|
||||
// static mut HTTP_PORT: u16 = 0;
|
||||
@ -96,10 +95,10 @@ use tokio::signal;
|
||||
// println!("Shutting down http server");
|
||||
// }
|
||||
|
||||
const LOG_FILE: &str = "/var/log/gpservice.log";
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
env_logger::Builder::from_env(Env::default().default_filter_or("info")).init();
|
||||
|
||||
// println!("{GPCLIENT_HASH}");
|
||||
|
||||
// unsafe {
|
||||
@ -110,6 +109,22 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
// start_http_server().await;
|
||||
// server::start().await
|
||||
|
||||
let log_file = File::create(LOG_FILE)?;
|
||||
fern::Dispatch::new()
|
||||
.format(|out, message, record| {
|
||||
out.finish(format_args!(
|
||||
"[{} {} {}] {}",
|
||||
humantime::format_rfc3339_millis(std::time::SystemTime::now()),
|
||||
record.level(),
|
||||
record.target(),
|
||||
message
|
||||
))
|
||||
})
|
||||
.level(log::LevelFilter::Info)
|
||||
.chain(std::io::stdout())
|
||||
.chain(log_file)
|
||||
.apply()?;
|
||||
|
||||
if let Err(err) = server::run(SOCKET_PATH, signal::ctrl_c()).await {
|
||||
error!("Error running server: {}", err);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user