From 134212399000851cc8c2417b8ce77172afa7e0e5 Mon Sep 17 00:00:00 2001 From: Nell Date: Fri, 20 Mar 2026 18:07:16 +0100 Subject: [PATCH] init --- resources/openapi.json | 1 + src-tauri/Cargo.lock | 1217 ++++++++++++++++++++--------- src-tauri/Cargo.toml | 14 +- src-tauri/src/api/client.rs | 247 ++++++ src-tauri/src/api/commands.rs | 133 ++++ src-tauri/src/api/mod.rs | 7 + src-tauri/src/api/models.rs | 115 +++ src-tauri/src/api/state.rs | 35 + src-tauri/src/app/mod.rs | 3 +- src-tauri/src/app/ox_speak_app.rs | 14 +- src-tauri/src/app/state.rs | 19 + src-tauri/src/config/commands.rs | 21 + src-tauri/src/config/config.rs | 46 +- src-tauri/src/config/mod.rs | 3 +- src-tauri/src/lib.rs | 3 +- src-tauri/src/tauri_app.rs | 37 +- src/api/README.md | 68 ++ src/api/client.ts | 53 ++ src/api/index.ts | 16 + src/api/tauri-client.ts | 83 ++ src/api/types.ts | 100 +++ src/config/README.md | 70 ++ src/config/client.ts | 80 ++ src/config/index.ts | 2 + src/config/types.ts | 18 + 25 files changed, 2023 insertions(+), 382 deletions(-) create mode 100644 resources/openapi.json create mode 100644 src-tauri/src/api/client.rs create mode 100644 src-tauri/src/api/commands.rs create mode 100644 src-tauri/src/api/mod.rs create mode 100644 src-tauri/src/api/models.rs create mode 100644 src-tauri/src/api/state.rs create mode 100644 src-tauri/src/app/state.rs create mode 100644 src-tauri/src/config/commands.rs create mode 100644 src/api/README.md create mode 100644 src/api/client.ts create mode 100644 src/api/index.ts create mode 100644 src/api/tauri-client.ts create mode 100644 src/api/types.ts create mode 100644 src/config/README.md create mode 100644 src/config/client.ts create mode 100644 src/config/index.ts create mode 100644 src/config/types.ts diff --git a/resources/openapi.json b/resources/openapi.json new file mode 100644 index 0000000..84887c5 --- /dev/null +++ b/resources/openapi.json @@ -0,0 +1 @@ +{"openapi":"3.1.0","info":{"title":"ox_speak_server","description":"","license":{"name":""},"version":"0.1.0"},"paths":{"/api/auth/claim-admin":{"post":{"tags":["auth"],"operationId":"claim_admin","responses":{"200":{"description":"Admin created successfully"},"400":{"description":"Bad request (token mismatch or user already exists)"},"500":{"description":"Internal server error"}}}},"/api/auth/login":{"post":{"tags":["auth"],"operationId":"login","responses":{"200":{"description":"Login successful","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LoginResponse"}}}},"401":{"description":"Unauthorized"}}}},"/api/auth/ssh-challenge":{"post":{"tags":["auth"],"operationId":"ssh_challenge","responses":{"200":{"description":"SSH Challenge generated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SshChallengeResponse"}}}},"404":{"description":"User not found"}}}},"/api/category":{"get":{"tags":["category"],"operationId":"category_list","parameters":[{"name":"server_id","in":"query","description":"Filter by server ID","required":false,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"List of categories","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/CategoryResponse"}}}}}}},"post":{"tags":["category"],"operationId":"category_create","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateCategoryRequest"}}},"required":true},"responses":{"200":{"description":"Category created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CategoryResponse"}}}},"403":{"description":"Forbidden"}}}},"/api/category/{id}":{"get":{"tags":["category"],"operationId":"category_detail","parameters":[{"name":"id","in":"path","description":"Category ID","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Category details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CategoryResponse"}}}},"404":{"description":"Category not found"}}},"put":{"tags":["category"],"operationId":"category_update","parameters":[{"name":"id","in":"path","description":"Category ID","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateCategoryRequest"}}},"required":true},"responses":{"200":{"description":"Category updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CategoryResponse"}}}},"403":{"description":"Forbidden"},"404":{"description":"Category not found"}}},"delete":{"tags":["category"],"operationId":"category_delete","parameters":[{"name":"id","in":"path","description":"Category ID","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"Category deleted"},"403":{"description":"Forbidden"},"404":{"description":"Category not found"}}}},"/api/channel":{"get":{"tags":["channel"],"operationId":"channel_list","responses":{"200":{"description":"List of all channels","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ChannelResponse"}}}}}}},"post":{"tags":["channel"],"operationId":"channel_create","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateChannelRequest"}}},"required":true},"responses":{"200":{"description":"Channel created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChannelResponse"}}}},"403":{"description":"Forbidden"}}}},"/api/channel/{id}":{"get":{"tags":["channel"],"operationId":"channel_detail","parameters":[{"name":"id","in":"path","description":"Channel ID","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Channel details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChannelResponse"}}}},"404":{"description":"Channel not found"}}},"put":{"tags":["channel"],"operationId":"channel_update","parameters":[{"name":"id","in":"path","description":"Channel ID","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateChannelRequest"}}},"required":true},"responses":{"200":{"description":"Channel updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChannelResponse"}}}},"403":{"description":"Forbidden"},"404":{"description":"Channel not found"}}},"delete":{"tags":["channel"],"operationId":"channel_delete","parameters":[{"name":"id","in":"path","description":"Channel ID","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"Channel deleted"},"403":{"description":"Forbidden"},"404":{"description":"Channel not found"}}}},"/api/message":{"get":{"tags":["message"],"operationId":"message_list","responses":{"200":{"description":"List of all messages","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/MessageResponse"}}}}}}},"post":{"tags":["message"],"operationId":"message_create","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateMessageRequest"}}},"required":true},"responses":{"200":{"description":"Message created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageResponse"}}}},"403":{"description":"Forbidden"},"404":{"description":"Channel not found"}},"security":[{"jwt":[]}]}},"/api/message/{id}":{"get":{"tags":["message"],"operationId":"message_detail","parameters":[{"name":"id","in":"path","description":"Message ID","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Message details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageResponse"}}}},"404":{"description":"Message not found"}}},"put":{"tags":["message"],"operationId":"message_update","parameters":[{"name":"id","in":"path","description":"Message ID","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateMessageRequest"}}},"required":true},"responses":{"200":{"description":"Message updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageResponse"}}}},"403":{"description":"Forbidden"},"404":{"description":"Message not found"}}},"delete":{"tags":["message"],"operationId":"message_delete","parameters":[{"name":"id","in":"path","description":"Message ID","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"Message deleted"},"403":{"description":"Forbidden"},"404":{"description":"Message not found"}}}},"/api/server":{"get":{"tags":["server"],"operationId":"server_list","responses":{"200":{"description":"List of all servers","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ServerResponse"}}}}}}},"post":{"tags":["server"],"operationId":"server_create","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateServerRequest"}}},"required":true},"responses":{"200":{"description":"Server created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServerResponse"}}}},"403":{"description":"Forbidden"}}}},"/api/server/{id}":{"get":{"tags":["server"],"operationId":"server_detail","parameters":[{"name":"id","in":"path","description":"Server ID","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Server details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServerResponse"}}}},"404":{"description":"Server not found"}}},"put":{"tags":["server"],"operationId":"server_update","parameters":[{"name":"id","in":"path","description":"Server ID","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateServerRequest"}}},"required":true},"responses":{"200":{"description":"Server updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServerResponse"}}}},"403":{"description":"Forbidden"},"404":{"description":"Server not found"}}},"delete":{"tags":["server"],"operationId":"server_delete","parameters":[{"name":"id","in":"path","description":"Server ID","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"Server deleted"},"403":{"description":"Forbidden"},"404":{"description":"Server not found"}}}},"/api/server/{id}/password":{"get":{"tags":["server"],"operationId":"server_password","parameters":[{"name":"id","in":"path","description":"Server ID","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Server password (hashed or plain depending on implementation)","content":{"application/json":{"schema":{"type":["string","null"]}}}},"404":{"description":"Server not found"}}}},"/api/server/{id}/tree":{"get":{"tags":["server"],"operationId":"tree","parameters":[{"name":"id","in":"path","description":"Server ID","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Server tree structure","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServerTreeResponse"}}}},"404":{"description":"Server not found"}}}},"/api/user":{"get":{"tags":["user"],"operationId":"user_list","responses":{"200":{"description":"List of all users","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/UserResponse"}}}}},"403":{"description":"Forbidden"}}}},"/api/user/me":{"get":{"tags":["user"],"operationId":"get_me","responses":{"200":{"description":"Current user information","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserResponse"}}}},"401":{"description":"Unauthorized"}},"security":[{"jwt":[]}]}},"/api/user/{id}":{"get":{"tags":["user"],"operationId":"user_detail","parameters":[{"name":"id","in":"path","description":"User ID","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"User details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserResponse"}}}},"404":{"description":"User not found"}}}},"/handler/ws/":{"get":{"tags":["ws_handler"],"summary":"WebSocket documentation placeholder.","description":"This is not a real HTTP endpoint, but it documents the WebSocket behavior.\n\n**Connection:** `GET /handler/ws/`\n\n**Protocol:** JSON messages over WebSocket.\n\n### Client -> Server\n- `SendMessage`: Send a JSON object matching `CreateMessageRequest`.\n\n### Server -> Client\n- `MessageReceived`: Receive a JSON object matching `MessageResponse`.","operationId":"ws_doc","responses":{"101":{"description":"Switching Protocols to WebSocket"},"401":{"description":"Unauthorized (Invalid JWT)"}},"security":[{"jwt":[]}]}}},"components":{"schemas":{"CategoryQuery":{"type":"object","properties":{"server_id":{"type":["string","null"],"format":"uuid"}}},"CategoryResponse":{"type":"object","required":["id","name"],"properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"}}},"ChannelResponse":{"type":"object","required":["id","position","channel_type"],"properties":{"category_id":{"type":["string","null"],"format":"uuid"},"channel_type":{"$ref":"#/components/schemas/ChannelType"},"id":{"type":"string","format":"uuid"},"name":{"type":["string","null"]},"position":{"type":"integer","format":"int32"},"server_id":{"type":["string","null"],"format":"uuid"}}},"ChannelType":{"type":"string","enum":["text","voice","d_m"]},"ClaimAdminRequest":{"type":"object","required":["token","username","password"],"properties":{"password":{"type":"string"},"token":{"type":"string"},"username":{"type":"string"}}},"CreateCategoryRequest":{"type":"object","required":["server_id","name"],"properties":{"name":{"type":"string"},"server_id":{"type":"string","format":"uuid"}}},"CreateChannelRequest":{"type":"object","required":["channel_type"],"properties":{"category_id":{"type":["string","null"],"format":"uuid"},"channel_type":{"$ref":"#/components/schemas/ChannelType"},"name":{"type":["string","null"]},"position":{"type":["integer","null"],"format":"int32"},"server_id":{"type":["string","null"],"format":"uuid"}}},"CreateMessageRequest":{"type":"object","required":["channel_id","content"],"properties":{"channel_id":{"type":"string","format":"uuid"},"content":{"type":"string"}}},"CreateServerRequest":{"type":"object","required":["name"],"properties":{"name":{"type":"string"},"password":{"type":["string","null"]}}},"CreateUserRequest":{"type":"object","required":["username"],"properties":{"username":{"type":"string"}}},"ListCategoryQuery":{"type":"object","required":["server_id"],"properties":{"server_id":{"type":"string","format":"uuid"}}},"LoginRequest":{"type":"object","required":["username","password"],"properties":{"password":{"type":"string"},"username":{"type":"string"}}},"LoginResponse":{"type":"object","required":["token","username"],"properties":{"token":{"type":"string"},"username":{"type":"string"}}},"MessageResponse":{"type":"object","required":["id","channel_id","author_id","content"],"properties":{"author_id":{"type":"string","format":"uuid"},"channel_id":{"type":"string","format":"uuid"},"content":{"type":"string"},"id":{"type":"string","format":"uuid"}}},"ServerResponse":{"type":"object","required":["id","name","created_at","updated_at"],"properties":{"created_at":{"type":"string"},"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"updated_at":{"type":"string"}}},"ServerTreeResponse":{"type":"object","required":["items"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/TreeItemType"}}}},"SshChallengeRequest":{"type":"object","required":["username"],"properties":{"username":{"type":"string"}}},"SshChallengeResponse":{"type":"object","required":["challenge"],"properties":{"challenge":{"type":"string"}}},"TreeItemType":{"oneOf":[{"allOf":[{"$ref":"#/components/schemas/CategoryResponse"},{"type":"object","required":["channels"],"properties":{"channels":{"type":"array","items":{"$ref":"#/components/schemas/ChannelResponse"}}}},{"type":"object","required":["type"],"properties":{"type":{"type":"string","enum":["category"]}}}]},{"allOf":[{"$ref":"#/components/schemas/ChannelResponse"},{"type":"object","required":["type"],"properties":{"type":{"type":"string","enum":["channel"]}}}]}]},"UserResponse":{"type":"object","required":["id","username","pub_key"],"properties":{"id":{"type":"string","format":"uuid"},"pub_key":{"type":"string"},"username":{"type":"string"}}}},"securitySchemes":{"jwt":{"type":"http","scheme":"bearer","bearerFormat":"JWT"}}},"tags":[{"name":"ox-speak","description":"Ox Speak API"}]} \ No newline at end of file diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index 281fde6..044cef6 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -8,6 +8,43 @@ version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" +[[package]] +name = "aead" +version = "0.6.0-rc.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b657e772794c6b04730ea897b66a058ccd866c16d1967da05eeeecec39043fe" +dependencies = [ + "crypto-common 0.2.1", + "inout", +] + +[[package]] +name = "aes" +version = "0.9.0-rc.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04097e08a47d9ad181c2e1f4a5fabc9ae06ce8839a333ba9a949bcb0d31fd2a3" +dependencies = [ + "cipher", + "cpubits", + "cpufeatures 0.2.17", + "zeroize", +] + +[[package]] +name = "aes-gcm" +version = "0.11.0-rc.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e22c0c90bbe8d4f77c3ca9ddabe41a1f8382d6fc1f7cea89459d0f320371f972" +dependencies = [ + "aead", + "aes", + "cipher", + "ctr", + "ghash", + "subtle", + "zeroize", +] + [[package]] name = "aho-corasick" version = "1.1.4" @@ -223,10 +260,32 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] -name = "base16ct" -version = "0.2.0" +name = "aws-lc-rs" +version = "1.16.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" +checksum = "a054912289d18629dc78375ba2c3726a3afe3ff71b4edba9dedfca0e3446d1fc" +dependencies = [ + "aws-lc-sys", + "zeroize", +] + +[[package]] +name = "aws-lc-sys" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fa7e52a4c5c547c741610a2c6f123f3881e409b714cd27e6798ef020c514f0a" +dependencies = [ + "cc", + "cmake", + "dunce", + "fs_extra", +] + +[[package]] +name = "base16ct" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd307490d624467aa6f74b0eabb77633d1f758a7b25f12bceb0b22e08d9726f6" [[package]] name = "base64" @@ -270,6 +329,16 @@ dependencies = [ "generic-array", ] +[[package]] +name = "block-buffer" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdd35008169921d80bc60d3d0ab416eecb028c4cd653352907921d95084790be" +dependencies = [ + "hybrid-array", + "zeroize", +] + [[package]] name = "block2" version = "0.6.2" @@ -414,6 +483,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cd4932aefd12402b36c60956a4fe0035421f544799057659ff86f923657aada3" dependencies = [ "find-msvc-tools", + "jobserver", + "libc", "shlex", ] @@ -450,6 +521,24 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + +[[package]] +name = "chacha20" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f8d983286843e49675a4b7a2d174efe136dc93a18d69130dd18198a6c167601" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures 0.3.0", + "zeroize", +] + [[package]] name = "chrono" version = "0.4.43" @@ -464,12 +553,14 @@ dependencies = [ [[package]] name = "cipher" -version = "0.4.4" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +checksum = "e34d8227fe1ba289043aeb13792056ff80fd6de1a9f49137a5f499de8e8c78ea" dependencies = [ - "crypto-common", + "block-buffer 0.12.0", + "crypto-common 0.2.1", "inout", + "zeroize", ] [[package]] @@ -481,6 +572,12 @@ dependencies = [ "cc", ] +[[package]] +name = "cmov" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de0758edba32d61d1fd9f4d69491b47604b91ee2f7e6b33de7e54ca4ebe55dc3" + [[package]] name = "combine" version = "4.6.7" @@ -502,9 +599,9 @@ dependencies = [ [[package]] name = "const-oid" -version = "0.9.6" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" +checksum = "a6ef517f0926dd24a1582492c791b6a4818a4d94e789a334894aa15b0d12f55c" [[package]] name = "convert_case" @@ -522,6 +619,16 @@ dependencies = [ "version_check", ] +[[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.1" @@ -545,7 +652,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fa95a34622365fa5bbf40b20b75dba8dfa8c94c734aea8ac9a5ca38af14316f1" dependencies = [ "bitflags 2.10.0", - "core-foundation", + "core-foundation 0.10.1", "core-graphics-types", "foreign-types", "libc", @@ -558,10 +665,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d44a101f213f6c4cdc1853d4b78aef6db6bdfa3468798cc1d9912f4735013eb" dependencies = [ "bitflags 2.10.0", - "core-foundation", + "core-foundation 0.10.1", "libc", ] +[[package]] +name = "cpubits" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ef0c543070d296ea414df2dd7625d1b24866ce206709d8a4a424f28377f5861" + [[package]] name = "cpufeatures" version = "0.2.17" @@ -571,6 +684,15 @@ dependencies = [ "libc", ] +[[package]] +name = "cpufeatures" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201" +dependencies = [ + "libc", +] + [[package]] name = "crc32fast" version = "1.5.0" @@ -597,12 +719,16 @@ checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" [[package]] name = "crypto-bigint" -version = "0.5.5" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" +checksum = "9fde2467e74147f492aebb834985186b2c74761927b8b9b3bd303bcb2e72199d" dependencies = [ - "generic-array", - "rand_core 0.6.4", + "cpubits", + "ctutils", + "hybrid-array", + "num-traits", + "rand_core 0.10.0", + "serdect", "subtle", "zeroize", ] @@ -617,6 +743,27 @@ dependencies = [ "typenum", ] +[[package]] +name = "crypto-common" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77727bb15fa921304124b128af125e7e3b968275d1b108b379190264f4423710" +dependencies = [ + "hybrid-array", + "rand_core 0.10.0", +] + +[[package]] +name = "crypto-primes" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21f41f23de7d24cdbda7f0c4d9c0351f99a4ceb258ef30e5c1927af8987ffe5a" +dependencies = [ + "crypto-bigint", + "libm", + "rand_core 0.10.0", +] + [[package]] name = "cssparser" version = "0.29.6" @@ -655,15 +802,34 @@ dependencies = [ ] [[package]] -name = "curve25519-dalek" -version = "4.1.3" +name = "ctr" +version = "0.10.0-rc.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be" +checksum = "fee683dd898fbd052617b4514bc31f98bc32081a83b69ec46adef3b1ef4ae36f" +dependencies = [ + "cipher", +] + +[[package]] +name = "ctutils" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1005a6d4446f5120ef475ad3d2af2b30c49c2c9c6904258e3bb30219bebed5e4" +dependencies = [ + "cmov", + "subtle", +] + +[[package]] +name = "curve25519-dalek" +version = "5.0.0-pre.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "335f1947f241137a14106b6f5acc5918a5ede29c9d71d3f2cb1678d5075d9fc3" dependencies = [ "cfg-if", - "cpufeatures", + "cpufeatures 0.2.17", "curve25519-dalek-derive", - "digest", + "digest 0.11.2", "fiat-crypto", "rustc_version", "subtle", @@ -717,9 +883,9 @@ dependencies = [ [[package]] name = "der" -version = "0.7.10" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" +checksum = "71fd89660b2dc699704064e59e9dba0147b903e85319429e131620d022be411b" dependencies = [ "const-oid", "zeroize", @@ -748,16 +914,35 @@ dependencies = [ "syn 2.0.114", ] +[[package]] +name = "des" +version = "0.9.0-rc.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3214053e68a813b9c06ef61075c844f3a1cdeb307d8998ea8555c063caa52fa9" +dependencies = [ + "cipher", +] + [[package]] name = "digest" version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ - "block-buffer", + "block-buffer 0.10.4", + "crypto-common 0.1.7", +] + +[[package]] +name = "digest" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4850db49bf08e663084f7fb5c87d202ef91a3907271aff24a94eb97ff039153c" +dependencies = [ + "block-buffer 0.12.0", "const-oid", - "crypto-common", - "subtle", + "crypto-common 0.2.1", + "ctutils", ] [[package]] @@ -869,53 +1054,53 @@ checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555" [[package]] name = "ecdsa" -version = "0.16.9" +version = "0.17.0-rc.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" +checksum = "91bbdd377139884fafcad8dc43a760a3e1e681aa26db910257fa6535b70e1829" dependencies = [ "der", - "digest", + "digest 0.11.2", "elliptic-curve", "rfc6979", "signature", - "spki", + "zeroize", ] [[package]] name = "ed25519" -version = "2.2.3" +version = "3.0.0-rc.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" +checksum = "c6e914c7c52decb085cea910552e24c63ac019e3ab8bf001ff736da9a9d9d890" dependencies = [ "signature", ] [[package]] name = "ed25519-dalek" -version = "2.2.0" +version = "3.0.0-pre.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70e796c081cee67dc755e1a36a0a172b897fab85fc3f6bc48307991f64e4eca9" +checksum = "053618a4c3d3bc24f188aa660ae75a46eeab74ef07fb415c61431e5e7cd4749b" dependencies = [ "curve25519-dalek", "ed25519", - "sha2", + "sha2 0.11.0-rc.5", "subtle", ] [[package]] name = "elliptic-curve" -version = "0.13.8" +version = "0.14.0-rc.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" +checksum = "e84043d573efd4ac9d2d125817979a379204bf7e328b25a4a30487e8d100e618" dependencies = [ "base16ct", "crypto-bigint", - "digest", - "ff", - "generic-array", - "group", - "pkcs8", - "rand_core 0.6.4", + "crypto-common 0.2.1", + "digest 0.11.2", + "hybrid-array", + "rand_core 0.10.0", + "rustcrypto-ff", + "rustcrypto-group", "sec1", "subtle", "zeroize", @@ -941,6 +1126,15 @@ version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ef6b89e5b37196644d8796de5268852ff179b44e96276cf4290264843743bb7" +[[package]] +name = "encoding_rs" +version = "0.8.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" +dependencies = [ + "cfg-if", +] + [[package]] name = "endi" version = "1.1.1" @@ -1031,21 +1225,11 @@ dependencies = [ "simd-adler32", ] -[[package]] -name = "ff" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0b50bfb653653f9ca9095b427bed08ab8d75a137839d9ad64eb11810d5b6393" -dependencies = [ - "rand_core 0.6.4", - "subtle", -] - [[package]] name = "fiat-crypto" -version = "0.2.9" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" +checksum = "64cd1e32ddd350061ae6edb1b082d7c54915b5c672c389143b9a63403a109f24" [[package]] name = "field-offset" @@ -1127,6 +1311,12 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "fs_extra" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" + [[package]] name = "futf" version = "0.1.5" @@ -1338,7 +1528,6 @@ checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" dependencies = [ "typenum", "version_check", - "zeroize", ] [[package]] @@ -1359,8 +1548,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" dependencies = [ "cfg-if", + "js-sys", "libc", "wasi 0.11.1+wasi-snapshot-preview1", + "wasm-bindgen", ] [[package]] @@ -1370,9 +1561,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" dependencies = [ "cfg-if", + "js-sys", "libc", "r-efi", "wasip2", + "wasm-bindgen", +] + +[[package]] +name = "ghash" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2eecf2d5dc9b66b732b97707a0210906b1d30523eb773193ab777c0c84b3e8d5" +dependencies = [ + "polyval", ] [[package]] @@ -1471,17 +1673,6 @@ dependencies = [ "system-deps", ] -[[package]] -name = "group" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" -dependencies = [ - "ff", - "rand_core 0.6.4", - "subtle", -] - [[package]] name = "gtk" version = "0.18.2" @@ -1534,6 +1725,25 @@ dependencies = [ "syn 2.0.114", ] +[[package]] +name = "h2" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f44da3a8150a6703ed5d34e164b875fd14c2cdab9af1252a9a1020bde2bdc54" +dependencies = [ + "atomic-waker", + "bytes", + "fnv", + "futures-core", + "futures-sink", + "http", + "indexmap 2.13.0", + "slab", + "tokio", + "tokio-util", + "tracing", +] + [[package]] name = "hashbrown" version = "0.12.3" @@ -1572,11 +1782,11 @@ checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" [[package]] name = "hmac" -version = "0.12.1" +version = "0.13.0-rc.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +checksum = "ef451d73f36d8a3f93ad32c332ea01146c9650e1ec821a9b0e46c01277d544f8" dependencies = [ - "digest", + "digest 0.11.2", ] [[package]] @@ -1630,6 +1840,17 @@ version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" +[[package]] +name = "hybrid-array" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8655f91cd07f2b9d0c24137bd650fe69617773435ee5ec83022377777ce65ef1" +dependencies = [ + "subtle", + "typenum", + "zeroize", +] + [[package]] name = "hyper" version = "1.8.1" @@ -1640,6 +1861,7 @@ dependencies = [ "bytes", "futures-channel", "futures-core", + "h2", "http", "http-body", "httparse", @@ -1651,6 +1873,22 @@ dependencies = [ "want", ] +[[package]] +name = "hyper-rustls" +version = "0.27.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58" +dependencies = [ + "http", + "hyper", + "hyper-util", + "rustls", + "rustls-pki-types", + "tokio", + "tokio-rustls", + "tower-service", +] + [[package]] name = "hyper-util" version = "0.1.19" @@ -1670,9 +1908,11 @@ dependencies = [ "percent-encoding", "pin-project-lite", "socket2", + "system-configuration", "tokio", "tower-service", "tracing", + "windows-registry", ] [[package]] @@ -1701,9 +1941,9 @@ dependencies = [ [[package]] name = "ico" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc50b891e4acf8fe0e71ef88ec43ad82ee07b3810ad09de10f1d01f072ed4b98" +checksum = "3e795dff5605e0f04bff85ca41b51a96b83e80b281e96231bcaaf1ac35103371" dependencies = [ "byteorder", "png", @@ -1851,11 +2091,11 @@ dependencies = [ [[package]] name = "inout" -version = "0.1.4" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01" +checksum = "4250ce6452e92010fdf7268ccc5d14faa80bb12fc741938534c58f16804e03c7" dependencies = [ - "generic-array", + "hybrid-array", ] [[package]] @@ -1944,6 +2184,16 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" +[[package]] +name = "jobserver" +version = "0.1.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" +dependencies = [ + "getrandom 0.3.4", + "libc", +] + [[package]] name = "js-sys" version = "0.3.85" @@ -2004,9 +2254,6 @@ name = "lazy_static" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" -dependencies = [ - "spin", -] [[package]] name = "libappindicator" @@ -2091,6 +2338,12 @@ version = "0.4.29" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" +[[package]] +name = "lru-slab" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" + [[package]] name = "mac" version = "0.1.1" @@ -2233,48 +2486,12 @@ version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" -[[package]] -name = "num-bigint-dig" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e661dda6640fad38e827a6d4a310ff4763082116fe217f279885c97f511bb0b7" -dependencies = [ - "lazy_static", - "libm", - "num-integer", - "num-iter", - "num-traits", - "rand 0.8.5", - "smallvec", - "zeroize", -] - [[package]] name = "num-conv" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" -[[package]] -name = "num-integer" -version = "0.1.46" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" -dependencies = [ - "num-traits", -] - -[[package]] -name = "num-iter" -version = "0.1.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" -dependencies = [ - "autocfg", - "num-integer", - "num-traits", -] - [[package]] name = "num-traits" version = "0.2.19" @@ -2282,7 +2499,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", - "libm", ] [[package]] @@ -2325,38 +2541,8 @@ checksum = "d49e936b501e5c5bf01fda3a9452ff86dc3ea98ad5f283e1455153142d97518c" dependencies = [ "bitflags 2.10.0", "block2", - "libc", "objc2", - "objc2-cloud-kit", - "objc2-core-data", "objc2-core-foundation", - "objc2-core-graphics", - "objc2-core-image", - "objc2-core-text", - "objc2-core-video", - "objc2-foundation", - "objc2-quartz-core", -] - -[[package]] -name = "objc2-cloud-kit" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73ad74d880bb43877038da939b7427bba67e9dd42004a18b809ba7d87cee241c" -dependencies = [ - "bitflags 2.10.0", - "objc2", - "objc2-foundation", -] - -[[package]] -name = "objc2-core-data" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b402a653efbb5e82ce4df10683b6b28027616a2715e90009947d50b8dd298fa" -dependencies = [ - "bitflags 2.10.0", - "objc2", "objc2-foundation", ] @@ -2384,41 +2570,6 @@ dependencies = [ "objc2-io-surface", ] -[[package]] -name = "objc2-core-image" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5d563b38d2b97209f8e861173de434bd0214cf020e3423a52624cd1d989f006" -dependencies = [ - "objc2", - "objc2-foundation", -] - -[[package]] -name = "objc2-core-text" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cde0dfb48d25d2b4862161a4d5fcc0e3c24367869ad306b0c9ec0073bfed92d" -dependencies = [ - "bitflags 2.10.0", - "objc2", - "objc2-core-foundation", - "objc2-core-graphics", -] - -[[package]] -name = "objc2-core-video" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d425caf1df73233f29fd8a5c3e5edbc30d2d4307870f802d18f00d83dc5141a6" -dependencies = [ - "bitflags 2.10.0", - "objc2", - "objc2-core-foundation", - "objc2-core-graphics", - "objc2-io-surface", -] - [[package]] name = "objc2-encode" version = "4.1.0" @@ -2442,7 +2593,6 @@ checksum = "e3e0adef53c21f888deb4fa59fc59f7eb17404926ee8a6f59f5df0fd7f9f3272" dependencies = [ "bitflags 2.10.0", "block2", - "libc", "objc2", "objc2-core-foundation", ] @@ -2458,16 +2608,6 @@ dependencies = [ "objc2-core-foundation", ] -[[package]] -name = "objc2-javascript-core" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a1e6550c4caed348956ce3370c9ffeca70bb1dbed4fa96112e7c6170e074586" -dependencies = [ - "objc2", - "objc2-core-foundation", -] - [[package]] name = "objc2-quartz-core" version = "0.3.2" @@ -2480,17 +2620,6 @@ dependencies = [ "objc2-foundation", ] -[[package]] -name = "objc2-security" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "709fe137109bd1e8b5a99390f77a7d8b2961dafc1a1c5db8f2e60329ad6d895a" -dependencies = [ - "bitflags 2.10.0", - "objc2", - "objc2-core-foundation", -] - [[package]] name = "objc2-ui-kit" version = "0.3.2" @@ -2515,8 +2644,6 @@ dependencies = [ "objc2-app-kit", "objc2-core-foundation", "objc2-foundation", - "objc2-javascript-core", - "objc2-security", ] [[package]] @@ -2537,6 +2664,12 @@ dependencies = [ "pathdiff", ] +[[package]] +name = "openssl-probe" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe" + [[package]] name = "option-ext" version = "0.2.0" @@ -2545,12 +2678,11 @@ checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" [[package]] name = "opusic-sys" -version = "0.5.8" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f43c183739dc81651487e7c9f3e4330fe4a3fd26c0fa961c788ce5fb21fa75b" +checksum = "dc3280fe5b6f97ac1a35a0ac003e2fb0b92f8e4bdf2b2057e1bf9b87acca5696" dependencies = [ "cmake", - "libc", ] [[package]] @@ -2571,52 +2703,57 @@ dependencies = [ "figment", "opusic-sys", "parking_lot", + "reqwest", "serde", "serde_json", "ssh-key", "tauri", "tauri-build", "tauri-plugin-opener", + "thiserror 2.0.17", "tokio", - "toml 0.9.11+spec-1.1.0", + "toml 1.0.7+spec-1.1.0", ] [[package]] name = "p256" -version = "0.13.2" +version = "0.14.0-rc.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9863ad85fa8f4460f9c48cb909d38a0d689dba1f6f6988a5e3e0d31071bcd4b" +checksum = "44f0a10fe314869359cb2901342b045f4e5a962ef9febc006f03d2a8c848fe4c" dependencies = [ "ecdsa", "elliptic-curve", + "primefield", "primeorder", - "sha2", + "sha2 0.11.0-rc.5", ] [[package]] name = "p384" -version = "0.13.1" +version = "0.14.0-rc.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe42f1670a52a47d448f14b6a5c61dd78fce51856e68edaa38f7ae3a46b8d6b6" +checksum = "b079e66810c55ab3d6ba424e056dc4aefcdb8046c8c3f3816142edbdd7af7721" dependencies = [ "ecdsa", "elliptic-curve", + "fiat-crypto", + "primefield", "primeorder", - "sha2", + "sha2 0.11.0-rc.5", ] [[package]] name = "p521" -version = "0.13.3" +version = "0.14.0-rc.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fc9e2161f1f215afdfce23677034ae137bbd45016a880c2eb3ba8eb95f085b2" +checksum = "9eecc34c4c6e6596d5271fecf90ac4f16593fa198e77282214d0c22736aa9266" dependencies = [ "base16ct", "ecdsa", "elliptic-curve", + "primefield", "primeorder", - "rand_core 0.6.4", - "sha2", + "sha2 0.11.0-rc.5", ] [[package]] @@ -2681,9 +2818,9 @@ checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3" [[package]] name = "pem-rfc7468" -version = "0.7.0" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" +checksum = "a6305423e0e7738146434843d1694d621cce767262b2a86910beab705e4493d9" dependencies = [ "base64ct", ] @@ -2851,27 +2988,6 @@ dependencies = [ "futures-io", ] -[[package]] -name = "pkcs1" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8ffb9f10fa047879315e6625af03c164b16962a5368d724ed16323b68ace47f" -dependencies = [ - "der", - "pkcs8", - "spki", -] - -[[package]] -name = "pkcs8" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" -dependencies = [ - "der", - "spki", -] - [[package]] name = "pkg-config" version = "0.3.32" @@ -2918,6 +3034,28 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "poly1305" +version = "0.9.0-rc.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19feddcbdf17fad33f40041c7f9e768faf19455f32a6d52ba1b8b65ffc7b1cae" +dependencies = [ + "cpufeatures 0.3.0", + "universal-hash", + "zeroize", +] + +[[package]] +name = "polyval" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dfc63250416fea14f5749b90725916a6c903f599d51cb635aa7a52bfd03eede" +dependencies = [ + "cpubits", + "cpufeatures 0.3.0", + "universal-hash", +] + [[package]] name = "potential_utf" version = "0.1.4" @@ -2949,10 +3087,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" [[package]] -name = "primeorder" -version = "0.13.6" +name = "primefield" +version = "0.14.0-rc.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "353e1ca18966c16d9deb1c69278edbc5f194139612772bd9537af60ac231e1e6" +checksum = "c6543f5eec854fbf74ba5ef651fbdc9408919b47c3e1526623687135c16d12e9" +dependencies = [ + "crypto-bigint", + "crypto-common 0.2.1", + "rand_core 0.10.0", + "rustcrypto-ff", + "subtle", + "zeroize", +] + +[[package]] +name = "primeorder" +version = "0.14.0-rc.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "569d9ad6ef822bb0322c7e7d84e5e286244050bd5246cac4c013535ae91c2c90" dependencies = [ "elliptic-curve", ] @@ -3034,6 +3186,62 @@ dependencies = [ "memchr", ] +[[package]] +name = "quinn" +version = "0.11.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e20a958963c291dc322d98411f541009df2ced7b5a4f2bd52337638cfccf20" +dependencies = [ + "bytes", + "cfg_aliases", + "pin-project-lite", + "quinn-proto", + "quinn-udp", + "rustc-hash", + "rustls", + "socket2", + "thiserror 2.0.17", + "tokio", + "tracing", + "web-time", +] + +[[package]] +name = "quinn-proto" +version = "0.11.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "434b42fec591c96ef50e21e886936e66d3cc3f737104fdb9b737c40ffb94c098" +dependencies = [ + "aws-lc-rs", + "bytes", + "getrandom 0.3.4", + "lru-slab", + "rand 0.9.2", + "ring", + "rustc-hash", + "rustls", + "rustls-pki-types", + "slab", + "thiserror 2.0.17", + "tinyvec", + "tracing", + "web-time", +] + +[[package]] +name = "quinn-udp" +version = "0.5.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "addec6a0dcad8a8d96a771f815f0eaf55f9d1805756410b39f5fa81332574cbd" +dependencies = [ + "cfg_aliases", + "libc", + "once_cell", + "socket2", + "tracing", + "windows-sys 0.60.2", +] + [[package]] name = "quote" version = "1.0.43" @@ -3074,6 +3282,16 @@ dependencies = [ "rand_core 0.6.4", ] +[[package]] +name = "rand" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" +dependencies = [ + "rand_chacha 0.9.0", + "rand_core 0.9.5", +] + [[package]] name = "rand_chacha" version = "0.2.2" @@ -3094,6 +3312,16 @@ dependencies = [ "rand_core 0.6.4", ] +[[package]] +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core 0.9.5", +] + [[package]] name = "rand_core" version = "0.5.1" @@ -3112,6 +3340,21 @@ dependencies = [ "getrandom 0.2.17", ] +[[package]] +name = "rand_core" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" +dependencies = [ + "getrandom 0.3.4", +] + +[[package]] +name = "rand_core" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c8d0fd677905edcbeedbf2edb6494d676f0e98d54d5cf9bda0b061cb8fb8aba" + [[package]] name = "rand_hc" version = "0.2.0" @@ -3207,28 +3450,36 @@ checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" [[package]] name = "reqwest" -version = "0.12.28" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eddd3ca559203180a307f12d114c268abf583f59b03cb906fd0b3ff8646c1147" +checksum = "ab3f43e3283ab1488b624b44b0e988d0acea0b3214e694730a055cb6b2efa801" dependencies = [ "base64 0.22.1", "bytes", + "encoding_rs", "futures-core", "futures-util", + "h2", "http", "http-body", "http-body-util", "hyper", + "hyper-rustls", "hyper-util", "js-sys", "log", + "mime", "percent-encoding", "pin-project-lite", + "quinn", + "rustls", + "rustls-pki-types", + "rustls-platform-verifier", "serde", "serde_json", - "serde_urlencoded", "sync_wrapper", "tokio", + "tokio-rustls", "tokio-util", "tower", "tower-http", @@ -3242,35 +3493,50 @@ dependencies = [ [[package]] name = "rfc6979" -version = "0.4.0" +version = "0.5.0-rc.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" +checksum = "23a3127ee32baec36af75b4107082d9bd823501ec14a4e016be4b6b37faa74ae" dependencies = [ "hmac", "subtle", ] [[package]] -name = "rsa" -version = "0.9.10" +name = "ring" +version = "0.17.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8573f03f5883dcaebdfcf4725caa1ecb9c15b2ef50c43a07b816e06799bb12d" +checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" +dependencies = [ + "cc", + "cfg-if", + "getrandom 0.2.17", + "libc", + "untrusted", + "windows-sys 0.52.0", +] + +[[package]] +name = "rsa" +version = "0.10.0-rc.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87ed3e93fc7e473e464b9726f4759659e72bc8665e4b8ea227547024f416d905" dependencies = [ "const-oid", - "digest", - "num-bigint-dig", - "num-integer", - "num-traits", - "pkcs1", - "pkcs8", - "rand_core 0.6.4", - "sha2", + "crypto-bigint", + "crypto-primes", + "digest 0.11.2", + "rand_core 0.10.0", + "sha2 0.11.0-rc.5", "signature", - "spki", - "subtle", "zeroize", ] +[[package]] +name = "rustc-hash" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" + [[package]] name = "rustc_version" version = "0.4.1" @@ -3280,6 +3546,27 @@ dependencies = [ "semver", ] +[[package]] +name = "rustcrypto-ff" +version = "0.14.0-rc.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5db129183b2c139d7d87d08be57cba626c715789db17aec65c8866bfd767d1f" +dependencies = [ + "rand_core 0.10.0", + "subtle", +] + +[[package]] +name = "rustcrypto-group" +version = "0.14.0-rc.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c4b1463f274a3ff6fb2f44da43e576cb9424367bd96f185ead87b52fe00523" +dependencies = [ + "rand_core 0.10.0", + "rustcrypto-ff", + "subtle", +] + [[package]] name = "rustix" version = "1.1.3" @@ -3293,18 +3580,87 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "rustls" +version = "0.23.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "758025cb5fccfd3bc2fd74708fd4682be41d99e5dff73c377c0646c6012c73a4" +dependencies = [ + "aws-lc-rs", + "once_cell", + "rustls-pki-types", + "rustls-webpki", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-native-certs" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "612460d5f7bea540c490b2b6395d8e34a953e52b491accd6c86c8164c5932a63" +dependencies = [ + "openssl-probe", + "rustls-pki-types", + "schannel", + "security-framework", +] + +[[package]] +name = "rustls-pki-types" +version = "1.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be040f8b0a225e40375822a563fa9524378b9d63112f53e19ffff34df5d33fdd" +dependencies = [ + "web-time", + "zeroize", +] + +[[package]] +name = "rustls-platform-verifier" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d99feebc72bae7ab76ba994bb5e121b8d83d910ca40b36e0921f53becc41784" +dependencies = [ + "core-foundation 0.10.1", + "core-foundation-sys", + "jni", + "log", + "once_cell", + "rustls", + "rustls-native-certs", + "rustls-platform-verifier-android", + "rustls-webpki", + "security-framework", + "security-framework-sys", + "webpki-root-certs", + "windows-sys 0.52.0", +] + +[[package]] +name = "rustls-platform-verifier-android" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f" + +[[package]] +name = "rustls-webpki" +version = "0.103.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7df23109aa6c1567d1c575b9952556388da57401e4ace1d15f79eedad0d8f53" +dependencies = [ + "aws-lc-rs", + "ring", + "rustls-pki-types", + "untrusted", +] + [[package]] name = "rustversion" version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" -[[package]] -name = "ryu" -version = "1.0.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a50f4cf475b65d88e057964e0e9bb1f0aa9bbb2036dc65c64596b42932536984" - [[package]] name = "same-file" version = "1.0.6" @@ -3314,6 +3670,15 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "schannel" +version = "0.1.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91c1b7e4904c873ef0710c1f407dde2e6287de2bebc1bbbf7d430bb7cbffd939" +dependencies = [ + "windows-sys 0.61.2", +] + [[package]] name = "schemars" version = "0.8.22" @@ -3373,18 +3738,41 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "sec1" -version = "0.7.3" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" +checksum = "f46b9a5ab87780a3189a1d704766579517a04ad59de653b7aad7d38e8a15f7dc" dependencies = [ "base16ct", + "ctutils", "der", - "generic-array", - "pkcs8", + "hybrid-array", "subtle", "zeroize", ] +[[package]] +name = "security-framework" +version = "3.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d17b898a6d6948c3a8ee4372c17cb384f90d2e6e912ef00895b14fd7ab54ec38" +dependencies = [ + "bitflags 2.10.0", + "core-foundation 0.10.1", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2691df843ecc5d231c0b14ece2acc3efb62c0a398c7e1d875f3983ce020e3" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "selectors" version = "0.24.0" @@ -3508,18 +3896,6 @@ dependencies = [ "serde_core", ] -[[package]] -name = "serde_urlencoded" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" -dependencies = [ - "form_urlencoded", - "itoa", - "ryu", - "serde", -] - [[package]] name = "serde_with" version = "3.16.1" @@ -3551,6 +3927,16 @@ dependencies = [ "syn 2.0.114", ] +[[package]] +name = "serdect" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9af4a3e75ebd5599b30d4de5768e00b5095d518a79fefc3ecbaf77e665d1ec06" +dependencies = [ + "base16ct", + "serde", +] + [[package]] name = "serialize-to-javascript" version = "0.1.2" @@ -3590,8 +3976,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" dependencies = [ "cfg-if", - "cpufeatures", - "digest", + "cpufeatures 0.2.17", + "digest 0.10.7", +] + +[[package]] +name = "sha2" +version = "0.11.0-rc.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c5f3b1e2dc8aad28310d8410bd4d7e180eca65fca176c52ab00d364475d0024" +dependencies = [ + "cfg-if", + "cpufeatures 0.2.17", + "digest 0.11.2", ] [[package]] @@ -3612,12 +4009,12 @@ dependencies = [ [[package]] name = "signature" -version = "2.2.0" +version = "3.0.0-rc.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +checksum = "7f1880df446116126965eeec169136b2e0251dba37c6223bcc819569550edea3" dependencies = [ - "digest", - "rand_core 0.6.4", + "digest 0.11.2", + "rand_core 0.10.0", ] [[package]] @@ -3708,58 +4105,50 @@ dependencies = [ "system-deps", ] -[[package]] -name = "spin" -version = "0.9.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" - -[[package]] -name = "spki" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" -dependencies = [ - "base64ct", - "der", -] - [[package]] name = "ssh-cipher" -version = "0.2.0" +version = "0.3.0-rc.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "caac132742f0d33c3af65bfcde7f6aa8f62f0e991d80db99149eb9d44708784f" +checksum = "20540e2cbcf285a8e0172717b3ae77ccc2bbf63f3967263ea71e8048173b09ff" dependencies = [ + "aes", + "aes-gcm", + "chacha20", "cipher", + "des", + "poly1305", "ssh-encoding", + "zeroize", ] [[package]] name = "ssh-encoding" -version = "0.2.0" +version = "0.3.0-rc.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb9242b9ef4108a78e8cd1a2c98e193ef372437f8c22be363075233321dd4a15" +checksum = "af0ddb05d9c6034911bbdc541170b3068a2c019c7a10824e92921151563fb5af" dependencies = [ "base64ct", + "crypto-bigint", + "digest 0.11.2", "pem-rfc7468", - "sha2", + "subtle", + "zeroize", ] [[package]] name = "ssh-key" -version = "0.6.7" +version = "0.7.0-rc.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b86f5297f0f04d08cabaa0f6bff7cb6aec4d9c3b49d87990d63da9d9156a8c3" +checksum = "8ae7221717f89c8629a83ba265a004cb864df267485656f790444fff1b69fa36" dependencies = [ "ed25519-dalek", - "num-bigint-dig", "p256", "p384", "p521", - "rand_core 0.6.4", + "rand_core 0.10.0", "rsa", "sec1", - "sha2", + "sha2 0.11.0-rc.5", "signature", "ssh-cipher", "ssh-encoding", @@ -3863,6 +4252,27 @@ dependencies = [ "syn 2.0.114", ] +[[package]] +name = "system-configuration" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" +dependencies = [ + "bitflags 2.10.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" @@ -3884,7 +4294,7 @@ checksum = "f3a753bdc39c07b192151523a3f77cd0394aa75413802c883a0f6f6a0e5ee2e7" dependencies = [ "bitflags 2.10.0", "block2", - "core-foundation", + "core-foundation 0.10.1", "core-graphics", "crossbeam-channel", "dispatch", @@ -3935,9 +4345,9 @@ checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" [[package]] name = "tauri" -version = "2.9.5" +version = "2.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a3868da5508446a7cd08956d523ac3edf0a8bc20bf7e4038f9a95c2800d2033" +checksum = "da77cc00fb9028caf5b5d4650f75e31f1ef3693459dfca7f7e506d1ecef0ba2d" dependencies = [ "anyhow", "bytes", @@ -3986,9 +4396,9 @@ dependencies = [ [[package]] name = "tauri-build" -version = "2.5.3" +version = "2.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17fcb8819fd16463512a12f531d44826ce566f486d7ccd211c9c8cebdaec4e08" +checksum = "4bbc990d1dbf57a8e1c7fa2327f2a614d8b757805603c1b9ba5c81bade09fd4d" dependencies = [ "anyhow", "cargo_toml", @@ -4008,9 +4418,9 @@ dependencies = [ [[package]] name = "tauri-codegen" -version = "2.5.2" +version = "2.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fa9844cefcf99554a16e0a278156ae73b0d8680bbc0e2ad1e4287aadd8489cf" +checksum = "d4a24476afd977c5d5d169f72425868613d82747916dd29e0a357c84c4bd6d29" dependencies = [ "base64 0.22.1", "brotli", @@ -4023,7 +4433,7 @@ dependencies = [ "semver", "serde", "serde_json", - "sha2", + "sha2 0.10.9", "syn 2.0.114", "tauri-utils", "thiserror 2.0.17", @@ -4035,9 +4445,9 @@ dependencies = [ [[package]] name = "tauri-macros" -version = "2.5.2" +version = "2.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3764a12f886d8245e66b7ee9b43ccc47883399be2019a61d80cf0f4117446fde" +checksum = "d39b349a98dadaffebb73f0a40dcd1f23c999211e5a2e744403db384d0c33de7" dependencies = [ "heck 0.5.0", "proc-macro2", @@ -4088,9 +4498,9 @@ dependencies = [ [[package]] name = "tauri-runtime" -version = "2.9.2" +version = "2.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87f766fe9f3d1efc4b59b17e7a891ad5ed195fa8d23582abb02e6c9a01137892" +checksum = "2826d79a3297ed08cd6ea7f412644ef58e32969504bc4fbd8d7dbeabc4445ea2" dependencies = [ "cookie", "dpi", @@ -4113,9 +4523,9 @@ dependencies = [ [[package]] name = "tauri-runtime-wry" -version = "2.9.3" +version = "2.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "187a3f26f681bdf028f796ccf57cf478c1ee422c50128e5a0a6ebeb3f5910065" +checksum = "e11ea2e6f801d275fdd890d6c9603736012742a1c33b96d0db788c9cdebf7f9e" dependencies = [ "gtk", "http", @@ -4123,7 +4533,6 @@ dependencies = [ "log", "objc2", "objc2-app-kit", - "objc2-foundation", "once_cell", "percent-encoding", "raw-window-handle", @@ -4140,9 +4549,9 @@ dependencies = [ [[package]] name = "tauri-utils" -version = "2.8.1" +version = "2.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76a423c51176eb3616ee9b516a9fa67fed5f0e78baaba680e44eb5dd2cc37490" +checksum = "219a1f983a2af3653f75b5747f76733b0da7ff03069c7a41901a5eb3ace4557d" dependencies = [ "anyhow", "brotli", @@ -4293,10 +4702,25 @@ dependencies = [ ] [[package]] -name = "tokio" -version = "1.49.0" +name = "tinyvec" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72a2903cd7736441aac9df9d7688bd0ce48edccaadf181c3b90be801e81d3d86" +checksum = "3e61e67053d25a4e82c844e8424039d9745781b3fc4f32b8d55ed50f5f667ef3" +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.50.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27ad5e34374e03cfffefc301becb44e9dc3c17584f414349ebe29ed26661822d" dependencies = [ "bytes", "libc", @@ -4320,6 +4744,16 @@ dependencies = [ "syn 2.0.114", ] +[[package]] +name = "tokio-rustls" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" +dependencies = [ + "rustls", + "tokio", +] + [[package]] name = "tokio-util" version = "0.7.18" @@ -4360,6 +4794,21 @@ dependencies = [ "winnow 0.7.14", ] +[[package]] +name = "toml" +version = "1.0.7+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd28d57d8a6f6e458bc0b8784f8fdcc4b99a437936056fa122cb234f18656a96" +dependencies = [ + "indexmap 2.13.0", + "serde_core", + "serde_spanned 1.0.4", + "toml_datetime 1.0.1+spec-1.1.0", + "toml_parser", + "toml_writer", + "winnow 1.0.0", +] + [[package]] name = "toml_datetime" version = "0.6.3" @@ -4378,6 +4827,15 @@ dependencies = [ "serde_core", ] +[[package]] +name = "toml_datetime" +version = "1.0.1+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b320e741db58cac564e26c607d3cc1fdc4a88fd36c879568c07856ed83ff3e9" +dependencies = [ + "serde_core", +] + [[package]] name = "toml_edit" version = "0.19.15" @@ -4416,18 +4874,18 @@ dependencies = [ [[package]] name = "toml_parser" -version = "1.0.6+spec-1.1.0" +version = "1.0.10+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3198b4b0a8e11f09dd03e133c0280504d0801269e9afa46362ffde1cbeebf44" +checksum = "7df25b4befd31c4816df190124375d5a20c6b6921e2cad937316de3fccd63420" dependencies = [ - "winnow 0.7.14", + "winnow 1.0.0", ] [[package]] name = "toml_writer" -version = "1.0.6+spec-1.1.0" +version = "1.0.7+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab16f14aed21ee8bfd8ec22513f7287cd4a91aa92e44edfe2c17ddd004e92607" +checksum = "f17aaa1c6e3dc22b1da4b6bba97d066e354c7945cac2f7852d4e4e7ca7a6b56d" [[package]] name = "tower" @@ -4618,6 +5076,22 @@ version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" +[[package]] +name = "universal-hash" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4987bdc12753382e0bec4a65c50738ffaabc998b9cdd1f952fb5f39b0048a96" +dependencies = [ + "crypto-common 0.2.1", + "ctutils", +] + +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + [[package]] name = "url" version = "2.5.8" @@ -4800,9 +5274,9 @@ dependencies = [ [[package]] name = "wasm-streams" -version = "0.4.2" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15053d8d85c7eccdbefef60f06769760a563c7f0a9d6902a13d35c7800b0ad65" +checksum = "9d1ec4f6517c9e11ae630e200b2b65d193279042e28edd4a2cda233e46670bbb" dependencies = [ "futures-util", "js-sys", @@ -4822,10 +5296,20 @@ dependencies = [ ] [[package]] -name = "webkit2gtk" -version = "2.0.1" +name = "web-time" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76b1bc1e54c581da1e9f179d0b38512ba358fb1af2d634a1affe42e37172361a" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "webkit2gtk" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1027150013530fb2eaf806408df88461ae4815a45c541c8975e61d6f2fc4793" dependencies = [ "bitflags 1.3.2", "cairo-rs", @@ -4847,9 +5331,9 @@ dependencies = [ [[package]] name = "webkit2gtk-sys" -version = "2.0.1" +version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62daa38afc514d1f8f12b8693d30d5993ff77ced33ce30cd04deebc267a6d57c" +checksum = "916a5f65c2ef0dfe12fff695960a2ec3d4565359fdbb2e9943c974e06c734ea5" dependencies = [ "bitflags 1.3.2", "cairo-sys-rs", @@ -4865,6 +5349,15 @@ dependencies = [ "system-deps", ] +[[package]] +name = "webpki-root-certs" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "804f18a4ac2676ffb4e8b5b5fa9ae38af06df08162314f96a68d2a363e21a8ca" +dependencies = [ + "rustls-pki-types", +] + [[package]] name = "webview2-com" version = "0.38.2" @@ -5050,6 +5543,17 @@ dependencies = [ "windows-link 0.1.3", ] +[[package]] +name = "windows-registry" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02752bf7fbdcce7f2a27a742f798510f3e5ad88dbe84871e5168e2120c3d5720" +dependencies = [ + "windows-link 0.2.1", + "windows-result 0.4.1", + "windows-strings 0.5.1", +] + [[package]] name = "windows-result" version = "0.3.4" @@ -5095,6 +5599,15 @@ dependencies = [ "windows-targets 0.42.2", ] +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.6", +] + [[package]] name = "windows-sys" version = "0.59.0" @@ -5344,6 +5857,12 @@ dependencies = [ "memchr", ] +[[package]] +name = "winnow" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a90e88e4667264a994d34e6d1ab2d26d398dcdca8b7f52bec8668957517fc7d8" + [[package]] name = "winreg" version = "0.55.0" @@ -5368,9 +5887,9 @@ checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" [[package]] name = "wry" -version = "0.53.5" +version = "0.54.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "728b7d4c8ec8d81cab295e0b5b8a4c263c0d41a785fb8f8c4df284e5411140a2" +checksum = "bb26159b420aa77684589a744ae9a9461a95395b848764ad12290a14d960a11a" dependencies = [ "base64 0.22.1", "block2", @@ -5397,7 +5916,7 @@ dependencies = [ "once_cell", "percent-encoding", "raw-window-handle", - "sha2", + "sha2 0.10.9", "soup3", "tao-macros", "thiserror 2.0.17", diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index cb0e565..0495f13 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -18,15 +18,17 @@ crate-type = ["staticlib", "cdylib", "rlib"] tauri-build = { version = "2", features = [] } [dependencies] -tauri = { version = "2", features = [] } +tauri = { version = "2.10.3", features = [] } tauri-plugin-opener = "2" serde = { version = "1", features = ["derive"] } serde_json = "1" -opusic-sys = "0.5" -tokio = { version = "1.49", features = ["full"] } +opusic-sys = "0.6" +tokio = { version = "1.50", features = ["full"] } +reqwest = { version = "0.13", features = ["json", "rustls"] } +thiserror = "2.0" figment = "0.10.19" parking_lot = "0.12" -toml = "0.9" -ssh-key = { version = "0.6", features = ["default", "crypto"] } -base64 = "0.22" \ No newline at end of file +toml = "1.0.7+spec-1.1.0" +ssh-key = { version = "0.7.0-rc.9", features = ["default", "crypto"] } +base64 = "0.22" diff --git a/src-tauri/src/api/client.rs b/src-tauri/src/api/client.rs new file mode 100644 index 0000000..e55d1c2 --- /dev/null +++ b/src-tauri/src/api/client.rs @@ -0,0 +1,247 @@ +use crate::api::models::*; +use parking_lot::RwLock; +use reqwest::{header, Client, Method, RequestBuilder, Response}; +use serde::de::DeserializeOwned; +use serde::Serialize; +use std::sync::Arc; + +/// Erreurs possibles lors de l'utilisation du client API. +#[derive(Debug, thiserror::Error, Serialize)] +#[serde(tag = "type", content = "data")] +pub enum ApiError { + #[error("Erreur de requête HTTP: {0}")] + Http(String), + #[error("Erreur de désérialisation: {0}")] + Json(String), + #[error("Réponse d'erreur du serveur: {status} - {body}")] + ServerError { status: u16, body: String }, +} + +impl From for ApiError { + fn from(err: reqwest::Error) -> Self { + ApiError::Http(err.to_string()) + } +} + +impl From for ApiError { + fn from(err: serde_json::Error) -> Self { + ApiError::Json(err.to_string()) + } +} + +pub type ApiResult = Result; + +/// Un client API générique capable de se connecter à plusieurs serveurs. +/// Il gère l'authentification par token JWT de manière thread-safe. +#[derive(Clone, Debug)] +pub struct ApiClient { + base_url: String, + inner: Client, + token: Arc>>, +} + +impl ApiClient { + /// Initialise un nouveau client pour un serveur spécifique. + pub fn new(base_url: String) -> Self { + let mut headers = header::HeaderMap::new(); + headers.insert( + header::CONTENT_TYPE, + header::HeaderValue::from_static("application/json"), + ); + + let inner = Client::builder() + .default_headers(headers) + .build() + .unwrap_or_else(|_| Client::new()); + + Self { + base_url: base_url.trim_end_matches('/').to_string(), + inner, + token: Arc::new(RwLock::new(None)), + } + } + + /// Définit le token JWT à utiliser pour les requêtes authentifiées. + pub fn set_token(&self, token: String) { + let mut lock = self.token.write(); + *lock = Some(token); + } + + /// Récupère le token JWT actuel s'il existe. + pub fn get_token(&self) -> Option { + self.token.read().clone() + } + + /// Supprime le token JWT actuel. + pub fn clear_token(&self) { + let mut lock = self.token.write(); + *lock = None; + } + + /// Construit une requête HTTP avec l'authentification si disponible. + fn build_request(&self, method: Method, path: &str) -> RequestBuilder { + let url = if path.starts_with("http") { + path.to_string() + } else { + format!("{}/{}", self.base_url, path.trim_start_matches('/')) + }; + let mut rb = self.inner.request(method, url); + + if let Some(token) = self.token.read().as_ref() { + rb = rb.header(header::AUTHORIZATION, format!("Bearer {}", token)); + } + + rb + } + + async fn handle_response(&self, response: Response) -> ApiResult { + let status = response.status(); + if status.is_success() { + let data = response.json::().await?; + Ok(data) + } else { + let body = response.text().await.unwrap_or_default(); + Err(ApiError::ServerError { + status: status.as_u16(), + body, + }) + } + } + + pub async fn get(&self, path: &str) -> ApiResult { + let response = self.build_request(Method::GET, path).send().await?; + self.handle_response(response).await + } + + pub async fn post( + &self, + path: &str, + body: &B, + ) -> ApiResult { + let response = self + .build_request(Method::POST, path) + .json(body) + .send() + .await?; + self.handle_response(response).await + } + + pub async fn post_empty(&self, path: &str) -> ApiResult { + let response = self.build_request(Method::POST, path).send().await?; + self.handle_response(response).await + } + + pub async fn put( + &self, + path: &str, + body: &B, + ) -> ApiResult { + let response = self + .build_request(Method::PUT, path) + .json(body) + .send() + .await?; + self.handle_response(response).await + } + + pub async fn delete(&self, path: &str) -> ApiResult { + let response = self.build_request(Method::DELETE, path).send().await?; + self.handle_response(response).await + } + + // --- ECOSYSTEMS --- + + // Auth + pub async fn login(&self, req: &LoginRequest) -> ApiResult { + self.post("api/auth/login", req).await + } + + pub async fn claim_admin(&self, req: &ClaimAdminRequest) -> ApiResult<()> { + self.post("api/auth/claim-admin", req).await + } + + pub async fn ssh_challenge(&self) -> ApiResult { + self.post_empty("api/auth/ssh-challenge").await + } + + // Server + pub async fn server_list(&self) -> ApiResult> { + self.get("api/server").await + } + + pub async fn server_create(&self, req: &CreateServerRequest) -> ApiResult { + self.post("api/server", req).await + } + + // Category + pub async fn category_list(&self, server_id: Option<&str>) -> ApiResult> { + let path = if let Some(id) = server_id { + format!("api/category?server_id={}", id) + } else { + "api/category".to_string() + }; + self.get(&path).await + } + + pub async fn category_create( + &self, + req: &CreateCategoryRequest, + ) -> ApiResult { + self.post("api/category", req).await + } + + pub async fn category_detail(&self, id: &str) -> ApiResult { + self.get(&format!("api/category/{}", id)).await + } + + pub async fn category_update( + &self, + id: &str, + req: &CreateCategoryRequest, + ) -> ApiResult { + self.put(&format!("api/category/{}", id), req).await + } + + pub async fn category_delete(&self, id: &str) -> ApiResult<()> { + self.delete(&format!("api/category/{}", id)).await + } + + // Channel + pub async fn channel_list(&self) -> ApiResult> { + self.get("api/channel").await + } + + pub async fn channel_create(&self, req: &CreateChannelRequest) -> ApiResult { + self.post("api/channel", req).await + } + + pub async fn channel_detail(&self, id: &str) -> ApiResult { + self.get(&format!("api/channel/{}", id)).await + } + + pub async fn channel_update( + &self, + id: &str, + req: &CreateChannelRequest, + ) -> ApiResult { + self.put(&format!("api/channel/{}", id), req).await + } + + pub async fn channel_delete(&self, id: &str) -> ApiResult<()> { + self.delete(&format!("api/channel/{}", id)).await + } + + // Message + pub async fn message_list(&self) -> ApiResult> { + self.get("api/message").await + } + + pub async fn message_create(&self, req: &CreateMessageRequest) -> ApiResult { + self.post("api/message", req).await + } + + // User + pub async fn user_list(&self) -> ApiResult> { + self.get("api/user").await + } +} diff --git a/src-tauri/src/api/commands.rs b/src-tauri/src/api/commands.rs new file mode 100644 index 0000000..0d2d187 --- /dev/null +++ b/src-tauri/src/api/commands.rs @@ -0,0 +1,133 @@ +use crate::api::models::*; +use crate::api::ApiResult; +use crate::app::state::AppState; +use tauri::{command, State}; + +// --- AUTH --- + +#[command] +pub async fn api_login( + state: State<'_, AppState>, + base_url: String, + req: LoginRequest, +) -> ApiResult { + let client = state.api.get_or_create_client(base_url); + let res = client.login(&req).await?; + client.set_token(res.token.clone()); + Ok(res) +} + +#[command] +pub async fn api_claim_admin( + state: State<'_, AppState>, + base_url: String, + req: ClaimAdminRequest, +) -> ApiResult<()> { + let client = state.api.get_or_create_client(base_url); + client.claim_admin(&req).await +} + +#[command] +pub async fn api_ssh_challenge( + state: State<'_, AppState>, + base_url: String, +) -> ApiResult { + let client = state.api.get_or_create_client(base_url); + client.ssh_challenge().await +} + +// --- SERVER --- + +#[command] +pub async fn api_server_list( + state: State<'_, AppState>, + base_url: String, +) -> ApiResult> { + let client = state.api.get_or_create_client(base_url); + client.server_list().await +} + +#[command] +pub async fn api_server_create( + state: State<'_, AppState>, + base_url: String, + req: CreateServerRequest, +) -> ApiResult { + let client = state.api.get_or_create_client(base_url); + client.server_create(&req).await +} + +// --- CATEGORY --- + +#[command] +pub async fn api_category_list( + state: State<'_, AppState>, + base_url: String, + server_id: Option, +) -> ApiResult> { + let client = state.api.get_or_create_client(base_url); + client.category_list(server_id.as_deref()).await +} + +#[command] +pub async fn api_category_create( + state: State<'_, AppState>, + base_url: String, + req: CreateCategoryRequest, +) -> ApiResult { + let client = state.api.get_or_create_client(base_url); + client.category_create(&req).await +} + +// --- CHANNEL --- + +#[command] +pub async fn api_channel_list( + state: State<'_, AppState>, + base_url: String, +) -> ApiResult> { + let client = state.api.get_or_create_client(base_url); + client.channel_list().await +} + +#[command] +pub async fn api_channel_create( + state: State<'_, AppState>, + base_url: String, + req: CreateChannelRequest, +) -> ApiResult { + let client = state.api.get_or_create_client(base_url); + client.channel_create(&req).await +} + +// --- MESSAGE --- + +#[command] +pub async fn api_message_list( + state: State<'_, AppState>, + base_url: String, +) -> ApiResult> { + let client = state.api.get_or_create_client(base_url); + client.message_list().await +} + +#[command] +pub async fn api_message_create( + state: State<'_, AppState>, + base_url: String, + req: CreateMessageRequest, +) -> ApiResult { + let client = state.api.get_or_create_client(base_url); + client.message_create(&req).await +} + +// --- USER --- + +#[command] +pub async fn api_user_list( + state: State<'_, AppState>, + base_url: String, +) -> ApiResult> { + let client = state.api.get_or_create_client(base_url); + client.user_list().await +} diff --git a/src-tauri/src/api/mod.rs b/src-tauri/src/api/mod.rs new file mode 100644 index 0000000..d7f6d6a --- /dev/null +++ b/src-tauri/src/api/mod.rs @@ -0,0 +1,7 @@ +pub mod client; +pub mod commands; +pub mod models; +pub mod state; + +pub use client::{ApiClient, ApiError, ApiResult}; +pub use state::ApiManager; diff --git a/src-tauri/src/api/models.rs b/src-tauri/src/api/models.rs new file mode 100644 index 0000000..b60894f --- /dev/null +++ b/src-tauri/src/api/models.rs @@ -0,0 +1,115 @@ +use serde::{Deserialize, Serialize}; + +// --- AUTH --- + +#[derive(Debug, Clone, Deserialize, Serialize)] +pub struct LoginRequest { + pub username: String, + pub password: Option, +} + +#[derive(Debug, Clone, Deserialize, Serialize)] +pub struct LoginResponse { + pub token: String, + pub username: String, +} + +#[derive(Debug, Clone, Deserialize, Serialize)] +pub struct ClaimAdminRequest { + pub token: String, + pub username: String, + pub password: Option, +} + +#[derive(Debug, Clone, Deserialize, Serialize)] +pub struct SshChallengeResponse { + pub challenge: String, +} + +// --- SERVER --- + +#[derive(Debug, Clone, Deserialize, Serialize)] +pub struct CreateServerRequest { + pub name: String, + pub password: Option, +} + +#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)] +pub struct ServerResponse { + pub id: String, + pub name: String, + pub created_at: String, + pub updated_at: String, +} + +// --- CATEGORY --- + +#[derive(Debug, Clone, Deserialize, Serialize)] +pub struct CreateCategoryRequest { + pub server_id: String, + pub name: String, +} + +#[derive(Debug, Clone, Deserialize, Serialize)] +pub struct CategoryResponse { + pub id: String, + pub name: String, +} + +// --- CHANNEL --- + +#[derive(Debug, Clone, Copy, Deserialize, Serialize, PartialEq, Eq)] +#[serde(rename_all = "snake_case")] +pub enum ChannelType { + Text, + Voice, + DM, +} + +#[derive(Debug, Clone, Deserialize, Serialize)] +pub struct CreateChannelRequest { + pub channel_type: ChannelType, + pub category_id: Option, + pub name: Option, + pub position: Option, + pub server_id: Option, +} + +#[derive(Debug, Clone, Deserialize, Serialize)] +pub struct ChannelResponse { + pub id: String, + pub name: Option, + pub position: i32, + pub channel_type: ChannelType, + pub category_id: Option, +} + +// --- MESSAGE --- + +#[derive(Debug, Clone, Deserialize, Serialize)] +pub struct CreateMessageRequest { + pub channel_id: String, + pub content: String, +} + +#[derive(Debug, Clone, Deserialize, Serialize)] +pub struct MessageResponse { + pub id: String, + pub channel_id: String, + pub author_id: String, + pub content: String, +} + +// --- USER --- + +#[derive(Debug, Clone, Deserialize, Serialize)] +pub struct CreateUserRequest { + pub username: String, +} + +#[derive(Debug, Clone, Deserialize, Serialize)] +pub struct UserResponse { + pub id: String, + pub username: String, + pub pub_key: String, +} diff --git a/src-tauri/src/api/state.rs b/src-tauri/src/api/state.rs new file mode 100644 index 0000000..d8bf684 --- /dev/null +++ b/src-tauri/src/api/state.rs @@ -0,0 +1,35 @@ +use crate::api::client::ApiClient; +use parking_lot::RwLock; +use std::collections::HashMap; + +/// Gère plusieurs instances de ApiClient (une par serveur). +#[derive(Debug, Default)] +pub struct ApiManager { + clients: RwLock>, +} + +impl ApiManager { + pub fn new() -> Self { + Self { + clients: RwLock::new(HashMap::new()), + } + } + + /// Récupère ou crée un client pour une base_url donnée. + pub fn get_or_create_client(&self, base_url: String) -> ApiClient { + let mut clients = self.clients.write(); + if let Some(client) = clients.get(&base_url) { + client.clone() + } else { + let client = ApiClient::new(base_url.clone()); + clients.insert(base_url, client.clone()); + client + } + } + + /// Supprime un client. + pub fn remove_client(&self, base_url: &str) { + let mut clients = self.clients.write(); + clients.remove(base_url); + } +} diff --git a/src-tauri/src/app/mod.rs b/src-tauri/src/app/mod.rs index eaa763c..84cab4c 100644 --- a/src-tauri/src/app/mod.rs +++ b/src-tauri/src/app/mod.rs @@ -1 +1,2 @@ -pub mod ox_speak_app; \ No newline at end of file +pub mod ox_speak_app; +pub mod state; diff --git a/src-tauri/src/app/ox_speak_app.rs b/src-tauri/src/app/ox_speak_app.rs index bc9b562..ae65a50 100644 --- a/src-tauri/src/app/ox_speak_app.rs +++ b/src-tauri/src/app/ox_speak_app.rs @@ -1,5 +1,5 @@ use crate::config::ConfigManager; -use tauri::{AppHandle, Manager}; +use tauri::AppHandle; pub struct OxSpeakApp { tauri_handle: AppHandle, @@ -7,17 +7,7 @@ pub struct OxSpeakApp { } impl OxSpeakApp { - pub async fn new(tauri_handle: AppHandle) -> Self { - // Chargement de la configuration - let config_dir = tauri_handle - .path() - .app_config_dir() - .expect("Failed to get app config dir"); - - let config = ConfigManager::load(config_dir) - .await - .expect("Failed to load config"); - + pub async fn new(tauri_handle: AppHandle, config: ConfigManager) -> Self { Self { tauri_handle, config, diff --git a/src-tauri/src/app/state.rs b/src-tauri/src/app/state.rs new file mode 100644 index 0000000..eb04aac --- /dev/null +++ b/src-tauri/src/app/state.rs @@ -0,0 +1,19 @@ +use crate::api::state::ApiManager; +use crate::config::ConfigManager; +use std::sync::OnceLock; + +/// État global de l'application. +#[derive(Debug, Default)] +pub struct AppState { + pub api: ApiManager, + pub config: OnceLock, +} + +impl AppState { + pub fn new() -> Self { + Self { + api: ApiManager::new(), + config: OnceLock::new(), + } + } +} diff --git a/src-tauri/src/config/commands.rs b/src-tauri/src/config/commands.rs new file mode 100644 index 0000000..bc5376a --- /dev/null +++ b/src-tauri/src/config/commands.rs @@ -0,0 +1,21 @@ +use crate::app::state::AppState; +use crate::config::config::ConfigTree; +use tauri::{command, State}; + +#[command] +pub async fn config_get(state: State<'_, AppState>) -> Result { + let config = state.config.get().ok_or("Config non initialisée")?; + Ok(config.get_config()) +} + +#[command] +pub async fn config_update( + state: State<'_, AppState>, + new_config: ConfigTree, +) -> Result<(), String> { + let config = state.config.get().ok_or("Config non initialisée")?; + config + .update_config(new_config) + .await + .map_err(|e| e.to_string()) +} diff --git a/src-tauri/src/config/config.rs b/src-tauri/src/config/config.rs index dfaedf1..6c4421a 100644 --- a/src-tauri/src/config/config.rs +++ b/src-tauri/src/config/config.rs @@ -5,35 +5,37 @@ use ssh_key::PrivateKey; use std::net::{SocketAddr, ToSocketAddrs}; use std::path::PathBuf; use std::sync::Arc; +use tauri::{AppHandle, Emitter}; use tokio::fs; #[derive(Debug, Clone)] pub struct ConfigManager { tree_config: Arc>, // On garanti l'unicité avec un Mutex path: PathBuf, + app_handle: Option, } #[derive(Deserialize, Serialize, Debug, Clone)] -struct ConfigTree { +pub struct ConfigTree { pub servers: Vec, pub identities: Vec, } #[derive(Deserialize, Serialize, Debug, Clone)] -struct ConfigServer { +pub struct ConfigServer { pub adresse: String, pub identity: String, } #[derive(Deserialize, Serialize, Debug, Clone)] #[serde(rename_all = "snake_case")] -enum IdentityMode { +pub enum IdentityMode { PrivateKeyPath, PrivateKeyBase64, } #[derive(Deserialize, Serialize, Debug, Clone)] -struct IdentityConfig { +pub struct IdentityConfig { pub id: String, pub username: String, pub private_key: String, @@ -41,7 +43,26 @@ struct IdentityConfig { } impl ConfigManager { - pub async fn load(config_dir: PathBuf) -> Result { + pub fn get_config(&self) -> ConfigTree { + self.tree_config.lock().clone() + } + + pub async fn update_config(&self, new_config: ConfigTree) -> Result<(), std::io::Error> { + { + let mut lock = self.tree_config.lock(); + *lock = new_config.clone(); + } + self.save().await?; + + // Notifier le front-end du changement + if let Some(handle) = &self.app_handle { + let _ = handle.emit("config-changed", new_config); + } + + Ok(()) + } + + pub async fn load(config_dir: PathBuf, app_handle: AppHandle) -> Result { let config_path = config_dir.join("config.toml"); if config_path.exists() && config_path.is_file() { @@ -50,14 +71,15 @@ impl ConfigManager { return Ok(Self { tree_config: Arc::new(Mutex::new(tree_config)), path: config_path, + app_handle: Some(app_handle), }); } } - Self::create(config_dir).await + Self::create(config_dir, app_handle).await } - async fn create(config_dir: PathBuf) -> Result { + async fn create(config_dir: PathBuf, app_handle: AppHandle) -> Result { let config_path = config_dir.join("config.toml"); let tree_config = ConfigTree { @@ -68,6 +90,7 @@ impl ConfigManager { let config = ConfigManager { tree_config: Arc::new(Mutex::new(tree_config)), path: config_path, + app_handle: Some(app_handle), }; config.save().await?; @@ -83,10 +106,11 @@ impl ConfigManager { } // Lock le mutex pour lire tree_config - let tree_config = self.tree_config.lock(); - let serialized = toml::to_string_pretty(&*tree_config) - .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e))?; - drop(tree_config); // Libère le lock explicitement + let serialized = { + let tree_config = self.tree_config.lock(); + toml::to_string_pretty(&*tree_config) + .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e))? + }; fs::write(&self.path, serialized).await?; Ok(()) diff --git a/src-tauri/src/config/mod.rs b/src-tauri/src/config/mod.rs index 735d3cd..561ea95 100644 --- a/src-tauri/src/config/mod.rs +++ b/src-tauri/src/config/mod.rs @@ -1,2 +1,3 @@ -mod config; +pub mod commands; +pub mod config; pub use config::ConfigManager; diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index 7b23a0d..94fa286 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -13,8 +13,9 @@ // .expect("error while running tauri application"); // } +mod app; pub mod tauri_app; mod utils; -mod app; +pub mod api; mod config; diff --git a/src-tauri/src/tauri_app.rs b/src-tauri/src/tauri_app.rs index fe9d562..5e0c67e 100644 --- a/src-tauri/src/tauri_app.rs +++ b/src-tauri/src/tauri_app.rs @@ -1,4 +1,8 @@ +use crate::api::commands::*; use crate::app::ox_speak_app::OxSpeakApp; +use crate::app::state::AppState; +use crate::config::commands::*; +use crate::config::ConfigManager; use std::sync::Arc; use tauri::{Manager, WindowEvent}; @@ -15,12 +19,43 @@ pub async fn run() { tauri::Builder::default() .plugin(tauri_plugin_opener::init()) + .manage(AppState::new()) + .invoke_handler(tauri::generate_handler![ + greet, + api_login, + api_claim_admin, + api_ssh_challenge, + api_server_list, + api_server_create, + api_category_list, + api_category_create, + api_channel_list, + api_channel_create, + api_message_list, + api_message_create, + api_user_list, + config_get, + config_update, + ]) .setup(|app| { let handle = app.handle().clone(); // Démarrer le backend tauri::async_runtime::spawn(async move { - let ox_speak = Arc::new(OxSpeakApp::new(handle.clone()).await); + let app_state = handle.state::(); + let config_dir = handle + .path() + .app_config_dir() + .expect("Failed to get app config dir"); + + let config = ConfigManager::load(config_dir, handle.clone()) + .await + .expect("Failed to load config"); + + // Mettre la config dans AppState + let _ = app_state.config.set(config.clone()); + + let ox_speak = Arc::new(OxSpeakApp::new(handle.clone(), config).await); handle.manage(ox_speak.clone()); ox_speak.run().await; }); diff --git a/src/api/README.md b/src/api/README.md new file mode 100644 index 0000000..5261362 --- /dev/null +++ b/src/api/README.md @@ -0,0 +1,68 @@ +# OxSpeak API Client (TypeScript) + +Cette interface permet de communiquer avec les serveurs OxSpeak via Tauri (et plus tard via le Web). + +## Installation + +Assurez-vous d'avoir installé les dépendances Tauri dans votre projet frontend : + +```bash +yarn add @tauri-apps/api +``` + +## Utilisation + +L'API est conçue pour supporter plusieurs serveurs simultanément. Chaque serveur est représenté par une instance de +`IApiClient`. + +### Créer un client + +```typescript +import { createApiClient } from './api'; + +const client = createApiClient('http://localhost:8080'); +``` + +### Authentification + +```typescript +try { + const response = await client.login({ + username: 'mon_pseudo', + password: 'mon_password' + }); + console.log('Connecté ! Token:', response.token); +} catch (error) { + console.error('Erreur de connexion:', error); +} +``` + +### Lister les serveurs + +```typescript +const servers = await client.getServerList(); +servers.forEach(s => console.log(`Serveur: ${s.name} (${s.id})`)); +``` + +### Créer un canal + +```typescript +import { ChannelType } from './api'; + +const newChannel = await client.createChannel({ + name: 'Général', + channel_type: 'text', + server_id: 'server-123' +}); +``` + +## Architecture + +L'interface est séparée en trois parties pour permettre une évolution vers une version Web sans casser le code +existant : + +1. `types.ts` : Les définitions d'interfaces de données (identiques aux modèles Rust). +2. `client.ts` : L'interface `IApiClient` définissant le contrat. +3. `tauri-client.ts` : L'implémentation concrète utilisant Tauri `invoke`. + +Le fichier `index.ts` expose une usine `createApiClient` qui instancie la bonne implémentation. diff --git a/src/api/client.ts b/src/api/client.ts new file mode 100644 index 0000000..4800f33 --- /dev/null +++ b/src/api/client.ts @@ -0,0 +1,53 @@ +import type { + CategoryResponse, + ChannelResponse, + ClaimAdminRequest, + CreateCategoryRequest, + CreateChannelRequest, + CreateMessageRequest, + CreateServerRequest, + LoginRequest, + LoginResponse, + MessageResponse, + ServerResponse, + SshChallengeResponse, + UserResponse, +} from './types'; + +/** + * Interface générique pour l'API OxSpeak. + * Elle permet de découpler l'implémentation (Tauri, Web, etc.) de l'utilisation. + */ +export interface IApiClient { + readonly baseUrl: string; + + // AUTH + login(req: LoginRequest): Promise; + + claimAdmin(req: ClaimAdminRequest): Promise; + + sshChallenge(): Promise; + + // SERVER + getServerList(): Promise; + + createServer(req: CreateServerRequest): Promise; + + // CATEGORY + getCategoryList(serverId?: string): Promise; + + createCategory(req: CreateCategoryRequest): Promise; + + // CHANNEL + getChannelList(): Promise; + + createChannel(req: CreateChannelRequest): Promise; + + // MESSAGE + getMessageList(): Promise; + + createMessage(req: CreateMessageRequest): Promise; + + // USER + getUserList(): Promise; +} diff --git a/src/api/index.ts b/src/api/index.ts new file mode 100644 index 0000000..8279d38 --- /dev/null +++ b/src/api/index.ts @@ -0,0 +1,16 @@ +export * from './types'; +export * from './client'; +export * from './tauri-client'; + +import {TauriApiClient} from './tauri-client'; +import type {IApiClient} from './client'; + +/** + * Usine pour créer des clients API. + * Plus tard, cette usine pourra retourner une implémentation Web ou Tauri + * selon l'environnement (isTauri). + */ +export function createApiClient(baseUrl: string): IApiClient { + // Pour le moment, on retourne systématiquement l'implémentation Tauri. + return new TauriApiClient(baseUrl); +} diff --git a/src/api/tauri-client.ts b/src/api/tauri-client.ts new file mode 100644 index 0000000..2d239f9 --- /dev/null +++ b/src/api/tauri-client.ts @@ -0,0 +1,83 @@ +import {invoke} from '@tauri-apps/api/core'; +import type {IApiClient} from './client'; +import type { + CategoryResponse, + ChannelResponse, + ClaimAdminRequest, + CreateCategoryRequest, + CreateChannelRequest, + CreateMessageRequest, + CreateServerRequest, + LoginRequest, + LoginResponse, + MessageResponse, + ServerResponse, + SshChallengeResponse, + UserResponse, +} from './types'; + +/** + * Implémentation Tauri de l'interface API. + * Cette version utilise 'invoke' pour communiquer avec le backend Rust. + */ +export class TauriApiClient implements IApiClient { + constructor(public readonly baseUrl: string) { + } + + // AUTH + async login(req: LoginRequest): Promise { + return await invoke('api_login', {baseUrl: this.baseUrl, req}); + } + + async claimAdmin(req: ClaimAdminRequest): Promise { + return await invoke('api_claim_admin', {baseUrl: this.baseUrl, req}); + } + + async sshChallenge(): Promise { + return await invoke('api_ssh_challenge', {baseUrl: this.baseUrl}); + } + + // SERVER + async getServerList(): Promise { + return await invoke('api_server_list', {baseUrl: this.baseUrl}); + } + + async createServer(req: CreateServerRequest): Promise { + return await invoke('api_server_create', {baseUrl: this.baseUrl, req}); + } + + // CATEGORY + async getCategoryList(serverId?: string): Promise { + return await invoke('api_category_list', { + baseUrl: this.baseUrl, + serverId: serverId ?? null + }); + } + + async createCategory(req: CreateCategoryRequest): Promise { + return await invoke('api_category_create', {baseUrl: this.baseUrl, req}); + } + + // CHANNEL + async getChannelList(): Promise { + return await invoke('api_channel_list', {baseUrl: this.baseUrl}); + } + + async createChannel(req: CreateChannelRequest): Promise { + return await invoke('api_channel_create', {baseUrl: this.baseUrl, req}); + } + + // MESSAGE + async getMessageList(): Promise { + return await invoke('api_message_list', {baseUrl: this.baseUrl}); + } + + async createMessage(req: CreateMessageRequest): Promise { + return await invoke('api_message_create', {baseUrl: this.baseUrl, req}); + } + + // USER + async getUserList(): Promise { + return await invoke('api_user_list', {baseUrl: this.baseUrl}); + } +} diff --git a/src/api/types.ts b/src/api/types.ts new file mode 100644 index 0000000..ca2426b --- /dev/null +++ b/src/api/types.ts @@ -0,0 +1,100 @@ +// --- AUTH --- + +export interface LoginRequest { + username: string; + password?: string; +} + +export interface LoginResponse { + token: string; + username: string; +} + +export interface ClaimAdminRequest { + token: string; + username: string; + password?: string; +} + +export interface SshChallengeResponse { + challenge: string; +} + +// --- SERVER --- + +export interface CreateServerRequest { + name: string; + password?: string; +} + +export interface ServerResponse { + id: string; + name: string; + created_at: string; + updated_at: string; +} + +// --- CATEGORY --- + +export interface CreateCategoryRequest { + server_id: string; + name: string; +} + +export interface CategoryResponse { + id: string; + name: string; +} + +// --- CHANNEL --- + +export type ChannelType = 'text' | 'voice' | 'd_m'; + +export interface CreateChannelRequest { + channel_type: ChannelType; + category_id?: string; + name?: string; + position?: number; + server_id?: string; +} + +export interface ChannelResponse { + id: string; + name?: string; + position: number; + channel_type: ChannelType; + category_id?: string; +} + +// --- MESSAGE --- + +export interface CreateMessageRequest { + channel_id: string; + content: string; +} + +export interface MessageResponse { + id: string; + channel_id: string; + author_id: string; + content: string; +} + +// --- USER --- + +export interface CreateUserRequest { + username: string; +} + +export interface UserResponse { + id: string; + username: string; + pub_key: string; +} + +// --- ERRORS --- + +export interface ApiError { + type: string; + data: string | { status: number, body: string }; +} diff --git a/src/config/README.md b/src/config/README.md new file mode 100644 index 0000000..1da279b --- /dev/null +++ b/src/config/README.md @@ -0,0 +1,70 @@ +# Système de Configuration OxSpeak + +Ce module permet de gérer la configuration globale de l'application (serveurs enregistrés et identités). + +## Utilisation + +Le système utilise une interface générique `IConfigClient` qui permet d'utiliser le même code pour Tauri et +une version Web (localStorage). + +### Détection de l'environnement + +La factory `createConfigClient()` détecte automatiquement si l'application tourne dans Tauri ou dans un navigateur +standard : + +- **Tauri** : Utilise les commandes Rust et le stockage TOML local. +- **Web** : Utilise le `localStorage` du navigateur. + +### Écoute des changements + +Vous pouvez écouter les modifications de configuration de manière réactive : + +```typescript +const configClient = createConfigClient(); + +// S'abonner aux changements +const unlisten = await configClient.onChanged((newConfig) => { + console.log('La config a changé !', newConfig); +}); + +// Plus tard, pour arrêter d'écouter +// unlisten(); +``` + +### Exemple en TypeScript + +```typescript +import {createConfigClient} from '@/config'; + +const configClient = createConfigClient(); + +// Récupérer la configuration +async function loadConfig() { + try { + const config = await configClient.get(); + console.log('Serveurs configurés:', config.servers); + } catch (error) { + console.error('Erreur lors du chargement de la config:', error); + } +} + +// Mettre à jour la configuration +async function addServer(name: string, identityId: string) { + const config = await configClient.get(); + + config.servers.push({ + adresse: name, + identity: identityId + }); + + await configClient.update(config); + console.log('Serveur ajouté !'); +} +``` + +### Structures de données + +- **ConfigTree** : La racine de la configuration contenant les serveurs et les identités. +- **ConfigServer** : Définit un serveur (adresse et identité liée). +- **IdentityConfig** : Définit une identité utilisateur avec sa clé privée SSH. +- **IdentityMode** : `private_key_path` (chemin vers le fichier) ou `private_key_base64` (clé brute encodée). diff --git a/src/config/client.ts b/src/config/client.ts new file mode 100644 index 0000000..d4894cc --- /dev/null +++ b/src/config/client.ts @@ -0,0 +1,80 @@ +import {invoke} from '@tauri-apps/api/core'; +import {listen} from '@tauri-apps/api/event'; +import type {ConfigTree} from './types'; + +export interface IConfigClient { + get(): Promise; + + update(config: ConfigTree): Promise; + + /** + * Écoute les changements de configuration. + * Retourne une fonction pour arrêter l'écoute. + */ + onChanged(callback: (config: ConfigTree) => void): Promise<() => void>; +} + +/** + * Implémentation Tauri pour le client de configuration. + */ +export class TauriConfigClient implements IConfigClient { + async get(): Promise { + return await invoke('config_get'); + } + + async update(config: ConfigTree): Promise { + await invoke('config_update', {newConfig: config}); + } + + async onChanged(callback: (config: ConfigTree) => void): Promise<() => void> { + const unlisten = await listen('config-changed', (event) => { + callback(event.payload); + }); + return unlisten; + } +} + +/** + * Implémentation Web (LocalStorage) pour le client de configuration. + * Utile pour le développement hors-Tauri ou la future version Web. + */ +export class WebConfigClient implements IConfigClient { + private STORAGE_KEY = 'ox-speak-config'; + + async get(): Promise { + const data = localStorage.getItem(this.STORAGE_KEY); + if (data) { + try { + return JSON.parse(data); + } catch (e) { + console.error('Failed to parse config from localStorage', e); + } + } + return {servers: [], identities: []}; + } + + async update(config: ConfigTree): Promise { + localStorage.setItem(this.STORAGE_KEY, JSON.stringify(config)); + // Simuler un événement de changement pour les autres composants de la même page + window.dispatchEvent(new CustomEvent('ox-config-changed', {detail: config})); + } + + async onChanged(callback: (config: ConfigTree) => void): Promise<() => void> { + const handler = (event: any) => { + callback(event.detail); + }; + window.addEventListener('ox-config-changed', handler); + return () => window.removeEventListener('ox-config-changed', handler); + } +} + +/** + * Usine pour créer le client de configuration approprié. + */ +export function createConfigClient(): IConfigClient { + // Détection automatique de l'environnement + if ((window as any).__TAURI_INTERNALS__) { + return new TauriConfigClient(); + } + return new WebConfigClient(); +} diff --git a/src/config/index.ts b/src/config/index.ts new file mode 100644 index 0000000..70f3c79 --- /dev/null +++ b/src/config/index.ts @@ -0,0 +1,2 @@ +export * from './types'; +export * from './client'; diff --git a/src/config/types.ts b/src/config/types.ts new file mode 100644 index 0000000..5fd5ec5 --- /dev/null +++ b/src/config/types.ts @@ -0,0 +1,18 @@ +export type IdentityMode = 'private_key_path' | 'private_key_base64'; + +export interface IdentityConfig { + id: string; + username: string; + private_key: string; + mode: IdentityMode; +} + +export interface ConfigServer { + adresse: string; + identity: string; +} + +export interface ConfigTree { + servers: ConfigServer[]; + identities: IdentityConfig[]; +}