mirror of
				https://github.com/yuezk/GlobalProtect-openconnect.git
				synced 2025-05-20 07:26:58 -04:00 
			
		
		
		
	refactor: encrypt the sensitive data
This commit is contained in:
		
							
								
								
									
										5
									
								
								.vscode/settings.json
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										5
									
								
								.vscode/settings.json
									
									
									
									
										vendored
									
									
								
							| @@ -5,11 +5,13 @@ | |||||||
|     "clickaway", |     "clickaway", | ||||||
|     "clientgpversion", |     "clientgpversion", | ||||||
|     "clientos", |     "clientos", | ||||||
|  |     "consts", | ||||||
|     "devicename", |     "devicename", | ||||||
|     "distro", |     "distro", | ||||||
|     "gpcommon", |     "gpcommon", | ||||||
|     "gpgui", |     "gpgui", | ||||||
|     "gpservice", |     "gpservice", | ||||||
|  |     "humantime", | ||||||
|     "Immer", |     "Immer", | ||||||
|     "jnlp", |     "jnlp", | ||||||
|     "oneshot", |     "oneshot", | ||||||
| @@ -17,7 +19,10 @@ | |||||||
|     "prelogin", |     "prelogin", | ||||||
|     "prelogon", |     "prelogon", | ||||||
|     "prelogonuserauthcookie", |     "prelogonuserauthcookie", | ||||||
|  |     "repr", | ||||||
|  |     "rustc", | ||||||
|     "tauri", |     "tauri", | ||||||
|  |     "thiserror", | ||||||
|     "unlisten", |     "unlisten", | ||||||
|     "userauthcookie", |     "userauthcookie", | ||||||
|     "vpnc", |     "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" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" | 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]] | [[package]] | ||||||
| name = "aho-corasick" | name = "aho-corasick" | ||||||
| version = "0.7.20" | version = "0.7.20" | ||||||
| @@ -51,8 +98,11 @@ checksum = "224afbd727c3d6e4b90103ece64b8d1b67fbb1973b1046c2281eed3f3803f800" | |||||||
| name = "app" | name = "app" | ||||||
| version = "0.1.0" | version = "0.1.0" | ||||||
| dependencies = [ | dependencies = [ | ||||||
|  "env_logger", |  "aes-gcm", | ||||||
|  |  "anyhow", | ||||||
|  "gpcommon", |  "gpcommon", | ||||||
|  |  "hex", | ||||||
|  |  "keyring", | ||||||
|  "log", |  "log", | ||||||
|  "openssl", |  "openssl", | ||||||
|  "regex", |  "regex", | ||||||
| @@ -69,6 +119,117 @@ dependencies = [ | |||||||
|  "whoami", |  "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]] | [[package]] | ||||||
| name = "async-trait" | name = "async-trait" | ||||||
| version = "0.1.66" | version = "0.1.66" | ||||||
| @@ -104,6 +265,12 @@ dependencies = [ | |||||||
|  "system-deps 6.0.3", |  "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]] | [[package]] | ||||||
| name = "attohttpc" | name = "attohttpc" | ||||||
| version = "0.22.0" | version = "0.22.0" | ||||||
| @@ -170,6 +337,37 @@ dependencies = [ | |||||||
|  "generic-array", |  "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]] | [[package]] | ||||||
| name = "brotli" | name = "brotli" | ||||||
| version = "3.3.4" | version = "3.3.4" | ||||||
| @@ -329,6 +527,25 @@ dependencies = [ | |||||||
|  "winapi", |  "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]] | [[package]] | ||||||
| name = "cocoa" | name = "cocoa" | ||||||
| version = "0.24.1" | version = "0.24.1" | ||||||
| @@ -387,6 +604,15 @@ dependencies = [ | |||||||
|  "memchr", |  "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]] | [[package]] | ||||||
| name = "convert_case" | name = "convert_case" | ||||||
| version = "0.4.0" | version = "0.4.0" | ||||||
| @@ -478,6 +704,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" | |||||||
| checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" | checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" | ||||||
| dependencies = [ | dependencies = [ | ||||||
|  "generic-array", |  "generic-array", | ||||||
|  |  "rand_core 0.6.4", | ||||||
|  "typenum", |  "typenum", | ||||||
| ] | ] | ||||||
|  |  | ||||||
| @@ -518,6 +745,15 @@ dependencies = [ | |||||||
|  "syn 1.0.107", |  "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]] | [[package]] | ||||||
| name = "cty" | name = "cty" | ||||||
| version = "0.2.2" | version = "0.2.2" | ||||||
| @@ -571,6 +807,17 @@ version = "0.2.0" | |||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| checksum = "8d7439c3735f405729d52c3fbbe4de140eaf938a1fe47d227c27f8254d4302a5" | 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]] | [[package]] | ||||||
| name = "derive_more" | name = "derive_more" | ||||||
| version = "0.99.17" | version = "0.99.17" | ||||||
| @@ -592,6 +839,7 @@ checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f" | |||||||
| dependencies = [ | dependencies = [ | ||||||
|  "block-buffer", |  "block-buffer", | ||||||
|  "crypto-common", |  "crypto-common", | ||||||
|  |  "subtle", | ||||||
| ] | ] | ||||||
|  |  | ||||||
| [[package]] | [[package]] | ||||||
| @@ -671,16 +919,24 @@ dependencies = [ | |||||||
| ] | ] | ||||||
|  |  | ||||||
| [[package]] | [[package]] | ||||||
| name = "env_logger" | name = "enumflags2" | ||||||
| version = "0.10.0" | version = "0.7.7" | ||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| checksum = "85cdab6a89accf66733ad5a1693a4dcced6aeff64602b634530dd73c1f3ee9f0" | checksum = "c041f5090df68b32bcd905365fd51769c8b9d553fe87fde0b683534f10c01bd2" | ||||||
| dependencies = [ | dependencies = [ | ||||||
|  "humantime", |  "enumflags2_derive", | ||||||
|  "is-terminal", |  "serde", | ||||||
|  "log", | ] | ||||||
|  "regex", |  | ||||||
|  "termcolor", | [[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]] | [[package]] | ||||||
| @@ -704,6 +960,12 @@ dependencies = [ | |||||||
|  "libc", |  "libc", | ||||||
| ] | ] | ||||||
|  |  | ||||||
|  | [[package]] | ||||||
|  | name = "event-listener" | ||||||
|  | version = "2.5.3" | ||||||
|  | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
|  | checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" | ||||||
|  |  | ||||||
| [[package]] | [[package]] | ||||||
| name = "fastrand" | name = "fastrand" | ||||||
| version = "1.8.0" | version = "1.8.0" | ||||||
| @@ -729,7 +991,7 @@ version = "0.3.4" | |||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| checksum = "1e1c54951450cbd39f3dbcf1005ac413b49487dabf18a720ad2383eccfeffb92" | checksum = "1e1c54951450cbd39f3dbcf1005ac413b49487dabf18a720ad2383eccfeffb92" | ||||||
| dependencies = [ | dependencies = [ | ||||||
|  "memoffset", |  "memoffset 0.6.5", | ||||||
|  "rustc_version 0.3.3", |  "rustc_version 0.3.3", | ||||||
| ] | ] | ||||||
|  |  | ||||||
| @@ -827,6 +1089,21 @@ version = "0.3.26" | |||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| checksum = "bfb8371b6fb2aeb2d280374607aeabfc99d95c72edfe51692e42d3d7f0d08531" | 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]] | [[package]] | ||||||
| name = "futures-macro" | name = "futures-macro" | ||||||
| version = "0.3.26" | version = "0.3.26" | ||||||
| @@ -857,8 +1134,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" | |||||||
| checksum = "9c1d6de3acfef38d2be4b1f543f553131788603495be83da675e180c8d6b7bd1" | checksum = "9c1d6de3acfef38d2be4b1f543f553131788603495be83da675e180c8d6b7bd1" | ||||||
| dependencies = [ | dependencies = [ | ||||||
|  "futures-core", |  "futures-core", | ||||||
|  |  "futures-io", | ||||||
|  "futures-macro", |  "futures-macro", | ||||||
|  |  "futures-sink", | ||||||
|  "futures-task", |  "futures-task", | ||||||
|  |  "memchr", | ||||||
|  "pin-project-lite", |  "pin-project-lite", | ||||||
|  "pin-utils", |  "pin-utils", | ||||||
|  "slab", |  "slab", | ||||||
| @@ -1004,6 +1284,16 @@ dependencies = [ | |||||||
|  "wasi 0.11.0+wasi-snapshot-preview1", |  "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]] | [[package]] | ||||||
| name = "gio" | name = "gio" | ||||||
| version = "0.15.12" | version = "0.15.12" | ||||||
| @@ -1139,8 +1429,9 @@ dependencies = [ | |||||||
| name = "gpservice" | name = "gpservice" | ||||||
| version = "0.1.0" | version = "0.1.0" | ||||||
| dependencies = [ | dependencies = [ | ||||||
|  "env_logger", |  "fern", | ||||||
|  "gpcommon", |  "gpcommon", | ||||||
|  |  "humantime", | ||||||
|  "log", |  "log", | ||||||
|  "tokio", |  "tokio", | ||||||
| ] | ] | ||||||
| @@ -1251,6 +1542,24 @@ version = "0.4.3" | |||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" | 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]] | [[package]] | ||||||
| name = "html5ever" | name = "html5ever" | ||||||
| version = "0.25.2" | version = "0.25.2" | ||||||
| @@ -1388,6 +1697,15 @@ dependencies = [ | |||||||
|  "cfb", |  "cfb", | ||||||
| ] | ] | ||||||
|  |  | ||||||
|  | [[package]] | ||||||
|  | name = "inout" | ||||||
|  | version = "0.1.3" | ||||||
|  | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
|  | checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" | ||||||
|  | dependencies = [ | ||||||
|  |  "generic-array", | ||||||
|  | ] | ||||||
|  |  | ||||||
| [[package]] | [[package]] | ||||||
| name = "instant" | name = "instant" | ||||||
| version = "0.1.12" | version = "0.1.12" | ||||||
| @@ -1408,18 +1726,6 @@ dependencies = [ | |||||||
|  "windows-sys 0.48.0", |  "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]] | [[package]] | ||||||
| name = "is_executable" | name = "is_executable" | ||||||
| version = "1.0.1" | version = "1.0.1" | ||||||
| @@ -1505,6 +1811,20 @@ dependencies = [ | |||||||
|  "treediff", |  "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]] | [[package]] | ||||||
| name = "kuchiki" | name = "kuchiki" | ||||||
| version = "0.8.1" | version = "0.8.1" | ||||||
| @@ -1538,6 +1858,16 @@ dependencies = [ | |||||||
|  "safemem", |  "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]] | [[package]] | ||||||
| name = "linux-raw-sys" | name = "linux-raw-sys" | ||||||
| version = "0.3.7" | version = "0.3.7" | ||||||
| @@ -1638,6 +1968,15 @@ dependencies = [ | |||||||
|  "autocfg", |  "autocfg", | ||||||
| ] | ] | ||||||
|  |  | ||||||
|  | [[package]] | ||||||
|  | name = "memoffset" | ||||||
|  | version = "0.7.1" | ||||||
|  | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
|  | checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4" | ||||||
|  | dependencies = [ | ||||||
|  |  "autocfg", | ||||||
|  | ] | ||||||
|  |  | ||||||
| [[package]] | [[package]] | ||||||
| name = "miniz_oxide" | name = "miniz_oxide" | ||||||
| version = "0.6.2" | version = "0.6.2" | ||||||
| @@ -1711,6 +2050,19 @@ version = "1.0.4" | |||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54" | 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]] | [[package]] | ||||||
| name = "nodrop" | name = "nodrop" | ||||||
| version = "0.1.14" | version = "0.1.14" | ||||||
| @@ -1727,6 +2079,40 @@ dependencies = [ | |||||||
|  "winapi", |  "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]] | [[package]] | ||||||
| name = "num-integer" | name = "num-integer" | ||||||
| version = "0.1.45" | version = "0.1.45" | ||||||
| @@ -1737,6 +2123,17 @@ dependencies = [ | |||||||
|  "num-traits", |  "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]] | [[package]] | ||||||
| name = "num-rational" | name = "num-rational" | ||||||
| version = "0.4.1" | version = "0.4.1" | ||||||
| @@ -1744,6 +2141,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" | |||||||
| checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" | checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" | ||||||
| dependencies = [ | dependencies = [ | ||||||
|  "autocfg", |  "autocfg", | ||||||
|  |  "num-bigint", | ||||||
|  "num-integer", |  "num-integer", | ||||||
|  "num-traits", |  "num-traits", | ||||||
| ] | ] | ||||||
| @@ -1831,6 +2229,12 @@ version = "1.17.0" | |||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| checksum = "6f61fba1741ea2b3d6a1e3178721804bb716a68a6aeba1149b5d52e3d464ea66" | checksum = "6f61fba1741ea2b3d6a1e3178721804bb716a68a6aeba1149b5d52e3d464ea66" | ||||||
|  |  | ||||||
|  | [[package]] | ||||||
|  | name = "opaque-debug" | ||||||
|  | version = "0.3.0" | ||||||
|  | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
|  | checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" | ||||||
|  |  | ||||||
| [[package]] | [[package]] | ||||||
| name = "open" | name = "open" | ||||||
| version = "3.2.0" | version = "3.2.0" | ||||||
| @@ -1886,6 +2290,16 @@ dependencies = [ | |||||||
|  "vcpkg", |  "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]] | [[package]] | ||||||
| name = "overload" | name = "overload" | ||||||
| version = "0.1.1" | version = "0.1.1" | ||||||
| @@ -1917,6 +2331,12 @@ dependencies = [ | |||||||
|  "system-deps 6.0.3", |  "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]] | [[package]] | ||||||
| name = "parking_lot" | name = "parking_lot" | ||||||
| version = "0.12.1" | version = "0.12.1" | ||||||
| @@ -2104,6 +2524,34 @@ dependencies = [ | |||||||
|  "miniz_oxide", |  "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]] | [[package]] | ||||||
| name = "ppv-lite86" | name = "ppv-lite86" | ||||||
| version = "0.2.17" | version = "0.2.17" | ||||||
| @@ -2423,6 +2871,25 @@ version = "1.1.0" | |||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" | 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]] | [[package]] | ||||||
| name = "security-framework" | name = "security-framework" | ||||||
| version = "2.8.2" | version = "2.8.2" | ||||||
| @@ -2616,6 +3083,17 @@ dependencies = [ | |||||||
|  "stable_deref_trait", |  "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]] | [[package]] | ||||||
| name = "sha2" | name = "sha2" | ||||||
| version = "0.10.6" | version = "0.10.6" | ||||||
| @@ -2636,6 +3114,16 @@ dependencies = [ | |||||||
|  "lazy_static", |  "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]] | [[package]] | ||||||
| name = "signal-hook-registry" | name = "signal-hook-registry" | ||||||
| version = "1.4.0" | version = "1.4.0" | ||||||
| @@ -2725,6 +3213,12 @@ dependencies = [ | |||||||
|  "loom", |  "loom", | ||||||
| ] | ] | ||||||
|  |  | ||||||
|  | [[package]] | ||||||
|  | name = "static_assertions" | ||||||
|  | version = "1.1.0" | ||||||
|  | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
|  | checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" | ||||||
|  |  | ||||||
| [[package]] | [[package]] | ||||||
| name = "string_cache" | name = "string_cache" | ||||||
| version = "0.8.4" | version = "0.8.4" | ||||||
| @@ -2757,6 +3251,12 @@ version = "0.10.0" | |||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" | checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" | ||||||
|  |  | ||||||
|  | [[package]] | ||||||
|  | name = "subtle" | ||||||
|  | version = "2.4.1" | ||||||
|  | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
|  | checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" | ||||||
|  |  | ||||||
| [[package]] | [[package]] | ||||||
| name = "syn" | name = "syn" | ||||||
| version = "1.0.107" | version = "1.0.107" | ||||||
| @@ -3112,15 +3612,6 @@ dependencies = [ | |||||||
|  "utf-8", |  "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]] | [[package]] | ||||||
| name = "thin-slice" | name = "thin-slice" | ||||||
| version = "0.1.1" | version = "0.1.1" | ||||||
| @@ -3354,6 +3845,16 @@ version = "0.1.5" | |||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| checksum = "9e79c4d996edb816c91e4308506774452e55e95c3c9de07b6729e17e15a5ef81" | 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]] | [[package]] | ||||||
| name = "unicode-bidi" | name = "unicode-bidi" | ||||||
| version = "0.3.10" | version = "0.3.10" | ||||||
| @@ -3381,6 +3882,16 @@ version = "1.10.1" | |||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" | 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]] | [[package]] | ||||||
| name = "untrusted" | name = "untrusted" | ||||||
| version = "0.7.1" | version = "0.7.1" | ||||||
| @@ -3501,6 +4012,12 @@ dependencies = [ | |||||||
|  "libc", |  "libc", | ||||||
| ] | ] | ||||||
|  |  | ||||||
|  | [[package]] | ||||||
|  | name = "waker-fn" | ||||||
|  | version = "1.1.0" | ||||||
|  | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
|  | checksum = "9d5b2c62b4012a3e1eca5a7e077d13b3bf498c4073e33ccd58626607748ceeca" | ||||||
|  |  | ||||||
| [[package]] | [[package]] | ||||||
| name = "walkdir" | name = "walkdir" | ||||||
| version = "2.3.2" | version = "2.3.2" | ||||||
| @@ -4041,3 +4558,117 @@ checksum = "6d1526bbe5aaeb5eb06885f4d987bcdfa5e23187055de9b83fe00156a821fabc" | |||||||
| dependencies = [ | dependencies = [ | ||||||
|  "libc", |  "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> { |     pub async fn connect( | ||||||
|         self.send_command(Connect::new(server, cookie).into()).await |         &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> { |     pub async fn disconnect(&self) -> Result<(), ServerApiError> { | ||||||
|   | |||||||
| @@ -7,11 +7,16 @@ use serde::{Deserialize, Serialize}; | |||||||
| pub struct Connect { | pub struct Connect { | ||||||
|     server: String, |     server: String, | ||||||
|     cookie: String, |     cookie: String, | ||||||
|  |     user_agent: String, | ||||||
| } | } | ||||||
|  |  | ||||||
| impl Connect { | impl Connect { | ||||||
|     pub fn new(server: String, cookie: String) -> Self { |     pub fn new(server: String, cookie: String, user_agent: String) -> Self { | ||||||
|         Self { server, cookie } |         Self { | ||||||
|  |             server, | ||||||
|  |             cookie, | ||||||
|  |             user_agent, | ||||||
|  |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -25,7 +30,7 @@ impl Command for Connect { | |||||||
|             return Err(format!("VPN is already in state: {:?}", status).into()); |             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()); |             return Err(err.to_string().into()); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -5,16 +5,17 @@ use tokio::sync::mpsc; | |||||||
| #[repr(C)] | #[repr(C)] | ||||||
| #[derive(Debug, Copy, Clone)] | #[derive(Debug, Copy, Clone)] | ||||||
| pub(crate) struct Options { | pub(crate) struct Options { | ||||||
|     pub server: *const ::std::os::raw::c_char, |     pub server: *const std::os::raw::c_char, | ||||||
|     pub cookie: *const ::std::os::raw::c_char, |     pub cookie: *const std::os::raw::c_char, | ||||||
|     pub script: *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, |     pub user_data: *mut c_void, | ||||||
| } | } | ||||||
|  |  | ||||||
| #[link(name = "vpn")] | #[link(name = "vpn")] | ||||||
| extern "C" { | extern "C" { | ||||||
|     #[link_name = "vpn_connect"] |     #[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"] |     #[link_name = "vpn_disconnect"] | ||||||
|     pub(crate) fn 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 | // level: 0 = error, 1 = info, 2 = debug, 3 = trace | ||||||
| // map the error level log in openconnect to the warning level | // map the error level log in openconnect to the warning level | ||||||
| #[no_mangle] | #[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 = unsafe { std::ffi::CStr::from_ptr(message) }; | ||||||
|     let message = message.to_str().unwrap_or("Invalid log message"); |     let message = message.to_str().unwrap_or("Invalid log message"); | ||||||
|     // Strip the trailing newline |     // Strip the trailing newline | ||||||
|   | |||||||
| @@ -56,6 +56,7 @@ pub(crate) struct VpnOptions { | |||||||
|     server: CString, |     server: CString, | ||||||
|     cookie: CString, |     cookie: CString, | ||||||
|     script: CString, |     script: CString, | ||||||
|  |     user_agent: CString, | ||||||
| } | } | ||||||
|  |  | ||||||
| impl VpnOptions { | impl VpnOptions { | ||||||
| @@ -64,6 +65,7 @@ impl VpnOptions { | |||||||
|             server: self.server.as_ptr(), |             server: self.server.as_ptr(), | ||||||
|             cookie: self.cookie.as_ptr(), |             cookie: self.cookie.as_ptr(), | ||||||
|             script: self.script.as_ptr(), |             script: self.script.as_ptr(), | ||||||
|  |             user_agent: self.user_agent.as_ptr(), | ||||||
|             user_data, |             user_data, | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| @@ -88,6 +90,7 @@ impl Vpn { | |||||||
|         &self, |         &self, | ||||||
|         server: &str, |         server: &str, | ||||||
|         cookie: &str, |         cookie: &str, | ||||||
|  |         user_agent: &str, | ||||||
|     ) -> Result<(), Box<dyn std::error::Error>> { |     ) -> Result<(), Box<dyn std::error::Error>> { | ||||||
|         let script = match find_default_vpnc_script() { |         let script = match find_default_vpnc_script() { | ||||||
|             Some(script) => { |             Some(script) => { | ||||||
| @@ -104,6 +107,7 @@ impl Vpn { | |||||||
|             server: VpnOptions::to_cstr(server), |             server: VpnOptions::to_cstr(server), | ||||||
|             cookie: VpnOptions::to_cstr(cookie), |             cookie: VpnOptions::to_cstr(cookie), | ||||||
|             script: VpnOptions::to_cstr(script), |             script: VpnOptions::to_cstr(script), | ||||||
|  |             user_agent: VpnOptions::to_cstr(user_agent), | ||||||
|         }); |         }); | ||||||
|  |  | ||||||
|         let vpn_options = self.vpn_options.clone(); |         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_user_data = options->user_data; | ||||||
|     g_vpnc_script = options->script; |     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) |     if (!vpninfo) | ||||||
|     { |     { | ||||||
|   | |||||||
| @@ -8,6 +8,7 @@ typedef struct vpn_options | |||||||
|     const char *server; |     const char *server; | ||||||
|     const char *cookie; |     const char *cookie; | ||||||
|     const char *script; |     const char *script; | ||||||
|  |     const char *user_agent; | ||||||
|     void *user_data; |     void *user_data; | ||||||
| } vpn_options; | } vpn_options; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -23,8 +23,7 @@ | |||||||
|     "react": "^18.2.0", |     "react": "^18.2.0", | ||||||
|     "react-dom": "^18.2.0", |     "react-dom": "^18.2.0", | ||||||
|     "react-spinners": "^0.13.8", |     "react-spinners": "^0.13.8", | ||||||
|     "tauri-plugin-log-api": "github:tauri-apps/tauri-plugin-log", |     "tauri-plugin-log-api": "github:tauri-apps/tauri-plugin-log#v1" | ||||||
|     "tauri-plugin-store-api": "github:tauri-apps/tauri-plugin-store#v1" |  | ||||||
|   }, |   }, | ||||||
|   "devDependencies": { |   "devDependencies": { | ||||||
|     "@tauri-apps/cli": "^1.3.1", |     "@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: | settings: | ||||||
|   autoInstallPeers: true |   autoInstallPeers: true | ||||||
| @@ -48,11 +48,8 @@ dependencies: | |||||||
|     specifier: ^0.13.8 |     specifier: ^0.13.8 | ||||||
|     version: 0.13.8(react-dom@18.2.0)(react@18.2.0) |     version: 0.13.8(react-dom@18.2.0)(react@18.2.0) | ||||||
|   tauri-plugin-log-api: |   tauri-plugin-log-api: | ||||||
|     specifier: github:tauri-apps/tauri-plugin-log |     specifier: github:tauri-apps/tauri-plugin-log#v1 | ||||||
|     version: github.com/tauri-apps/tauri-plugin-log/21921031d74f871180381317a338559f588ad8e9 |     version: github.com/tauri-apps/tauri-plugin-log/fbbb126e6d7fba7a7e6772d33f99c0fb689f32b6 | ||||||
|   tauri-plugin-store-api: |  | ||||||
|     specifier: github:tauri-apps/tauri-plugin-store#v1 |  | ||||||
|     version: github.com/tauri-apps/tauri-plugin-store/1467ba770623ab1d41d825841c3d9435d9eaa0f1 |  | ||||||
|  |  | ||||||
| devDependencies: | devDependencies: | ||||||
|   '@tauri-apps/cli': |   '@tauri-apps/cli': | ||||||
| @@ -878,6 +875,11 @@ packages: | |||||||
|     engines: {node: '>= 14.6.0', npm: '>= 6.6.0', yarn: '>= 1.19.1'} |     engines: {node: '>= 14.6.0', npm: '>= 6.6.0', yarn: '>= 1.19.1'} | ||||||
|     dev: false |     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: |   /@tauri-apps/cli-darwin-arm64@1.3.1: | ||||||
|     resolution: {integrity: sha512-QlepYVPgOgspcwA/u4kGG4ZUijlXfdRtno00zEy+LxinN/IRXtk+6ErVtsmoLi1ZC9WbuMwzAcsRvqsD+RtNAg==} |     resolution: {integrity: sha512-QlepYVPgOgspcwA/u4kGG4ZUijlXfdRtno00zEy+LxinN/IRXtk+6ErVtsmoLi1ZC9WbuMwzAcsRvqsD+RtNAg==} | ||||||
|     engines: {node: '>= 10'} |     engines: {node: '>= 10'} | ||||||
| @@ -1465,18 +1467,10 @@ packages: | |||||||
|     engines: {node: '>= 6'} |     engines: {node: '>= 6'} | ||||||
|     dev: false |     dev: false | ||||||
|  |  | ||||||
|   github.com/tauri-apps/tauri-plugin-log/21921031d74f871180381317a338559f588ad8e9: |   github.com/tauri-apps/tauri-plugin-log/fbbb126e6d7fba7a7e6772d33f99c0fb689f32b6: | ||||||
|     resolution: {tarball: https://codeload.github.com/tauri-apps/tauri-plugin-log/tar.gz/21921031d74f871180381317a338559f588ad8e9} |     resolution: {tarball: https://codeload.github.com/tauri-apps/tauri-plugin-log/tar.gz/fbbb126e6d7fba7a7e6772d33f99c0fb689f32b6} | ||||||
|     name: tauri-plugin-log-api |     name: tauri-plugin-log-api | ||||||
|     version: 0.0.0 |     version: 0.0.0 | ||||||
|     dependencies: |     dependencies: | ||||||
|       '@tauri-apps/api': 1.3.0 |       '@tauri-apps/api': 1.4.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 |  | ||||||
|     dev: false |     dev: false | ||||||
|   | |||||||
| @@ -23,7 +23,6 @@ tauri-plugin-log = { git = "https://github.com/tauri-apps/plugins-workspace", br | |||||||
| serde_json = "1.0" | serde_json = "1.0" | ||||||
| serde = { version = "1.0", features = ["derive"] } | serde = { version = "1.0", features = ["derive"] } | ||||||
| log = "0.4" | log = "0.4" | ||||||
| env_logger = "0.10" |  | ||||||
| webkit2gtk = "0.18.2" | webkit2gtk = "0.18.2" | ||||||
| regex = "1" | regex = "1" | ||||||
| url = "2.3" | url = "2.3" | ||||||
| @@ -32,6 +31,10 @@ veil = "0.1.6" | |||||||
| whoami = "1.4.1" | whoami = "1.4.1" | ||||||
| tauri-plugin-store = { git = "https://github.com/tauri-apps/plugins-workspace", branch = "v1" } | tauri-plugin-store = { git = "https://github.com/tauri-apps/plugins-workspace", branch = "v1" } | ||||||
| openssl = "0.10" | openssl = "0.10" | ||||||
|  | keyring = "2" | ||||||
|  | aes-gcm = { version = "0.10", features = ["std"] } | ||||||
|  | hex = "0.4" | ||||||
|  | anyhow = "1.0" | ||||||
|  |  | ||||||
| [features] | [features] | ||||||
| # by default Tauri runs in production mode | # 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) |     Window::builder(app_handle, AUTH_WINDOW_LABEL, url) | ||||||
|         .visible(false) |         .visible(false) | ||||||
|         .title("GlobalProtect Login") |         .title("GlobalProtect Login") | ||||||
|         .inner_size(400.0, 647.0) |         .inner_size(600.0, 500.0) | ||||||
|         .min_inner_size(370.0, 600.0) |         .min_inner_size(370.0, 600.0) | ||||||
|         .user_agent(ua) |         .user_agent(ua) | ||||||
|         .always_on_top(true) |         .always_on_top(true) | ||||||
|   | |||||||
| @@ -1,9 +1,11 @@ | |||||||
| use crate::{ | use crate::{ | ||||||
|     auth::{self, AuthData, AuthRequest, SamlBinding, SamlLoginParams}, |     auth::{self, AuthData, AuthRequest, SamlBinding, SamlLoginParams}, | ||||||
|  |     storage::{AppStorage, KeyHint}, | ||||||
|     utils::get_openssl_conf, |     utils::get_openssl_conf, | ||||||
|     utils::get_openssl_conf_path, |     utils::get_openssl_conf_path, | ||||||
| }; | }; | ||||||
| use gpcommon::{Client, ServerApiError, VpnStatus}; | use gpcommon::{Client, ServerApiError, VpnStatus}; | ||||||
|  | use serde_json::Value; | ||||||
| use std::sync::Arc; | use std::sync::Arc; | ||||||
| use tauri::{AppHandle, State}; | use tauri::{AppHandle, State}; | ||||||
| use tokio::fs; | use tokio::fs; | ||||||
| @@ -24,9 +26,10 @@ pub(crate) async fn vpn_status<'a>( | |||||||
| pub(crate) async fn vpn_connect<'a>( | pub(crate) async fn vpn_connect<'a>( | ||||||
|     server: String, |     server: String, | ||||||
|     cookie: String, |     cookie: String, | ||||||
|  |     user_agent: String, | ||||||
|     client: State<'a, Arc<Client>>, |     client: State<'a, Arc<Client>>, | ||||||
| ) -> Result<(), ServerApiError> { | ) -> Result<(), ServerApiError> { | ||||||
|     client.connect(server, cookie).await |     client.connect(server, cookie, user_agent).await | ||||||
| } | } | ||||||
|  |  | ||||||
| #[tauri::command] | #[tauri::command] | ||||||
| @@ -40,10 +43,10 @@ pub(crate) async fn vpn_disconnect<'a>( | |||||||
| pub(crate) async fn saml_login( | pub(crate) async fn saml_login( | ||||||
|     binding: SamlBinding, |     binding: SamlBinding, | ||||||
|     request: String, |     request: String, | ||||||
|  |     user_agent: String, | ||||||
|     clear_cookies: bool, |     clear_cookies: bool, | ||||||
|     app_handle: AppHandle, |     app_handle: AppHandle, | ||||||
| ) -> tauri::Result<Option<AuthData>> { | ) -> tauri::Result<Option<AuthData>> { | ||||||
|     let user_agent = String::from("PAN GlobalProtect"); |  | ||||||
|     let params = SamlLoginParams { |     let params = SamlLoginParams { | ||||||
|         auth_request: AuthRequest::new(binding, request), |         auth_request: AuthRequest::new(binding, request), | ||||||
|         user_agent, |         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?; |     fs::write(openssl_conf_path, openssl_conf).await?; | ||||||
|     Ok(()) |     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"), |     all(not(debug_assertions), target_os = "windows"), | ||||||
|     windows_subsystem = "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_log::LogTarget; | ||||||
| use tauri_plugin_store::{with_store, StoreCollection}; |  | ||||||
|  |  | ||||||
| mod auth; | mod auth; | ||||||
| mod commands; | mod commands; | ||||||
|  | mod crypto; | ||||||
|  | mod settings; | ||||||
|  | mod setup; | ||||||
|  | mod storage; | ||||||
| mod utils; | 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() { | fn main() { | ||||||
|     // env_logger::Builder::from_env(Env::default().default_filter_or("info")).init(); |  | ||||||
|     tauri::Builder::default() |     tauri::Builder::default() | ||||||
|         .plugin( |         .plugin( | ||||||
|             tauri_plugin_log::Builder::default() |             tauri_plugin_log::Builder::default() | ||||||
|                 .targets([ |                 .targets([LogTarget::LogDir, LogTarget::Stdout]) | ||||||
|                     LogTarget::LogDir, |  | ||||||
|                     LogTarget::Stdout, /*LogTarget::Webview*/ |  | ||||||
|                 ]) |  | ||||||
|                 .level(log::LevelFilter::Info) |                 .level(log::LevelFilter::Info) | ||||||
|                 .with_colors(Default::default()) |  | ||||||
|                 .build(), |                 .build(), | ||||||
|         ) |         ) | ||||||
|         .plugin(tauri_plugin_store::Builder::default().build()) |         .plugin(tauri_plugin_store::Builder::default().build()) | ||||||
|         .setup(setup) |         .setup(setup::setup) | ||||||
|         .invoke_handler(tauri::generate_handler![ |         .invoke_handler(tauri::generate_handler![ | ||||||
|             commands::service_online, |             commands::service_online, | ||||||
|             commands::vpn_status, |             commands::vpn_status, | ||||||
| @@ -98,6 +31,9 @@ fn main() { | |||||||
|             commands::os_version, |             commands::os_version, | ||||||
|             commands::openssl_config, |             commands::openssl_config, | ||||||
|             commands::update_openssl_config, |             commands::update_openssl_config, | ||||||
|  |             commands::store_get, | ||||||
|  |             commands::store_set, | ||||||
|  |             commands::store_save, | ||||||
|         ]) |         ]) | ||||||
|         .run(tauri::generate_context!()) |         .run(tauri::generate_context!()) | ||||||
|         .expect("error while running tauri application"); |         .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( | 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) => { |   async (get, set, update: string) => { | ||||||
|     const portalData = get(currentPortalDataAtom); |     const portalData = get(currentPortalDataAtom); | ||||||
|     await set(updatePortalDataAtom, { ...portalData, selectedGateway: update }); |     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 |     // 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( |     const selectedGateway = gateways.find( | ||||||
|       ({ name }) => name === previousSelectedGateway |       ({ name }) => name === previousSelectedGateway | ||||||
|     ); |     ); | ||||||
|   | |||||||
| @@ -1,7 +1,7 @@ | |||||||
| import { atom } from "jotai"; | import { atom } from "jotai"; | ||||||
| import { atomWithDefault } from "jotai/utils"; | import { atomWithDefault } from "jotai/utils"; | ||||||
| import { PortalCredential } from "../services/portalService"; | import { PortalCredential } from "../services/portalService"; | ||||||
| import { atomWithTauriStorage } from "../services/storeService"; | import { atomWithTauriStorage } from "../services/storageService"; | ||||||
| import { unwrap } from "./unwrap"; | import { unwrap } from "./unwrap"; | ||||||
|  |  | ||||||
| export type GatewayData = { | export type GatewayData = { | ||||||
| @@ -31,7 +31,11 @@ const DEFAULT_APP_DATA: AppData = { | |||||||
|   clearCookies: true, |   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( | const unwrappedAppDataAtom = atom( | ||||||
|   (get) => get(unwrap(appDataAtom)) || DEFAULT_APP_DATA |   (get) => get(unwrap(appDataAtom)) || DEFAULT_APP_DATA | ||||||
| ); | ); | ||||||
| @@ -51,6 +55,11 @@ export const currentPortalDataAtom = atom<PortalData>((get) => { | |||||||
|   return portalData || { address: portalAddress, gateways: [] }; |   return portalData || { address: portalAddress, gateways: [] }; | ||||||
| }); | }); | ||||||
|  |  | ||||||
|  | export const allPortalsAtom = atom((get) => { | ||||||
|  |   const { portals } = get(unwrappedAppDataAtom); | ||||||
|  |   return portals.map(({ address }) => address); | ||||||
|  | }); | ||||||
|  |  | ||||||
| export const updatePortalDataAtom = atom( | export const updatePortalDataAtom = atom( | ||||||
|   null, |   null, | ||||||
|   async (get, set, update: PortalData) => { |   async (get, set, update: PortalData) => { | ||||||
|   | |||||||
| @@ -5,7 +5,7 @@ import settingsService, { | |||||||
|   DEFAULT_SETTINGS_DATA, |   DEFAULT_SETTINGS_DATA, | ||||||
|   SETTINGS_DATA, |   SETTINGS_DATA, | ||||||
| } from "../services/settingsService"; | } from "../services/settingsService"; | ||||||
| import { atomWithTauriStorage } from "../services/storeService"; | import { atomWithTauriStorage } from "../services/storageService"; | ||||||
| import { unwrap } from "./unwrap"; | import { unwrap } from "./unwrap"; | ||||||
|  |  | ||||||
| const settingsDataAtom = atomWithTauriStorage( | const settingsDataAtom = atomWithTauriStorage( | ||||||
|   | |||||||
| @@ -4,6 +4,7 @@ import vpnService from "../services/vpnService"; | |||||||
| import { selectedGatewayAtom, switchGatewayAtom } from "./gateway"; | import { selectedGatewayAtom, switchGatewayAtom } from "./gateway"; | ||||||
| import { notifyErrorAtom, notifySuccessAtom } from "./notification"; | import { notifyErrorAtom, notifySuccessAtom } from "./notification"; | ||||||
| import { unwrap } from "./unwrap"; | import { unwrap } from "./unwrap"; | ||||||
|  | import { portalAddressAtom } from "./portal"; | ||||||
|  |  | ||||||
| export type Status = | export type Status = | ||||||
|   | "disconnected" |   | "disconnected" | ||||||
| @@ -75,14 +76,16 @@ export const statusTextAtom = atom<string>((get) => { | |||||||
|  |  | ||||||
|   if (status === "connected") { |   if (status === "connected") { | ||||||
|     const selectedGateway = get(selectedGatewayAtom); |     const selectedGateway = get(selectedGatewayAtom); | ||||||
|     return selectedGateway |     const portalAddress = get(portalAddressAtom); | ||||||
|       ? `Gateway: ${selectedGateway}` |  | ||||||
|       : statusTextMap[status]; |     return selectedGateway?.address === portalAddress | ||||||
|  |       ? statusTextMap[status] | ||||||
|  |       : selectedGateway?.address!; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   if (switchingGateway) { |   if (switchingGateway) { | ||||||
|     const selectedGateway = get(selectedGatewayAtom); |     const selectedGateway = get(selectedGatewayAtom); | ||||||
|     return `Switching to ${selectedGateway}`; |     return `Switching to ${selectedGateway?.name}`; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   return statusTextMap[status]; |   return statusTextMap[status]; | ||||||
|   | |||||||
| @@ -1,13 +1,8 @@ | |||||||
| import { | import { Box, CssBaseline, ThemeProvider } from "@mui/material"; | ||||||
|   Box, | import React, { Suspense } from "react"; | ||||||
|   CssBaseline, |  | ||||||
|   ThemeProvider, |  | ||||||
|   createTheme, |  | ||||||
|   useMediaQuery, |  | ||||||
| } from "@mui/material"; |  | ||||||
| import React, { Suspense, useMemo } from "react"; |  | ||||||
| import { createRoot } from "react-dom/client"; | import { createRoot } from "react-dom/client"; | ||||||
| import "./styles.css"; | import "./styles.css"; | ||||||
|  | import useGlobalTheme from "./useGlobalTheme"; | ||||||
|  |  | ||||||
| function Loading() { | function Loading() { | ||||||
|   console.warn("Loading rendered"); |   console.warn("Loading rendered"); | ||||||
| @@ -27,16 +22,7 @@ function Loading() { | |||||||
| } | } | ||||||
|  |  | ||||||
| function AppShell({ children }: { children: React.ReactNode }) { | function AppShell({ children }: { children: React.ReactNode }) { | ||||||
|   const prefersDarkMode = useMediaQuery("(prefers-color-scheme: dark)"); |   const theme = useGlobalTheme(); | ||||||
|   const theme = useMemo( |  | ||||||
|     () => |  | ||||||
|       createTheme({ |  | ||||||
|         palette: { |  | ||||||
|           mode: prefersDarkMode ? "dark" : "light", |  | ||||||
|         }, |  | ||||||
|       }), |  | ||||||
|     [prefersDarkMode] |  | ||||||
|   ); |  | ||||||
|  |  | ||||||
|   return ( |   return ( | ||||||
|     <React.StrictMode> |     <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 |             <Button | ||||||
|               variant="outlined" |               variant="outlined" | ||||||
|               onClick={cancelPasswordAuth} |               onClick={cancelPasswordAuth} | ||||||
|               sx={{ flex: 1, textTransform: "none" }} |               sx={{ flex: 1 }} | ||||||
|             > |             > | ||||||
|               Cancel |               Cancel | ||||||
|             </Button> |             </Button> | ||||||
| @@ -66,7 +66,6 @@ export default function PasswordAuth() { | |||||||
|               type="submit" |               type="submit" | ||||||
|               loading={loading} |               loading={loading} | ||||||
|               disabled={loading} |               disabled={loading} | ||||||
|               sx={{ flex: 1, textTransform: "none" }} |  | ||||||
|             > |             > | ||||||
|               Login |               Login | ||||||
|             </LoadingButton> |             </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 { useAtom, useAtomValue, useSetAtom } from "jotai"; | ||||||
| import { ChangeEvent } from "react"; | import { ChangeEvent, useState } from "react"; | ||||||
| import { | import { | ||||||
|   cancelConnectPortalAtom, |   cancelConnectPortalAtom, | ||||||
|   connectPortalAtom, |   connectPortalAtom, | ||||||
| } from "../../atoms/connectPortal"; | } from "../../atoms/connectPortal"; | ||||||
| import { switchGatewayAtom } from "../../atoms/gateway"; | import { switchGatewayAtom } from "../../atoms/gateway"; | ||||||
| import { portalAddressAtom } from "../../atoms/portal"; | import { allPortalsAtom, portalAddressAtom } from "../../atoms/portal"; | ||||||
| import { | import { | ||||||
|   backgroundServiceStartedAtom, |   backgroundServiceStartedAtom, | ||||||
|   isProcessingAtom, |   isProcessingAtom, | ||||||
| @@ -26,6 +26,7 @@ function normalizePortalAddress(input: string) { | |||||||
|  |  | ||||||
| export default function PortalForm() { | export default function PortalForm() { | ||||||
|   const backgroundServiceStarted = useAtomValue(backgroundServiceStartedAtom); |   const backgroundServiceStarted = useAtomValue(backgroundServiceStartedAtom); | ||||||
|  |   const allPortals = useAtomValue(allPortalsAtom); | ||||||
|   const [portalAddress, setPortalAddress] = useAtom(portalAddressAtom); |   const [portalAddress, setPortalAddress] = useAtom(portalAddressAtom); | ||||||
|   // Use useAtom instead of useSetAtom, otherwise the onMount of the atom is not triggered |   // Use useAtom instead of useSetAtom, otherwise the onMount of the atom is not triggered | ||||||
|   const [, connectPortal] = useAtom(connectPortalAtom); |   const [, connectPortal] = useAtom(connectPortalAtom); | ||||||
| @@ -35,8 +36,10 @@ export default function PortalForm() { | |||||||
|   const disconnectVpn = useSetAtom(disconnectVpnAtom); |   const disconnectVpn = useSetAtom(disconnectVpnAtom); | ||||||
|   const switchingGateway = useAtomValue(switchGatewayAtom); |   const switchingGateway = useAtomValue(switchGatewayAtom); | ||||||
|  |  | ||||||
|   function handlePortalAddressChange(e: ChangeEvent<HTMLInputElement>) { |   const readOnly = status !== "disconnected" || switchingGateway; | ||||||
|     setPortalAddress(normalizePortalAddress(e.target.value)); |  | ||||||
|  |   function handlePortalAddressChange(e: unknown, value: string) { | ||||||
|  |     setPortalAddress(normalizePortalAddress(value)); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   function handleSubmit(e: ChangeEvent<HTMLFormElement>) { |   function handleSubmit(e: ChangeEvent<HTMLFormElement>) { | ||||||
| @@ -46,16 +49,35 @@ export default function PortalForm() { | |||||||
|  |  | ||||||
|   return ( |   return ( | ||||||
|     <form onSubmit={handleSubmit} data-tauri-drag-region> |     <form onSubmit={handleSubmit} data-tauri-drag-region> | ||||||
|  |       <Autocomplete | ||||||
|  |         freeSolo | ||||||
|  |         options={allPortals} | ||||||
|  |         inputValue={portalAddress} | ||||||
|  |         onInputChange={handlePortalAddressChange} | ||||||
|  |         readOnly={readOnly} | ||||||
|  |         forcePopupIcon={!readOnly} | ||||||
|  |         disableClearable | ||||||
|  |         size="small" | ||||||
|  |         sx={{ | ||||||
|  |           mb: 1, | ||||||
|  |         }} | ||||||
|  |         componentsProps={{ | ||||||
|  |           paper: { | ||||||
|  |             sx: { | ||||||
|  |               "& .MuiAutocomplete-listbox .MuiAutocomplete-option": { | ||||||
|  |                 minHeight: "auto", | ||||||
|  |               }, | ||||||
|  |             }, | ||||||
|  |           }, | ||||||
|  |         }} | ||||||
|  |         renderInput={(params) => ( | ||||||
|           <TextField |           <TextField | ||||||
|  |             {...params} | ||||||
|             autoFocus |             autoFocus | ||||||
|             label="Portal address" |             label="Portal address" | ||||||
|             placeholder="Hostname or IP address" |             placeholder="Hostname or IP address" | ||||||
|         fullWidth |           /> | ||||||
|         size="small" |         )} | ||||||
|         value={portalAddress} |  | ||||||
|         onChange={handlePortalAddressChange} |  | ||||||
|         InputProps={{ readOnly: status !== "disconnected" || switchingGateway }} |  | ||||||
|         sx={{ mb: 1 }} |  | ||||||
|       /> |       /> | ||||||
|  |  | ||||||
|       {status === "disconnected" && !switchingGateway && ( |       {status === "disconnected" && !switchingGateway && ( | ||||||
| @@ -64,7 +86,6 @@ export default function PortalForm() { | |||||||
|           type="submit" |           type="submit" | ||||||
|           variant="contained" |           variant="contained" | ||||||
|           disabled={!backgroundServiceStarted} |           disabled={!backgroundServiceStarted} | ||||||
|           sx={{ textTransform: "none" }} |  | ||||||
|         > |         > | ||||||
|           Connect |           Connect | ||||||
|         </Button> |         </Button> | ||||||
| @@ -81,19 +102,13 @@ export default function PortalForm() { | |||||||
|             switchingGateway |             switchingGateway | ||||||
|           } |           } | ||||||
|           onClick={cancelConnectPortal} |           onClick={cancelConnectPortal} | ||||||
|           sx={{ textTransform: "none" }} |  | ||||||
|         > |         > | ||||||
|           Cancel |           Cancel | ||||||
|         </Button> |         </Button> | ||||||
|       )} |       )} | ||||||
|  |  | ||||||
|       {status === "connected" && ( |       {status === "connected" && ( | ||||||
|         <Button |         <Button fullWidth variant="contained" onClick={disconnectVpn}> | ||||||
|           fullWidth |  | ||||||
|           variant="contained" |  | ||||||
|           onClick={disconnectVpn} |  | ||||||
|           sx={{ textTransform: "none" }} |  | ||||||
|         > |  | ||||||
|           Disconnect |           Disconnect | ||||||
|         </Button> |         </Button> | ||||||
|       )} |       )} | ||||||
|   | |||||||
| @@ -1,7 +1,18 @@ | |||||||
| import { GppBad, VerifiedUser as VerifiedIcon } from "@mui/icons-material"; | import { GppBad, VerifiedUser as VerifiedIcon } from "@mui/icons-material"; | ||||||
| import { Box, CircularProgress, styled, useTheme } from "@mui/material"; | import { | ||||||
| import { useAtomValue } from "jotai"; |   Box, | ||||||
|  |   Button, | ||||||
|  |   CircularProgress, | ||||||
|  |   Tooltip, | ||||||
|  |   styled, | ||||||
|  |   useTheme, | ||||||
|  | } from "@mui/material"; | ||||||
|  | import { useAtomValue, useSetAtom } from "jotai"; | ||||||
| import { BeatLoader } from "react-spinners"; | import { BeatLoader } from "react-spinners"; | ||||||
|  | import { | ||||||
|  |   openGatewaySwitcherAtom, | ||||||
|  |   selectedGatewayAtom, | ||||||
|  | } from "../../atoms/gateway"; | ||||||
| import { isProcessingAtom, statusAtom } from "../../atoms/status"; | import { isProcessingAtom, statusAtom } from "../../atoms/status"; | ||||||
|  |  | ||||||
| function useStatusColor() { | function useStatusColor() { | ||||||
| @@ -59,11 +70,48 @@ function ProcessingIcon() { | |||||||
|   return <BeatLoader color={theme.palette.info.main} />; |   return <BeatLoader color={theme.palette.info.main} />; | ||||||
| } | } | ||||||
|  |  | ||||||
| const ConnectedIcon = styled(VerifiedIcon)(({ theme }) => ({ | 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", |             position: "relative", | ||||||
|   fontSize: 80, |             zIndex: 1, | ||||||
|   color: theme.palette.success.main, |             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 }) => | const IconContainer = styled(Box)(({ theme }) => | ||||||
|   theme.unstable_sx({ |   theme.unstable_sx({ | ||||||
|   | |||||||
| @@ -20,7 +20,7 @@ export default function GatewaySwitcher() { | |||||||
|     gatewaySwitcherVisibleAtom |     gatewaySwitcherVisibleAtom | ||||||
|   ); |   ); | ||||||
|   const gateways = useAtomValue(portalGatewaysAtom); |   const gateways = useAtomValue(portalGatewaysAtom); | ||||||
|   const selectedGateway = useAtomValue(selectedGatewayAtom); |   const selectedGateway = useAtomValue(selectedGatewayAtom)?.name; | ||||||
|   const switchGateway = useSetAtom(switchGatewayAtom); |   const switchGateway = useSetAtom(switchGatewayAtom); | ||||||
|  |  | ||||||
|   const handleClose = () => { |   const handleClose = () => { | ||||||
|   | |||||||
| @@ -43,14 +43,12 @@ export default function SettingsPanel() { | |||||||
|               value="simulation" |               value="simulation" | ||||||
|               icon={<Devices />} |               icon={<Devices />} | ||||||
|               iconPosition="start" |               iconPosition="start" | ||||||
|               sx={{ textTransform: "none" }} |  | ||||||
|             /> |             /> | ||||||
|             <Tab |             <Tab | ||||||
|               label="OpenSSL" |               label="OpenSSL" | ||||||
|               value="openssl" |               value="openssl" | ||||||
|               icon={<Https />} |               icon={<Https />} | ||||||
|               iconPosition="start" |               iconPosition="start" | ||||||
|               sx={{ textTransform: "none" }} |  | ||||||
|             /> |             /> | ||||||
|           </TabList> |           </TabList> | ||||||
|           <Box sx={{ flex: 1 }}> |           <Box sx={{ flex: 1 }}> | ||||||
| @@ -61,12 +59,8 @@ export default function SettingsPanel() { | |||||||
|       </Box> |       </Box> | ||||||
|       <Box sx={{ flexShrink: 0, borderTop: 1, borderColor: "divider" }}> |       <Box sx={{ flexShrink: 0, borderTop: 1, borderColor: "divider" }}> | ||||||
|         <DialogActions> |         <DialogActions> | ||||||
|           <Button sx={{ textTransform: "none" }} onClick={closeWindow}> |           <Button onClick={closeWindow}>Cancel</Button> | ||||||
|             Cancel |           <Button onClick={save}>Save</Button> | ||||||
|           </Button> |  | ||||||
|           <Button sx={{ textTransform: "none" }} onClick={save}> |  | ||||||
|             Save |  | ||||||
|           </Button> |  | ||||||
|         </DialogActions> |         </DialogActions> | ||||||
|       </Box> |       </Box> | ||||||
|     </Box> |     </Box> | ||||||
|   | |||||||
| @@ -1,4 +1,6 @@ | |||||||
| import { Box } from "@mui/material"; | import { Box } from "@mui/material"; | ||||||
|  | import { useAtomValue } from "jotai"; | ||||||
|  | import { appDataAtom } from "../atoms/portal"; | ||||||
| import { renderToRoot } from "../components/AppShell"; | import { renderToRoot } from "../components/AppShell"; | ||||||
| import ConnectForm from "../components/ConnectForm"; | import ConnectForm from "../components/ConnectForm"; | ||||||
| import ConnectionStatus from "../components/ConnectionStatus"; | import ConnectionStatus from "../components/ConnectionStatus"; | ||||||
| @@ -8,6 +10,10 @@ import MainMenu from "../components/MainMenu"; | |||||||
| import Notification from "../components/Notification"; | import Notification from "../components/Notification"; | ||||||
|  |  | ||||||
| export default function App() { | export default function App() { | ||||||
|  |   // Use the this atom to trigger loading data from the storage | ||||||
|  |   // And render the loading indicator | ||||||
|  |   useAtomValue(appDataAtom); | ||||||
|  |  | ||||||
|   return ( |   return ( | ||||||
|     <Box data-tauri-drag-region padding={2} paddingBottom={0}> |     <Box data-tauri-drag-region padding={2} paddingBottom={0}> | ||||||
|       <MainMenu /> |       <MainMenu /> | ||||||
|   | |||||||
| @@ -1,5 +1,6 @@ | |||||||
| import { emit, listen } from "@tauri-apps/api/event"; | import { emit, listen } from "@tauri-apps/api/event"; | ||||||
| import invokeCommand from "../utils/invokeCommand"; | import invokeCommand from "../utils/invokeCommand"; | ||||||
|  | import settingsService from "./settingsService"; | ||||||
|  |  | ||||||
| export type AuthData = { | export type AuthData = { | ||||||
|   username: string; |   username: string; | ||||||
| @@ -30,9 +31,12 @@ class AuthService { | |||||||
|  |  | ||||||
|   // binding: "POST" | "REDIRECT" |   // binding: "POST" | "REDIRECT" | ||||||
|   async samlLogin(binding: string, request: string, clearCookies: boolean) { |   async samlLogin(binding: string, request: string, clearCookies: boolean) { | ||||||
|  |     const { userAgent } = await settingsService.getSimulation(); | ||||||
|  |  | ||||||
|     return invokeCommand<AuthData>("saml_login", { |     return invokeCommand<AuthData>("saml_login", { | ||||||
|       binding, |       binding, | ||||||
|       request, |       request, | ||||||
|  |       userAgent: `${userAgent} ${navigator.userAgent}`, | ||||||
|       clearCookies, |       clearCookies, | ||||||
|     }); |     }); | ||||||
|   } |   } | ||||||
|   | |||||||
| @@ -1,5 +1,6 @@ | |||||||
| import { Body, ResponseType, fetch } from "@tauri-apps/api/http"; | import { Body, ResponseType, fetch } from "@tauri-apps/api/http"; | ||||||
| import { parseXml } from "../utils/parseXml"; | import { parseXml } from "../utils/parseXml"; | ||||||
|  | import settingsService from "./settingsService"; | ||||||
|  |  | ||||||
| type LoginParams = { | type LoginParams = { | ||||||
|   user: string; |   user: string; | ||||||
| @@ -15,6 +16,9 @@ class GatewayService { | |||||||
|       throw new Error("Gateway address is required"); |       throw new Error("Gateway address is required"); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     const { userAgent, clientOS, osVersion } = | ||||||
|  |       await settingsService.getSimulation(); | ||||||
|  |  | ||||||
|     const loginUrl = `https://${gateway}/ssl-vpn/login.esp`; |     const loginUrl = `https://${gateway}/ssl-vpn/login.esp`; | ||||||
|     const body = Body.form({ |     const body = Body.form({ | ||||||
|       prot: "https:", |       prot: "https:", | ||||||
| @@ -25,8 +29,8 @@ class GatewayService { | |||||||
|       direct: "yes", |       direct: "yes", | ||||||
|       "ipv6-support": "yes", |       "ipv6-support": "yes", | ||||||
|       clientVer: "4100", |       clientVer: "4100", | ||||||
|       clientos: "Linux", |       clientos: clientOS, | ||||||
|       "os-version": "Linux", |       "os-version": osVersion, | ||||||
|       server: gateway, |       server: gateway, | ||||||
|       user, |       user, | ||||||
|       passwd: passwd || "", |       passwd: passwd || "", | ||||||
| @@ -38,7 +42,7 @@ class GatewayService { | |||||||
|     const response = await fetch<string>(loginUrl, { |     const response = await fetch<string>(loginUrl, { | ||||||
|       method: "POST", |       method: "POST", | ||||||
|       headers: { |       headers: { | ||||||
|         "User-Agent": "PAN GlobalProtect", |         "User-Agent": userAgent, | ||||||
|       }, |       }, | ||||||
|       responseType: ResponseType.Text, |       responseType: ResponseType.Text, | ||||||
|       body, |       body, | ||||||
|   | |||||||
| @@ -2,6 +2,7 @@ import { Body, ResponseType, fetch } from "@tauri-apps/api/http"; | |||||||
| import ErrorWithTitle from "../utils/ErrorWithTitle"; | import ErrorWithTitle from "../utils/ErrorWithTitle"; | ||||||
| import { parseXml } from "../utils/parseXml"; | import { parseXml } from "../utils/parseXml"; | ||||||
| import { Gateway } from "./types"; | import { Gateway } from "./types"; | ||||||
|  | import settingsService from "./settingsService"; | ||||||
|  |  | ||||||
| export type SamlPrelogin = { | export type SamlPrelogin = { | ||||||
|   isSamlAuth: true; |   isSamlAuth: true; | ||||||
| @@ -37,12 +38,15 @@ export type PortalCredential = { | |||||||
| class PortalService { | class PortalService { | ||||||
|   async prelogin(portal: string): Promise<Prelogin> { |   async prelogin(portal: string): Promise<Prelogin> { | ||||||
|     const preloginUrl = `https://${portal}/global-protect/prelogin.esp`; |     const preloginUrl = `https://${portal}/global-protect/prelogin.esp`; | ||||||
|  |     const { userAgent, clientOS, osVersion } = | ||||||
|  |       await settingsService.getSimulation(); | ||||||
|  |  | ||||||
|     let response; |     let response; | ||||||
|     try { |     try { | ||||||
|       response = await fetch<string>(preloginUrl, { |       response = await fetch<string>(preloginUrl, { | ||||||
|         method: "POST", |         method: "POST", | ||||||
|         headers: { |         headers: { | ||||||
|           "User-Agent": "PAN GlobalProtect", |           "User-Agent": userAgent, | ||||||
|         }, |         }, | ||||||
|         responseType: ResponseType.Text, |         responseType: ResponseType.Text, | ||||||
|         query: { |         query: { | ||||||
| @@ -51,8 +55,8 @@ class PortalService { | |||||||
|         body: Body.form({ |         body: Body.form({ | ||||||
|           tmp: "tmp", |           tmp: "tmp", | ||||||
|           clientVer: "4100", |           clientVer: "4100", | ||||||
|           clientos: "Linux", |           clientos: clientOS, | ||||||
|           "os-version": "Linux", |           "os-version": osVersion, | ||||||
|           "ipv6-support": "yes", |           "ipv6-support": "yes", | ||||||
|           "default-browser": "0", |           "default-browser": "0", | ||||||
|           "cas-support": "yes", |           "cas-support": "yes", | ||||||
| @@ -118,6 +122,9 @@ class PortalService { | |||||||
|   } |   } | ||||||
|  |  | ||||||
|   async fetchConfig(portal: string, params: PortalCredential) { |   async fetchConfig(portal: string, params: PortalCredential) { | ||||||
|  |     const { userAgent, clientOS, osVersion, clientVersion } = | ||||||
|  |       await settingsService.getSimulation(); | ||||||
|  |  | ||||||
|     const { |     const { | ||||||
|       user, |       user, | ||||||
|       passwd, |       passwd, | ||||||
| @@ -132,12 +139,12 @@ class PortalService { | |||||||
|       inputStr: "", |       inputStr: "", | ||||||
|       jnlpReady: "jnlpReady", |       jnlpReady: "jnlpReady", | ||||||
|       computer: "Linux", // TODO |       computer: "Linux", // TODO | ||||||
|       clientos: "Linux", |       clientos: clientOS, | ||||||
|       ok: "Login", |       ok: "Login", | ||||||
|       direct: "yes", |       direct: "yes", | ||||||
|       clientVer: "4100", |       clientVer: "4100", | ||||||
|       "os-version": "Linux", |       "os-version": osVersion, | ||||||
|       clientgpversion: "6.0.1-19", |       clientgpversion: clientVersion, | ||||||
|       "ipv6-support": "yes", |       "ipv6-support": "yes", | ||||||
|       server: portal, |       server: portal, | ||||||
|       host: portal, |       host: portal, | ||||||
| @@ -151,7 +158,7 @@ class PortalService { | |||||||
|     const response = await fetch<string>(configUrl, { |     const response = await fetch<string>(configUrl, { | ||||||
|       method: "POST", |       method: "POST", | ||||||
|       headers: { |       headers: { | ||||||
|         "User-Agent": "PAN GlobalProtect", |         "User-Agent": userAgent, | ||||||
|       }, |       }, | ||||||
|       responseType: ResponseType.Text, |       responseType: ResponseType.Text, | ||||||
|       body, |       body, | ||||||
| @@ -166,8 +173,6 @@ class PortalService { | |||||||
|   } |   } | ||||||
|  |  | ||||||
|   private parsePortalConfigResponse(response: string): PortalConfig { |   private parsePortalConfigResponse(response: string): PortalConfig { | ||||||
|     // console.log(response); |  | ||||||
|  |  | ||||||
|     const result = parseXml(response); |     const result = parseXml(response); | ||||||
|     const gateways = result.all("gateways list > entry").map((entry) => { |     const gateways = result.all("gateways list > entry").map((entry) => { | ||||||
|       const address = entry.attr("name"); |       const address = entry.attr("name"); | ||||||
|   | |||||||
| @@ -1,6 +1,6 @@ | |||||||
| import { UserAttentionType, WebviewWindow } from "@tauri-apps/api/window"; | import { UserAttentionType, WebviewWindow } from "@tauri-apps/api/window"; | ||||||
| import invokeCommand from "../utils/invokeCommand"; | import invokeCommand from "../utils/invokeCommand"; | ||||||
| import { appStore } from "./storeService"; | import { appStorage } from "./storageService"; | ||||||
|  |  | ||||||
| export type TabValue = "simulation" | "openssl"; | export type TabValue = "simulation" | "openssl"; | ||||||
| const SETTINGS_WINDOW_LABEL = "settings"; | const SETTINGS_WINDOW_LABEL = "settings"; | ||||||
| @@ -68,9 +68,10 @@ export const DEFAULT_SETTINGS_DATA: SettingsData = { | |||||||
|   customOpenSSL: false, |   customOpenSSL: false, | ||||||
| }; | }; | ||||||
|  |  | ||||||
| async function getSimulationSettings(): Promise<SimulationSettings> { | async function getSimulation(): Promise<SimulationSettings> { | ||||||
|   const { clientOS, osVersion, clientVersion } = |   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(); |   const currentOsVersion = await getCurrentOsVersion(); | ||||||
|  |  | ||||||
|   return { |   return { | ||||||
| @@ -81,8 +82,8 @@ async function getSimulationSettings(): Promise<SimulationSettings> { | |||||||
|       clientVersion |       clientVersion | ||||||
|     ), |     ), | ||||||
|     clientOS, |     clientOS, | ||||||
|     osVersion, |     osVersion: determineOsVersion(clientOS, osVersion, currentOsVersion), | ||||||
|     clientVersion, |     clientVersion: clientVersion || DEFAULT_CLIENT_VERSION, | ||||||
|   }; |   }; | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -131,7 +132,7 @@ export default { | |||||||
|   openSettings, |   openSettings, | ||||||
|   closeSettings, |   closeSettings, | ||||||
|   getCurrentOsVersion, |   getCurrentOsVersion, | ||||||
|   getSimulationSettings, |   getSimulation, | ||||||
|   buildUserAgent, |   buildUserAgent, | ||||||
|   determineOsVersion, |   determineOsVersion, | ||||||
|   getOpenSSLConfig, |   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 { Event, listen } from "@tauri-apps/api/event"; | ||||||
| import invokeCommand from "../utils/invokeCommand"; | import invokeCommand from "../utils/invokeCommand"; | ||||||
|  | import settingsService from "./settingsService"; | ||||||
|  |  | ||||||
| type VpnStatus = "disconnected" | "connecting" | "connected" | "disconnecting"; | type VpnStatus = "disconnected" | "connecting" | "connected" | "disconnecting"; | ||||||
| type VpnStatusCallback = (status: VpnStatus) => void; | type VpnStatusCallback = (status: VpnStatus) => void; | ||||||
| @@ -64,7 +65,8 @@ class VpnService { | |||||||
|   } |   } | ||||||
|  |  | ||||||
|   async connect(server: string, cookie: string) { |   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() { |   async disconnect() { | ||||||
|   | |||||||
| @@ -8,8 +8,9 @@ edition = "2021" | |||||||
| [dependencies] | [dependencies] | ||||||
| gpcommon = { path = "../gpcommon" } | gpcommon = { path = "../gpcommon" } | ||||||
| tokio = { version = "1", features = ["full"] } | tokio = { version = "1", features = ["full"] } | ||||||
| env_logger = "0.10" |  | ||||||
| log = "0.4" | log = "0.4" | ||||||
|  | fern = "0.6" | ||||||
|  | humantime = "2.1" | ||||||
| # warp = "0.3" | # warp = "0.3" | ||||||
| # aes-gcm = "0.10" | # aes-gcm = "0.10" | ||||||
| # procfs = "0.15" | # procfs = "0.15" | ||||||
|   | |||||||
| @@ -1,9 +1,8 @@ | |||||||
| include!(concat!(env!("OUT_DIR"), "/client_hash.rs")); | include!(concat!(env!("OUT_DIR"), "/client_hash.rs")); | ||||||
|  |  | ||||||
| // use aes_gcm::{aead::OsRng, Aes256Gcm, KeyInit}; |  | ||||||
| use gpcommon::{server, SOCKET_PATH}; | use gpcommon::{server, SOCKET_PATH}; | ||||||
| use env_logger::Env; |  | ||||||
| use log::error; | use log::error; | ||||||
|  | use std::fs::File; | ||||||
| use tokio::signal; | use tokio::signal; | ||||||
|  |  | ||||||
| // static mut HTTP_PORT: u16 = 0; | // static mut HTTP_PORT: u16 = 0; | ||||||
| @@ -96,10 +95,10 @@ use tokio::signal; | |||||||
| //     println!("Shutting down http server"); | //     println!("Shutting down http server"); | ||||||
| // } | // } | ||||||
|  |  | ||||||
|  | const LOG_FILE: &str = "/var/log/gpservice.log"; | ||||||
|  |  | ||||||
| #[tokio::main] | #[tokio::main] | ||||||
| async fn main() -> Result<(), Box<dyn std::error::Error>> { | async fn main() -> Result<(), Box<dyn std::error::Error>> { | ||||||
|     env_logger::Builder::from_env(Env::default().default_filter_or("info")).init(); |  | ||||||
|  |  | ||||||
|     // println!("{GPCLIENT_HASH}"); |     // println!("{GPCLIENT_HASH}"); | ||||||
|  |  | ||||||
|     // unsafe { |     // unsafe { | ||||||
| @@ -110,6 +109,22 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> { | |||||||
|     // start_http_server().await; |     // start_http_server().await; | ||||||
|     // server::start().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 { |     if let Err(err) = server::run(SOCKET_PATH, signal::ctrl_c()).await { | ||||||
|         error!("Error running server: {}", err); |         error!("Error running server: {}", err); | ||||||
|     } |     } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user