feat: authentication
This commit is contained in:
parent
76c294b709
commit
c30bfdb2eb
14 changed files with 501 additions and 50 deletions
3
.vscode/settings.json
vendored
3
.vscode/settings.json
vendored
|
@ -4,7 +4,8 @@
|
|||
"node_modules": true,
|
||||
".svelte-kit": true,
|
||||
"**/target": true,
|
||||
"build": true
|
||||
"build": true,
|
||||
"src-tauri/gen": true
|
||||
},
|
||||
"rust-analyzer.linkedProjects": [
|
||||
"src-tauri/Cargo.toml"
|
||||
|
|
2
justfile
2
justfile
|
@ -14,4 +14,4 @@ cargo +cmd:
|
|||
|
||||
[doc('Run tauri command')]
|
||||
tauri +cmd:
|
||||
pnpm run tauri {cmd}
|
||||
pnpm run tauri {{cmd}}
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@tauri-apps/api": "^2",
|
||||
"@tauri-apps/plugin-http": "~2",
|
||||
"@tauri-apps/plugin-shell": "^2"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
|
|
@ -11,6 +11,9 @@ importers:
|
|||
'@tauri-apps/api':
|
||||
specifier: ^2
|
||||
version: 2.1.1
|
||||
'@tauri-apps/plugin-http':
|
||||
specifier: ~2
|
||||
version: 2.0.1
|
||||
'@tauri-apps/plugin-shell':
|
||||
specifier: ^2
|
||||
version: 2.0.1
|
||||
|
@ -439,6 +442,9 @@ packages:
|
|||
engines: {node: '>= 10'}
|
||||
hasBin: true
|
||||
|
||||
'@tauri-apps/plugin-http@2.0.1':
|
||||
resolution: {integrity: sha512-j6IA3pVBybSCwPpsihpX4z8bs6PluuGtr06ahL/xy4D8HunNBTmRmadJrFOQi0gOAbaig4MkQ15nzNLBLy8R1A==}
|
||||
|
||||
'@tauri-apps/plugin-shell@2.0.1':
|
||||
resolution: {integrity: sha512-akU1b77sw3qHiynrK0s930y8zKmcdrSD60htjH+mFZqv5WaakZA/XxHR3/sF1nNv9Mgmt/Shls37HwnOr00aSw==}
|
||||
|
||||
|
@ -1318,6 +1324,10 @@ snapshots:
|
|||
'@tauri-apps/cli-win32-ia32-msvc': 2.1.0
|
||||
'@tauri-apps/cli-win32-x64-msvc': 2.1.0
|
||||
|
||||
'@tauri-apps/plugin-http@2.0.1':
|
||||
dependencies:
|
||||
'@tauri-apps/api': 2.1.1
|
||||
|
||||
'@tauri-apps/plugin-shell@2.0.1':
|
||||
dependencies:
|
||||
'@tauri-apps/api': 2.1.1
|
||||
|
|
352
src-tauri/Cargo.lock
generated
352
src-tauri/Cargo.lock
generated
|
@ -85,6 +85,12 @@ dependencies = [
|
|||
"system-deps",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "atomic-waker"
|
||||
version = "1.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0"
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.4.0"
|
||||
|
@ -342,7 +348,7 @@ dependencies = [
|
|||
"bitflags 2.6.0",
|
||||
"block",
|
||||
"cocoa-foundation",
|
||||
"core-foundation",
|
||||
"core-foundation 0.10.0",
|
||||
"core-graphics",
|
||||
"foreign-types",
|
||||
"libc",
|
||||
|
@ -357,7 +363,7 @@ checksum = "e14045fb83be07b5acf1c0884b2180461635b433455fa35d1cd6f17f1450679d"
|
|||
dependencies = [
|
||||
"bitflags 2.6.0",
|
||||
"block",
|
||||
"core-foundation",
|
||||
"core-foundation 0.10.0",
|
||||
"core-graphics-types",
|
||||
"libc",
|
||||
"objc",
|
||||
|
@ -408,6 +414,16 @@ dependencies = [
|
|||
"url",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "core-foundation"
|
||||
version = "0.9.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f"
|
||||
dependencies = [
|
||||
"core-foundation-sys",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "core-foundation"
|
||||
version = "0.10.0"
|
||||
|
@ -431,7 +447,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "fa95a34622365fa5bbf40b20b75dba8dfa8c94c734aea8ac9a5ca38af14316f1"
|
||||
dependencies = [
|
||||
"bitflags 2.6.0",
|
||||
"core-foundation",
|
||||
"core-foundation 0.10.0",
|
||||
"core-graphics-types",
|
||||
"foreign-types",
|
||||
"libc",
|
||||
|
@ -444,7 +460,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "3d44a101f213f6c4cdc1853d4b78aef6db6bdfa3468798cc1d9912f4735013eb"
|
||||
dependencies = [
|
||||
"bitflags 2.6.0",
|
||||
"core-foundation",
|
||||
"core-foundation 0.10.0",
|
||||
"libc",
|
||||
]
|
||||
|
||||
|
@ -563,6 +579,12 @@ dependencies = [
|
|||
"syn 2.0.89",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "data-url"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c297a1c74b71ae29df00c3e22dd9534821d60eb9af5a0192823fa2acea70c2a"
|
||||
|
||||
[[package]]
|
||||
name = "deranged"
|
||||
version = "0.3.11"
|
||||
|
@ -707,14 +729,15 @@ name = "echoed"
|
|||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"regex",
|
||||
"reqwest",
|
||||
"reqwest_cookie_store",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tauri",
|
||||
"tauri-build",
|
||||
"tauri-plugin-http",
|
||||
"tauri-plugin-shell",
|
||||
"thiserror 2.0.3",
|
||||
"url",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1068,8 +1091,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"js-sys",
|
||||
"libc",
|
||||
"wasi 0.11.0+wasi-snapshot-preview1",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1226,6 +1251,25 @@ dependencies = [
|
|||
"syn 2.0.89",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "h2"
|
||||
version = "0.4.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ccae279728d634d083c00f6099cb58f01cc99c145b84b8be2f6c74618d79922e"
|
||||
dependencies = [
|
||||
"atomic-waker",
|
||||
"bytes",
|
||||
"fnv",
|
||||
"futures-core",
|
||||
"futures-sink",
|
||||
"http",
|
||||
"indexmap 2.6.0",
|
||||
"slab",
|
||||
"tokio",
|
||||
"tokio-util",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.12.3"
|
||||
|
@ -1325,6 +1369,7 @@ dependencies = [
|
|||
"bytes",
|
||||
"futures-channel",
|
||||
"futures-util",
|
||||
"h2",
|
||||
"http",
|
||||
"http-body",
|
||||
"httparse",
|
||||
|
@ -1335,6 +1380,24 @@ dependencies = [
|
|||
"want",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hyper-rustls"
|
||||
version = "0.27.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "08afdbb5c31130e3034af566421053ab03787c640246a446327f550d11bcb333"
|
||||
dependencies = [
|
||||
"futures-util",
|
||||
"http",
|
||||
"hyper",
|
||||
"hyper-util",
|
||||
"rustls",
|
||||
"rustls-pki-types",
|
||||
"tokio",
|
||||
"tokio-rustls",
|
||||
"tower-service",
|
||||
"webpki-roots",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hyper-util"
|
||||
version = "0.1.10"
|
||||
|
@ -2591,6 +2654,58 @@ dependencies = [
|
|||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quinn"
|
||||
version = "0.11.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "62e96808277ec6f97351a2380e6c25114bc9e67037775464979f3037c92d05ef"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"pin-project-lite",
|
||||
"quinn-proto",
|
||||
"quinn-udp",
|
||||
"rustc-hash",
|
||||
"rustls",
|
||||
"socket2",
|
||||
"thiserror 2.0.3",
|
||||
"tokio",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quinn-proto"
|
||||
version = "0.11.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a2fe5ef3495d7d2e377ff17b1a8ce2ee2ec2a18cde8b6ad6619d65d0701c135d"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"getrandom 0.2.15",
|
||||
"rand 0.8.5",
|
||||
"ring",
|
||||
"rustc-hash",
|
||||
"rustls",
|
||||
"rustls-pki-types",
|
||||
"slab",
|
||||
"thiserror 2.0.3",
|
||||
"tinyvec",
|
||||
"tracing",
|
||||
"web-time",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quinn-udp"
|
||||
version = "0.5.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7d5a626c6807713b15cac82a6acaccd6043c9a5408c24baae07611fec3f243da"
|
||||
dependencies = [
|
||||
"cfg_aliases",
|
||||
"libc",
|
||||
"once_cell",
|
||||
"socket2",
|
||||
"tracing",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.37"
|
||||
|
@ -2746,12 +2861,15 @@ dependencies = [
|
|||
"bytes",
|
||||
"cookie",
|
||||
"cookie_store",
|
||||
"encoding_rs",
|
||||
"futures-core",
|
||||
"futures-util",
|
||||
"h2",
|
||||
"http",
|
||||
"http-body",
|
||||
"http-body-util",
|
||||
"hyper",
|
||||
"hyper-rustls",
|
||||
"hyper-util",
|
||||
"ipnet",
|
||||
"js-sys",
|
||||
|
@ -2761,11 +2879,17 @@ dependencies = [
|
|||
"once_cell",
|
||||
"percent-encoding",
|
||||
"pin-project-lite",
|
||||
"quinn",
|
||||
"rustls",
|
||||
"rustls-pemfile",
|
||||
"rustls-pki-types",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_urlencoded",
|
||||
"sync_wrapper",
|
||||
"system-configuration",
|
||||
"tokio",
|
||||
"tokio-rustls",
|
||||
"tokio-util",
|
||||
"tower-service",
|
||||
"url",
|
||||
|
@ -2773,6 +2897,7 @@ dependencies = [
|
|||
"wasm-bindgen-futures",
|
||||
"wasm-streams",
|
||||
"web-sys",
|
||||
"webpki-roots",
|
||||
"windows-registry",
|
||||
]
|
||||
|
||||
|
@ -2788,12 +2913,33 @@ dependencies = [
|
|||
"url",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ring"
|
||||
version = "0.17.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"cfg-if",
|
||||
"getrandom 0.2.15",
|
||||
"libc",
|
||||
"spin",
|
||||
"untrusted",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc-demangle"
|
||||
version = "0.1.24"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f"
|
||||
|
||||
[[package]]
|
||||
name = "rustc-hash"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "583034fd73374156e66797ed8e5b0d5690409c9226b22d87cb7f19821c05d152"
|
||||
|
||||
[[package]]
|
||||
name = "rustc_version"
|
||||
version = "0.4.1"
|
||||
|
@ -2803,6 +2949,49 @@ dependencies = [
|
|||
"semver",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustls"
|
||||
version = "0.23.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c9cc1d47e243d655ace55ed38201c19ae02c148ae56412ab8750e8f0166ab7f"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
"ring",
|
||||
"rustls-pki-types",
|
||||
"rustls-webpki",
|
||||
"subtle",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustls-pemfile"
|
||||
version = "2.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50"
|
||||
dependencies = [
|
||||
"rustls-pki-types",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustls-pki-types"
|
||||
version = "1.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "16f1201b3c9a7ee8039bcadc17b7e605e2945b27eee7631788c1bd2b0643674b"
|
||||
dependencies = [
|
||||
"web-time",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustls-webpki"
|
||||
version = "0.102.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9"
|
||||
dependencies = [
|
||||
"ring",
|
||||
"rustls-pki-types",
|
||||
"untrusted",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.18"
|
||||
|
@ -3140,6 +3329,12 @@ dependencies = [
|
|||
"system-deps",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "spin"
|
||||
version = "0.9.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
|
||||
|
||||
[[package]]
|
||||
name = "stable_deref_trait"
|
||||
version = "1.2.0"
|
||||
|
@ -3178,6 +3373,12 @@ version = "0.11.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
|
||||
|
||||
[[package]]
|
||||
name = "subtle"
|
||||
version = "2.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
|
||||
|
||||
[[package]]
|
||||
name = "swift-rs"
|
||||
version = "1.0.7"
|
||||
|
@ -3231,6 +3432,27 @@ dependencies = [
|
|||
"syn 2.0.89",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "system-configuration"
|
||||
version = "0.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b"
|
||||
dependencies = [
|
||||
"bitflags 2.6.0",
|
||||
"core-foundation 0.9.4",
|
||||
"system-configuration-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "system-configuration-sys"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4"
|
||||
dependencies = [
|
||||
"core-foundation-sys",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "system-deps"
|
||||
version = "6.2.2"
|
||||
|
@ -3252,7 +3474,7 @@ checksum = "6682a07cf5bab0b8a2bd20d0a542917ab928b5edb75ebd4eda6b05cbaab872da"
|
|||
dependencies = [
|
||||
"bitflags 2.6.0",
|
||||
"cocoa",
|
||||
"core-foundation",
|
||||
"core-foundation 0.10.0",
|
||||
"core-graphics",
|
||||
"crossbeam-channel",
|
||||
"dispatch",
|
||||
|
@ -3430,6 +3652,49 @@ dependencies = [
|
|||
"walkdir",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tauri-plugin-fs"
|
||||
version = "2.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "96ba7d46e86db8c830d143ef90ab5a453328365b0cc834c24edea4267b16aba0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"dunce",
|
||||
"glob",
|
||||
"percent-encoding",
|
||||
"schemars",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_repr",
|
||||
"tauri",
|
||||
"tauri-plugin",
|
||||
"thiserror 1.0.69",
|
||||
"url",
|
||||
"uuid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tauri-plugin-http"
|
||||
version = "2.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c752aee1b00ec3c4d4f440095995d9bd2c640b478f2067d1fba388900b82eb96"
|
||||
dependencies = [
|
||||
"data-url",
|
||||
"http",
|
||||
"regex",
|
||||
"reqwest",
|
||||
"schemars",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tauri",
|
||||
"tauri-plugin",
|
||||
"tauri-plugin-fs",
|
||||
"thiserror 1.0.69",
|
||||
"tokio",
|
||||
"url",
|
||||
"urlpattern",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tauri-plugin-shell"
|
||||
version = "2.0.2"
|
||||
|
@ -3641,6 +3906,21 @@ dependencies = [
|
|||
"zerovec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tinyvec"
|
||||
version = "1.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938"
|
||||
dependencies = [
|
||||
"tinyvec_macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tinyvec_macros"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
|
||||
|
||||
[[package]]
|
||||
name = "tokio"
|
||||
version = "1.41.1"
|
||||
|
@ -3653,9 +3933,32 @@ dependencies = [
|
|||
"mio",
|
||||
"pin-project-lite",
|
||||
"socket2",
|
||||
"tokio-macros",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-macros"
|
||||
version = "2.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.89",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-rustls"
|
||||
version = "0.26.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4"
|
||||
dependencies = [
|
||||
"rustls",
|
||||
"rustls-pki-types",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-util"
|
||||
version = "0.7.12"
|
||||
|
@ -3852,10 +4155,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493"
|
||||
|
||||
[[package]]
|
||||
name = "url"
|
||||
version = "2.5.3"
|
||||
name = "untrusted"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8d157f1b96d14500ffdc1f10ba712e780825526c03d9a49b4d0324b0d9113ada"
|
||||
checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1"
|
||||
|
||||
[[package]]
|
||||
name = "url"
|
||||
version = "2.5.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60"
|
||||
dependencies = [
|
||||
"form_urlencoded",
|
||||
"idna",
|
||||
|
@ -4056,6 +4365,16 @@ dependencies = [
|
|||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "web-time"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb"
|
||||
dependencies = [
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "webkit2gtk"
|
||||
version = "2.0.1"
|
||||
|
@ -4100,6 +4419,15 @@ dependencies = [
|
|||
"system-deps",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "webpki-roots"
|
||||
version = "0.26.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5d642ff16b7e79272ae451b7322067cdc17cadf68c23264be9d94a32319efe7e"
|
||||
dependencies = [
|
||||
"rustls-pki-types",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "webview2-com"
|
||||
version = "0.33.0"
|
||||
|
@ -4649,6 +4977,12 @@ dependencies = [
|
|||
"synstructure",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zeroize"
|
||||
version = "1.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde"
|
||||
|
||||
[[package]]
|
||||
name = "zerovec"
|
||||
version = "0.10.4"
|
||||
|
|
|
@ -18,10 +18,11 @@ tauri = { version = "2", features = [] }
|
|||
tauri-plugin-shell = "2"
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
serde_json = "1"
|
||||
reqwest = { version = "0.12.9", default-features = false, features = ["json", "multipart"] }
|
||||
reqwest_cookie_store = { path = "../reqwest_cookie_store_tokio" }
|
||||
thiserror = "2.0.3"
|
||||
regex = { version = "1.11.1", default-features = false, features = ["perf", "std"] }
|
||||
url = { version = "2.5.4", default-features = false }
|
||||
tauri-plugin-http = { version = "2", features = ["multipart", "json"] }
|
||||
|
||||
[profile.dev]
|
||||
incremental = true # Compile your binary in smaller steps.
|
||||
|
|
|
@ -2,9 +2,12 @@
|
|||
"$schema": "../gen/schemas/desktop-schema.json",
|
||||
"identifier": "default",
|
||||
"description": "Capability for the main window",
|
||||
"windows": ["main"],
|
||||
"windows": [
|
||||
"main"
|
||||
],
|
||||
"permissions": [
|
||||
"core:default",
|
||||
"shell:allow-open"
|
||||
"shell:allow-open",
|
||||
"http:default"
|
||||
]
|
||||
}
|
||||
}
|
1
src-tauri/src/commands.rs
Normal file
1
src-tauri/src/commands.rs
Normal file
|
@ -0,0 +1 @@
|
|||
pub mod auth;
|
89
src-tauri/src/commands/auth.rs
Normal file
89
src-tauri/src/commands/auth.rs
Normal file
|
@ -0,0 +1,89 @@
|
|||
use crate::prelude::*;
|
||||
use tauri_plugin_http::reqwest::multipart::Form;
|
||||
use url::Url;
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum Error {
|
||||
#[error("Failed to find {0}.")]
|
||||
Find(&'static str),
|
||||
|
||||
#[error("Invalid details.")]
|
||||
InvalidDetails,
|
||||
|
||||
#[error("Invalid URL.")]
|
||||
InvalidUrl,
|
||||
}
|
||||
|
||||
/// Authenticate with echo360
|
||||
#[command]
|
||||
pub async fn authenticate(
|
||||
email: Cow<'static, str>,
|
||||
password: Cow<'static, str>,
|
||||
url: Cow<'static, str>,
|
||||
state: State<'_>,
|
||||
) -> Result<()> {
|
||||
let tauri_state = state;
|
||||
let state = state.lock().await;
|
||||
let parsed_url = Url::parse(&url)?;
|
||||
let domain = parsed_url.domain().ok_or(Error::InvalidUrl)?;
|
||||
|
||||
// get csrf token
|
||||
state.client.get(url.to_string()).send().await?;
|
||||
|
||||
let csrf_token = state
|
||||
.jar
|
||||
.lock()
|
||||
.await
|
||||
.get(domain, "/", "PLAY_SESSION")
|
||||
.map(|cookie| {
|
||||
let value = cookie.value().to_string();
|
||||
value
|
||||
.split('&')
|
||||
.nth(1)
|
||||
.map(|part| part.split('=').last())
|
||||
.flatten()
|
||||
.map(|x| x.to_string())
|
||||
})
|
||||
.flatten()
|
||||
.ok_or(Error::Find("CSRF token"))?;
|
||||
|
||||
// authenticate
|
||||
state
|
||||
.client
|
||||
.post(format!("{}/login", url))
|
||||
.query(&[("csrfToken", csrf_token)])
|
||||
.multipart(Form::new().text("email", email).text("password", password))
|
||||
.send()
|
||||
.await?;
|
||||
|
||||
// check if authentication was successful
|
||||
drop(state);
|
||||
if is_authenticated(url, tauri_state).await? {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(Error::InvalidDetails.into())
|
||||
}
|
||||
}
|
||||
|
||||
/// Check if the user is authenticated with echo360
|
||||
#[command]
|
||||
pub async fn is_authenticated(url: Cow<'static, str>, state: State<'_>) -> Result<bool> {
|
||||
let state = state.lock().await;
|
||||
|
||||
// fetch courses page
|
||||
let html = state
|
||||
.client
|
||||
.get(format!("{}/courses", url))
|
||||
.send()
|
||||
.await?
|
||||
.text()
|
||||
.await?;
|
||||
|
||||
// the courses page redirects to a sign in page if the user is not authenticated
|
||||
// if we can find the user's first name somewhere in the html, then the user must be authenticated
|
||||
let authenticated = regex::Regex::new(r#"\\"firstName\\":\\"(\w+)\\""#)?
|
||||
.captures(&html)
|
||||
.is_some();
|
||||
|
||||
Ok(authenticated)
|
||||
}
|
|
@ -1,10 +1,15 @@
|
|||
use reqwest_cookie_store::CookieStoreMutex;
|
||||
use std::sync::Arc;
|
||||
use tauri::async_runtime::Mutex;
|
||||
use tauri_plugin_http::reqwest;
|
||||
|
||||
// todo: reqwest client for each profile, or a way to swap the cookie jar used by a reqwest client
|
||||
/// Tauri application state
|
||||
pub struct AppState {
|
||||
/// Reqwest client connected to profile cookie jar
|
||||
pub client: reqwest::Client,
|
||||
/// Cookie jar attached to the reqwest client
|
||||
pub jar: Arc<CookieStoreMutex>,
|
||||
}
|
||||
|
||||
/// Wrapper around `tauri::State` to use custom app state.
|
||||
|
|
|
@ -1,13 +1,23 @@
|
|||
use crate::commands::*;
|
||||
|
||||
pub type Result<T, E = Error> = std::result::Result<T, E>;
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum Error {
|
||||
#[error(transparent)]
|
||||
Tauri(#[from] tauri::Error),
|
||||
|
||||
#[error(transparent)]
|
||||
Reqwest(#[from] reqwest::Error),
|
||||
#[error(transparent)]
|
||||
Http(#[from] tauri_plugin_http::reqwest::Error),
|
||||
|
||||
#[error("Failed to parse regex.")]
|
||||
Regex(#[from] regex::Error),
|
||||
|
||||
#[error("Failed to parse url.")]
|
||||
Url(#[from] url::ParseError),
|
||||
|
||||
#[error(transparent)]
|
||||
Auth(#[from] auth::Error),
|
||||
}
|
||||
|
||||
impl serde::Serialize for Error {
|
||||
|
|
|
@ -1,46 +1,23 @@
|
|||
use data::{AppState, State};
|
||||
use error::Result;
|
||||
use commands::auth::*;
|
||||
use data::AppState;
|
||||
use reqwest_cookie_store::CookieStoreMutex;
|
||||
use std::sync::Arc;
|
||||
use tauri::{async_runtime::Mutex, Manager};
|
||||
|
||||
mod commands;
|
||||
mod data;
|
||||
mod error;
|
||||
mod prelude;
|
||||
|
||||
#[macro_use]
|
||||
extern crate tauri;
|
||||
|
||||
const DEFAULT_ECHO360: &str = "https://echo360.org.uk";
|
||||
|
||||
/// Check if the user is authenticated with echo360
|
||||
#[command(rename_all = "snake_case")]
|
||||
async fn is_authenticated(state: State<'_>) -> Result<bool> {
|
||||
// get client
|
||||
let state = state.lock().await;
|
||||
|
||||
// fetch courses page
|
||||
let html = state
|
||||
.client
|
||||
.get(format!("{}/courses", DEFAULT_ECHO360))
|
||||
.send()
|
||||
.await?
|
||||
.text()
|
||||
.await?;
|
||||
|
||||
// the courses page redirects to a sign in page if the user is not authenticated
|
||||
// if we can find the user's first name somewhere in the html, then the user must be authenticated
|
||||
let authenticated = regex::Regex::new(r#"\\"firstName\\":\\"(\w+)\\""#)?
|
||||
.captures(&html)
|
||||
.is_some();
|
||||
|
||||
Ok(authenticated)
|
||||
}
|
||||
|
||||
#[cfg_attr(mobile, mobile_entry_point)]
|
||||
pub fn run() {
|
||||
tauri::Builder::default()
|
||||
.plugin(tauri_plugin_http::init())
|
||||
.plugin(tauri_plugin_shell::init())
|
||||
.invoke_handler(tauri::generate_handler![is_authenticated])
|
||||
.invoke_handler(tauri::generate_handler![authenticate, is_authenticated])
|
||||
.setup(|app| {
|
||||
// todo: load profile file, or create if it does not exist
|
||||
|
||||
|
@ -48,12 +25,12 @@ pub fn run() {
|
|||
// todo: load cookies into cookie jar
|
||||
//? https://docs.rs/tauri/1.8.1/tauri/api/path/fn.app_config_dir.html
|
||||
let jar = Arc::new(CookieStoreMutex::default());
|
||||
let client = reqwest::Client::builder()
|
||||
let client = tauri_plugin_http::reqwest::Client::builder()
|
||||
.cookie_provider(jar.clone())
|
||||
.build()?;
|
||||
|
||||
// store app state
|
||||
app.manage(Mutex::new(AppState { client }));
|
||||
app.manage(Mutex::new(AppState { client, jar }));
|
||||
|
||||
Ok(())
|
||||
})
|
||||
|
|
2
src-tauri/src/prelude.rs
Normal file
2
src-tauri/src/prelude.rs
Normal file
|
@ -0,0 +1,2 @@
|
|||
pub use crate::{data::State, error::Result};
|
||||
pub use std::borrow::Cow;
|
|
@ -1,7 +1,20 @@
|
|||
<script lang="ts">
|
||||
import { invoke } from "@tauri-apps/api/core";
|
||||
|
||||
let is_authenticated: Promise<boolean> = invoke("is_authenticated");
|
||||
let email = $state();
|
||||
let password = $state();
|
||||
// todo: ensure domain is valid
|
||||
let url = $state("https://echo360.org.uk");
|
||||
|
||||
// svelte-ignore state_referenced_locally
|
||||
let is_authenticated: Promise<boolean> = $state(invoke("is_authenticated", { url }));
|
||||
|
||||
async function login() {
|
||||
// todo: ensure email is valid
|
||||
// todo: ensure password is valid
|
||||
console.log(await invoke("authenticate", { email, password, url }));
|
||||
is_authenticated = invoke("is_authenticated", { url });
|
||||
}
|
||||
</script>
|
||||
|
||||
{#await is_authenticated}
|
||||
|
@ -10,7 +23,11 @@
|
|||
{#if authenticated}
|
||||
<h1 class="text-green-500">Authenticated</h1>
|
||||
{:else}
|
||||
<h1 class="text-red-500">Unauthenticated</h1>
|
||||
<form>
|
||||
<input type="email" bind:value={email} placeholder="Email" />
|
||||
<input type="password" bind:value={password} placeholder="Password" />
|
||||
<button onclick={login}>Login</button>
|
||||
</form>
|
||||
{/if}
|
||||
{/await}
|
||||
|
||||
|
|
Loading…
Reference in a new issue