From 67601680f438906273c5c9fe887a13e37b570044 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adam=20Ciarcin=CC=81ski?= Date: Wed, 1 Oct 2025 12:58:58 +0200 Subject: [PATCH 01/28] macOS: use VPN network extension --- package.json | 10 +- pnpm-lock.yaml | 422 +++++++++++++++++---------------- src-tauri/Cargo.lock | 139 ++++++----- src-tauri/Cargo.toml | 10 +- src-tauri/build.rs | 9 + src-tauri/src/commands.rs | 4 + swift/.gitignore | 10 + swift/Package.swift | 32 +++ swift/Sources/Shared.swift | 68 ++++++ swift/Sources/VPNError.swift | 36 +++ swift/Sources/VPNManager.swift | 112 +++++++++ swift/Sources/Wireguard.swift | 18 ++ 12 files changed, 588 insertions(+), 282 deletions(-) create mode 100644 swift/.gitignore create mode 100644 swift/Package.swift create mode 100644 swift/Sources/Shared.swift create mode 100644 swift/Sources/VPNError.swift create mode 100644 swift/Sources/VPNManager.swift create mode 100644 swift/Sources/Wireguard.swift diff --git a/package.json b/package.json index ee8a6109..322b1bb0 100644 --- a/package.json +++ b/package.json @@ -83,7 +83,7 @@ "lodash-es": "^4.17.21", "merge-refs": "^2.0.0", "millify": "^6.1.0", - "motion": "^12.23.21", + "motion": "^12.23.22", "p-timeout": "^6.1.4", "prop-types": "^15.8.1", "radash": "^12.1.1", @@ -114,10 +114,10 @@ "@tauri-apps/cli": "^2.8.4", "@types/file-saver": "^2.0.7", "@types/lodash-es": "^4.17.12", - "@types/node": "^24.5.2", - "@types/react": "^19.1.13", + "@types/node": "^24.6.1", + "@types/react": "^19.1.16", "@types/react-dom": "^19.1.9", - "@vitejs/plugin-react": "^5.0.3", + "@vitejs/plugin-react": "^5.0.4", "@vitejs/plugin-react-swc": "^4.1.0", "autoprefixer": "^10.4.21", "npm-run-all": "^4.1.5", @@ -126,7 +126,7 @@ "sass": "~1.92.1", "typedoc": "^0.28.13", "typesafe-i18n": "^5.26.2", - "typescript": "^5.9.2", + "typescript": "^5.9.3", "vite": "^7.1.7" }, "volta": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b2cd5ffb..5f28b2d6 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -100,7 +100,7 @@ importers: version: 1.0.3 html-react-parser: specifier: ^5.2.6 - version: 5.2.6(@types/react@19.1.13)(react@19.1.1) + version: 5.2.6(@types/react@19.1.16)(react@19.1.1) itertools: specifier: ^2.5.0 version: 2.5.0 @@ -112,13 +112,13 @@ importers: version: 4.17.21 merge-refs: specifier: ^2.0.0 - version: 2.0.0(@types/react@19.1.13) + version: 2.0.0(@types/react@19.1.16) millify: specifier: ^6.1.0 version: 6.1.0 motion: - specifier: ^12.23.21 - version: 12.23.21(@emotion/is-prop-valid@1.4.0)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + specifier: ^12.23.22 + version: 12.23.22(@emotion/is-prop-valid@1.4.0)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) p-timeout: specifier: ^6.1.4 version: 6.1.4 @@ -148,7 +148,7 @@ importers: version: 3.5.0(react@19.1.1) react-markdown: specifier: ^10.1.0 - version: 10.1.0(@types/react@19.1.13)(react@19.1.1) + version: 10.1.0(@types/react@19.1.16)(react@19.1.1) react-qr-code: specifier: ^2.0.18 version: 2.0.18(react@19.1.1) @@ -163,7 +163,7 @@ importers: version: 1.0.26(react-dom@19.1.1(react@19.1.1))(react@19.1.1) recharts: specifier: ^3.2.1 - version: 3.2.1(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react-is@18.3.1)(react@19.1.1)(redux@5.0.1) + version: 3.2.1(@types/react@19.1.16)(react-dom@19.1.1(react@19.1.1))(react-is@18.3.1)(react@19.1.1)(redux@5.0.1) rehype-sanitize: specifier: ^6.0.0 version: 6.0.0 @@ -178,17 +178,17 @@ importers: version: 3.25.76 zustand: specifier: ^5.0.8 - version: 5.0.8(@types/react@19.1.13)(immer@10.1.3)(react@19.1.1)(use-sync-external-store@1.5.0(react@19.1.1)) + version: 5.0.8(@types/react@19.1.16)(immer@10.1.3)(react@19.1.1)(use-sync-external-store@1.5.0(react@19.1.1)) devDependencies: '@biomejs/biome': specifier: ^2.2.4 version: 2.2.4 '@hookform/devtools': specifier: ^4.4.0 - version: 4.4.0(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + version: 4.4.0(@types/react@19.1.16)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) '@svgr/cli': specifier: ^8.1.0 - version: 8.1.0(typescript@5.9.2) + version: 8.1.0(typescript@5.9.3) '@tanstack/react-query': specifier: ^5.90.2 version: 5.90.2(react@19.1.1) @@ -205,20 +205,20 @@ importers: specifier: ^4.17.12 version: 4.17.12 '@types/node': - specifier: ^24.5.2 - version: 24.5.2 + specifier: ^24.6.1 + version: 24.6.1 '@types/react': - specifier: ^19.1.13 - version: 19.1.13 + specifier: ^19.1.16 + version: 19.1.16 '@types/react-dom': specifier: ^19.1.9 - version: 19.1.9(@types/react@19.1.13) + version: 19.1.9(@types/react@19.1.16) '@vitejs/plugin-react': - specifier: ^5.0.3 - version: 5.0.3(vite@7.1.7(@types/node@24.5.2)(sass@1.92.1)(yaml@2.8.1)) + specifier: ^5.0.4 + version: 5.0.4(vite@7.1.7(@types/node@24.6.1)(sass@1.92.1)(yaml@2.8.1)) '@vitejs/plugin-react-swc': specifier: ^4.1.0 - version: 4.1.0(vite@7.1.7(@types/node@24.5.2)(sass@1.92.1)(yaml@2.8.1)) + version: 4.1.0(vite@7.1.7(@types/node@24.6.1)(sass@1.92.1)(yaml@2.8.1)) autoprefixer: specifier: ^10.4.21 version: 10.4.21(postcss@8.5.6) @@ -236,16 +236,16 @@ importers: version: 1.92.1 typedoc: specifier: ^0.28.13 - version: 0.28.13(typescript@5.9.2) + version: 0.28.13(typescript@5.9.3) typesafe-i18n: specifier: ^5.26.2 - version: 5.26.2(typescript@5.9.2) + version: 5.26.2(typescript@5.9.3) typescript: - specifier: ^5.9.2 - version: 5.9.2 + specifier: ^5.9.3 + version: 5.9.3 vite: specifier: ^7.1.7 - version: 7.1.7(@types/node@24.5.2)(sass@1.92.1)(yaml@2.8.1) + version: 7.1.7(@types/node@24.6.1)(sass@1.92.1)(yaml@2.8.1) packages: @@ -765,113 +765,116 @@ packages: '@rolldown/pluginutils@1.0.0-beta.35': resolution: {integrity: sha512-slYrCpoxJUqzFDDNlvrOYRazQUNRvWPjXA17dAOISY3rDMxX6k8K4cj2H+hEYMHF81HO3uNd5rHVigAWRM5dSg==} - '@rollup/rollup-android-arm-eabi@4.52.2': - resolution: {integrity: sha512-o3pcKzJgSGt4d74lSZ+OCnHwkKBeAbFDmbEm5gg70eA8VkyCuC/zV9TwBnmw6VjDlRdF4Pshfb+WE9E6XY1PoQ==} + '@rolldown/pluginutils@1.0.0-beta.38': + resolution: {integrity: sha512-N/ICGKleNhA5nc9XXQG/kkKHJ7S55u0x0XUJbbkmdCnFuoRkM1Il12q9q0eX19+M7KKUEPw/daUPIRnxhcxAIw==} + + '@rollup/rollup-android-arm-eabi@4.52.3': + resolution: {integrity: sha512-h6cqHGZ6VdnwliFG1NXvMPTy/9PS3h8oLh7ImwR+kl+oYnQizgjxsONmmPSb2C66RksfkfIxEVtDSEcJiO0tqw==} cpu: [arm] os: [android] - '@rollup/rollup-android-arm64@4.52.2': - resolution: {integrity: sha512-cqFSWO5tX2vhC9hJTK8WAiPIm4Q8q/cU8j2HQA0L3E1uXvBYbOZMhE2oFL8n2pKB5sOCHY6bBuHaRwG7TkfJyw==} + '@rollup/rollup-android-arm64@4.52.3': + resolution: {integrity: sha512-wd+u7SLT/u6knklV/ifG7gr5Qy4GUbH2hMWcDauPFJzmCZUAJ8L2bTkVXC2niOIxp8lk3iH/QX8kSrUxVZrOVw==} cpu: [arm64] os: [android] - '@rollup/rollup-darwin-arm64@4.52.2': - resolution: {integrity: sha512-vngduywkkv8Fkh3wIZf5nFPXzWsNsVu1kvtLETWxTFf/5opZmflgVSeLgdHR56RQh71xhPhWoOkEBvbehwTlVA==} + '@rollup/rollup-darwin-arm64@4.52.3': + resolution: {integrity: sha512-lj9ViATR1SsqycwFkJCtYfQTheBdvlWJqzqxwc9f2qrcVrQaF/gCuBRTiTolkRWS6KvNxSk4KHZWG7tDktLgjg==} cpu: [arm64] os: [darwin] - '@rollup/rollup-darwin-x64@4.52.2': - resolution: {integrity: sha512-h11KikYrUCYTrDj6h939hhMNlqU2fo/X4NB0OZcys3fya49o1hmFaczAiJWVAFgrM1NCP6RrO7lQKeVYSKBPSQ==} + '@rollup/rollup-darwin-x64@4.52.3': + resolution: {integrity: sha512-+Dyo7O1KUmIsbzx1l+4V4tvEVnVQqMOIYtrxK7ncLSknl1xnMHLgn7gddJVrYPNZfEB8CIi3hK8gq8bDhb3h5A==} cpu: [x64] os: [darwin] - '@rollup/rollup-freebsd-arm64@4.52.2': - resolution: {integrity: sha512-/eg4CI61ZUkLXxMHyVlmlGrSQZ34xqWlZNW43IAU4RmdzWEx0mQJ2mN/Cx4IHLVZFL6UBGAh+/GXhgvGb+nVxw==} + '@rollup/rollup-freebsd-arm64@4.52.3': + resolution: {integrity: sha512-u9Xg2FavYbD30g3DSfNhxgNrxhi6xVG4Y6i9Ur1C7xUuGDW3banRbXj+qgnIrwRN4KeJ396jchwy9bCIzbyBEQ==} cpu: [arm64] os: [freebsd] - '@rollup/rollup-freebsd-x64@4.52.2': - resolution: {integrity: sha512-QOWgFH5X9+p+S1NAfOqc0z8qEpJIoUHf7OWjNUGOeW18Mx22lAUOiA9b6r2/vpzLdfxi/f+VWsYjUOMCcYh0Ng==} + '@rollup/rollup-freebsd-x64@4.52.3': + resolution: {integrity: sha512-5M8kyi/OX96wtD5qJR89a/3x5x8x5inXBZO04JWhkQb2JWavOWfjgkdvUqibGJeNNaz1/Z1PPza5/tAPXICI6A==} cpu: [x64] os: [freebsd] - '@rollup/rollup-linux-arm-gnueabihf@4.52.2': - resolution: {integrity: sha512-kDWSPafToDd8LcBYd1t5jw7bD5Ojcu12S3uT372e5HKPzQt532vW+rGFFOaiR0opxePyUkHrwz8iWYEyH1IIQA==} + '@rollup/rollup-linux-arm-gnueabihf@4.52.3': + resolution: {integrity: sha512-IoerZJ4l1wRMopEHRKOO16e04iXRDyZFZnNZKrWeNquh5d6bucjezgd+OxG03mOMTnS1x7hilzb3uURPkJ0OfA==} cpu: [arm] os: [linux] - '@rollup/rollup-linux-arm-musleabihf@4.52.2': - resolution: {integrity: sha512-gKm7Mk9wCv6/rkzwCiUC4KnevYhlf8ztBrDRT9g/u//1fZLapSRc+eDZj2Eu2wpJ+0RzUKgtNijnVIB4ZxyL+w==} + '@rollup/rollup-linux-arm-musleabihf@4.52.3': + resolution: {integrity: sha512-ZYdtqgHTDfvrJHSh3W22TvjWxwOgc3ThK/XjgcNGP2DIwFIPeAPNsQxrJO5XqleSlgDux2VAoWQ5iJrtaC1TbA==} cpu: [arm] os: [linux] - '@rollup/rollup-linux-arm64-gnu@4.52.2': - resolution: {integrity: sha512-66lA8vnj5mB/rtDNwPgrrKUOtCLVQypkyDa2gMfOefXK6rcZAxKLO9Fy3GkW8VkPnENv9hBkNOFfGLf6rNKGUg==} + '@rollup/rollup-linux-arm64-gnu@4.52.3': + resolution: {integrity: sha512-NcViG7A0YtuFDA6xWSgmFb6iPFzHlf5vcqb2p0lGEbT+gjrEEz8nC/EeDHvx6mnGXnGCC1SeVV+8u+smj0CeGQ==} cpu: [arm64] os: [linux] - '@rollup/rollup-linux-arm64-musl@4.52.2': - resolution: {integrity: sha512-s+OPucLNdJHvuZHuIz2WwncJ+SfWHFEmlC5nKMUgAelUeBUnlB4wt7rXWiyG4Zn07uY2Dd+SGyVa9oyLkVGOjA==} + '@rollup/rollup-linux-arm64-musl@4.52.3': + resolution: {integrity: sha512-d3pY7LWno6SYNXRm6Ebsq0DJGoiLXTb83AIPCXl9fmtIQs/rXoS8SJxxUNtFbJ5MiOvs+7y34np77+9l4nfFMw==} cpu: [arm64] os: [linux] - '@rollup/rollup-linux-loong64-gnu@4.52.2': - resolution: {integrity: sha512-8wTRM3+gVMDLLDdaT6tKmOE3lJyRy9NpJUS/ZRWmLCmOPIJhVyXwjBo+XbrrwtV33Em1/eCTd5TuGJm4+DmYjw==} + '@rollup/rollup-linux-loong64-gnu@4.52.3': + resolution: {integrity: sha512-3y5GA0JkBuirLqmjwAKwB0keDlI6JfGYduMlJD/Rl7fvb4Ni8iKdQs1eiunMZJhwDWdCvrcqXRY++VEBbvk6Eg==} cpu: [loong64] os: [linux] - '@rollup/rollup-linux-ppc64-gnu@4.52.2': - resolution: {integrity: sha512-6yqEfgJ1anIeuP2P/zhtfBlDpXUb80t8DpbYwXQ3bQd95JMvUaqiX+fKqYqUwZXqdJDd8xdilNtsHM2N0cFm6A==} + '@rollup/rollup-linux-ppc64-gnu@4.52.3': + resolution: {integrity: sha512-AUUH65a0p3Q0Yfm5oD2KVgzTKgwPyp9DSXc3UA7DtxhEb/WSPfbG4wqXeSN62OG5gSo18em4xv6dbfcUGXcagw==} cpu: [ppc64] os: [linux] - '@rollup/rollup-linux-riscv64-gnu@4.52.2': - resolution: {integrity: sha512-sshYUiYVSEI2B6dp4jMncwxbrUqRdNApF2c3bhtLAU0qA8Lrri0p0NauOsTWh3yCCCDyBOjESHMExonp7Nzc0w==} + '@rollup/rollup-linux-riscv64-gnu@4.52.3': + resolution: {integrity: sha512-1makPhFFVBqZE+XFg3Dkq+IkQ7JvmUrwwqaYBL2CE+ZpxPaqkGaiWFEWVGyvTwZace6WLJHwjVh/+CXbKDGPmg==} cpu: [riscv64] os: [linux] - '@rollup/rollup-linux-riscv64-musl@4.52.2': - resolution: {integrity: sha512-duBLgd+3pqC4MMwBrKkFxaZerUxZcYApQVC5SdbF5/e/589GwVvlRUnyqMFbM8iUSb1BaoX/3fRL7hB9m2Pj8Q==} + '@rollup/rollup-linux-riscv64-musl@4.52.3': + resolution: {integrity: sha512-OOFJa28dxfl8kLOPMUOQBCO6z3X2SAfzIE276fwT52uXDWUS178KWq0pL7d6p1kz7pkzA0yQwtqL0dEPoVcRWg==} cpu: [riscv64] os: [linux] - '@rollup/rollup-linux-s390x-gnu@4.52.2': - resolution: {integrity: sha512-tzhYJJidDUVGMgVyE+PmxENPHlvvqm1KILjjZhB8/xHYqAGeizh3GBGf9u6WdJpZrz1aCpIIHG0LgJgH9rVjHQ==} + '@rollup/rollup-linux-s390x-gnu@4.52.3': + resolution: {integrity: sha512-jMdsML2VI5l+V7cKfZx3ak+SLlJ8fKvLJ0Eoa4b9/vCUrzXKgoKxvHqvJ/mkWhFiyp88nCkM5S2v6nIwRtPcgg==} cpu: [s390x] os: [linux] - '@rollup/rollup-linux-x64-gnu@4.52.2': - resolution: {integrity: sha512-opH8GSUuVcCSSyHHcl5hELrmnk4waZoVpgn/4FDao9iyE4WpQhyWJ5ryl5M3ocp4qkRuHfyXnGqg8M9oKCEKRA==} + '@rollup/rollup-linux-x64-gnu@4.52.3': + resolution: {integrity: sha512-tPgGd6bY2M2LJTA1uGq8fkSPK8ZLYjDjY+ZLK9WHncCnfIz29LIXIqUgzCR0hIefzy6Hpbe8Th5WOSwTM8E7LA==} cpu: [x64] os: [linux] - '@rollup/rollup-linux-x64-musl@4.52.2': - resolution: {integrity: sha512-LSeBHnGli1pPKVJ79ZVJgeZWWZXkEe/5o8kcn23M8eMKCUANejchJbF/JqzM4RRjOJfNRhKJk8FuqL1GKjF5oQ==} + '@rollup/rollup-linux-x64-musl@4.52.3': + resolution: {integrity: sha512-BCFkJjgk+WFzP+tcSMXq77ymAPIxsX9lFJWs+2JzuZTLtksJ2o5hvgTdIcZ5+oKzUDMwI0PfWzRBYAydAHF2Mw==} cpu: [x64] os: [linux] - '@rollup/rollup-openharmony-arm64@4.52.2': - resolution: {integrity: sha512-uPj7MQ6/s+/GOpolavm6BPo+6CbhbKYyZHUDvZ/SmJM7pfDBgdGisFX3bY/CBDMg2ZO4utfhlApkSfZ92yXw7Q==} + '@rollup/rollup-openharmony-arm64@4.52.3': + resolution: {integrity: sha512-KTD/EqjZF3yvRaWUJdD1cW+IQBk4fbQaHYJUmP8N4XoKFZilVL8cobFSTDnjTtxWJQ3JYaMgF4nObY/+nYkumA==} cpu: [arm64] os: [openharmony] - '@rollup/rollup-win32-arm64-msvc@4.52.2': - resolution: {integrity: sha512-Z9MUCrSgIaUeeHAiNkm3cQyst2UhzjPraR3gYYfOjAuZI7tcFRTOD+4cHLPoS/3qinchth+V56vtqz1Tv+6KPA==} + '@rollup/rollup-win32-arm64-msvc@4.52.3': + resolution: {integrity: sha512-+zteHZdoUYLkyYKObGHieibUFLbttX2r+58l27XZauq0tcWYYuKUwY2wjeCN9oK1Um2YgH2ibd6cnX/wFD7DuA==} cpu: [arm64] os: [win32] - '@rollup/rollup-win32-ia32-msvc@4.52.2': - resolution: {integrity: sha512-+GnYBmpjldD3XQd+HMejo+0gJGwYIOfFeoBQv32xF/RUIvccUz20/V6Otdv+57NE70D5pa8W/jVGDoGq0oON4A==} + '@rollup/rollup-win32-ia32-msvc@4.52.3': + resolution: {integrity: sha512-of1iHkTQSo3kr6dTIRX6t81uj/c/b15HXVsPcEElN5sS859qHrOepM5p9G41Hah+CTqSh2r8Bm56dL2z9UQQ7g==} cpu: [ia32] os: [win32] - '@rollup/rollup-win32-x64-gnu@4.52.2': - resolution: {integrity: sha512-ApXFKluSB6kDQkAqZOKXBjiaqdF1BlKi+/eqnYe9Ee7U2K3pUDKsIyr8EYm/QDHTJIM+4X+lI0gJc3TTRhd+dA==} + '@rollup/rollup-win32-x64-gnu@4.52.3': + resolution: {integrity: sha512-s0hybmlHb56mWVZQj8ra9048/WZTPLILKxcvcq+8awSZmyiSUZjjem1AhU3Tf4ZKpYhK4mg36HtHDOe8QJS5PQ==} cpu: [x64] os: [win32] - '@rollup/rollup-win32-x64-msvc@4.52.2': - resolution: {integrity: sha512-ARz+Bs8kY6FtitYM96PqPEVvPXqEZmPZsSkXvyX19YzDqkCaIlhCieLLMI5hxO9SRZ2XtCtm8wxhy0iJ2jxNfw==} + '@rollup/rollup-win32-x64-msvc@4.52.3': + resolution: {integrity: sha512-zGIbEVVXVtauFgl3MRwGWEN36P5ZGenHRMgNw88X5wEhEBpq0XrMEZwOn07+ICrwM17XO5xfMZqh0OldCH5VTA==} cpu: [x64] os: [win32] @@ -1283,8 +1286,8 @@ packages: '@types/ms@2.1.0': resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==} - '@types/node@24.5.2': - resolution: {integrity: sha512-FYxk1I7wPv3K2XBaoyH2cTnocQEu8AOZ60hPbsyukMPLv5/5qr7V1i8PLHdl6Zf87I+xZXFvPCXYjiTFq+YSDQ==} + '@types/node@24.6.1': + resolution: {integrity: sha512-ljvjjs3DNXummeIaooB4cLBKg2U6SPI6Hjra/9rRIy7CpM0HpLtG9HptkMKAb4HYWy5S7HUvJEuWgr/y0U8SHw==} '@types/parse-json@4.0.2': resolution: {integrity: sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==} @@ -1294,8 +1297,8 @@ packages: peerDependencies: '@types/react': ^19.0.0 - '@types/react@19.1.13': - resolution: {integrity: sha512-hHkbU/eoO3EG5/MZkuFSKmYqPbSVk5byPFa3e7y/8TybHiLMACgI8seVYlicwk7H5K/rI2px9xrQp/C+AUDTiQ==} + '@types/react@19.1.16': + resolution: {integrity: sha512-WBM/nDbEZmDUORKnh5i1bTnAz6vTohUf9b8esSMu+b24+srbaxa04UbJgWx78CVfNXA20sNu0odEIluZDFdCog==} '@types/unist@2.0.11': resolution: {integrity: sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==} @@ -1323,8 +1326,8 @@ packages: peerDependencies: vite: ^4 || ^5 || ^6 || ^7 - '@vitejs/plugin-react@5.0.3': - resolution: {integrity: sha512-PFVHhosKkofGH0Yzrw1BipSedTH68BFF8ZWy1kfUpCtJcouXXY0+racG8sExw7hw0HoX36813ga5o3LTWZ4FUg==} + '@vitejs/plugin-react@5.0.4': + resolution: {integrity: sha512-La0KD0vGkVkSk6K+piWDKRUyg8Rl5iAIKRMH0vMJI0Eg47bq1eOxmoObAaQG37WMW9MSyk7Cs8EIWwJC1PtzKA==} engines: {node: ^20.19.0 || >=22.12.0} peerDependencies: vite: ^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 @@ -1377,8 +1380,8 @@ packages: balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} - baseline-browser-mapping@2.8.6: - resolution: {integrity: sha512-wrH5NNqren/QMtKUEEJf7z86YjfqW/2uw3IL3/xpqZUC95SSVIFXYQeeGjL6FT/X68IROu6RMehZQS5foy2BXw==} + baseline-browser-mapping@2.8.9: + resolution: {integrity: sha512-hY/u2lxLrbecMEWSB0IpGzGyDyeoMFQhCvZd2jGFSE5I17Fh01sYUBPCJtkWERw7zrac9+cIghxm/ytJa2X8iA==} hasBin: true boolbase@1.0.0: @@ -1428,8 +1431,8 @@ packages: resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} engines: {node: '>=10'} - caniuse-lite@1.0.30001743: - resolution: {integrity: sha512-e6Ojr7RV14Un7dz6ASD0aZDmQPT/A+eZU+nuTNfjqmRrmkmQlnTNWH0SKmqagx9PeW87UVqapSurtAXifmtdmw==} + caniuse-lite@1.0.30001746: + resolution: {integrity: sha512-eA7Ys/DGw+pnkWWSE/id29f2IcPHVoE8wxtvE5JdvD2V28VTDPy1yEeo11Guz0sJ4ZeGRcm3uaTcAqK1LXaphA==} ccount@2.0.1: resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} @@ -1673,8 +1676,8 @@ packages: resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} engines: {node: '>= 0.4'} - electron-to-chromium@1.5.223: - resolution: {integrity: sha512-qKm55ic6nbEmagFlTFczML33rF90aU+WtrJ9MdTCThrcvDNdUHN4p6QfVN78U06ZmguqXIyMPyYhw2TrbDUwPQ==} + electron-to-chromium@1.5.228: + resolution: {integrity: sha512-nxkiyuqAn4MJ1QbobwqJILiDtu/jk14hEAWaMiJmNPh1Z+jqoFlBFZjdXwLWGeVSeu9hGLg6+2G9yJaW8rBIFA==} emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} @@ -1772,8 +1775,8 @@ packages: fraction.js@4.3.7: resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==} - framer-motion@12.23.21: - resolution: {integrity: sha512-UWDtzzPdRA3UpSNGril5HjUtPF1Uo/BCt5VKG/YQ8tVpSkAZ22+q8o+hYO0C1uDAZuotQjcfzsTsDtQxD46E/Q==} + framer-motion@12.23.22: + resolution: {integrity: sha512-ZgGvdxXCw55ZYvhoZChTlG6pUuehecgvEAJz0BHoC5pQKW1EC5xf1Mul1ej5+ai+pVY0pylyFfdl45qnM1/GsA==} peerDependencies: '@emotion/is-prop-valid': '*' react: ^18.0.0 || ^19.0.0 @@ -1804,6 +1807,10 @@ packages: functions-have-names@1.2.3: resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} + generator-function@2.0.1: + resolution: {integrity: sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==} + engines: {node: '>= 0.4'} + gensync@1.0.0-beta.2: resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} engines: {node: '>=6.9.0'} @@ -1991,8 +1998,8 @@ packages: resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} engines: {node: '>=8'} - is-generator-function@1.1.0: - resolution: {integrity: sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ==} + is-generator-function@1.1.2: + resolution: {integrity: sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==} engines: {node: '>= 0.4'} is-glob@4.0.3: @@ -2271,8 +2278,8 @@ packages: motion-utils@12.23.6: resolution: {integrity: sha512-eAWoPgr4eFEOFfg2WjIsMoqJTW6Z8MTUCgn/GZ3VRpClWBdnbjryiA3ZSNLyxCTmCQx4RmYX6jX1iWHbenUPNQ==} - motion@12.23.21: - resolution: {integrity: sha512-FzgbQNeZXHWXXEKmpfenYvF5wdc5i7lT/Kwr3xV4dmGVsU7Y30QcgCZsWHAlE/4McAWhNGbOAhgdiabXZ1EjnA==} + motion@12.23.22: + resolution: {integrity: sha512-iSq6X9vLHbeYwmHvhK//+U74ROaPnZmBuy60XZzqNl0QtZkWfoZyMDHYnpKuWFv0sNMqHgED8aCXk94LCoQPGg==} peerDependencies: '@emotion/is-prop-valid': '*' react: ^18.0.0 || ^19.0.0 @@ -2587,8 +2594,8 @@ packages: engines: {node: '>= 0.4'} hasBin: true - rollup@4.52.2: - resolution: {integrity: sha512-I25/2QgoROE1vYV+NQ1En9T9UFB9Cmfm2CJ83zZOlaDpvz29wGQSZXWKw7MiNXau7wYgB/T9fVIdIuEQ+KbiiA==} + rollup@4.52.3: + resolution: {integrity: sha512-RIDh866U8agLgiIcdpB+COKnlCreHJLfIhWC3LVflku5YHfpnsIKigRZeFfMfCc4dVcqNVfQQ5gO/afOck064A==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true @@ -2805,8 +2812,8 @@ packages: peerDependencies: typescript: '>=3.5.1' - typescript@5.9.2: - resolution: {integrity: sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==} + typescript@5.9.3: + resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} engines: {node: '>=14.17'} hasBin: true @@ -2817,8 +2824,8 @@ packages: resolution: {integrity: sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==} engines: {node: '>= 0.4'} - undici-types@7.12.0: - resolution: {integrity: sha512-goOacqME2GYyOZZfb5Lgtu+1IDmAlAEu5xnD3+xTzS10hT0vzpf0SPjkXwAw9Jm+4n/mQGDP3LO8CPbYROeBfQ==} + undici-types@7.13.0: + resolution: {integrity: sha512-Ov2Rr9Sx+fRgagJ5AX0qvItZG/JKKoBRAVITs1zk7IqZGTJUwgUr7qoYBpWwakpWilTZFM98rG/AFRocu10iIQ==} unified@11.0.5: resolution: {integrity: sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==} @@ -3175,7 +3182,7 @@ snapshots: '@emotion/memoize@0.9.0': {} - '@emotion/react@11.14.0(@types/react@19.1.13)(react@19.1.1)': + '@emotion/react@11.14.0(@types/react@19.1.16)(react@19.1.1)': dependencies: '@babel/runtime': 7.28.4 '@emotion/babel-plugin': 11.13.5 @@ -3187,7 +3194,7 @@ snapshots: hoist-non-react-statics: 3.3.2 react: 19.1.1 optionalDependencies: - '@types/react': 19.1.13 + '@types/react': 19.1.16 transitivePeerDependencies: - supports-color @@ -3201,18 +3208,18 @@ snapshots: '@emotion/sheet@1.4.0': {} - '@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.13)(react@19.1.1))(@types/react@19.1.13)(react@19.1.1)': + '@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.16)(react@19.1.1))(@types/react@19.1.16)(react@19.1.1)': dependencies: '@babel/runtime': 7.28.4 '@emotion/babel-plugin': 11.13.5 '@emotion/is-prop-valid': 1.4.0 - '@emotion/react': 11.14.0(@types/react@19.1.13)(react@19.1.1) + '@emotion/react': 11.14.0(@types/react@19.1.16)(react@19.1.1) '@emotion/serialize': 1.3.3 '@emotion/use-insertion-effect-with-fallbacks': 1.2.0(react@19.1.1) '@emotion/utils': 1.4.2 react: 19.1.1 optionalDependencies: - '@types/react': 19.1.13 + '@types/react': 19.1.16 transitivePeerDependencies: - supports-color @@ -3337,10 +3344,10 @@ snapshots: '@shikijs/types': 3.13.0 '@shikijs/vscode-textmate': 10.0.2 - '@hookform/devtools@4.4.0(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + '@hookform/devtools@4.4.0(@types/react@19.1.16)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': dependencies: - '@emotion/react': 11.14.0(@types/react@19.1.13)(react@19.1.1) - '@emotion/styled': 11.14.1(@emotion/react@11.14.0(@types/react@19.1.13)(react@19.1.1))(@types/react@19.1.13)(react@19.1.1) + '@emotion/react': 11.14.0(@types/react@19.1.16)(react@19.1.1) + '@emotion/styled': 11.14.1(@emotion/react@11.14.0(@types/react@19.1.16)(react@19.1.1))(@types/react@19.1.16)(react@19.1.1) '@types/lodash': 4.17.20 little-state-machine: 4.8.1(react@19.1.1) lodash: 4.17.21 @@ -3451,7 +3458,7 @@ snapshots: '@react-hook/passive-layout-effect': 1.2.1(react@19.1.1) react: 19.1.1 - '@reduxjs/toolkit@2.9.0(react-redux@9.2.0(@types/react@19.1.13)(react@19.1.1)(redux@5.0.1))(react@19.1.1)': + '@reduxjs/toolkit@2.9.0(react-redux@9.2.0(@types/react@19.1.16)(react@19.1.1)(redux@5.0.1))(react@19.1.1)': dependencies: '@standard-schema/spec': 1.0.0 '@standard-schema/utils': 0.3.0 @@ -3461,76 +3468,78 @@ snapshots: reselect: 5.1.1 optionalDependencies: react: 19.1.1 - react-redux: 9.2.0(@types/react@19.1.13)(react@19.1.1)(redux@5.0.1) + react-redux: 9.2.0(@types/react@19.1.16)(react@19.1.1)(redux@5.0.1) '@remix-run/router@1.23.0': {} '@rolldown/pluginutils@1.0.0-beta.35': {} - '@rollup/rollup-android-arm-eabi@4.52.2': + '@rolldown/pluginutils@1.0.0-beta.38': {} + + '@rollup/rollup-android-arm-eabi@4.52.3': optional: true - '@rollup/rollup-android-arm64@4.52.2': + '@rollup/rollup-android-arm64@4.52.3': optional: true - '@rollup/rollup-darwin-arm64@4.52.2': + '@rollup/rollup-darwin-arm64@4.52.3': optional: true - '@rollup/rollup-darwin-x64@4.52.2': + '@rollup/rollup-darwin-x64@4.52.3': optional: true - '@rollup/rollup-freebsd-arm64@4.52.2': + '@rollup/rollup-freebsd-arm64@4.52.3': optional: true - '@rollup/rollup-freebsd-x64@4.52.2': + '@rollup/rollup-freebsd-x64@4.52.3': optional: true - '@rollup/rollup-linux-arm-gnueabihf@4.52.2': + '@rollup/rollup-linux-arm-gnueabihf@4.52.3': optional: true - '@rollup/rollup-linux-arm-musleabihf@4.52.2': + '@rollup/rollup-linux-arm-musleabihf@4.52.3': optional: true - '@rollup/rollup-linux-arm64-gnu@4.52.2': + '@rollup/rollup-linux-arm64-gnu@4.52.3': optional: true - '@rollup/rollup-linux-arm64-musl@4.52.2': + '@rollup/rollup-linux-arm64-musl@4.52.3': optional: true - '@rollup/rollup-linux-loong64-gnu@4.52.2': + '@rollup/rollup-linux-loong64-gnu@4.52.3': optional: true - '@rollup/rollup-linux-ppc64-gnu@4.52.2': + '@rollup/rollup-linux-ppc64-gnu@4.52.3': optional: true - '@rollup/rollup-linux-riscv64-gnu@4.52.2': + '@rollup/rollup-linux-riscv64-gnu@4.52.3': optional: true - '@rollup/rollup-linux-riscv64-musl@4.52.2': + '@rollup/rollup-linux-riscv64-musl@4.52.3': optional: true - '@rollup/rollup-linux-s390x-gnu@4.52.2': + '@rollup/rollup-linux-s390x-gnu@4.52.3': optional: true - '@rollup/rollup-linux-x64-gnu@4.52.2': + '@rollup/rollup-linux-x64-gnu@4.52.3': optional: true - '@rollup/rollup-linux-x64-musl@4.52.2': + '@rollup/rollup-linux-x64-musl@4.52.3': optional: true - '@rollup/rollup-openharmony-arm64@4.52.2': + '@rollup/rollup-openharmony-arm64@4.52.3': optional: true - '@rollup/rollup-win32-arm64-msvc@4.52.2': + '@rollup/rollup-win32-arm64-msvc@4.52.3': optional: true - '@rollup/rollup-win32-ia32-msvc@4.52.2': + '@rollup/rollup-win32-ia32-msvc@4.52.3': optional: true - '@rollup/rollup-win32-x64-gnu@4.52.2': + '@rollup/rollup-win32-x64-gnu@4.52.3': optional: true - '@rollup/rollup-win32-x64-msvc@4.52.2': + '@rollup/rollup-win32-x64-msvc@4.52.3': optional: true '@shikijs/engine-oniguruma@3.13.0': @@ -3628,12 +3637,12 @@ snapshots: '@svgr/babel-plugin-transform-react-native-svg': 8.1.0(@babel/core@7.28.4) '@svgr/babel-plugin-transform-svg-component': 8.0.0(@babel/core@7.28.4) - '@svgr/cli@8.1.0(typescript@5.9.2)': + '@svgr/cli@8.1.0(typescript@5.9.3)': dependencies: - '@svgr/core': 8.1.0(typescript@5.9.2) - '@svgr/plugin-jsx': 8.1.0(@svgr/core@8.1.0(typescript@5.9.2)) - '@svgr/plugin-prettier': 8.1.0(@svgr/core@8.1.0(typescript@5.9.2)) - '@svgr/plugin-svgo': 8.1.0(@svgr/core@8.1.0(typescript@5.9.2))(typescript@5.9.2) + '@svgr/core': 8.1.0(typescript@5.9.3) + '@svgr/plugin-jsx': 8.1.0(@svgr/core@8.1.0(typescript@5.9.3)) + '@svgr/plugin-prettier': 8.1.0(@svgr/core@8.1.0(typescript@5.9.3)) + '@svgr/plugin-svgo': 8.1.0(@svgr/core@8.1.0(typescript@5.9.3))(typescript@5.9.3) camelcase: 6.3.0 chalk: 4.1.2 commander: 9.5.0 @@ -3644,12 +3653,12 @@ snapshots: - supports-color - typescript - '@svgr/core@8.1.0(typescript@5.9.2)': + '@svgr/core@8.1.0(typescript@5.9.3)': dependencies: '@babel/core': 7.28.4 '@svgr/babel-preset': 8.1.0(@babel/core@7.28.4) camelcase: 6.3.0 - cosmiconfig: 8.3.6(typescript@5.9.2) + cosmiconfig: 8.3.6(typescript@5.9.3) snake-case: 3.0.4 transitivePeerDependencies: - supports-color @@ -3660,26 +3669,26 @@ snapshots: '@babel/types': 7.28.4 entities: 4.5.0 - '@svgr/plugin-jsx@8.1.0(@svgr/core@8.1.0(typescript@5.9.2))': + '@svgr/plugin-jsx@8.1.0(@svgr/core@8.1.0(typescript@5.9.3))': dependencies: '@babel/core': 7.28.4 '@svgr/babel-preset': 8.1.0(@babel/core@7.28.4) - '@svgr/core': 8.1.0(typescript@5.9.2) + '@svgr/core': 8.1.0(typescript@5.9.3) '@svgr/hast-util-to-babel-ast': 8.0.0 svg-parser: 2.0.4 transitivePeerDependencies: - supports-color - '@svgr/plugin-prettier@8.1.0(@svgr/core@8.1.0(typescript@5.9.2))': + '@svgr/plugin-prettier@8.1.0(@svgr/core@8.1.0(typescript@5.9.3))': dependencies: - '@svgr/core': 8.1.0(typescript@5.9.2) + '@svgr/core': 8.1.0(typescript@5.9.3) deepmerge: 4.3.1 prettier: 2.8.8 - '@svgr/plugin-svgo@8.1.0(@svgr/core@8.1.0(typescript@5.9.2))(typescript@5.9.2)': + '@svgr/plugin-svgo@8.1.0(@svgr/core@8.1.0(typescript@5.9.3))(typescript@5.9.3)': dependencies: - '@svgr/core': 8.1.0(typescript@5.9.2) - cosmiconfig: 8.3.6(typescript@5.9.2) + '@svgr/core': 8.1.0(typescript@5.9.3) + cosmiconfig: 8.3.6(typescript@5.9.3) deepmerge: 4.3.1 svgo: 3.3.2 transitivePeerDependencies: @@ -3926,17 +3935,17 @@ snapshots: '@types/ms@2.1.0': {} - '@types/node@24.5.2': + '@types/node@24.6.1': dependencies: - undici-types: 7.12.0 + undici-types: 7.13.0 '@types/parse-json@4.0.2': {} - '@types/react-dom@19.1.9(@types/react@19.1.13)': + '@types/react-dom@19.1.9(@types/react@19.1.16)': dependencies: - '@types/react': 19.1.13 + '@types/react': 19.1.16 - '@types/react@19.1.13': + '@types/react@19.1.16': dependencies: csstype: 3.1.3 @@ -3955,23 +3964,23 @@ snapshots: '@use-gesture/core': 10.3.1 react: 19.1.1 - '@vitejs/plugin-react-swc@4.1.0(vite@7.1.7(@types/node@24.5.2)(sass@1.92.1)(yaml@2.8.1))': + '@vitejs/plugin-react-swc@4.1.0(vite@7.1.7(@types/node@24.6.1)(sass@1.92.1)(yaml@2.8.1))': dependencies: '@rolldown/pluginutils': 1.0.0-beta.35 '@swc/core': 1.13.5 - vite: 7.1.7(@types/node@24.5.2)(sass@1.92.1)(yaml@2.8.1) + vite: 7.1.7(@types/node@24.6.1)(sass@1.92.1)(yaml@2.8.1) transitivePeerDependencies: - '@swc/helpers' - '@vitejs/plugin-react@5.0.3(vite@7.1.7(@types/node@24.5.2)(sass@1.92.1)(yaml@2.8.1))': + '@vitejs/plugin-react@5.0.4(vite@7.1.7(@types/node@24.6.1)(sass@1.92.1)(yaml@2.8.1))': dependencies: '@babel/core': 7.28.4 '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.28.4) '@babel/plugin-transform-react-jsx-source': 7.27.1(@babel/core@7.28.4) - '@rolldown/pluginutils': 1.0.0-beta.35 + '@rolldown/pluginutils': 1.0.0-beta.38 '@types/babel__core': 7.20.5 react-refresh: 0.17.0 - vite: 7.1.7(@types/node@24.5.2)(sass@1.92.1)(yaml@2.8.1) + vite: 7.1.7(@types/node@24.6.1)(sass@1.92.1)(yaml@2.8.1) transitivePeerDependencies: - supports-color @@ -4007,7 +4016,7 @@ snapshots: autoprefixer@10.4.21(postcss@8.5.6): dependencies: browserslist: 4.26.2 - caniuse-lite: 1.0.30001743 + caniuse-lite: 1.0.30001746 fraction.js: 4.3.7 normalize-range: 0.1.2 picocolors: 1.1.1 @@ -4028,7 +4037,7 @@ snapshots: balanced-match@1.0.2: {} - baseline-browser-mapping@2.8.6: {} + baseline-browser-mapping@2.8.9: {} boolbase@1.0.0: {} @@ -4048,9 +4057,9 @@ snapshots: browserslist@4.26.2: dependencies: - baseline-browser-mapping: 2.8.6 - caniuse-lite: 1.0.30001743 - electron-to-chromium: 1.5.223 + baseline-browser-mapping: 2.8.9 + caniuse-lite: 1.0.30001746 + electron-to-chromium: 1.5.228 node-releases: 2.0.21 update-browserslist-db: 1.1.3(browserslist@4.26.2) @@ -4077,7 +4086,7 @@ snapshots: camelcase@6.3.0: {} - caniuse-lite@1.0.30001743: {} + caniuse-lite@1.0.30001746: {} ccount@2.0.1: {} @@ -4148,14 +4157,14 @@ snapshots: path-type: 4.0.0 yaml: 1.10.2 - cosmiconfig@8.3.6(typescript@5.9.2): + cosmiconfig@8.3.6(typescript@5.9.3): dependencies: import-fresh: 3.3.1 js-yaml: 4.1.0 parse-json: 5.2.0 path-type: 4.0.0 optionalDependencies: - typescript: 5.9.2 + typescript: 5.9.3 cross-spawn@6.0.6: dependencies: @@ -4317,7 +4326,7 @@ snapshots: es-errors: 1.3.0 gopd: 1.2.0 - electron-to-chromium@1.5.223: {} + electron-to-chromium@1.5.228: {} emoji-regex@8.0.0: {} @@ -4471,7 +4480,7 @@ snapshots: fraction.js@4.3.7: {} - framer-motion@12.23.21(@emotion/is-prop-valid@1.4.0)(react-dom@19.1.1(react@19.1.1))(react@19.1.1): + framer-motion@12.23.22(@emotion/is-prop-valid@1.4.0)(react-dom@19.1.1(react@19.1.1))(react@19.1.1): dependencies: motion-dom: 12.23.21 motion-utils: 12.23.6 @@ -4499,6 +4508,8 @@ snapshots: functions-have-names@1.2.3: {} + generator-function@2.0.1: {} + gensync@1.0.0-beta.2: {} get-caller-file@2.0.5: {} @@ -4611,7 +4622,7 @@ snapshots: domhandler: 5.0.3 htmlparser2: 10.0.0 - html-react-parser@5.2.6(@types/react@19.1.13)(react@19.1.1): + html-react-parser@5.2.6(@types/react@19.1.16)(react@19.1.1): dependencies: domhandler: 5.0.3 html-dom-parser: 5.1.1 @@ -4619,7 +4630,7 @@ snapshots: react-property: 2.0.2 style-to-js: 1.1.17 optionalDependencies: - '@types/react': 19.1.13 + '@types/react': 19.1.16 html-url-attributes@3.0.1: {} @@ -4716,9 +4727,10 @@ snapshots: is-fullwidth-code-point@3.0.0: {} - is-generator-function@1.1.0: + is-generator-function@1.1.2: dependencies: call-bound: 1.0.4 + generator-function: 2.0.1 get-proto: 1.0.1 has-tostringtag: 1.0.2 safe-regex-test: 1.1.0 @@ -4950,9 +4962,9 @@ snapshots: memorystream@0.3.1: {} - merge-refs@2.0.0(@types/react@19.1.13): + merge-refs@2.0.0(@types/react@19.1.16): optionalDependencies: - '@types/react': 19.1.13 + '@types/react': 19.1.16 micromark-core-commonmark@2.0.3: dependencies: @@ -5115,9 +5127,9 @@ snapshots: motion-utils@12.23.6: {} - motion@12.23.21(@emotion/is-prop-valid@1.4.0)(react-dom@19.1.1(react@19.1.1))(react@19.1.1): + motion@12.23.22(@emotion/is-prop-valid@1.4.0)(react-dom@19.1.1(react@19.1.1))(react@19.1.1): dependencies: - framer-motion: 12.23.21(@emotion/is-prop-valid@1.4.0)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + framer-motion: 12.23.22(@emotion/is-prop-valid@1.4.0)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) tslib: 2.8.1 optionalDependencies: '@emotion/is-prop-valid': 1.4.0 @@ -5293,11 +5305,11 @@ snapshots: dependencies: react: 19.1.1 - react-markdown@10.1.0(@types/react@19.1.13)(react@19.1.1): + react-markdown@10.1.0(@types/react@19.1.16)(react@19.1.1): dependencies: '@types/hast': 3.0.4 '@types/mdast': 4.0.4 - '@types/react': 19.1.13 + '@types/react': 19.1.16 devlop: 1.1.0 hast-util-to-jsx-runtime: 2.3.6 html-url-attributes: 3.0.1 @@ -5319,13 +5331,13 @@ snapshots: qr.js: 0.0.0 react: 19.1.1 - react-redux@9.2.0(@types/react@19.1.13)(react@19.1.1)(redux@5.0.1): + react-redux@9.2.0(@types/react@19.1.16)(react@19.1.1)(redux@5.0.1): dependencies: '@types/use-sync-external-store': 0.0.6 react: 19.1.1 use-sync-external-store: 1.5.0(react@19.1.1) optionalDependencies: - '@types/react': 19.1.13 + '@types/react': 19.1.16 redux: 5.0.1 react-refresh@0.17.0: {} @@ -5363,9 +5375,9 @@ snapshots: readdirp@4.1.2: {} - recharts@3.2.1(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react-is@18.3.1)(react@19.1.1)(redux@5.0.1): + recharts@3.2.1(@types/react@19.1.16)(react-dom@19.1.1(react@19.1.1))(react-is@18.3.1)(react@19.1.1)(redux@5.0.1): dependencies: - '@reduxjs/toolkit': 2.9.0(react-redux@9.2.0(@types/react@19.1.13)(react@19.1.1)(redux@5.0.1))(react@19.1.1) + '@reduxjs/toolkit': 2.9.0(react-redux@9.2.0(@types/react@19.1.16)(react@19.1.1)(redux@5.0.1))(react@19.1.1) clsx: 2.1.1 decimal.js-light: 2.5.1 es-toolkit: 1.39.10 @@ -5374,7 +5386,7 @@ snapshots: react: 19.1.1 react-dom: 19.1.1(react@19.1.1) react-is: 18.3.1 - react-redux: 9.2.0(@types/react@19.1.13)(react@19.1.1)(redux@5.0.1) + react-redux: 9.2.0(@types/react@19.1.16)(react@19.1.1)(redux@5.0.1) reselect: 5.1.1 tiny-invariant: 1.3.3 use-sync-external-store: 1.5.0(react@19.1.1) @@ -5443,32 +5455,32 @@ snapshots: path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 - rollup@4.52.2: + rollup@4.52.3: dependencies: '@types/estree': 1.0.8 optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.52.2 - '@rollup/rollup-android-arm64': 4.52.2 - '@rollup/rollup-darwin-arm64': 4.52.2 - '@rollup/rollup-darwin-x64': 4.52.2 - '@rollup/rollup-freebsd-arm64': 4.52.2 - '@rollup/rollup-freebsd-x64': 4.52.2 - '@rollup/rollup-linux-arm-gnueabihf': 4.52.2 - '@rollup/rollup-linux-arm-musleabihf': 4.52.2 - '@rollup/rollup-linux-arm64-gnu': 4.52.2 - '@rollup/rollup-linux-arm64-musl': 4.52.2 - '@rollup/rollup-linux-loong64-gnu': 4.52.2 - '@rollup/rollup-linux-ppc64-gnu': 4.52.2 - '@rollup/rollup-linux-riscv64-gnu': 4.52.2 - '@rollup/rollup-linux-riscv64-musl': 4.52.2 - '@rollup/rollup-linux-s390x-gnu': 4.52.2 - '@rollup/rollup-linux-x64-gnu': 4.52.2 - '@rollup/rollup-linux-x64-musl': 4.52.2 - '@rollup/rollup-openharmony-arm64': 4.52.2 - '@rollup/rollup-win32-arm64-msvc': 4.52.2 - '@rollup/rollup-win32-ia32-msvc': 4.52.2 - '@rollup/rollup-win32-x64-gnu': 4.52.2 - '@rollup/rollup-win32-x64-msvc': 4.52.2 + '@rollup/rollup-android-arm-eabi': 4.52.3 + '@rollup/rollup-android-arm64': 4.52.3 + '@rollup/rollup-darwin-arm64': 4.52.3 + '@rollup/rollup-darwin-x64': 4.52.3 + '@rollup/rollup-freebsd-arm64': 4.52.3 + '@rollup/rollup-freebsd-x64': 4.52.3 + '@rollup/rollup-linux-arm-gnueabihf': 4.52.3 + '@rollup/rollup-linux-arm-musleabihf': 4.52.3 + '@rollup/rollup-linux-arm64-gnu': 4.52.3 + '@rollup/rollup-linux-arm64-musl': 4.52.3 + '@rollup/rollup-linux-loong64-gnu': 4.52.3 + '@rollup/rollup-linux-ppc64-gnu': 4.52.3 + '@rollup/rollup-linux-riscv64-gnu': 4.52.3 + '@rollup/rollup-linux-riscv64-musl': 4.52.3 + '@rollup/rollup-linux-s390x-gnu': 4.52.3 + '@rollup/rollup-linux-x64-gnu': 4.52.3 + '@rollup/rollup-linux-x64-musl': 4.52.3 + '@rollup/rollup-openharmony-arm64': 4.52.3 + '@rollup/rollup-win32-arm64-msvc': 4.52.3 + '@rollup/rollup-win32-ia32-msvc': 4.52.3 + '@rollup/rollup-win32-x64-gnu': 4.52.3 + '@rollup/rollup-win32-x64-msvc': 4.52.3 fsevents: 2.3.3 rxjs@7.8.2: @@ -5728,20 +5740,20 @@ snapshots: possible-typed-array-names: 1.1.0 reflect.getprototypeof: 1.0.10 - typedoc@0.28.13(typescript@5.9.2): + typedoc@0.28.13(typescript@5.9.3): dependencies: '@gerrit0/mini-shiki': 3.13.0 lunr: 2.3.9 markdown-it: 14.1.0 minimatch: 9.0.5 - typescript: 5.9.2 + typescript: 5.9.3 yaml: 2.8.1 - typesafe-i18n@5.26.2(typescript@5.9.2): + typesafe-i18n@5.26.2(typescript@5.9.3): dependencies: - typescript: 5.9.2 + typescript: 5.9.3 - typescript@5.9.2: {} + typescript@5.9.3: {} uc.micro@2.1.0: {} @@ -5752,7 +5764,7 @@ snapshots: has-symbols: 1.1.0 which-boxed-primitive: 1.1.1 - undici-types@7.12.0: {} + undici-types@7.13.0: {} unified@11.0.5: dependencies: @@ -5842,16 +5854,16 @@ snapshots: d3-time: 3.1.0 d3-timer: 3.0.1 - vite@7.1.7(@types/node@24.5.2)(sass@1.92.1)(yaml@2.8.1): + vite@7.1.7(@types/node@24.6.1)(sass@1.92.1)(yaml@2.8.1): dependencies: esbuild: 0.25.10 fdir: 6.5.0(picomatch@4.0.3) picomatch: 4.0.3 postcss: 8.5.6 - rollup: 4.52.2 + rollup: 4.52.3 tinyglobby: 0.2.15 optionalDependencies: - '@types/node': 24.5.2 + '@types/node': 24.6.1 fsevents: 2.3.3 sass: 1.92.1 yaml: 2.8.1 @@ -5872,7 +5884,7 @@ snapshots: is-async-function: 2.1.1 is-date-object: 1.1.0 is-finalizationregistry: 1.1.1 - is-generator-function: 1.1.0 + is-generator-function: 1.1.2 is-regex: 1.2.1 is-weakref: 1.1.1 isarray: 2.0.5 @@ -5931,9 +5943,9 @@ snapshots: zod@3.25.76: {} - zustand@5.0.8(@types/react@19.1.13)(immer@10.1.3)(react@19.1.1)(use-sync-external-store@1.5.0(react@19.1.1)): + zustand@5.0.8(@types/react@19.1.16)(immer@10.1.3)(react@19.1.1)(use-sync-external-store@1.5.0(react@19.1.1)): optionalDependencies: - '@types/react': 19.1.13 + '@types/react': 19.1.16 immer: 10.1.3 react: 19.1.1 use-sync-external-store: 1.5.0(react@19.1.1) diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index 778c9e01..c5a0ad53 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -101,9 +101,9 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.11" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "862ed96ca487e809f1c8e5a8447f6ee2cf102f846893800b20cebdf541fc6bbd" +checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78" [[package]] name = "anstyle-parse" @@ -457,9 +457,9 @@ checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] name = "axum" -version = "0.8.4" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "021e862c184ae977658b36c4500f7feac3221ca5da43e3f25bd04ab6c79a29b5" +checksum = "8a18ed336352031311f4e0b4dd2ff392d4fbb370777c9d18d7fc9d7359f73871" dependencies = [ "axum-core", "bytes", @@ -473,8 +473,7 @@ dependencies = [ "mime", "percent-encoding", "pin-project-lite", - "rustversion", - "serde", + "serde_core", "sync_wrapper", "tower", "tower-layer", @@ -483,9 +482,9 @@ dependencies = [ [[package]] name = "axum-core" -version = "0.5.2" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68464cd0412f486726fb3373129ef5d2993f90c34bc2bc1c1e9943b2f4fc7ca6" +checksum = "59446ce19cd142f8833f856eb31f3eb097812d1479ab224f54d72428ca21ea22" dependencies = [ "bytes", "futures-core", @@ -494,7 +493,6 @@ dependencies = [ "http-body-util", "mime", "pin-project-lite", - "rustversion", "sync_wrapper", "tower-layer", "tower-service", @@ -737,9 +735,9 @@ dependencies = [ [[package]] name = "camino" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1de8bc0aa9e9385ceb3bf0c152e3a9b9544f6c4a912c8ae504e80c1f0368603" +checksum = "276a59bf2b2c967788139340c9f0c5b12d7fd6630315c15c217e559de85d2609" dependencies = [ "serde_core", ] @@ -764,7 +762,7 @@ dependencies = [ "semver", "serde", "serde_json", - "thiserror 2.0.16", + "thiserror 2.0.17", ] [[package]] @@ -1287,6 +1285,7 @@ dependencies = [ "sqlx", "struct-patch", "strum", + "swift-rs", "tauri", "tauri-build", "tauri-plugin-clipboard-manager", @@ -1300,7 +1299,7 @@ dependencies = [ "tauri-plugin-os", "tauri-plugin-single-instance", "tauri-plugin-window-state", - "thiserror 2.0.16", + "thiserror 2.0.17", "time", "tokio", "tokio-stream", @@ -1331,7 +1330,7 @@ dependencies = [ "reqwest", "serde", "serde_json", - "thiserror 2.0.16", + "thiserror 2.0.17", "tokio", "tonic", "tonic-prost", @@ -1357,7 +1356,7 @@ dependencies = [ "netlink-sys", "nix", "serde", - "thiserror 2.0.16", + "thiserror 2.0.17", "x25519-dalek", ] @@ -3336,7 +3335,7 @@ dependencies = [ "once_cell", "png 0.17.16", "serde", - "thiserror 2.0.16", + "thiserror 2.0.17", "windows-sys 0.60.2", ] @@ -3431,7 +3430,7 @@ checksum = "3176f18d11a1ae46053e59ec89d46ba318ae1343615bd3f8c908bfc84edae35c" dependencies = [ "byteorder", "pastey", - "thiserror 2.0.16", + "thiserror 2.0.17", ] [[package]] @@ -3903,9 +3902,9 @@ checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" [[package]] name = "openssl-src" -version = "300.5.2+3.5.2" +version = "300.5.3+3.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d270b79e2926f5150189d475bc7e9d2c69f9c4697b185fa917d5a32b792d21b4" +checksum = "dc6bad8cd0233b63971e232cc9c5e83039375b8586d2312f31fda85db8f888c2" dependencies = [ "cc", ] @@ -4600,7 +4599,7 @@ dependencies = [ "rustc-hash", "rustls", "socket2", - "thiserror 2.0.16", + "thiserror 2.0.17", "tokio", "tracing", "web-time", @@ -4621,7 +4620,7 @@ dependencies = [ "rustls", "rustls-pki-types", "slab", - "thiserror 2.0.16", + "thiserror 2.0.17", "tinyvec", "tracing", "web-time", @@ -4643,9 +4642,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.40" +version = "1.0.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +checksum = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1" dependencies = [ "proc-macro2", ] @@ -4806,23 +4805,23 @@ checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac" dependencies = [ "getrandom 0.2.16", "libredox", - "thiserror 2.0.16", + "thiserror 2.0.17", ] [[package]] name = "ref-cast" -version = "1.0.24" +version = "1.0.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a0ae411dbe946a674d89546582cea4ba2bb8defac896622d6496f14c23ba5cf" +checksum = "f354300ae66f76f1c85c5f84693f0ce81d747e2c3f21a45fef496d89c960bf7d" dependencies = [ "ref-cast-impl", ] [[package]] name = "ref-cast-impl" -version = "1.0.24" +version = "1.0.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1165225c21bff1f3bbce98f5a1f889949bc902d3575308cc7b0de30b4f6d27c7" +checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da" dependencies = [ "proc-macro2", "quote", @@ -5102,7 +5101,7 @@ dependencies = [ "openssl-probe", "rustls-pki-types", "schannel", - "security-framework 3.5.0", + "security-framework 3.5.1", ] [[package]] @@ -5240,9 +5239,9 @@ dependencies = [ [[package]] name = "security-framework" -version = "3.5.0" +version = "3.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc198e42d9b7510827939c9a15f5062a0c913f3371d765977e586d2fe6c16f4a" +checksum = "b3297343eaf830f66ede390ea39da1d462b6b0c1b000f420d0a83f898bbbe6ef" dependencies = [ "bitflags 2.9.4", "core-foundation 0.10.1", @@ -5291,9 +5290,9 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.227" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80ece43fc6fbed4eb5392ab50c07334d3e577cbf40997ee896fe7af40bba4245" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" dependencies = [ "serde_core", "serde_derive", @@ -5313,18 +5312,18 @@ dependencies = [ [[package]] name = "serde_core" -version = "1.0.227" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a576275b607a2c86ea29e410193df32bc680303c82f31e275bbfcafe8b33be5" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.227" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51e694923b8824cf0e9b382adf0f60d4e05f348f357b38833a3fa5ed7c2ede04" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", @@ -5673,7 +5672,7 @@ dependencies = [ "serde_json", "sha2", "smallvec", - "thiserror 2.0.16", + "thiserror 2.0.17", "tokio", "tokio-stream", "tracing", @@ -5757,7 +5756,7 @@ dependencies = [ "smallvec", "sqlx-core", "stringprep", - "thiserror 2.0.16", + "thiserror 2.0.17", "tracing", "uuid", "whoami", @@ -5796,7 +5795,7 @@ dependencies = [ "smallvec", "sqlx-core", "stringprep", - "thiserror 2.0.16", + "thiserror 2.0.17", "tracing", "uuid", "whoami", @@ -5822,7 +5821,7 @@ dependencies = [ "serde", "serde_urlencoded", "sqlx-core", - "thiserror 2.0.16", + "thiserror 2.0.17", "tracing", "url", "uuid", @@ -6130,7 +6129,7 @@ dependencies = [ "tauri-runtime", "tauri-runtime-wry", "tauri-utils", - "thiserror 2.0.16", + "thiserror 2.0.17", "tokio", "tray-icon", "url", @@ -6183,7 +6182,7 @@ dependencies = [ "sha2", "syn 2.0.106", "tauri-utils", - "thiserror 2.0.16", + "thiserror 2.0.17", "time", "url", "uuid", @@ -6233,7 +6232,7 @@ dependencies = [ "serde_json", "tauri", "tauri-plugin", - "thiserror 2.0.16", + "thiserror 2.0.17", ] [[package]] @@ -6250,7 +6249,7 @@ dependencies = [ "tauri", "tauri-plugin", "tauri-utils", - "thiserror 2.0.16", + "thiserror 2.0.17", "tracing", "url", "windows-registry", @@ -6271,7 +6270,7 @@ dependencies = [ "tauri", "tauri-plugin", "tauri-plugin-fs", - "thiserror 2.0.16", + "thiserror 2.0.17", "url", ] @@ -6292,7 +6291,7 @@ dependencies = [ "tauri", "tauri-plugin", "tauri-utils", - "thiserror 2.0.16", + "thiserror 2.0.17", "toml 0.9.7", "url", ] @@ -6315,7 +6314,7 @@ dependencies = [ "tauri", "tauri-plugin", "tauri-plugin-fs", - "thiserror 2.0.16", + "thiserror 2.0.17", "tokio", "url", "urlpattern", @@ -6339,7 +6338,7 @@ dependencies = [ "swift-rs", "tauri", "tauri-plugin", - "thiserror 2.0.16", + "thiserror 2.0.17", "time", ] @@ -6357,7 +6356,7 @@ dependencies = [ "serde_repr", "tauri", "tauri-plugin", - "thiserror 2.0.16", + "thiserror 2.0.17", "time", "url", ] @@ -6378,7 +6377,7 @@ dependencies = [ "serde_json", "tauri", "tauri-plugin", - "thiserror 2.0.16", + "thiserror 2.0.17", "url", "windows", "zbus", @@ -6399,7 +6398,7 @@ dependencies = [ "sys-locale", "tauri", "tauri-plugin", - "thiserror 2.0.16", + "thiserror 2.0.17", ] [[package]] @@ -6412,7 +6411,7 @@ dependencies = [ "serde_json", "tauri", "tauri-plugin-deep-link", - "thiserror 2.0.16", + "thiserror 2.0.17", "tracing", "windows-sys 0.60.2", "zbus", @@ -6430,7 +6429,7 @@ dependencies = [ "serde_json", "tauri", "tauri-plugin", - "thiserror 2.0.16", + "thiserror 2.0.17", ] [[package]] @@ -6451,7 +6450,7 @@ dependencies = [ "serde", "serde_json", "tauri-utils", - "thiserror 2.0.16", + "thiserror 2.0.17", "url", "webkit2gtk", "webview2-com", @@ -6515,7 +6514,7 @@ dependencies = [ "serde_json", "serde_with", "swift-rs", - "thiserror 2.0.16", + "thiserror 2.0.17", "toml 0.9.7", "url", "urlpattern", @@ -6540,7 +6539,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b1e66e07de489fe43a46678dd0b8df65e0c973909df1b60ba33874e297ba9b9" dependencies = [ "quick-xml 0.37.5", - "thiserror 2.0.16", + "thiserror 2.0.17", "windows", "windows-version", ] @@ -6580,11 +6579,11 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.16" +version = "2.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3467d614147380f2e4e374161426ff399c91084acd2363eaf549172b3d5e60c0" +checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8" dependencies = [ - "thiserror-impl 2.0.16", + "thiserror-impl 2.0.17", ] [[package]] @@ -6600,9 +6599,9 @@ dependencies = [ [[package]] name = "thiserror-impl" -version = "2.0.16" +version = "2.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c5e1be1c48b9172ee610da68fd9cd2770e7a4056cb3fc98710ee6906f0c7960" +checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" dependencies = [ "proc-macro2", "quote", @@ -6743,9 +6742,9 @@ dependencies = [ [[package]] name = "tokio-rustls" -version = "0.26.3" +version = "0.26.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f63835928ca123f1bef57abbcd23bb2ba0ac9ae1235f1e65bda0d06e7786bd" +checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" dependencies = [ "rustls", "tokio", @@ -7096,7 +7095,7 @@ dependencies = [ "once_cell", "png 0.17.16", "serde", - "thiserror 2.0.16", + "thiserror 2.0.17", "windows-sys 0.59.0", ] @@ -7715,7 +7714,7 @@ version = "0.38.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "36695906a1b53a3bf5c4289621efedac12b73eeb0b89e7e1a89b517302d5d75c" dependencies = [ - "thiserror 2.0.16", + "thiserror 2.0.17", "windows", "windows-core 0.61.2", ] @@ -8319,7 +8318,7 @@ dependencies = [ "os_pipe", "rustix 0.38.44", "tempfile", - "thiserror 2.0.16", + "thiserror 2.0.17", "tree_magic_mini", "wayland-backend", "wayland-client", @@ -8367,7 +8366,7 @@ dependencies = [ "sha2", "soup3", "tao-macros", - "thiserror 2.0.16", + "thiserror 2.0.17", "url", "webkit2gtk", "webkit2gtk-sys", @@ -8565,9 +8564,9 @@ dependencies = [ [[package]] name = "zeroize" -version = "1.8.1" +version = "1.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" +checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" dependencies = [ "zeroize_derive", ] diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index e7ec0f43..400a331b 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -91,8 +91,8 @@ tauri-plugin-fs = "2" tauri-plugin-http = { version = "2", features = ["unsafe-headers"] } tauri-plugin-log = "2" tauri-plugin-notification = "2" -tauri-plugin-opener = "2.5.0" -tauri-plugin-os = "2.3.1" +tauri-plugin-opener = "2" +tauri-plugin-os = "2" tauri-plugin-single-instance = { version = "2", features = ["deep-link"] } tauri-plugin-window-state = "2" thiserror.workspace = true @@ -111,6 +111,12 @@ x25519-dalek = { version = "2", features = [ "static_secrets", ] } +[target.'cfg(target_os = "macos")'.dependencies] +swift-rs = "1.0" + +[target.'cfg(target_os = "macos")'.build-dependencies] +swift-rs = { version = "1.0", features = ["build"] } + [target.'cfg(unix)'.dependencies] hyper-util = "0.1" nix = { version = "0.30.1", features = ["user", "fs"] } diff --git a/src-tauri/build.rs b/src-tauri/build.rs index 91455f0e..6145784e 100644 --- a/src-tauri/build.rs +++ b/src-tauri/build.rs @@ -1,3 +1,5 @@ +#[cfg(target_os = "macos")] +use swift_rs::SwiftLinker; use vergen_git2::{Emitter, Git2Builder}; fn main() -> Result<(), Box> { @@ -23,6 +25,13 @@ fn main() -> Result<(), Box> { tauri_build::build(); + #[cfg(target_os = "macos")] + SwiftLinker::new("13") + .with_ios("15") + .with_package("defguard-vpn-extension", "../swift/") + .link(); + println!("cargo:rerun-if-changed=proto"); + println!("cargo:rerun-if-changed=../swift"); Ok(()) } diff --git a/src-tauri/src/commands.rs b/src-tauri/src/commands.rs index c638e105..33f70283 100644 --- a/src-tauri/src/commands.rs +++ b/src-tauri/src/commands.rs @@ -57,6 +57,10 @@ pub async fn connect( handle: AppHandle, ) -> Result<(), Error> { debug!("Received a command to connect to a {connection_type} with ID {location_id}"); + swift_rs::swift!(fn start_tunnel()); + unsafe { + start_tunnel(); + } if connection_type == ConnectionType::Location { if let Some(location) = Location::find_by_id(&*DB_POOL, location_id).await? { debug!( diff --git a/swift/.gitignore b/swift/.gitignore new file mode 100644 index 00000000..5922fdaa --- /dev/null +++ b/swift/.gitignore @@ -0,0 +1,10 @@ +.DS_Store +/.build +/Packages +/*.xcodeproj +xcuserdata/ +DerivedData/ +.swiftpm/config/registries.json +.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata +.netrc +Package.resolved diff --git a/swift/Package.swift b/swift/Package.swift new file mode 100644 index 00000000..6c6fb59c --- /dev/null +++ b/swift/Package.swift @@ -0,0 +1,32 @@ +// swift-tools-version:5.3 +// The swift-tools-version declares the minimum version of Swift required to build this package. + +import PackageDescription + +let package = Package( + name: "defguard-vpn-extension", + platforms: [ + .macOS("13.5"), + .iOS("15.6"), + ], + products: [ + // Products define the executables and libraries a package produces, and make them visible to other packages. + .library( + name: "defguard-vpn-extension", + type: .static, + targets: ["defguard-vpn-extension"]) + ], + // dependencies: [ + // .package(name: "Tauri", path: "../.tauri/tauri-api") + // ], + targets: [ + // Targets are the basic building blocks of a package. A target can define a module or a test suite. + // Targets can depend on other targets in this package, and on products in packages this package depends on. + .target( + name: "defguard-vpn-extension", + // dependencies: [ + // .byName(name: "Tauri") + // ], + path: "Sources") + ] +) diff --git a/swift/Sources/Shared.swift b/swift/Sources/Shared.swift new file mode 100644 index 00000000..43fb683c --- /dev/null +++ b/swift/Sources/Shared.swift @@ -0,0 +1,68 @@ +// +// THIS IS A SIMPLE TEMPORARY SOLUTION TO SHARE SOME TYPES BETWEEN THE POD AND VPNEXTENSION +// WE SHOULD PROBABLY COME UP WITH A BETTER SOLUTION IN THE FUTURE +// + +import Foundation + +let suiteName = "group.net.defguard.mobile" + +public enum TunnelTraffic: String, Codable { + case All = "all" + case Predefined = "predefined" +} + +public struct TunnelStartData: Codable { + public var publicKey: String + public var privateKey: String + public var address: String + public var dns: String? + public var endpoint: String + public var allowedIps: String + public var keepalive: Int + public var presharedKey: String? + public var traffic: TunnelTraffic + public var locationName: String + public var locationId: Int + public var instanceId: Int + + public init(publicKey: String, privateKey: String, address: String, dns: String? = nil, + endpoint: String, allowedIps: String, keepalive: Int, presharedKey: String? = nil, + traffic: TunnelTraffic, locationName: String, locationId: Int, instanceId: Int) { + self.publicKey = publicKey + self.privateKey = privateKey + self.address = address + self.dns = dns + self.endpoint = endpoint + self.allowedIps = allowedIps + self.keepalive = keepalive + self.presharedKey = presharedKey + self.traffic = traffic + self.locationName = locationName + self.locationId = locationId + self.instanceId = instanceId + } +} + +public struct ActiveTunnelData: Codable { + var locationId: Int + var instanceId: Int + var traffic: TunnelTraffic + + init(fromConfig: TunnelStartData) { + self.locationId = fromConfig.locationId + self.instanceId = fromConfig.instanceId + self.traffic = fromConfig.traffic + } +} + +public enum WireguardEvent: String { + case tunnelUp = "tunnel_up" + case tunnelDown = "tunnel_down" + case tunnelWaiting = "tunnel_waiting" + case MFASessionExpired = "mfa_session_expired" +} + +public enum TunnelStopError: String { + case mfaSessionExpired = "mfa_session_expired" +} diff --git a/swift/Sources/VPNError.swift b/swift/Sources/VPNError.swift new file mode 100644 index 00000000..c448c944 --- /dev/null +++ b/swift/Sources/VPNError.swift @@ -0,0 +1,36 @@ +import Foundation + +enum VPNError: Error, LocalizedError { + case invalidArguments(String) + case noManager(String = "No VPN manager available") + case configurationError(Error) + case timeoutError(String) + case saveError(Error) + case startError(Error) + case stopError(Error) + + var errorDescription: String? { + switch self { + case .invalidArguments(let msg): return "Invalid arguments: \(msg)" + case .noManager(let msg): return "\(msg)" + case .configurationError(let error): + return "Configuration parsing error: \(error.localizedDescription)" + case .timeoutError(let msg): return "Timeout: \(msg)" + case .saveError(let error): return "Save error: \(error.localizedDescription)" + case .startError(let error): return "Start error: \(error.localizedDescription)" + case .stopError(let error): return "Stop error: \(error.localizedDescription)" + } + } + + private var code: String { + switch self { + case .invalidArguments: return "INVALID_ARGUMENTS" + case .noManager: return "NO_MANAGER" + case .configurationError: return "CONFIG_ERROR" + case .timeoutError: return "TIMEOUT_ERROR" + case .saveError: return "SAVE_ERROR" + case .startError: return "START_ERROR" + case .stopError: return "STOP_ERROR" + } + } +} diff --git a/swift/Sources/VPNManager.swift b/swift/Sources/VPNManager.swift new file mode 100644 index 00000000..47d7ddb1 --- /dev/null +++ b/swift/Sources/VPNManager.swift @@ -0,0 +1,112 @@ +import NetworkExtension +import os + +public enum VPNManagerError: Error { + case providerManagerNotSet +} + +/// Define protocol so `VPNManager` can be mocked for testing in `MockVPNManager`. +public protocol VPNManagement { + var providerManager: NETunnelProviderManager? { get } + var connectionStatus: NEVPNStatus? { get } + + func loadProviderManager( + completion: @escaping (NETunnelProviderManager?) -> Void + ) + func saveProviderManager( + _ manager: NETunnelProviderManager, + completion: @escaping (Error?) -> Void + ) + func startTunnel() throws + func stopTunnel() throws + func handleVPNConfigurationChange() +} + +public class VPNManager: VPNManagement { + static let shared = VPNManager() + private var logger = Logger(subsystem: appId, category: "WireguardPlugin.VPNManager") + + public private(set) var providerManager: NETunnelProviderManager? + + public var connectionStatus: NEVPNStatus? { + providerManager?.connection.status + } + + /// Loads the provider manager from the system preferences. + public func loadProviderManager( + completion: @escaping (NETunnelProviderManager?) -> Void + ) { + NETunnelProviderManager.loadAllFromPreferences { managers, error in + self.logger.log( + "Loaded \(managers?.count ?? 0, privacy: .public) tunnel provider managers.") + guard error == nil else { + self.logger.log( + "Error loading managers: \(String(describing: error), privacy: .public)") + self.providerManager = nil + completion(nil) + return + } + guard let providerManager = managers?.first else { + self.logger.log("No VPN manager found") + self.providerManager = nil + completion(nil) + return + } + + self.providerManager = providerManager + self.logger.log( + "Loaded provider manager: \(String(describing: providerManager.localizedDescription), privacy: .public)" + ) + completion(providerManager) + } + } + + public func saveProviderManager( + _ manager: NETunnelProviderManager, + completion: @escaping (Error?) -> Void + ) { + manager.saveToPreferences { error in + if let error = error { + self.logger.log("Failed to save provider manager: \(error, privacy: .public)") + completion(error) + } else { + self.logger.log("Provider manager saved successfully, reloading it") + self.loadProviderManager { providerManager in + self.providerManager = providerManager + self.logger.log("The provider manager has been reloaded.") + completion(nil) + } + } + + } + } + + public func handleVPNConfigurationChange() { + logger.log("VPN configuration changed, updating provider manager") + loadProviderManager { providerManager in + guard let providerManager = providerManager else { + self.logger.log("No VPN manager found after configuration change") + return + } + self.providerManager = providerManager + } + } + + public func startTunnel() throws { + guard let providerManager = providerManager else { + throw VPNManagerError.providerManagerNotSet + } + + try providerManager.connection.startVPNTunnel() + logger.log("VPN tunnel started successfully") + } + + public func stopTunnel() throws { + guard let providerManager = providerManager else { + throw VPNManagerError.providerManagerNotSet + } + + providerManager.connection.stopVPNTunnel() + logger.log("VPN tunnel stopped successfully") + } +} diff --git a/swift/Sources/Wireguard.swift b/swift/Sources/Wireguard.swift new file mode 100644 index 00000000..1413057d --- /dev/null +++ b/swift/Sources/Wireguard.swift @@ -0,0 +1,18 @@ +import NetworkExtension +import os + +let appId = Bundle.main.bundleIdentifier ?? "net.defguard.desktop" +let vpnManager = VPNManager.shared +let logger = Logger(subsystem: appId, category: "WireguardPlugin") + +@_cdecl("start_tunnel") +public func startTunnel() { + logger.log("Starting tunnel") + vpnManager.loadProviderManager { manager in + let providerManager = manager ?? NETunnelProviderManager() + let tunnelProtocol = NETunnelProviderProtocol() + tunnelProtocol.providerBundleIdentifier = "\(appId).VPNExtension" + providerManager.protocolConfiguration = tunnelProtocol + providerManager.isEnabled = true + } +} From fb5674de9076d145c98c13af2dd3ab63c5296959 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adam=20Ciarcin=CC=81ski?= Date: Tue, 7 Oct 2025 18:11:32 +0200 Subject: [PATCH 02/28] Work in progress --- build-macos-package.sh | 2 +- src-tauri/Cargo.lock | 391 ++++++++++-------- src-tauri/Cargo.toml | 3 +- src-tauri/cli/src/bin/dg.rs | 2 +- src-tauri/src/commands.rs | 11 +- src-tauri/src/database/models/location.rs | 121 +++++- src-tauri/src/database/models/tunnel.rs | 16 +- .../src/database/models/wireguard_keys.rs | 1 - src-tauri/src/error.rs | 2 - src-tauri/src/export.rs | 144 +++++++ src-tauri/src/lib.rs | 46 +-- src-tauri/src/proto.rs | 40 ++ src-tauri/src/service/mod.rs | 4 +- src-tauri/src/utils.rs | 208 +++------- swift/Package.swift | 17 +- swift/Sources/Endpoint.swift | 82 ++++ swift/Sources/IpAddrMask.swift | 109 +++++ swift/Sources/Peer.swift | 43 ++ swift/Sources/Shared.swift | 10 +- swift/Sources/TunnelConfiguration.swift | 18 + swift/Sources/Wireguard.swift | 65 ++- 21 files changed, 929 insertions(+), 406 deletions(-) create mode 100644 src-tauri/src/export.rs create mode 100644 src-tauri/src/proto.rs create mode 100644 swift/Sources/Endpoint.swift create mode 100644 swift/Sources/IpAddrMask.swift create mode 100644 swift/Sources/Peer.swift create mode 100644 swift/Sources/TunnelConfiguration.swift diff --git a/build-macos-package.sh b/build-macos-package.sh index 99ed7b29..85c6002f 100755 --- a/build-macos-package.sh +++ b/build-macos-package.sh @@ -19,7 +19,7 @@ pkgbuild \ --analyze \ --root ${APP_ROOT} \ "${TARGET_DIRECTORY}/defguard-client.plist" - + PACKAGE_PATH="${TARGET_DIRECTORY}/package/defguard.pkg" pkgbuild \ diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index a2863ae7..94af07e3 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -159,11 +159,11 @@ dependencies = [ "clipboard-win", "image", "log", - "objc2 0.6.2", + "objc2 0.6.3", "objc2-app-kit", "objc2-core-foundation", "objc2-core-graphics", - "objc2-foundation 0.3.1", + "objc2-foundation 0.3.2", "parking_lot", "percent-encoding", "windows-sys 0.60.2", @@ -348,7 +348,7 @@ dependencies = [ "polling", "rustix 1.1.2", "slab", - "windows-sys 0.61.1", + "windows-sys 0.61.2", ] [[package]] @@ -417,7 +417,7 @@ dependencies = [ "rustix 1.1.2", "signal-hook-registry", "slab", - "windows-sys 0.61.1", + "windows-sys 0.61.2", ] [[package]] @@ -562,7 +562,7 @@ dependencies = [ "miniz_oxide", "object", "rustc-demangle", - "windows-link 0.2.0", + "windows-link 0.2.1", ] [[package]] @@ -648,11 +648,11 @@ dependencies = [ [[package]] name = "block2" -version = "0.6.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "340d2f0bdb2a43c1d3cd40513185b2bd7def0aa1052f956455114bc98f82dcf2" +checksum = "cdeb9d870516001442e364c5220d3574d2da8dc765554b4a617230d33fa58ef5" dependencies = [ - "objc2 0.6.2", + "objc2 0.6.3", ] [[package]] @@ -671,7 +671,6 @@ dependencies = [ [[package]] name = "boringtun" version = "0.6.0" -source = "git+https://github.com/DefGuard/wireguard-rs?rev=42d478b980cb3f7549f20f2f492c896a7389a79d#42d478b980cb3f7549f20f2f492c896a7389a79d" dependencies = [ "aead", "base64 0.22.1", @@ -778,9 +777,9 @@ dependencies = [ [[package]] name = "bytemuck" -version = "1.23.2" +version = "1.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3995eaeebcdf32f91f980d360f78732ddc061097ab4e39991ae7a6ace9194677" +checksum = "1fbdf580320f38b612e485521afda1ee26d10cc9884efaaa750d383e13e3c5f4" [[package]] name = "byteorder" @@ -872,9 +871,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.39" +version = "1.2.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1354349954c6fc9cb0deab020f27f783cf0b604e8bb754dc4658ecf0d29c35f" +checksum = "e1d05d92f4b1fd76aad469d46cdd858ca761576082cd37df81416691e50199fb" dependencies = [ "find-msvc-tools", "jobserver", @@ -956,7 +955,7 @@ dependencies = [ "num-traits", "serde", "wasm-bindgen", - "windows-link 0.2.0", + "windows-link 0.2.1", ] [[package]] @@ -1473,7 +1472,6 @@ dependencies = [ [[package]] name = "defguard_wireguard_rs" version = "0.8.0" -source = "git+https://github.com/DefGuard/wireguard-rs?rev=42d478b980cb3f7549f20f2f492c896a7389a79d#42d478b980cb3f7549f20f2f492c896a7389a79d" dependencies = [ "base64 0.22.1", "boringtun", @@ -1596,7 +1594,7 @@ dependencies = [ "libc", "option-ext", "redox_users 0.5.2", - "windows-sys 0.61.1", + "windows-sys 0.61.2", ] [[package]] @@ -1623,9 +1621,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "89a09f22a6c6069a18470eb92d2298acf25463f14256d24778e1230d789a2aec" dependencies = [ "bitflags 2.9.4", - "block2 0.6.1", + "block2 0.6.2", "libc", - "objc2 0.6.2", + "objc2 0.6.3", ] [[package]] @@ -1836,7 +1834,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.61.1", + "windows-sys 0.61.2", ] [[package]] @@ -1945,9 +1943,9 @@ dependencies = [ [[package]] name = "find-msvc-tools" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ced73b1dacfc750a6db6c0a0c3a3853c8b41997e2e2c563dc90804ae6867959" +checksum = "0399f9d26e5191ce32c498bebd31e7a3ceabc2745f0ac54af3f335126c3f24b3" [[package]] name = "fixedbitset" @@ -1963,9 +1961,9 @@ checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99" [[package]] name = "flate2" -version = "1.1.2" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a3d7db9596fecd151c5f638c0ee5d5bd487b6e0ea232e5dc96d5250f6f94b1d" +checksum = "dc5a4e564e38c699f2880d3fda590bedc2e69f3f84cd48b457bd892ce61d0aa9" dependencies = [ "crc32fast", "miniz_oxide", @@ -2578,6 +2576,12 @@ dependencies = [ "foldhash", ] +[[package]] +name = "hashbrown" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d" + [[package]] name = "hashlink" version = "0.10.0" @@ -2803,7 +2807,7 @@ dependencies = [ "js-sys", "log", "wasm-bindgen", - "windows-core 0.62.1", + "windows-core 0.62.2", ] [[package]] @@ -2970,7 +2974,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4b0f83760fb341a774ed326568e19f5a863af4a952def8c39f9ab92fd95b88e5" dependencies = [ "equivalent", - "hashbrown 0.15.5", + "hashbrown 0.16.0", "serde", "serde_core", ] @@ -3269,7 +3273,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55" dependencies = [ "cfg-if", - "windows-link 0.2.0", + "windows-link 0.2.1", ] [[package]] @@ -3338,11 +3342,10 @@ checksum = "f5e54036fe321fd421e10d732f155734c4e4afd610dd556d9a82833ab3ee0bed" [[package]] name = "lock_api" -version = "0.4.13" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" dependencies = [ - "autocfg", "scopeguard", ] @@ -3375,8 +3378,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "119c8490084af61b44c9eda9d626475847a186737c0378c85e32d77c33a01cd4" dependencies = [ "cc", - "objc2 0.6.2", - "objc2-foundation 0.3.1", + "objc2 0.6.3", + "objc2-foundation 0.3.2", "time", ] @@ -3486,9 +3489,9 @@ dependencies = [ [[package]] name = "moxcms" -version = "0.7.5" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddd32fa8935aeadb8a8a6b6b351e40225570a37c43de67690383d87ef170cd08" +checksum = "1cc7d85f3d741164e8972ad355e26ac6e51b20fcae5f911c7da8f2d8bbbb3f33" dependencies = [ "num-traits", "pxfm", @@ -3504,10 +3507,10 @@ dependencies = [ "dpi", "gtk", "keyboard-types", - "objc2 0.6.2", + "objc2 0.6.3", "objc2-app-kit", "objc2-core-foundation", - "objc2-foundation 0.3.1", + "objc2-foundation 0.3.2", "once_cell", "png 0.17.16", "serde", @@ -3792,9 +3795,9 @@ dependencies = [ [[package]] name = "objc2" -version = "0.6.2" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "561f357ba7f3a2a61563a186a163d0a3a5247e1089524a3981d49adb775078bc" +checksum = "b7c2599ce0ec54857b29ce62166b0ed9b4f6f1a70ccc9a71165b6154caca8c05" dependencies = [ "objc2-encode", "objc2-exception-helper", @@ -3802,77 +3805,104 @@ dependencies = [ [[package]] name = "objc2-app-kit" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6f29f568bec459b0ddff777cec4fe3fd8666d82d5a40ebd0ff7e66134f89bcc" +checksum = "d49e936b501e5c5bf01fda3a9452ff86dc3ea98ad5f283e1455153142d97518c" dependencies = [ "bitflags 2.9.4", - "block2 0.6.1", + "block2 0.6.2", "libc", - "objc2 0.6.2", + "objc2 0.6.3", "objc2-cloud-kit", "objc2-core-data", "objc2-core-foundation", "objc2-core-graphics", "objc2-core-image", - "objc2-foundation 0.3.1", - "objc2-quartz-core 0.3.1", + "objc2-core-text", + "objc2-core-video", + "objc2-foundation 0.3.2", + "objc2-quartz-core 0.3.2", ] [[package]] name = "objc2-cloud-kit" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17614fdcd9b411e6ff1117dfb1d0150f908ba83a7df81b1f118005fe0a8ea15d" +checksum = "73ad74d880bb43877038da939b7427bba67e9dd42004a18b809ba7d87cee241c" dependencies = [ "bitflags 2.9.4", - "objc2 0.6.2", - "objc2-foundation 0.3.1", + "objc2 0.6.3", + "objc2-foundation 0.3.2", ] [[package]] name = "objc2-core-data" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291fbbf7d29287518e8686417cf7239c74700fd4b607623140a7d4a3c834329d" +checksum = "0b402a653efbb5e82ce4df10683b6b28027616a2715e90009947d50b8dd298fa" dependencies = [ "bitflags 2.9.4", - "objc2 0.6.2", - "objc2-foundation 0.3.1", + "objc2 0.6.3", + "objc2-foundation 0.3.2", ] [[package]] name = "objc2-core-foundation" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c10c2894a6fed806ade6027bcd50662746363a9589d3ec9d9bef30a4e4bc166" +checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536" dependencies = [ "bitflags 2.9.4", "dispatch2", - "objc2 0.6.2", + "objc2 0.6.3", ] [[package]] name = "objc2-core-graphics" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "989c6c68c13021b5c2d6b71456ebb0f9dc78d752e86a98da7c716f4f9470f5a4" +checksum = "e022c9d066895efa1345f8e33e584b9f958da2fd4cd116792e15e07e4720a807" dependencies = [ "bitflags 2.9.4", "dispatch2", - "objc2 0.6.2", + "objc2 0.6.3", "objc2-core-foundation", "objc2-io-surface", ] [[package]] name = "objc2-core-image" -version = "0.3.1" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5d563b38d2b97209f8e861173de434bd0214cf020e3423a52624cd1d989f006" +dependencies = [ + "objc2 0.6.3", + "objc2-foundation 0.3.2", +] + +[[package]] +name = "objc2-core-text" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cde0dfb48d25d2b4862161a4d5fcc0e3c24367869ad306b0c9ec0073bfed92d" +dependencies = [ + "bitflags 2.9.4", + "objc2 0.6.3", + "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 = "79b3dc0cc4386b6ccf21c157591b34a7f44c8e75b064f85502901ab2188c007e" +checksum = "d425caf1df73233f29fd8a5c3e5edbc30d2d4307870f802d18f00d83dc5141a6" dependencies = [ - "objc2 0.6.2", - "objc2-foundation 0.3.1", + "bitflags 2.9.4", + "objc2 0.6.3", + "objc2-core-foundation", + "objc2-core-graphics", + "objc2-io-surface", ] [[package]] @@ -3904,35 +3934,35 @@ dependencies = [ [[package]] name = "objc2-foundation" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "900831247d2fe1a09a683278e5384cfb8c80c79fe6b166f9d14bfdde0ea1b03c" +checksum = "e3e0adef53c21f888deb4fa59fc59f7eb17404926ee8a6f59f5df0fd7f9f3272" dependencies = [ "bitflags 2.9.4", - "block2 0.6.1", + "block2 0.6.2", "libc", - "objc2 0.6.2", + "objc2 0.6.3", "objc2-core-foundation", ] [[package]] name = "objc2-io-surface" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7282e9ac92529fa3457ce90ebb15f4ecbc383e8338060960760fa2cf75420c3c" +checksum = "180788110936d59bab6bd83b6060ffdfffb3b922ba1396b312ae795e1de9d81d" dependencies = [ "bitflags 2.9.4", - "objc2 0.6.2", + "objc2 0.6.3", "objc2-core-foundation", ] [[package]] name = "objc2-javascript-core" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9052cb1bb50a4c161d934befcf879526fb87ae9a68858f241e693ca46225cf5a" +checksum = "2a1e6550c4caed348956ce3370c9ffeca70bb1dbed4fa96112e7c6170e074586" dependencies = [ - "objc2 0.6.2", + "objc2 0.6.3", "objc2-core-foundation", ] @@ -3963,50 +3993,50 @@ dependencies = [ [[package]] name = "objc2-quartz-core" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90ffb6a0cd5f182dc964334388560b12a57f7b74b3e2dec5e2722aa2dfb2ccd5" +checksum = "96c1358452b371bf9f104e21ec536d37a650eb10f7ee379fff67d2e08d537f1f" dependencies = [ "bitflags 2.9.4", - "objc2 0.6.2", - "objc2-foundation 0.3.1", + "objc2 0.6.3", + "objc2-foundation 0.3.2", ] [[package]] name = "objc2-security" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1f8e0ef3ab66b08c42644dcb34dba6ec0a574bbd8adbb8bdbdc7a2779731a44" +checksum = "709fe137109bd1e8b5a99390f77a7d8b2961dafc1a1c5db8f2e60329ad6d895a" dependencies = [ "bitflags 2.9.4", - "objc2 0.6.2", + "objc2 0.6.3", "objc2-core-foundation", ] [[package]] name = "objc2-ui-kit" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25b1312ad7bc8a0e92adae17aa10f90aae1fb618832f9b993b022b591027daed" +checksum = "d87d638e33c06f577498cbcc50491496a3ed4246998a7fbba7ccb98b1e7eab22" dependencies = [ "bitflags 2.9.4", - "objc2 0.6.2", + "objc2 0.6.3", "objc2-core-foundation", - "objc2-foundation 0.3.1", + "objc2-foundation 0.3.2", ] [[package]] name = "objc2-web-kit" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91672909de8b1ce1c2252e95bbee8c1649c9ad9d14b9248b3d7b4c47903c47ad" +checksum = "b2e5aaab980c433cf470df9d7af96a7b46a9d892d521a2cbbb2f8a4c16751e7f" dependencies = [ "bitflags 2.9.4", - "block2 0.6.1", - "objc2 0.6.2", + "block2 0.6.2", + "objc2 0.6.3", "objc2-app-kit", "objc2-core-foundation", - "objc2-foundation 0.3.1", + "objc2-foundation 0.3.2", "objc2-javascript-core", "objc2-security", ] @@ -4185,9 +4215,9 @@ checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" [[package]] name = "parking_lot" -version = "0.12.4" +version = "0.12.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13" +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" dependencies = [ "lock_api", "parking_lot_core", @@ -4195,15 +4225,15 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.11" +version = "0.9.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5" +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" dependencies = [ "cfg-if", "libc", "redox_syscall", "smallvec", - "windows-targets 0.52.6", + "windows-link 0.2.1", ] [[package]] @@ -4519,7 +4549,7 @@ dependencies = [ "hermit-abi", "pin-project-lite", "rustix 1.1.2", - "windows-sys 0.61.1", + "windows-sys 0.61.2", ] [[package]] @@ -4978,9 +5008,9 @@ checksum = "20675572f6f24e9e76ef639bc5552774ed45f1c30e2951e1e99c59888861c539" [[package]] name = "redox_syscall" -version = "0.5.17" +version = "0.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5407465600fb0548f1442edf71dd20683c6ed326200ace4b1ef0763521bb3b77" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" dependencies = [ "bitflags 2.9.4", ] @@ -5121,17 +5151,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef2bee61e6cffa4635c72d7d81a84294e28f0930db0ddcb0f66d10244674ebed" dependencies = [ "ashpd 0.11.0", - "block2 0.6.1", + "block2 0.6.2", "dispatch2", "glib-sys", "gobject-sys", "gtk-sys", "js-sys", "log", - "objc2 0.6.2", + "objc2 0.6.3", "objc2-app-kit", "objc2-core-foundation", - "objc2-foundation 0.3.1", + "objc2-foundation 0.3.2", "raw-window-handle", "wasm-bindgen", "wasm-bindgen-futures", @@ -5273,7 +5303,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys 0.11.0", - "windows-sys 0.61.1", + "windows-sys 0.61.2", ] [[package]] @@ -5351,7 +5381,7 @@ version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "891d81b926048e76efe18581bf793546b4c0eaf8448d72be8de2bbee5fd166e1" dependencies = [ - "windows-sys 0.61.1", + "windows-sys 0.61.2", ] [[package]] @@ -5616,9 +5646,9 @@ dependencies = [ [[package]] name = "serde_with" -version = "3.14.1" +version = "3.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c522100790450cf78eeac1507263d0a350d4d5b30df0c8e1fe051a10c22b376e" +checksum = "6093cd8c01b25262b84927e0f7151692158fab02d961e04c979d3903eba7ecc5" dependencies = [ "base64 0.22.1", "chrono", @@ -5627,8 +5657,7 @@ dependencies = [ "indexmap 2.11.4", "schemars 0.9.0", "schemars 1.0.4", - "serde", - "serde_derive", + "serde_core", "serde_json", "serde_with_macros", "time", @@ -5636,9 +5665,9 @@ dependencies = [ [[package]] name = "serde_with_macros" -version = "3.14.1" +version = "3.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "327ada00f7d64abaac1e55a6911e90cf665aa051b9a561c7006c157f4633135e" +checksum = "a7e6c180db0816026a61afa1cff5344fb7ebded7e4d3062772179f2501481c27" dependencies = [ "darling 0.21.3", "proc-macro2", @@ -6256,7 +6285,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "959469667dbcea91e5485fc48ba7dd6023face91bb0f1a14681a70f99847c3f7" dependencies = [ "bitflags 2.9.4", - "block2 0.6.1", + "block2 0.6.2", "core-foundation 0.10.1", "core-graphics", "crossbeam-channel", @@ -6273,9 +6302,9 @@ dependencies = [ "ndk", "ndk-context", "ndk-sys", - "objc2 0.6.2", + "objc2 0.6.3", "objc2-app-kit", - "objc2-foundation 0.3.1", + "objc2-foundation 0.3.2", "once_cell", "parking_lot", "raw-window-handle", @@ -6335,9 +6364,9 @@ dependencies = [ "log", "mime", "muda", - "objc2 0.6.2", + "objc2 0.6.3", "objc2-app-kit", - "objc2-foundation 0.3.1", + "objc2-foundation 0.3.2", "objc2-ui-kit", "objc2-web-kit", "percent-encoding", @@ -6555,8 +6584,8 @@ dependencies = [ "byte-unit", "fern", "log", - "objc2 0.6.2", - "objc2-foundation 0.3.1", + "objc2 0.6.3", + "objc2-foundation 0.3.2", "serde", "serde_json", "serde_repr", @@ -6595,7 +6624,7 @@ dependencies = [ "dunce", "glob", "objc2-app-kit", - "objc2-foundation 0.3.1", + "objc2-foundation 0.3.2", "open", "schemars 0.8.22", "serde", @@ -6668,7 +6697,7 @@ dependencies = [ "gtk", "http", "jni", - "objc2 0.6.2", + "objc2 0.6.3", "objc2-ui-kit", "objc2-web-kit", "raw-window-handle", @@ -6692,9 +6721,9 @@ dependencies = [ "http", "jni", "log", - "objc2 0.6.2", + "objc2 0.6.3", "objc2-app-kit", - "objc2-foundation 0.3.1", + "objc2-foundation 0.3.2", "once_cell", "percent-encoding", "raw-window-handle", @@ -6779,7 +6808,7 @@ dependencies = [ "getrandom 0.3.3", "once_cell", "rustix 1.1.2", - "windows-sys 0.61.1", + "windows-sys 0.61.2", ] [[package]] @@ -7330,11 +7359,11 @@ dependencies = [ "dirs", "libappindicator", "muda", - "objc2 0.6.2", + "objc2 0.6.3", "objc2-app-kit", "objc2-core-foundation", "objc2-core-graphics", - "objc2-foundation 0.3.1", + "objc2-foundation 0.3.2", "once_cell", "png 0.17.16", "serde", @@ -8010,8 +8039,8 @@ dependencies = [ "jni", "log", "ndk-context", - "objc2 0.6.2", - "objc2-foundation 0.3.1", + "objc2 0.6.3", + "objc2-foundation 0.3.2", "url", "web-sys", ] @@ -8158,7 +8187,7 @@ version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "windows-sys 0.61.1", + "windows-sys 0.61.2", ] [[package]] @@ -8173,10 +8202,10 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9bec5a31f3f9362f2258fd0e9c9dd61a9ca432e7306cc78c444258f0dce9a9c" dependencies = [ - "objc2 0.6.2", + "objc2 0.6.3", "objc2-app-kit", "objc2-core-foundation", - "objc2-foundation 0.3.1", + "objc2-foundation 0.3.2", "raw-window-handle", "windows-sys 0.59.0", "windows-version", @@ -8219,15 +8248,15 @@ dependencies = [ [[package]] name = "windows-core" -version = "0.62.1" +version = "0.62.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6844ee5416b285084d3d3fffd743b925a6c9385455f64f6d4fa3031c4c2749a9" +checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" dependencies = [ "windows-implement", "windows-interface", - "windows-link 0.2.0", - "windows-result 0.4.0", - "windows-strings 0.5.0", + "windows-link 0.2.1", + "windows-result 0.4.1", + "windows-strings 0.5.1", ] [[package]] @@ -8243,9 +8272,9 @@ dependencies = [ [[package]] name = "windows-implement" -version = "0.60.1" +version = "0.60.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edb307e42a74fb6de9bf3a02d9712678b22399c87e6fa869d6dfcd8c1b7754e0" +checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" dependencies = [ "proc-macro2", "quote", @@ -8254,9 +8283,9 @@ dependencies = [ [[package]] name = "windows-interface" -version = "0.59.2" +version = "0.59.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0abd1ddbc6964ac14db11c7213d6532ef34bd9aa042c2e5935f59d7908b46a5" +checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" dependencies = [ "proc-macro2", "quote", @@ -8271,9 +8300,9 @@ checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" [[package]] name = "windows-link" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45e46c0661abb7180e7b9c281db115305d49ca1709ab8242adf09666d2173c65" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" [[package]] name = "windows-numerics" @@ -8307,11 +8336,11 @@ dependencies = [ [[package]] name = "windows-result" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7084dcc306f89883455a206237404d3eaf961e5bd7e0f312f7c91f57eb44167f" +checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" dependencies = [ - "windows-link 0.2.0", + "windows-link 0.2.1", ] [[package]] @@ -8336,11 +8365,11 @@ dependencies = [ [[package]] name = "windows-strings" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7218c655a553b0bed4426cf54b20d7ba363ef543b52d515b3e48d7fd55318dda" +checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" dependencies = [ - "windows-link 0.2.0", + "windows-link 0.2.1", ] [[package]] @@ -8385,16 +8414,16 @@ version = "0.60.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" dependencies = [ - "windows-targets 0.53.4", + "windows-targets 0.53.5", ] [[package]] name = "windows-sys" -version = "0.61.1" +version = "0.61.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f109e41dd4a3c848907eb83d5a42ea98b3769495597450cf6d153507b166f0f" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" dependencies = [ - "windows-link 0.2.0", + "windows-link 0.2.1", ] [[package]] @@ -8445,19 +8474,19 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.53.4" +version = "0.53.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d42b7b7f66d2a06854650af09cfdf8713e427a439c97ad65a6375318033ac4b" +checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" dependencies = [ - "windows-link 0.2.0", - "windows_aarch64_gnullvm 0.53.0", - "windows_aarch64_msvc 0.53.0", - "windows_i686_gnu 0.53.0", - "windows_i686_gnullvm 0.53.0", - "windows_i686_msvc 0.53.0", - "windows_x86_64_gnu 0.53.0", - "windows_x86_64_gnullvm 0.53.0", - "windows_x86_64_msvc 0.53.0", + "windows-link 0.2.1", + "windows_aarch64_gnullvm 0.53.1", + "windows_aarch64_msvc 0.53.1", + "windows_i686_gnu 0.53.1", + "windows_i686_gnullvm 0.53.1", + "windows_i686_msvc 0.53.1", + "windows_x86_64_gnu 0.53.1", + "windows_x86_64_gnullvm 0.53.1", + "windows_x86_64_msvc 0.53.1", ] [[package]] @@ -8471,11 +8500,11 @@ dependencies = [ [[package]] name = "windows-version" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "700dad7c058606087f6fdc1f88da5841e06da40334413c6cd4367b25ef26d24e" +checksum = "e4060a1da109b9d0326b7262c8e12c84df67cc0dbc9e33cf49e01ccc2eb63631" dependencies = [ - "windows-link 0.2.0", + "windows-link 0.2.1", ] [[package]] @@ -8498,9 +8527,9 @@ checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_gnullvm" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" +checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" [[package]] name = "windows_aarch64_msvc" @@ -8522,9 +8551,9 @@ checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_aarch64_msvc" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" +checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" [[package]] name = "windows_i686_gnu" @@ -8546,9 +8575,9 @@ checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" [[package]] name = "windows_i686_gnu" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" +checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" [[package]] name = "windows_i686_gnullvm" @@ -8558,9 +8587,9 @@ checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_gnullvm" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" +checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" [[package]] name = "windows_i686_msvc" @@ -8582,9 +8611,9 @@ checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_i686_msvc" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" +checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" [[package]] name = "windows_x86_64_gnu" @@ -8606,9 +8635,9 @@ checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnu" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" +checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" [[package]] name = "windows_x86_64_gnullvm" @@ -8630,9 +8659,9 @@ checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_gnullvm" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" +checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" [[package]] name = "windows_x86_64_msvc" @@ -8654,9 +8683,9 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "windows_x86_64_msvc" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" +checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" [[package]] name = "winnow" @@ -8729,12 +8758,12 @@ checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" [[package]] name = "wry" -version = "0.53.3" +version = "0.53.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31f0e9642a0d061f6236c54ccae64c2722a7879ad4ec7dff59bd376d446d8e90" +checksum = "6d78ec082b80fa088569a970d043bb3050abaabf4454101d44514ee8d9a8c9f6" dependencies = [ "base64 0.22.1", - "block2 0.6.1", + "block2 0.6.2", "cookie", "crossbeam-channel", "dirs", @@ -8749,10 +8778,10 @@ dependencies = [ "kuchikiki", "libc", "ndk", - "objc2 0.6.2", + "objc2 0.6.3", "objc2-app-kit", "objc2-core-foundation", - "objc2-foundation 0.3.1", + "objc2-foundation 0.3.2", "objc2-ui-kit", "objc2-web-kit", "once_cell", diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 75911d02..47662cab 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -4,7 +4,8 @@ default-members = [".", "cli"] [workspace.dependencies] clap = { version = "4.5", features = ["cargo", "derive", "env"] } -defguard_wireguard_rs = { git = "https://github.com/DefGuard/wireguard-rs", rev = "42d478b980cb3f7549f20f2f492c896a7389a79d" } +defguard_wireguard_rs = { path = "../../wireguard-rs" } +# defguard_wireguard_rs = { git = "https://github.com/DefGuard/wireguard-rs", rev = "42d478b980cb3f7549f20f2f492c896a7389a79d" } dirs-next = "2.0" prost = "0.14" reqwest = { version = "0.12", features = ["cookies", "json"] } diff --git a/src-tauri/cli/src/bin/dg.rs b/src-tauri/cli/src/bin/dg.rs index 1252de10..927fe917 100644 --- a/src-tauri/cli/src/bin/dg.rs +++ b/src-tauri/cli/src/bin/dg.rs @@ -237,7 +237,7 @@ async fn connect(config: CliConfig, ifname: String, trigger: Arc) -> Res name: config.instance_info.name.clone(), prvkey: config.private_key.to_string(), addresses, - port: u32::from(find_free_tcp_port().ok_or(CliError::FreeTCPPort)?), + port: find_free_tcp_port().ok_or(CliError::FreeTCPPort)?, peers: vec![peer.clone()], mtu: None, }; diff --git a/src-tauri/src/commands.rs b/src-tauri/src/commands.rs index 33f70283..06a6ca05 100644 --- a/src-tauri/src/commands.rs +++ b/src-tauri/src/commands.rs @@ -48,7 +48,7 @@ use crate::{ CommonConnection, CommonConnectionInfo, CommonLocationStats, ConnectionType, }; -// Create new WireGuard interface +/// Open new WireGuard connection. #[tauri::command(async)] pub async fn connect( location_id: Id, @@ -57,10 +57,6 @@ pub async fn connect( handle: AppHandle, ) -> Result<(), Error> { debug!("Received a command to connect to a {connection_type} with ID {location_id}"); - swift_rs::swift!(fn start_tunnel()); - unsafe { - start_tunnel(); - } if connection_type == ConnectionType::Location { if let Some(location) = Location::find_by_id(&*DB_POOL, location_id).await? { debug!( @@ -875,7 +871,7 @@ pub fn parse_tunnel_config(config: &str) -> Result { #[tauri::command(async)] pub async fn update_tunnel(mut tunnel: Tunnel, handle: AppHandle) -> Result<(), Error> { - debug!("Received tunnel configuration to update: {tunnel:?}"); + debug!("Received tunnel configuration to update: {tunnel}"); tunnel.save(&*DB_POOL).await?; info!("The tunnel {tunnel} configuration has been updated."); handle.emit(EventKey::LocationUpdate.into(), ())?; @@ -884,7 +880,7 @@ pub async fn update_tunnel(mut tunnel: Tunnel, handle: AppHandle) -> Result< #[tauri::command(async)] pub async fn save_tunnel(tunnel: Tunnel, handle: AppHandle) -> Result<(), Error> { - debug!("Received tunnel configuration to save: {tunnel:?}"); + debug!("Received tunnel configuration to save: {tunnel}"); let tunnel = tunnel.save(&*DB_POOL).await?; info!("The tunnel {tunnel} configuration has been saved."); handle.emit(EventKey::LocationUpdate.into(), ())?; @@ -908,7 +904,6 @@ pub async fn all_tunnels() -> Result>, Error> { let tunnels = Tunnel::all(&*DB_POOL).await?; trace!("Found ({}) tunnels to get information about", tunnels.len()); - trace!("Tunnels found: {tunnels:#?}"); let mut tunnel_info = Vec::new(); let active_tunnel_ids = get_connection_id_by_type(ConnectionType::Tunnel).await; diff --git a/src-tauri/src/database/models/location.rs b/src-tauri/src/database/models/location.rs index 97d20dc6..94c78ad8 100644 --- a/src-tauri/src/database/models/location.rs +++ b/src-tauri/src/database/models/location.rs @@ -1,10 +1,16 @@ -use std::fmt; +use std::{fmt, net::IpAddr, str::FromStr}; +use defguard_wireguard_rs::{host::Peer, key::Key, net::IpAddrMask, InterfaceConfiguration}; use serde::{Deserialize, Serialize}; use sqlx::{prelude::Type, query, query_as, query_scalar, Error as SqlxError, SqliteExecutor}; use super::{Id, NoId}; -use crate::{error::Error, proto::LocationMfaMode as ProtoLocationMfaMode}; +use crate::{ + database::models::wireguard_keys::WireguardKeys, + error::Error, + proto::LocationMfaMode as ProtoLocationMfaMode, + utils::{DEFAULT_ROUTE_IPV4, DEFAULT_ROUTE_IPV6}, +}; #[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Hash, Type)] #[repr(u32)] @@ -35,7 +41,7 @@ pub struct Location { pub network_id: Id, pub name: String, pub address: String, - pub pubkey: String, + pub pubkey: String, // Remote pub endpoint: String, pub allowed_ips: String, pub dns: Option, @@ -189,6 +195,115 @@ impl Location { LocationMfaMode::Internal | LocationMfaMode::External => true, } } + + /// Split DNS settings into resolver IP addresses and search domains. + pub(crate) fn dns(&self) -> (Vec, Vec) { + let mut dns = Vec::new(); + let mut dns_search = Vec::new(); + + if let Some(dns_string) = &self.dns { + for entry in dns_string.split(',').map(str::trim) { + // Assume that every entry that can't be parsed as an IP address is a domain name. + if let Ok(ip) = entry.parse::() { + dns.push(ip); + } else { + dns_search.push(entry.into()); + } + } + } + + (dns, dns_search) + } + + pub(crate) async fn interface_configurarion<'e, E>( + &self, + executor: E, + interface_name: String, + preshared_key: Option, + ) -> Result + where + E: SqliteExecutor<'e>, + { + debug!("Looking for WireGuard keys for location {self} instance"); + let Some(keys) = WireguardKeys::find_by_instance_id(executor, self.instance_id).await? + else { + error!("No keys found for instance: {}", self.instance_id); + return Err(Error::InternalError( + "No keys found for instance".to_string(), + )); + }; + debug!("WireGuard keys found for location {self} instance"); + + // prepare peer config + debug!("Decoding location {self} public key: {}.", self.pubkey); + let peer_key = Key::from_str(&self.pubkey)?; + debug!("Location {self} public key decoded: {peer_key}"); + let mut peer = Peer::new(peer_key); + + debug!("Parsing location {self} endpoint: {}", self.endpoint); + peer.set_endpoint(&self.endpoint)?; + peer.persistent_keepalive_interval = Some(25); + debug!("Parsed location {self} endpoint: {}", self.endpoint); + + if let Some(psk) = preshared_key { + debug!("Decoding location {self} preshared key."); + let peer_psk = Key::from_str(&psk)?; + info!("Location {self} preshared key decoded."); + peer.preshared_key = Some(peer_psk); + } + + debug!("Parsing location {self} allowed IPs: {}", self.allowed_ips); + let allowed_ips = if self.route_all_traffic { + debug!("Using all traffic routing for location {self}"); + vec![DEFAULT_ROUTE_IPV4.into(), DEFAULT_ROUTE_IPV6.into()] + } else { + debug!( + "Using predefined location {self} traffic: {}", + self.allowed_ips + ); + self.allowed_ips.split(',').map(str::to_string).collect() + }; + for allowed_ip in &allowed_ips { + match IpAddrMask::from_str(allowed_ip) { + Ok(addr) => { + peer.allowed_ips.push(addr); + } + Err(err) => { + // Handle the error from IpAddrMask::from_str, if needed + error!( + "Error parsing IP address {allowed_ip} while setting up interface for \ + location {self}, error details: {err}" + ); + } + } + } + debug!( + "Parsed allowed IPs for location {self}: {:?}", + peer.allowed_ips + ); + + let addresses = self + .address + .split(',') + .map(str::trim) + .map(IpAddrMask::from_str) + .collect::>() + .map_err(|err| { + let msg = format!("Failed to parse IP addresses '{}': {err}", self.address); + error!("{msg}"); + Error::InternalError(msg) + })?; + let interface_config = InterfaceConfiguration { + name: interface_name, + prvkey: keys.prvkey, + addresses, + port: 0, + peers: vec![peer], + mtu: None, + }; + + Ok(interface_config) + } } impl Location { diff --git a/src-tauri/src/database/models/tunnel.rs b/src-tauri/src/database/models/tunnel.rs index 974861c7..7510ea0e 100644 --- a/src-tauri/src/database/models/tunnel.rs +++ b/src-tauri/src/database/models/tunnel.rs @@ -14,13 +14,13 @@ use crate::{ }; #[serde_as] -#[derive(Debug, Serialize, Deserialize)] +#[derive(Serialize, Deserialize)] pub struct Tunnel { pub id: I, pub name: String, - // user keys - pub pubkey: String, - pub prvkey: String, + // encryption keys + pub pubkey: String, // Remote + pub prvkey: String, // Local // server config pub address: String, pub server_pubkey: String, @@ -32,7 +32,7 @@ pub struct Tunnel { pub endpoint: String, #[serde_as(as = "NoneAsEmptyString")] pub dns: Option, - pub persistent_keep_alive: i64, // New field + pub persistent_keep_alive: i64, pub route_all_traffic: bool, // additional commands #[serde_as(as = "NoneAsEmptyString")] @@ -51,6 +51,12 @@ impl fmt::Display for Tunnel { } } +impl fmt::Display for Tunnel { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.name) + } +} + impl Tunnel { pub(crate) async fn save<'e, E>(&mut self, executor: E) -> Result<(), SqlxError> where diff --git a/src-tauri/src/database/models/wireguard_keys.rs b/src-tauri/src/database/models/wireguard_keys.rs index 38a27273..dce89689 100644 --- a/src-tauri/src/database/models/wireguard_keys.rs +++ b/src-tauri/src/database/models/wireguard_keys.rs @@ -5,7 +5,6 @@ use x25519_dalek::{PublicKey, StaticSecret}; use super::{Id, NoId}; // User key pair -#[derive(Debug)] pub struct WireguardKeys { pub id: I, pub instance_id: Id, diff --git a/src-tauri/src/error.rs b/src-tauri/src/error.rs index 4ba25ef5..a53b21dc 100644 --- a/src-tauri/src/error.rs +++ b/src-tauri/src/error.rs @@ -42,8 +42,6 @@ pub enum Error { NoToken, #[error("Failed to lock app state member.")] StateLockFail, - #[error("Failed to acquire lock on mutex. {0}")] - PoisonError(String), } // we must manually implement serde::Serialize diff --git a/src-tauri/src/export.rs b/src-tauri/src/export.rs new file mode 100644 index 00000000..2878acbc --- /dev/null +++ b/src-tauri/src/export.rs @@ -0,0 +1,144 @@ +//! Structures used for interchangeability with the Swift code. + +use std::{net::IpAddr, str::FromStr}; + +use defguard_wireguard_rs::{host::Peer, key::Key, net::IpAddrMask}; +use serde::Serialize; +use sqlx::SqliteExecutor; + +use crate::{ + database::models::{location::Location, wireguard_keys::WireguardKeys, Id}, + error::Error, + utils::{DEFAULT_ROUTE_IPV4, DEFAULT_ROUTE_IPV6}, +}; + +#[derive(Serialize)] +pub(crate) struct TunnelConfiguration { + name: String, + #[serde(rename = "privateKey")] + private_key: String, + addresses: Vec, + #[serde(rename = "listenPort")] + listen_port: Option, + peers: Vec, + mtu: Option, + dns: Vec, + #[serde(rename = "dnsSearch")] + dns_search: Vec, +} + +// impl TunnelConfiguration { +// #[must_use] +// pub(crate) fn new( +// interface_configuration: InterfaceConfiguration, +// dns: Vec, +// dns_search: Vec, +// ) -> Self { +// Self { +// name: interface_configuration.name, +// private_key: interface_configuration.prvkey, +// addresses: interface_configuration.addresses, +// listen_port: Some(interface_configuration.port), +// peers: interface_configuration.peers, +// mtu: interface_configuration.mtu, +// dns, +// dns_search, +// } +// } +// } + +impl Location { + pub(crate) async fn tunnel_configurarion<'e, E>( + &self, + executor: E, + name: String, + preshared_key: Option, + dns: Vec, + dns_search: Vec, + ) -> Result + where + E: SqliteExecutor<'e>, + { + debug!("Looking for WireGuard keys for location {self} instance"); + let Some(keys) = WireguardKeys::find_by_instance_id(executor, self.instance_id).await? + else { + error!("No keys found for instance: {}", self.instance_id); + return Err(Error::InternalError( + "No keys found for instance".to_string(), + )); + }; + debug!("WireGuard keys found for location {self} instance"); + + // prepare peer config + debug!("Decoding location {self} public key: {}.", self.pubkey); + let peer_key = Key::from_str(&self.pubkey)?; + debug!("Location {self} public key decoded: {peer_key}"); + let mut peer = Peer::new(peer_key); + + debug!("Parsing location {self} endpoint: {}", self.endpoint); + peer.set_endpoint(&self.endpoint)?; + peer.persistent_keepalive_interval = Some(25); + debug!("Parsed location {self} endpoint: {}", self.endpoint); + + if let Some(psk) = preshared_key { + debug!("Decoding location {self} preshared key."); + let peer_psk = Key::from_str(&psk)?; + info!("Location {self} preshared key decoded."); + peer.preshared_key = Some(peer_psk); + } + + debug!("Parsing location {self} allowed IPs: {}", self.allowed_ips); + let allowed_ips = if self.route_all_traffic { + debug!("Using all traffic routing for location {self}"); + vec![DEFAULT_ROUTE_IPV4.into(), DEFAULT_ROUTE_IPV6.into()] + } else { + debug!( + "Using predefined location {self} traffic: {}", + self.allowed_ips + ); + self.allowed_ips.split(',').map(str::to_string).collect() + }; + for allowed_ip in &allowed_ips { + match IpAddrMask::from_str(allowed_ip) { + Ok(addr) => { + peer.allowed_ips.push(addr); + } + Err(err) => { + // Handle the error from IpAddrMask::from_str, if needed + error!( + "Error parsing IP address {allowed_ip} while setting up interface for \ + location {self}, error details: {err}" + ); + } + } + } + debug!( + "Parsed allowed IPs for location {self}: {:?}", + peer.allowed_ips + ); + + let addresses = self + .address + .split(',') + .map(str::trim) + .map(IpAddrMask::from_str) + .collect::>() + .map_err(|err| { + let msg = format!("Failed to parse IP addresses '{}': {err}", self.address); + error!("{msg}"); + Error::InternalError(msg) + })?; + let interface_config = TunnelConfiguration { + name, + private_key: keys.prvkey, + addresses, + listen_port: Some(0), + peers: vec![], + mtu: None, + dns, + dns_search, + }; + + Ok(interface_config) + } +} diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index e22f4938..16692304 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -23,56 +23,16 @@ pub mod database; pub mod enterprise; pub mod error; pub mod events; +#[cfg(target_os = "macos")] +mod export; pub mod log_watcher; pub mod periodic; +pub mod proto; pub mod service; pub mod tray; pub mod utils; pub mod wg_config; -pub mod proto { - use crate::database::models::{ - location::{Location, LocationMfaMode as MfaMode}, - Id, NoId, - }; - - tonic::include_proto!("defguard.proxy"); - - impl DeviceConfig { - #[must_use] - pub(crate) fn into_location(self, instance_id: Id) -> Location { - let location_mfa_mode = match self.location_mfa_mode { - Some(_location_mfa_mode) => self.location_mfa_mode().into(), - None => { - // handle legacy core response - // DEPRECATED(1.5): superseeded by location_mfa_mode - #[allow(deprecated)] - if self.mfa_enabled { - MfaMode::Internal - } else { - MfaMode::Disabled - } - } - }; - - Location { - id: NoId, - instance_id, - network_id: self.network_id, - name: self.network_name, - address: self.assigned_ip, // Transforming assigned_ip to address - pubkey: self.pubkey, - endpoint: self.endpoint, - allowed_ips: self.allowed_ips, - dns: self.dns, - route_all_traffic: false, - keepalive_interval: self.keepalive_interval.into(), - location_mfa_mode, - } - } - } -} - pub const VERSION: &str = concat!(env!("CARGO_PKG_VERSION"), "-", env!("VERGEN_GIT_SHA")); pub const MIN_CORE_VERSION: Version = Version::new(1, 5, 0); pub const MIN_PROXY_VERSION: Version = Version::new(1, 5, 0); diff --git a/src-tauri/src/proto.rs b/src-tauri/src/proto.rs new file mode 100644 index 00000000..2174664f --- /dev/null +++ b/src-tauri/src/proto.rs @@ -0,0 +1,40 @@ +use crate::database::models::{ + location::{Location, LocationMfaMode as MfaMode}, + Id, NoId, +}; + +tonic::include_proto!("defguard.proxy"); + +impl DeviceConfig { + #[must_use] + pub(crate) fn into_location(self, instance_id: Id) -> Location { + let location_mfa_mode = match self.location_mfa_mode { + Some(_location_mfa_mode) => self.location_mfa_mode().into(), + None => { + // handle legacy core response + // DEPRECATED(1.5): superseeded by location_mfa_mode + #[allow(deprecated)] + if self.mfa_enabled { + MfaMode::Internal + } else { + MfaMode::Disabled + } + } + }; + + Location { + id: NoId, + instance_id, + network_id: self.network_id, + name: self.network_name, + address: self.assigned_ip, // Transforming assigned_ip to address + pubkey: self.pubkey, + endpoint: self.endpoint, + allowed_ips: self.allowed_ips, + dns: self.dns, + route_all_traffic: false, + keepalive_interval: self.keepalive_interval.into(), + location_mfa_mode, + } + } +} diff --git a/src-tauri/src/service/mod.rs b/src-tauri/src/service/mod.rs index 431a79f4..153251cd 100644 --- a/src-tauri/src/service/mod.rs +++ b/src-tauri/src/service/mod.rs @@ -447,7 +447,7 @@ impl From for proto::InterfaceConfig { .map(ToString::to_string) .collect::>() .join(","), - port: config.port, + port: u32::from(config.port), peers: config.peers.into_iter().map(Into::into).collect(), } } @@ -464,7 +464,7 @@ impl From for InterfaceConfiguration { name: config.name, prvkey: config.prvkey, addresses, - port: config.port, + port: config.port as u16, peers: config.peers.into_iter().map(Into::into).collect(), mtu: None, } diff --git a/src-tauri/src/utils.rs b/src-tauri/src/utils.rs index 987c1358..532836a4 100644 --- a/src-tauri/src/utils.rs +++ b/src-tauri/src/utils.rs @@ -3,6 +3,8 @@ use std::{env, path::Path, process::Command, str::FromStr}; use common::{find_free_tcp_port, get_interface_name}; use defguard_wireguard_rs::{host::Peer, key::Key, net::IpAddrMask, InterfaceConfiguration}; use sqlx::query; +#[cfg(target_os = "macos")] +use swift_rs::{swift, SRString}; use tauri::{AppHandle, Emitter, Manager}; use tonic::Code; use tracing::Level; @@ -44,7 +46,7 @@ use crate::active_connections::find_connection; pub(crate) static DEFAULT_ROUTE_IPV4: &str = "0.0.0.0/0"; pub(crate) static DEFAULT_ROUTE_IPV6: &str = "::/0"; -/// Setup client interface +/// Setup client interface for `Instance`. pub(crate) async fn setup_interface( location: &Location, interface_name: String, @@ -53,144 +55,68 @@ pub(crate) async fn setup_interface( ) -> Result<(), Error> { debug!("Setting up interface for location: {location}"); - debug!("Looking for WireGuard keys for location {location} instance"); - let Some(keys) = WireguardKeys::find_by_instance_id(pool, location.instance_id).await? else { - error!("No keys found for instance: {}", location.instance_id); - return Err(Error::InternalError( - "No keys found for instance".to_string(), - )); - }; - debug!("WireGuard keys found for location {location} instance"); - - // prepare peer config - debug!( - "Decoding location {location} public key: {}.", - location.pubkey - ); - let peer_key: Key = Key::from_str(&location.pubkey)?; - debug!("Location {location} public key decoded: {peer_key}"); - let mut peer = Peer::new(peer_key); - - debug!( - "Parsing location {location} endpoint: {}", - location.endpoint - ); - peer.set_endpoint(&location.endpoint)?; - peer.persistent_keepalive_interval = Some(25); - debug!("Parsed location {location} endpoint: {}", location.endpoint); - - if let Some(psk) = preshared_key { - debug!("Decoding location {location} preshared key."); - let peer_psk = Key::from_str(&psk)?; - info!("Location {location} preshared key decoded."); - peer.preshared_key = Some(peer_psk); - } - - debug!( - "Parsing location {location} allowed IPs: {}", - location.allowed_ips - ); - let allowed_ips = if location.route_all_traffic { - debug!( - "Using all traffic routing for location {location}: {DEFAULT_ROUTE_IPV4} \ - {DEFAULT_ROUTE_IPV6}" - ); - vec![DEFAULT_ROUTE_IPV4.into(), DEFAULT_ROUTE_IPV6.into()] - } else { - debug!( - "Using predefined location {location} traffic: {}", - location.allowed_ips - ); - location - .allowed_ips - .split(',') - .map(str::to_string) - .collect() - }; - for allowed_ip in &allowed_ips { - match IpAddrMask::from_str(allowed_ip) { - Ok(addr) => { - peer.allowed_ips.push(addr); - } - Err(err) => { - // Handle the error from IpAddrMask::from_str, if needed - error!( - "Error parsing IP address {allowed_ip} while setting up interface for \ - location {location}, error details: {err}" - ); - } - } - } - debug!( - "Parsed allowed IPs for location {location}: {:?}", - peer.allowed_ips - ); - // request interface configuration - debug!("Looking for a free port for interface {interface_name}..."); - let Some(port) = find_free_tcp_port() else { - let msg = format!( - "Couldn't find free port during interface {interface_name} setup for location \ - {location}" - ); - error!("{msg}"); - return Err(Error::InternalError(msg)); - }; - debug!("Found free port: {port} for interface {interface_name}."); - let addresses = location - .address - .split(',') - .map(str::trim) - .map(IpAddrMask::from_str) - .collect::>() - .map_err(|err| { - let msg = format!("Failed to parse IP addresses '{}': {err}", location.address); - error!("{msg}"); - Error::InternalError(msg) - })?; - let interface_config = InterfaceConfiguration { - name: interface_name, - prvkey: keys.prvkey, - addresses, - port: port.into(), - peers: vec![peer.clone()], - mtu: None, - }; - debug!("Creating interface for location {location} with configuration {interface_config:?}"); - let request = CreateInterfaceRequest { - config: Some(interface_config.clone().into()), - allowed_ips, - dns: location.dns.clone(), - }; - if let Err(error) = DAEMON_CLIENT.clone().create_interface(request).await { - if error.code() == Code::Unavailable { - error!( - "Failed to set up connection for location {location}; background service is \ - unavailable. Make sure the service is running. Error: {error}, Interface \ - configuration: {interface_config:?}" - ); - Err(Error::InternalError( - "Background service is unavailable. Make sure the service is running.".into(), - )) - } else { - error!( - "Failed to send a request to the background service to create an interface for \ - location {location} with the following configuration: {interface_config:?}. \ - Error: {error}" - ); - Err(Error::InternalError(format!( - "Failed to send a request to the background service to create an interface for \ - location {location}. Error: {error}. Check logs for details." - ))) - } - } else { - info!( - "The interface for location {location} has been created successfully, interface \ - name: {}.", - interface_config.name - ); - Ok(()) + // debug!("Looking for a free port for interface {interface_name}."); + // let Some(port) = find_free_tcp_port() else { + // let msg = format!( + // "Couldn't find free port during interface {interface_name} setup for location \ + // {location}" + // ); + // error!("{msg}"); + // return Err(Error::InternalError(msg)); + // }; + // debug!("Found free port: {port} for interface {interface_name}."); + + let (dns, dns_search) = location.dns(); + let tunnel_config = location + .tunnel_configurarion(pool, interface_name, preshared_key, dns, dns_search) + .await?; + // tunnel_config.port = port; + + swift!(fn start_tunnel(prvkey: &SRString)); + unsafe { + let prvkey: SRString = serde_json::to_string(&tunnel_config) + .unwrap() + .as_str() + .into(); + start_tunnel(&prvkey); } + Ok(()) + + // debug!("Creating interface for location {location} with configuration {interface_config:?}"); + // let request = CreateInterfaceRequest { + // config: Some(interface_config.clone().into()), + // dns: location.dns.clone(), + // }; + // if let Err(error) = DAEMON_CLIENT.clone().create_interface(request).await { + // if error.code() == Code::Unavailable { + // error!( + // "Failed to set up connection for location {location}; background service is \ + // unavailable. Make sure the service is running. Error: {error}, Interface \ + // configuration: {interface_config:?}" + // ); + // Err(Error::InternalError( + // "Background service is unavailable. Make sure the service is running.".into(), + // )) + // } else { + // error!( + // "Failed to send a request to the background service to create an interface for \ + // location {location} with the following configuration: {interface_config:?}. \ + // Error: {error}" + // ); + // Err(Error::InternalError(format!( + // "Failed to send a request to the background service to create an interface for \ + // location {location}. Error: {error}. Check logs for details." + // ))) + // } + // } else { + // info!( + // "The interface for location {location} has been created successfully, interface \ + // name: {}.", + // interface_config.name + // ); + // Ok(()) + // } } pub(crate) async fn stats_handler( @@ -380,10 +306,7 @@ pub async fn setup_interface_tunnel( tunnel.allowed_ips ); let allowed_ips = if tunnel.route_all_traffic { - debug!( - "Using all traffic routing for tunnel {tunnel}: {DEFAULT_ROUTE_IPV4} \ - {DEFAULT_ROUTE_IPV6}" - ); + debug!("Using all traffic routing for tunnel {tunnel}"); vec![DEFAULT_ROUTE_IPV4.into(), DEFAULT_ROUTE_IPV6.into()] } else { let msg = match &tunnel.allowed_ips { @@ -412,7 +335,7 @@ pub async fn setup_interface_tunnel( debug!("Parsed tunnel {tunnel} allowed IPs: {:?}", peer.allowed_ips); // request interface configuration - debug!("Looking for a free port for interface {interface_name}..."); + debug!("Looking for a free port for interface {interface_name}."); let Some(port) = find_free_tcp_port() else { let msg = format!( "Couldn't find free port for interface {interface_name} while setting up tunnel {tunnel}" @@ -444,7 +367,6 @@ pub async fn setup_interface_tunnel( debug!("Creating interface {interface_config:?}"); let request = CreateInterfaceRequest { config: Some(interface_config.clone().into()), - allowed_ips, dns: tunnel.dns.clone(), }; if let Some(pre_up) = &tunnel.pre_up { diff --git a/swift/Package.swift b/swift/Package.swift index 6c6fb59c..224cdfc2 100644 --- a/swift/Package.swift +++ b/swift/Package.swift @@ -16,17 +16,18 @@ let package = Package( type: .static, targets: ["defguard-vpn-extension"]) ], - // dependencies: [ - // .package(name: "Tauri", path: "../.tauri/tauri-api") - // ], + dependencies: [ + .package(url: "https://github.com/Brendonovich/swift-rs", from: "1.0.7") + ], targets: [ - // Targets are the basic building blocks of a package. A target can define a module or a test suite. - // Targets can depend on other targets in this package, and on products in packages this package depends on. .target( name: "defguard-vpn-extension", - // dependencies: [ - // .byName(name: "Tauri") - // ], + dependencies: [ + .product( + name: "SwiftRs", + package: "swift-rs" + ) + ], path: "Sources") ] ) diff --git a/swift/Sources/Endpoint.swift b/swift/Sources/Endpoint.swift new file mode 100644 index 00000000..bb218061 --- /dev/null +++ b/swift/Sources/Endpoint.swift @@ -0,0 +1,82 @@ +import Network + +struct Endpoint: Codable, CustomStringConvertible { + let host: NWEndpoint.Host + let port: NWEndpoint.Port + + init(host: NWEndpoint.Host, port: NWEndpoint.Port) { + self.host = host + self.port = port + } + + /// Custom initializer from String. Assume format "host:port". + init?(from string: String) { + let trimmedEndpoint = string.trimmingCharacters(in: .whitespaces) + var endpointHost = trimmedEndpoint + + // Extract host, supporting IPv4, IPv6, and domains + if trimmedEndpoint.hasPrefix("[") { // IPv6 with port, e.g. [fd00::1]:51820 + if let closing = trimmedEndpoint.firstIndex(of: "]") { + endpointHost = String( + trimmedEndpoint[ + trimmedEndpoint.index(after: trimmedEndpoint.startIndex).. 1 { + endpointHost = parts.dropLast().joined(separator: ":") + } + } + + let endpointPort: Network.NWEndpoint.Port + if let portPart = trimmedEndpoint.split(separator: ":").last, let port = Int(portPart), + let nwPort = NWEndpoint.Port(rawValue: UInt16(port)) + { + endpointPort = nwPort + } else { + return nil + } + + self.host = NWEndpoint.Host(endpointHost) + self.port = endpointPort + } + + /// A textual representation of this instance. Required for `CustomStringConvertible`. + var description: String { + "Endpoint(\(host):\(port))" + } + + var hostString: String { + "\(host)" + } + + func toString() -> String { + "\(host):\(port)" + } + + // Encode to a single string "host:port", to smoothly encode into JSON. + func encode(to encoder: Encoder) throws { + var container = encoder.singleValueContainer() + try container.encode(self.toString()) + } + + // Decode from a single string "host:port", to smoothly decode from JSON. + init(from decoder: Decoder) throws { + let container = try decoder.singleValueContainer() + let value = try container.decode(String.self) + guard let endpoint = Endpoint(from: value) else { + throw + DecodingError + .dataCorrupted( + DecodingError.Context( + codingPath: decoder.codingPath, + debugDescription: "Not in host:port format") + ) + } + self = endpoint + } + + func asNWEndpoint() -> NWEndpoint { + NWEndpoint.hostPort(host: host, port: port) + } +} diff --git a/swift/Sources/IpAddrMask.swift b/swift/Sources/IpAddrMask.swift new file mode 100644 index 00000000..afb347c9 --- /dev/null +++ b/swift/Sources/IpAddrMask.swift @@ -0,0 +1,109 @@ +import Foundation +import Network + +struct IpAddrMask: Codable, Equatable { + let address: IPAddress + let cidr: UInt8 + + init(address: IPAddress, cidr: UInt8) { + self.address = address + self.cidr = cidr + } + + init?(fromString string: String) { + let parts = string.split( + separator: "/", + maxSplits: 1, + ) + if let ipv4 = IPv4Address(String(parts[0])) { + address = ipv4 + } else if let ipv6 = IPv6Address(String(parts[0])) { + address = ipv6 + } else { + return nil + } + if parts.count > 1 { + cidr = UInt8(parts[1]) ?? 0 + } else { + cidr = 0 + } + } + + var stringRepresentation: String { + return "\(address)/\(cidr)" + } + + enum CodingKeys: String, CodingKey { + case address + case cidr + } + + /// Conform to `Encodable`. + func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encode("\(address)", forKey: .address) + try container.encode(cidr, forKey: .cidr) + } + + /// Conform to `Decodable`. + init(from decoder: Decoder) throws { + let values = try decoder.container(keyedBy: CodingKeys.self) + + let address_string = try values.decode(String.self, forKey: .address) + if let ipv4 = IPv4Address(address_string) { + address = ipv4 + } else if let ipv6 = IPv6Address(address_string) { + address = ipv6 + } else { + throw + DecodingError + .dataCorrupted( + DecodingError.Context( + codingPath: decoder.codingPath, + debugDescription: "Unable to decode IP address" + )) + } + + cidr = try values.decode(UInt8.self, forKey: .cidr) + } + + /// Conform to `Equatable`. + static func == (lhs: Self, rhs: Self) -> Bool { + return lhs.address.rawValue == rhs.address.rawValue && lhs.cidr == rhs.cidr + } + + func mask() -> IPAddress { + if address is IPv4Address { + var bytes = Data(count: 4) + let mask = cidr == 0 ? UInt32(0) : ~UInt32(0) << (32 - cidr) + for i in 0...3 { + bytes[i] = UInt8(truncatingIfNeeded: mask >> (24 - i * 8)) + } + return IPv4Address(bytes)! + } + // Note: UInt128 is available since iOS 18. Use UInt64 implementation. + if address is IPv6Address { + var bytes = Data(count: 16) + let (mask_upper, mask_lower) = + if cidr < 64 { + ( + cidr == 0 ? UInt64.min : UInt64.max << (64 - cidr), + UInt64.min + ) + } else { + ( + UInt64.max, + (cidr - 64) == 0 ? UInt64.min : UInt64.max << (128 - cidr) + ) + } + for i in 0...7 { + bytes[i] = UInt8(truncatingIfNeeded: mask_upper >> (56 - i * 8)) + } + for i in 8...15 { + bytes[i] = UInt8(truncatingIfNeeded: mask_lower >> (56 - (i - 8) * 8)) + } + return IPv6Address(bytes)! + } + fatalError() + } +} diff --git a/swift/Sources/Peer.swift b/swift/Sources/Peer.swift new file mode 100644 index 00000000..f405c31c --- /dev/null +++ b/swift/Sources/Peer.swift @@ -0,0 +1,43 @@ +import Foundation + +final class Peer: Codable { + var publicKey: String + var preSharedKey: String? + var endpoint: Endpoint? + var lastHandshake: Date? + var txBytes: UInt64 = 0 + var rxBytes: UInt64 = 0 + var persistentKeepAlive: UInt16? + var allowedIPs = [IpAddrMask]() + + init( + publicKey: String, preSharedKey: String? = nil, endpoint: Endpoint? = nil, + lastHandshake: Date? = nil, txBytes: UInt64 = 0, rxBytes: UInt64 = 0, + persistentKeepAlive: UInt16? = nil, allowedIPs: [IpAddrMask] = [IpAddrMask]() + ) { + self.publicKey = publicKey + self.preSharedKey = preSharedKey + self.endpoint = endpoint + self.lastHandshake = lastHandshake + self.txBytes = txBytes + self.rxBytes = rxBytes + self.persistentKeepAlive = persistentKeepAlive + self.allowedIPs = allowedIPs + } + + init(publicKey: String) { + self.publicKey = publicKey + } + + // Use snake_case to match Rust. + enum CodingKeys: String, CodingKey { + case publicKey = "public_key" + case preSharedKey = "preshared_key" + case endpoint + case lastHandshake = "last_handshake" + case txBytes = "tx_bytes" + case rxBytes = "rx_bytes" + case persistentKeepAlive = "persistent_keepalive_interval" + case allowedIPs = "allowed_ips" + } +} diff --git a/swift/Sources/Shared.swift b/swift/Sources/Shared.swift index 43fb683c..35eaaacc 100644 --- a/swift/Sources/Shared.swift +++ b/swift/Sources/Shared.swift @@ -26,9 +26,11 @@ public struct TunnelStartData: Codable { public var locationId: Int public var instanceId: Int - public init(publicKey: String, privateKey: String, address: String, dns: String? = nil, - endpoint: String, allowedIps: String, keepalive: Int, presharedKey: String? = nil, - traffic: TunnelTraffic, locationName: String, locationId: Int, instanceId: Int) { + public init( + publicKey: String, privateKey: String, address: String, dns: String? = nil, + endpoint: String, allowedIps: String, keepalive: Int, presharedKey: String? = nil, + traffic: TunnelTraffic, locationName: String, locationId: Int, instanceId: Int + ) { self.publicKey = publicKey self.privateKey = privateKey self.address = address @@ -48,7 +50,7 @@ public struct ActiveTunnelData: Codable { var locationId: Int var instanceId: Int var traffic: TunnelTraffic - + init(fromConfig: TunnelStartData) { self.locationId = fromConfig.locationId self.instanceId = fromConfig.instanceId diff --git a/swift/Sources/TunnelConfiguration.swift b/swift/Sources/TunnelConfiguration.swift new file mode 100644 index 00000000..01a002b1 --- /dev/null +++ b/swift/Sources/TunnelConfiguration.swift @@ -0,0 +1,18 @@ +import Foundation +import NetworkExtension + +final class TunnelConfiguration: Codable { + var name: String + var privateKey: String + var addresses: [IpAddrMask] = [] + var listenPort: UInt16? + var peers: [Peer] = [] + var mtu: UInt32? + var dns: [String] = [] + var dnsSearch: [String] = [] + + init(name: String, privateKey: String) { + self.name = name + self.privateKey = privateKey + } +} diff --git a/swift/Sources/Wireguard.swift b/swift/Sources/Wireguard.swift index 1413057d..8f7096be 100644 --- a/swift/Sources/Wireguard.swift +++ b/swift/Sources/Wireguard.swift @@ -1,18 +1,77 @@ import NetworkExtension +import SwiftRs import os -let appId = Bundle.main.bundleIdentifier ?? "net.defguard.desktop" +let appId = Bundle.main.bundleIdentifier ?? "net.defguard" let vpnManager = VPNManager.shared let logger = Logger(subsystem: appId, category: "WireguardPlugin") @_cdecl("start_tunnel") -public func startTunnel() { - logger.log("Starting tunnel") +public func startTunnel(json: SRString) { + let decoder = JSONDecoder() + guard let json_data = json.toString().data(using: .utf8) else { + logger.error("Failed to convert JSON string to data") + return + } + let config: TunnelConfiguration + do { config = try decoder.decode(TunnelConfiguration.self, from: json_data) } catch { + logger.error( + "Failed to decode tunnel configuration: \(error.localizedDescription, privacy: .public)" + ) + return + } + + logger.log("Starting tunnel with config: \(String(describing: config))") + vpnManager.loadProviderManager { manager in let providerManager = manager ?? NETunnelProviderManager() let tunnelProtocol = NETunnelProviderProtocol() tunnelProtocol.providerBundleIdentifier = "\(appId).VPNExtension" + tunnelProtocol.serverAddress = + config.peers[0].endpoint != nil ? config.peers[0].endpoint!.toString() : "" + // let configDict: [String: Any] + // do { + // configDict = try config.toDictionary() + // } catch { + // logger.log( + // "Failed to convert config to dictionary: \(error.localizedDescription, privacy: .public)" + // ) + // return + // } + // tunnelProtocol.providerConfiguration = configDict providerManager.protocolConfiguration = tunnelProtocol + providerManager.localizedDescription = config.name providerManager.isEnabled = true + + // if let status = vpnManager.connectionStatus { + // if status == .connected || status == .connecting { + // do { + // try vpnManager.stopTunnel() + // } catch { + // logger.log("Failed to stop VPN tunnel: \(error, privacy: .public)") + // return + // } + // logger.log("Stopped running VPN tunnel to update config") + // self.waitForTunnelStatus( + // desiredStatuses: [.disconnected, .invalid] + // ) { status in + // if let status = status { + // self.logger.log("Timeout waiting for tunnel to disconnect") + // return + // } + // self.saveAndStartTunnel( + // providerManager: providerManager, + // config: config, + // result: result + // ) + // return + // } + // } + // } + // self.saveAndStartTunnel( + // providerManager: providerManager, + // config: config, + // result: result + // ) } } From 722a8a8990a43055756392b9201f47ee423c0977 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adam=20Ciarcin=CC=81ski?= Date: Wed, 8 Oct 2025 11:42:12 +0200 Subject: [PATCH 03/28] Adopted plugin --- src-tauri/Cargo.lock | 4 +- src-tauri/tauri.macos.conf.json | 3 - swift/Sources/Decodabe+Encodable.swift | 22 ++ swift/Sources/Wireguard.swift | 56 +-- swift/Sources/WireguardPlugin.swift | 461 +++++++++++++++++++++++++ 5 files changed, 489 insertions(+), 57 deletions(-) create mode 100644 swift/Sources/Decodabe+Encodable.swift create mode 100644 swift/Sources/WireguardPlugin.swift diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index 94af07e3..0c97a857 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -8091,9 +8091,9 @@ dependencies = [ [[package]] name = "webpki-roots" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e8983c3ab33d6fb807cfcdad2491c4ea8cbc8ed839181c7dfd9c67c83e261b2" +checksum = "32b130c0d2d49f8b6889abc456e795e82525204f27c42cf767cf0d7734e089b8" dependencies = [ "rustls-pki-types", ] diff --git a/src-tauri/tauri.macos.conf.json b/src-tauri/tauri.macos.conf.json index bb2a7dfc..a724a03d 100644 --- a/src-tauri/tauri.macos.conf.json +++ b/src-tauri/tauri.macos.conf.json @@ -1,8 +1,5 @@ { "bundle": { - "externalBin": [ - "resources-macos/binaries/*" - ], "resources": [ "resources-macos/resources/*", "resources/icons/*" diff --git a/swift/Sources/Decodabe+Encodable.swift b/swift/Sources/Decodabe+Encodable.swift new file mode 100644 index 00000000..d3f8a8f0 --- /dev/null +++ b/swift/Sources/Decodabe+Encodable.swift @@ -0,0 +1,22 @@ +import Foundation + +extension Decodable { + static func from(dictionary: [String: Any]) throws -> Self { + let data = try JSONSerialization.data(withJSONObject: dictionary) + let decoder = JSONDecoder() + return try decoder.decode(Self.self, from: data) + } +} + +extension Encodable { + func toDictionary() throws -> [String: Any] { + let data = try JSONEncoder().encode(self) + let jsonObject = try JSONSerialization.jsonObject(with: data, options: .allowFragments) + guard let dictionary = jsonObject as? [String: Any] else { + throw NSError( + domain: "EncodingError", code: 0, + userInfo: [NSLocalizedDescriptionKey: "Failed to convert to dictionary"]) + } + return dictionary + } +} diff --git a/swift/Sources/Wireguard.swift b/swift/Sources/Wireguard.swift index 8f7096be..e9f242df 100644 --- a/swift/Sources/Wireguard.swift +++ b/swift/Sources/Wireguard.swift @@ -3,7 +3,8 @@ import SwiftRs import os let appId = Bundle.main.bundleIdentifier ?? "net.defguard" -let vpnManager = VPNManager.shared +// let vpnManager = VPNManager.shared +let plugin = WireguardPlugin() let logger = Logger(subsystem: appId, category: "WireguardPlugin") @_cdecl("start_tunnel") @@ -22,56 +23,7 @@ public func startTunnel(json: SRString) { } logger.log("Starting tunnel with config: \(String(describing: config))") - - vpnManager.loadProviderManager { manager in - let providerManager = manager ?? NETunnelProviderManager() - let tunnelProtocol = NETunnelProviderProtocol() - tunnelProtocol.providerBundleIdentifier = "\(appId).VPNExtension" - tunnelProtocol.serverAddress = - config.peers[0].endpoint != nil ? config.peers[0].endpoint!.toString() : "" - // let configDict: [String: Any] - // do { - // configDict = try config.toDictionary() - // } catch { - // logger.log( - // "Failed to convert config to dictionary: \(error.localizedDescription, privacy: .public)" - // ) - // return - // } - // tunnelProtocol.providerConfiguration = configDict - providerManager.protocolConfiguration = tunnelProtocol - providerManager.localizedDescription = config.name - providerManager.isEnabled = true - - // if let status = vpnManager.connectionStatus { - // if status == .connected || status == .connecting { - // do { - // try vpnManager.stopTunnel() - // } catch { - // logger.log("Failed to stop VPN tunnel: \(error, privacy: .public)") - // return - // } - // logger.log("Stopped running VPN tunnel to update config") - // self.waitForTunnelStatus( - // desiredStatuses: [.disconnected, .invalid] - // ) { status in - // if let status = status { - // self.logger.log("Timeout waiting for tunnel to disconnect") - // return - // } - // self.saveAndStartTunnel( - // providerManager: providerManager, - // config: config, - // result: result - // ) - // return - // } - // } - // } - // self.saveAndStartTunnel( - // providerManager: providerManager, - // config: config, - // result: result - // ) + try? plugin.startTunnel(config: config) { result in + // nothing here for the time being } } diff --git a/swift/Sources/WireguardPlugin.swift b/swift/Sources/WireguardPlugin.swift new file mode 100644 index 00000000..10ab28e5 --- /dev/null +++ b/swift/Sources/WireguardPlugin.swift @@ -0,0 +1,461 @@ +import NetworkExtension +import os + +// The timeout for waiting for the tunnel status to change (e.g. when connecting or disconnecting). +let tunnelStatusTimeout: TimeInterval = 10.0 + +public class WireguardPlugin: NSObject { + private var activeTunnelData: ActiveTunnelData? + private var connectionObserver: NSObjectProtocol? + private var configurationObserver: NSObjectProtocol? + private var vpnManager: VPNManagement + private var logger = Logger( + subsystem: Bundle.main.bundleIdentifier ?? "net.defguard.WireguardPlugin", + category: "WireguardPlugin") + + public init(vpnManager: VPNManagement? = nil) { + if let vpnManager = vpnManager { + self.logger.debug("Using provided VPN manager") + self.vpnManager = vpnManager + } else { + self.logger.debug("Creating new VPN manager instance") + self.vpnManager = VPNManager.shared + } + super.init() + } + + /// Loads the active tunnel data from the system configuration. + private func getActiveTunnelData(completion: @escaping (ActiveTunnelData?) -> Void) { + guard let providerManager = vpnManager.providerManager else { + logger.log("No VPN manager found") + return + } + + if let config = providerManager.protocolConfiguration + as? NETunnelProviderProtocol, + let configDict = config.providerConfiguration, + let activeTunnelData = try? ActiveTunnelData.from( + dictionary: configDict + ) + { + completion(activeTunnelData) + } else { + logger.log("No active tunnel data available") + completion(nil) + } + } + + /// Loads the possibly already existing VPN manager and sets up observers for VPN connection status changes if its present. + /// This is to ensure that the VPN status is observed and updated correctly when the app starts. + private func setupVPNManager( + completion: @escaping () -> Void + ) { + vpnManager.loadProviderManager { manager in + if manager == nil { + self.logger.log( + "No provider manager found, the VPN status won't be observed until the VPN is started." + ) + } else { + self.logger.log( + "VPN manager loaded successfully, the VPN status will be observed and updated.") + } + completion() + } + } + + /// Sets up observers for VPN connection status changes. + private func setupVPNObservers() { + if connectionObserver != nil { + logger.log("VPN observers already set up, removing it first") + removeVPNObservers() + } + guard let providerManager = vpnManager.providerManager else { + logger.log("No provider manager found, cannot set up VPN observers") + return + } + connectionObserver = NotificationCenter.default.addObserver( + forName: .NEVPNStatusDidChange, + object: providerManager.connection, + queue: .main, + using: { notification in + self.handleVPNStatusChange() + } + ) + configurationObserver = NotificationCenter.default.addObserver( + forName: .NEVPNConfigurationChange, + object: nil, + queue: .main, + using: { notification in + self.vpnManager.handleVPNConfigurationChange() + self.handleVPNStatusChange() + } + ) + } + + private func removeVPNObservers() { + if let observer = connectionObserver { + NotificationCenter.default.removeObserver(observer) + connectionObserver = nil + } + if let observer = configurationObserver { + NotificationCenter.default.removeObserver(observer) + configurationObserver = nil + } + } + + deinit { + removeVPNObservers() + } + + /// Updates the UI status of the VPN connection. Used when the status changes asynchronously. + private func handleVPNStatusChange() { + guard let vpnStatus = vpnManager.connectionStatus else { + logger.log("Failed to get VPN status, the provider manager has not been loaded yet.") + return + } + + switch vpnStatus { + case .connected: + logger.log("Detected that the VPN has connected, emitting event.") + let encoder = JSONEncoder() + encoder.keyEncodingStrategy = .convertToSnakeCase + if let activeTunnelData = activeTunnelData { + guard let data = try? encoder.encode(activeTunnelData), + let dataString = String(data: data, encoding: .utf8) + else { + logger.log("Failed to encode active tunnel data") + return + } + self.activeTunnelData = activeTunnelData + // self.emitEvent( + // event: WireguardEvent.tunnelUp, + // data: dataString + // ) + } else { + getActiveTunnelData { activeTunnelData in + guard let activeTunnelData = activeTunnelData else { + self.logger.log("No active tunnel data available") + // self.emitEvent( + // event: WireguardEvent.tunnelDown, + // data: nil + // ) + return + } + guard let data = try? encoder.encode(activeTunnelData), + let dataString = String(data: data, encoding: .utf8) + else { + self.logger.log("Failed to encode active tunnel data") + return + } + self.activeTunnelData = activeTunnelData + // self.emitEvent( + // event: WireguardEvent.tunnelUp, + // data: dataString + // ) + } + } + setupVPNObservers() + case .disconnected, .invalid: + logger.log( + "Detected that the system VPN status is disconnected. Emitting event if our state differs" + ) + // no point in emitting this event if we already agree that the tunnel is down + if activeTunnelData != nil { + if let lastError = getLastTunnelError() { + logger.log( + "Detected that the tunnel stopped due to the following error: \(lastError.rawValue, privacy: .public)" + ) + if lastError == .mfaSessionExpired { + logger.log( + "Detected that the tunnel stopped due to MFA session expiration, emitting event." + ) + // emitEvent(event: WireguardEvent.MFASessionExpired, data: nil) + } else { + logger.warning( + "Detected that the tunnel stopped due to an unknown error: \(lastError.rawValue, privacy: .public)" + ) + // emitEvent(event: WireguardEvent.tunnelDown, data: nil) + } + resetLastTunnelError() + } else { + // emitEvent(event: WireguardEvent.tunnelDown, data: nil) + } + + activeTunnelData = nil + + logger.log( + "Our state differed, emitted event to inform the frontend about stopped tunnel." + ) + } else { + logger.log("Our state did not differ, no event emitted.") + } + case .connecting: + logger.log( + "Detected that VPN is connecting, ignoring it since it is a temporary state we don't handle." + ) + case .disconnecting: + logger.log( + "Detected that VPN is disconnecting, ignoring it since it is a temporary state we don't handle." + ) + case .reasserting: + logger.log( + "Detected that VPN is reasserting, ignoring it since it is a temporary state we don't handle." + ) + @unknown default: + logger.log( + "Detected unknown VPN status: \(vpnStatus.rawValue, privacy: .public), ignoring it since it is a state we don't handle." + ) + } + } + + private func getLastTunnelError() -> TunnelStopError? { + let defaults = UserDefaults(suiteName: suiteName) + guard let lastError = defaults?.string(forKey: "lastTunnelError") else { + logger.log("No last tunnel error found in user defaults") + return nil + } + logger.log("Last tunnel error found: \(lastError, privacy: .public)") + if let error = TunnelStopError(rawValue: lastError) { + return error + } else { + logger.error( + "Last tunnel error is not a valid TunnelStopError: \(lastError, privacy: .public)") + return nil + } + } + + private func resetLastTunnelError() { + let defaults = UserDefaults(suiteName: suiteName) + defaults?.removeObject(forKey: "lastTunnelError") + } + + func startTunnel( + config: TunnelConfiguration, + result: @escaping (VPNError?) -> Void + ) { + logger.log("Starting tunnel with config: \(String(describing: config))") + + vpnManager.loadProviderManager { manager in + let appId = Bundle.main.bundleIdentifier ?? "net.defguard.mobile" + let providerManager = manager ?? NETunnelProviderManager() + let tunnelProtocol = NETunnelProviderProtocol() + tunnelProtocol.providerBundleIdentifier = "\(appId).VPNExtension" + tunnelProtocol.serverAddress = "" // config.endpoint + let configDict: [String: Any] + do { + configDict = try config.toDictionary() + } catch { + self.logger.log( + "Failed to convert config to dictionary: \(error.localizedDescription, privacy: .public)" + ) + result( + VPNError.configurationError(error) + ) + return + } + tunnelProtocol.providerConfiguration = configDict + providerManager.protocolConfiguration = tunnelProtocol + // providerManager.localizedDescription = config.locationName + providerManager.isEnabled = true + + if let status = self.vpnManager.connectionStatus { + if status == .connected || status == .connecting { + do { + try self.vpnManager.stopTunnel() + } catch { + self.logger.log("Failed to stop VPN tunnel: \(error, privacy: .public)") + result( + VPNError.stopError( + error + ) + ) + return + } + self.logger.log("Stopped running VPN tunnel to update config") + self.waitForTunnelStatus( + desiredStatuses: [.disconnected, .invalid] + ) { status in + if let status = status { + self.logger.log("Timeout waiting for tunnel to disconnect") + result( + VPNError.timeoutError( + "The tunnel disconnection has failed to complete in a specified amount of time (\(tunnelStatusTimeout) seconds). Please check your configuration and try again. Current status: \(status.rawValue)" + ) + ) + return + } + self.saveAndStartTunnel( + providerManager: providerManager, + config: config, + result: result + ) + return + } + } + } + self.saveAndStartTunnel( + providerManager: providerManager, + config: config, + result: result + ) + } + } + + /// Waits for the VPN connection to reach one of the desired statuses. + /// If it does not reach the desired status within the timeout, + /// it returns the current status. + private func waitForTunnelStatus( + desiredStatuses: [NEVPNStatus], + completion: @escaping (NEVPNStatus?) -> Void + ) { + let checkInterval = 0.2 + var elapsedTime = 0.0 + logger.log( + "Waiting for VPN status to change to one of: \(desiredStatuses.map { $0.rawValue })" + ) + func check() { + guard let status = vpnManager.connectionStatus else { + self.logger.log("No VPN connection status available") + completion(nil) + return + } + self.logger.log("Checking VPN status: \(status.rawValue, privacy: .public)") + if desiredStatuses.contains(status) { + self.logger.log( + "Desired VPN status reached: \(status.rawValue, privacy: .public)" + ) + completion(nil) + } else { + elapsedTime += checkInterval + if elapsedTime >= tunnelStatusTimeout { + completion(status) + } else { + DispatchQueue.main.asyncAfter( + deadline: .now() + checkInterval + ) { + check() + } + } + } + } + check() + } + + private func saveAndStartTunnel( + providerManager: NETunnelProviderManager, + config: TunnelConfiguration, + result: @escaping (VPNError?) -> Void + ) { + self.vpnManager.saveProviderManager(providerManager) { saveError in + if let saveError = saveError { + self.logger.log("Failed to save preferences: \(saveError, privacy: .public)") + result( + VPNError.saveError( + saveError + ) + ) + return + } + self.startVPNTunnel( + config: config, + result: result + ) + } + } + + private func closeTunnel(result: @escaping (VPNError?) -> Void) { + logger.log("Stopping tunnel") + + guard let status = vpnManager.connectionStatus else { + logger.log("No VPN connection status available") + result( + VPNError.noManager( + "No VPN connection status available. The tunnel may not be running." + ) + ) + // emitEvent(event: WireguardEvent.tunnelDown, data: nil) + return + } + + if status == .connected || status == .connecting { + removeVPNObservers() + do { + try vpnManager.stopTunnel() + } catch { + logger.log("Failed to stop VPN tunnel: \(error, privacy: .public)") + result( + VPNError.stopError(error) + ) + return + } + + waitForTunnelStatus(desiredStatuses: [.disconnected, .invalid]) { status in + if let status = status { + self.logger.log( + "Timeout waiting for tunnel to disconnect: \(status.rawValue, privacy: .public)" + ) + result( + VPNError.timeoutError( + "The tunnel disconnection has failed to complete in a specified amount of time (\(tunnelStatusTimeout) seconds). Please check your configuration and try again." + ) + ) + return + } + self.handleVPNStatusChange() + self.logger.log("VPN tunnel stopped") + result(nil) + } + } else { + logger.log("VPN tunnel is not running") + // Emit event just to update the UI if its broken + // emitEvent(event: WireguardEvent.tunnelDown, data: nil) + result(nil) + } + } + + // private func emitEvent(event: WireguardEvent, data: String?) { + // logger.log( + // "Emitting event: \(event.rawValue, privacy: .public), data: \(String(describing: data), privacy: .public)" + // ) + // guard let eventSink = eventSink else { + // logger.log("No event sink available, cannot emit event") + // return + // } + // let event: [String: Any?] = [ + // "event": event.rawValue, + // "data": data, + // ] + // eventSink(event) + // } + + private func startVPNTunnel( + config: TunnelConfiguration, + result: @escaping (VPNError?) -> Void + ) { + do { + try vpnManager.startTunnel() + // This is done because the frontend expects a blocking action to display a loading indicator. + waitForTunnelStatus(desiredStatuses: [.connected]) { status in + if status != nil { + self.logger.log("Timeout waiting for tunnel to connect.") + result( + VPNError.timeoutError( + "The tunnel connection has failed to be established in a specified amount of time. Please check your configuration and try again." + ) + ) + return + } + self.handleVPNStatusChange() + self.logger.log("VPN tunnel started successfully") + result(nil) + } + } catch { + logger.error("Failed to start VPN: \(error, privacy: .public)") + result( + VPNError.startError( + error, + ) + ) + } + } +} From 53fb561d497675b9066da80fc7faf89b71c7df3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adam=20Ciarcin=CC=81ski?= Date: Wed, 15 Oct 2025 10:40:46 +0200 Subject: [PATCH 04/28] More or less working plugin prototype --- package.json | 8 +- pnpm-lock.yaml | 174 ++++++------ src-tauri/Cargo.lock | 251 +++++++----------- src-tauri/Client.entitlements | 12 + src-tauri/build.rs | 3 +- swift/.gitignore | 2 +- swift/Sources/TunnelConfiguration.swift | 18 -- .../contents.xcworkspacedata | 7 + swift/{ => plugin}/Package.swift | 8 +- .../Sources/Decodabe+Encodable.swift | 0 swift/{ => plugin}/Sources/Endpoint.swift | 0 swift/{ => plugin}/Sources/IpAddrMask.swift | 0 swift/{ => plugin}/Sources/Peer.swift | 0 swift/{ => plugin}/Sources/Shared.swift | 0 .../plugin/Sources/TunnelConfiguration.swift | 112 ++++++++ swift/{ => plugin}/Sources/VPNError.swift | 0 swift/{ => plugin}/Sources/VPNManager.swift | 0 swift/{ => plugin}/Sources/Wireguard.swift | 8 +- .../Sources/WireguardPlugin.swift | 0 19 files changed, 327 insertions(+), 276 deletions(-) create mode 100644 src-tauri/Client.entitlements delete mode 100644 swift/Sources/TunnelConfiguration.swift create mode 100644 swift/plugin/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata rename swift/{ => plugin}/Package.swift (81%) rename swift/{ => plugin}/Sources/Decodabe+Encodable.swift (100%) rename swift/{ => plugin}/Sources/Endpoint.swift (100%) rename swift/{ => plugin}/Sources/IpAddrMask.swift (100%) rename swift/{ => plugin}/Sources/Peer.swift (100%) rename swift/{ => plugin}/Sources/Shared.swift (100%) create mode 100644 swift/plugin/Sources/TunnelConfiguration.swift rename swift/{ => plugin}/Sources/VPNError.swift (100%) rename swift/{ => plugin}/Sources/VPNManager.swift (100%) rename swift/{ => plugin}/Sources/Wireguard.swift (79%) rename swift/{ => plugin}/Sources/WireguardPlugin.swift (100%) diff --git a/package.json b/package.json index 68ec7964..c890a05d 100644 --- a/package.json +++ b/package.json @@ -91,7 +91,7 @@ "react-auth-code-input": "^3.2.1", "react-click-away-listener": "^2.4.0", "react-dom": "^19.2.0", - "react-hook-form": "^7.63.0", + "react-hook-form": "^7.64.0", "react-loading-skeleton": "^3.5.0", "react-markdown": "^10.1.0", "react-qr-code": "^2.0.18", @@ -114,9 +114,9 @@ "@tauri-apps/cli": "^2.8.4", "@types/file-saver": "^2.0.7", "@types/lodash-es": "^4.17.12", - "@types/node": "^24.6.2", - "@types/react": "^19.2.0", - "@types/react-dom": "^19.2.0", + "@types/node": "^24.7.0", + "@types/react": "^19.2.2", + "@types/react-dom": "^19.2.1", "@vitejs/plugin-react": "^5.0.4", "@vitejs/plugin-react-swc": "^4.1.0", "autoprefixer": "^10.4.21", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3afe7393..2e2265e9 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -13,7 +13,7 @@ importers: version: 0.27.16(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@hookform/resolvers': specifier: ^3.10.0 - version: 3.10.0(react-hook-form@7.63.0(react@19.2.0)) + version: 3.10.0(react-hook-form@7.64.0(react@19.2.0)) '@react-hook/resize-observer': specifier: ^2.0.2 version: 2.0.2(react@19.2.0) @@ -100,7 +100,7 @@ importers: version: 1.0.3 html-react-parser: specifier: ^5.2.6 - version: 5.2.6(@types/react@19.2.0)(react@19.2.0) + version: 5.2.6(@types/react@19.2.2)(react@19.2.0) itertools: specifier: ^2.5.0 version: 2.5.0 @@ -112,7 +112,7 @@ importers: version: 4.17.21 merge-refs: specifier: ^2.0.0 - version: 2.0.0(@types/react@19.2.0) + version: 2.0.0(@types/react@19.2.2) millify: specifier: ^6.1.0 version: 6.1.0 @@ -141,14 +141,14 @@ importers: specifier: ^19.2.0 version: 19.2.0(react@19.2.0) react-hook-form: - specifier: ^7.63.0 - version: 7.63.0(react@19.2.0) + specifier: ^7.64.0 + version: 7.64.0(react@19.2.0) react-loading-skeleton: specifier: ^3.5.0 version: 3.5.0(react@19.2.0) react-markdown: specifier: ^10.1.0 - version: 10.1.0(@types/react@19.2.0)(react@19.2.0) + version: 10.1.0(@types/react@19.2.2)(react@19.2.0) react-qr-code: specifier: ^2.0.18 version: 2.0.18(react@19.2.0) @@ -163,7 +163,7 @@ importers: version: 1.0.26(react-dom@19.2.0(react@19.2.0))(react@19.2.0) recharts: specifier: ^3.2.1 - version: 3.2.1(@types/react@19.2.0)(react-dom@19.2.0(react@19.2.0))(react-is@18.3.1)(react@19.2.0)(redux@5.0.1) + version: 3.2.1(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react-is@18.3.1)(react@19.2.0)(redux@5.0.1) rehype-sanitize: specifier: ^6.0.0 version: 6.0.0 @@ -178,14 +178,14 @@ importers: version: 3.25.76 zustand: specifier: ^5.0.8 - version: 5.0.8(@types/react@19.2.0)(immer@10.1.3)(react@19.2.0)(use-sync-external-store@1.6.0(react@19.2.0)) + version: 5.0.8(@types/react@19.2.2)(immer@10.1.3)(react@19.2.0)(use-sync-external-store@1.6.0(react@19.2.0)) devDependencies: '@biomejs/biome': specifier: ^2.2.5 version: 2.2.5 '@hookform/devtools': specifier: ^4.4.0 - version: 4.4.0(@types/react@19.2.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + version: 4.4.0(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@svgr/cli': specifier: ^8.1.0 version: 8.1.0(typescript@5.9.3) @@ -205,20 +205,20 @@ importers: specifier: ^4.17.12 version: 4.17.12 '@types/node': - specifier: ^24.6.2 - version: 24.6.2 + specifier: ^24.7.0 + version: 24.7.0 '@types/react': - specifier: ^19.2.0 - version: 19.2.0 + specifier: ^19.2.2 + version: 19.2.2 '@types/react-dom': - specifier: ^19.2.0 - version: 19.2.0(@types/react@19.2.0) + specifier: ^19.2.1 + version: 19.2.1(@types/react@19.2.2) '@vitejs/plugin-react': specifier: ^5.0.4 - version: 5.0.4(vite@7.1.9(@types/node@24.6.2)(sass@1.92.1)(yaml@2.8.1)) + version: 5.0.4(vite@7.1.9(@types/node@24.7.0)(sass@1.92.1)(yaml@2.8.1)) '@vitejs/plugin-react-swc': specifier: ^4.1.0 - version: 4.1.0(vite@7.1.9(@types/node@24.6.2)(sass@1.92.1)(yaml@2.8.1)) + version: 4.1.0(vite@7.1.9(@types/node@24.7.0)(sass@1.92.1)(yaml@2.8.1)) autoprefixer: specifier: ^10.4.21 version: 10.4.21(postcss@8.5.6) @@ -245,7 +245,7 @@ importers: version: 5.9.3 vite: specifier: ^7.1.9 - version: 7.1.9(@types/node@24.6.2)(sass@1.92.1)(yaml@2.8.1) + version: 7.1.9(@types/node@24.7.0)(sass@1.92.1)(yaml@2.8.1) packages: @@ -1286,19 +1286,19 @@ packages: '@types/ms@2.1.0': resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==} - '@types/node@24.6.2': - resolution: {integrity: sha512-d2L25Y4j+W3ZlNAeMKcy7yDsK425ibcAOO2t7aPTz6gNMH0z2GThtwENCDc0d/Pw9wgyRqE5Px1wkV7naz8ang==} + '@types/node@24.7.0': + resolution: {integrity: sha512-IbKooQVqUBrlzWTi79E8Fw78l8k1RNtlDDNWsFZs7XonuQSJ8oNYfEeclhprUldXISRMLzBpILuKgPlIxm+/Yw==} '@types/parse-json@4.0.2': resolution: {integrity: sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==} - '@types/react-dom@19.2.0': - resolution: {integrity: sha512-brtBs0MnE9SMx7px208g39lRmC5uHZs96caOJfTjFcYSLHNamvaSMfJNagChVNkup2SdtOxKX1FDBkRSJe1ZAg==} + '@types/react-dom@19.2.1': + resolution: {integrity: sha512-/EEvYBdT3BflCWvTMO7YkYBHVE9Ci6XdqZciZANQgKpaiDRGOLIlRo91jbTNRQjgPFWVaRxcYc0luVNFitz57A==} peerDependencies: '@types/react': ^19.2.0 - '@types/react@19.2.0': - resolution: {integrity: sha512-1LOH8xovvsKsCBq1wnT4ntDUdCJKmnEakhsuoUSy6ExlHCkGP2hqnatagYTgFk6oeL0VU31u7SNjunPN+GchtA==} + '@types/react@19.2.2': + resolution: {integrity: sha512-6mDvHUFSjyT2B2yeNx2nUgMxh9LtOWvkhIU3uePn2I2oyNymUAX1NIsdgviM4CH+JSrp2D2hsMvJOkxY+0wNRA==} '@types/unist@2.0.11': resolution: {integrity: sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==} @@ -1380,8 +1380,8 @@ packages: balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} - baseline-browser-mapping@2.8.10: - resolution: {integrity: sha512-uLfgBi+7IBNay8ECBO2mVMGZAc1VgZWEChxm4lv+TobGdG82LnXMjuNGo/BSSZZL4UmkWhxEHP2f5ziLNwGWMA==} + baseline-browser-mapping@2.8.14: + resolution: {integrity: sha512-GM9c0cWWR8Ga7//Ves/9KRgTS8nLausCkP3CGiFLrnwA2CDUluXgaQqvrULoR2Ujrd/mz/lkX87F5BHFsNr5sQ==} hasBin: true boolbase@1.0.0: @@ -1431,8 +1431,8 @@ packages: resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} engines: {node: '>=10'} - caniuse-lite@1.0.30001747: - resolution: {integrity: sha512-mzFa2DGIhuc5490Nd/G31xN1pnBnYMadtkyTjefPI7wzypqgCEpeWu9bJr0OnDsyKrW75zA9ZAt7pbQFmwLsQg==} + caniuse-lite@1.0.30001749: + resolution: {integrity: sha512-0rw2fJOmLfnzCRbkm8EyHL8SvI2Apu5UbnQuTsJ0ClgrH8hcwFooJ1s5R0EP8o8aVrFu8++ae29Kt9/gZAZp/Q==} ccount@2.0.1: resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} @@ -1676,8 +1676,8 @@ packages: resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} engines: {node: '>= 0.4'} - electron-to-chromium@1.5.230: - resolution: {integrity: sha512-A6A6Fd3+gMdaed9wX83CvHYJb4UuapPD5X5SLq72VZJzxHSY0/LUweGXRWmQlh2ln7KV7iw7jnwXK7dlPoOnHQ==} + electron-to-chromium@1.5.233: + resolution: {integrity: sha512-iUdTQSf7EFXsDdQsp8MwJz5SVk4APEFqXU/S47OtQ0YLqacSwPXdZ5vRlMX3neb07Cy2vgioNuRnWUXFwuslkg==} emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} @@ -1717,8 +1717,8 @@ packages: resolution: {integrity: sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==} engines: {node: '>= 0.4'} - es-toolkit@1.39.10: - resolution: {integrity: sha512-E0iGnTtbDhkeczB0T+mxmoVlT4YNweEKBLq7oaU4p11mecdsZpNWOglI4895Vh4usbQ+LsJiuLuI2L0Vdmfm2w==} + es-toolkit@1.40.0: + resolution: {integrity: sha512-8o6w0KFmU0CiIl0/Q/BCEOabF2IJaELM1T2PWj6e8KqzHv1gdx+7JtFnDwOx1kJH/isJ5NwlDG1nCr1HrRF94Q==} esbuild@0.25.10: resolution: {integrity: sha512-9RiGKvCwaqxO2owP61uQ4BgNborAQskMR6QusfWzQqv7AZOg5oGehdY2pRJMTKuwxd1IDBP4rSbI5lHzU7SMsQ==} @@ -2309,8 +2309,8 @@ packages: node-addon-api@7.1.1: resolution: {integrity: sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==} - node-releases@2.0.21: - resolution: {integrity: sha512-5b0pgg78U3hwXkCM8Z9b2FJdPZlr9Psr9V2gQPESdGHqbntyFJKFW4r5TeWGFzafGY3hzs1JC62VEQMbl1JFkw==} + node-releases@2.0.23: + resolution: {integrity: sha512-cCmFDMSm26S6tQSDpBCg/NR8NENrVPhAJSf+XbxBG4rPFaaonlEoE9wHQmun+cls499TQGSb7ZyPBRlzgKfpeg==} normalize-package-data@2.5.0: resolution: {integrity: sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==} @@ -2459,8 +2459,8 @@ packages: peerDependencies: react: ^19.2.0 - react-hook-form@7.63.0: - resolution: {integrity: sha512-ZwueDMvUeucovM2VjkCf7zIHcs1aAlDimZu2Hvel5C5907gUzMpm4xCrQXtRzCvsBqFjonB4m3x4LzCFI1ZKWA==} + react-hook-form@7.64.0: + resolution: {integrity: sha512-fnN+vvTiMLnRqKNTVhDysdrUay0kUUAymQnFIznmgDvapjveUWOOPqMNzPg+A+0yf9DuE2h6xzBjN1s+Qx8wcg==} engines: {node: '>=18.0.0'} peerDependencies: react: ^16.8.0 || ^17 || ^18 || ^19 @@ -2824,8 +2824,8 @@ packages: resolution: {integrity: sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==} engines: {node: '>= 0.4'} - undici-types@7.13.0: - resolution: {integrity: sha512-Ov2Rr9Sx+fRgagJ5AX0qvItZG/JKKoBRAVITs1zk7IqZGTJUwgUr7qoYBpWwakpWilTZFM98rG/AFRocu10iIQ==} + undici-types@7.14.0: + resolution: {integrity: sha512-QQiYxHuyZ9gQUIrmPo3IA+hUl4KYk8uSA7cHrcKd/l3p1OTpZcM0Tbp9x7FAtXdAYhlasd60ncPpgu6ihG6TOA==} unified@11.0.5: resolution: {integrity: sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==} @@ -3182,7 +3182,7 @@ snapshots: '@emotion/memoize@0.9.0': {} - '@emotion/react@11.14.0(@types/react@19.2.0)(react@19.2.0)': + '@emotion/react@11.14.0(@types/react@19.2.2)(react@19.2.0)': dependencies: '@babel/runtime': 7.28.4 '@emotion/babel-plugin': 11.13.5 @@ -3194,7 +3194,7 @@ snapshots: hoist-non-react-statics: 3.3.2 react: 19.2.0 optionalDependencies: - '@types/react': 19.2.0 + '@types/react': 19.2.2 transitivePeerDependencies: - supports-color @@ -3208,18 +3208,18 @@ snapshots: '@emotion/sheet@1.4.0': {} - '@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.0)(react@19.2.0))(@types/react@19.2.0)(react@19.2.0)': + '@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.2)(react@19.2.0))(@types/react@19.2.2)(react@19.2.0)': dependencies: '@babel/runtime': 7.28.4 '@emotion/babel-plugin': 11.13.5 '@emotion/is-prop-valid': 1.4.0 - '@emotion/react': 11.14.0(@types/react@19.2.0)(react@19.2.0) + '@emotion/react': 11.14.0(@types/react@19.2.2)(react@19.2.0) '@emotion/serialize': 1.3.3 '@emotion/use-insertion-effect-with-fallbacks': 1.2.0(react@19.2.0) '@emotion/utils': 1.4.2 react: 19.2.0 optionalDependencies: - '@types/react': 19.2.0 + '@types/react': 19.2.2 transitivePeerDependencies: - supports-color @@ -3344,10 +3344,10 @@ snapshots: '@shikijs/types': 3.13.0 '@shikijs/vscode-textmate': 10.0.2 - '@hookform/devtools@4.4.0(@types/react@19.2.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + '@hookform/devtools@4.4.0(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': dependencies: - '@emotion/react': 11.14.0(@types/react@19.2.0)(react@19.2.0) - '@emotion/styled': 11.14.1(@emotion/react@11.14.0(@types/react@19.2.0)(react@19.2.0))(@types/react@19.2.0)(react@19.2.0) + '@emotion/react': 11.14.0(@types/react@19.2.2)(react@19.2.0) + '@emotion/styled': 11.14.1(@emotion/react@11.14.0(@types/react@19.2.2)(react@19.2.0))(@types/react@19.2.2)(react@19.2.0) '@types/lodash': 4.17.20 little-state-machine: 4.8.1(react@19.2.0) lodash: 4.17.21 @@ -3360,9 +3360,9 @@ snapshots: - '@types/react' - supports-color - '@hookform/resolvers@3.10.0(react-hook-form@7.63.0(react@19.2.0))': + '@hookform/resolvers@3.10.0(react-hook-form@7.64.0(react@19.2.0))': dependencies: - react-hook-form: 7.63.0(react@19.2.0) + react-hook-form: 7.64.0(react@19.2.0) '@jridgewell/gen-mapping@0.3.13': dependencies: @@ -3458,7 +3458,7 @@ snapshots: '@react-hook/passive-layout-effect': 1.2.1(react@19.2.0) react: 19.2.0 - '@reduxjs/toolkit@2.9.0(react-redux@9.2.0(@types/react@19.2.0)(react@19.2.0)(redux@5.0.1))(react@19.2.0)': + '@reduxjs/toolkit@2.9.0(react-redux@9.2.0(@types/react@19.2.2)(react@19.2.0)(redux@5.0.1))(react@19.2.0)': dependencies: '@standard-schema/spec': 1.0.0 '@standard-schema/utils': 0.3.0 @@ -3468,7 +3468,7 @@ snapshots: reselect: 5.1.1 optionalDependencies: react: 19.2.0 - react-redux: 9.2.0(@types/react@19.2.0)(react@19.2.0)(redux@5.0.1) + react-redux: 9.2.0(@types/react@19.2.2)(react@19.2.0)(redux@5.0.1) '@remix-run/router@1.23.0': {} @@ -3935,17 +3935,17 @@ snapshots: '@types/ms@2.1.0': {} - '@types/node@24.6.2': + '@types/node@24.7.0': dependencies: - undici-types: 7.13.0 + undici-types: 7.14.0 '@types/parse-json@4.0.2': {} - '@types/react-dom@19.2.0(@types/react@19.2.0)': + '@types/react-dom@19.2.1(@types/react@19.2.2)': dependencies: - '@types/react': 19.2.0 + '@types/react': 19.2.2 - '@types/react@19.2.0': + '@types/react@19.2.2': dependencies: csstype: 3.1.3 @@ -3964,15 +3964,15 @@ snapshots: '@use-gesture/core': 10.3.1 react: 19.2.0 - '@vitejs/plugin-react-swc@4.1.0(vite@7.1.9(@types/node@24.6.2)(sass@1.92.1)(yaml@2.8.1))': + '@vitejs/plugin-react-swc@4.1.0(vite@7.1.9(@types/node@24.7.0)(sass@1.92.1)(yaml@2.8.1))': dependencies: '@rolldown/pluginutils': 1.0.0-beta.35 '@swc/core': 1.13.5 - vite: 7.1.9(@types/node@24.6.2)(sass@1.92.1)(yaml@2.8.1) + vite: 7.1.9(@types/node@24.7.0)(sass@1.92.1)(yaml@2.8.1) transitivePeerDependencies: - '@swc/helpers' - '@vitejs/plugin-react@5.0.4(vite@7.1.9(@types/node@24.6.2)(sass@1.92.1)(yaml@2.8.1))': + '@vitejs/plugin-react@5.0.4(vite@7.1.9(@types/node@24.7.0)(sass@1.92.1)(yaml@2.8.1))': dependencies: '@babel/core': 7.28.4 '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.28.4) @@ -3980,7 +3980,7 @@ snapshots: '@rolldown/pluginutils': 1.0.0-beta.38 '@types/babel__core': 7.20.5 react-refresh: 0.17.0 - vite: 7.1.9(@types/node@24.6.2)(sass@1.92.1)(yaml@2.8.1) + vite: 7.1.9(@types/node@24.7.0)(sass@1.92.1)(yaml@2.8.1) transitivePeerDependencies: - supports-color @@ -4016,7 +4016,7 @@ snapshots: autoprefixer@10.4.21(postcss@8.5.6): dependencies: browserslist: 4.26.3 - caniuse-lite: 1.0.30001747 + caniuse-lite: 1.0.30001749 fraction.js: 4.3.7 normalize-range: 0.1.2 picocolors: 1.1.1 @@ -4037,7 +4037,7 @@ snapshots: balanced-match@1.0.2: {} - baseline-browser-mapping@2.8.10: {} + baseline-browser-mapping@2.8.14: {} boolbase@1.0.0: {} @@ -4057,10 +4057,10 @@ snapshots: browserslist@4.26.3: dependencies: - baseline-browser-mapping: 2.8.10 - caniuse-lite: 1.0.30001747 - electron-to-chromium: 1.5.230 - node-releases: 2.0.21 + baseline-browser-mapping: 2.8.14 + caniuse-lite: 1.0.30001749 + electron-to-chromium: 1.5.233 + node-releases: 2.0.23 update-browserslist-db: 1.1.3(browserslist@4.26.3) byte-size@9.0.1: {} @@ -4086,7 +4086,7 @@ snapshots: camelcase@6.3.0: {} - caniuse-lite@1.0.30001747: {} + caniuse-lite@1.0.30001749: {} ccount@2.0.1: {} @@ -4326,7 +4326,7 @@ snapshots: es-errors: 1.3.0 gopd: 1.2.0 - electron-to-chromium@1.5.230: {} + electron-to-chromium@1.5.233: {} emoji-regex@8.0.0: {} @@ -4416,7 +4416,7 @@ snapshots: is-date-object: 1.1.0 is-symbol: 1.1.1 - es-toolkit@1.39.10: {} + es-toolkit@1.40.0: {} esbuild@0.25.10: optionalDependencies: @@ -4622,7 +4622,7 @@ snapshots: domhandler: 5.0.3 htmlparser2: 10.0.0 - html-react-parser@5.2.6(@types/react@19.2.0)(react@19.2.0): + html-react-parser@5.2.6(@types/react@19.2.2)(react@19.2.0): dependencies: domhandler: 5.0.3 html-dom-parser: 5.1.1 @@ -4630,7 +4630,7 @@ snapshots: react-property: 2.0.2 style-to-js: 1.1.17 optionalDependencies: - '@types/react': 19.2.0 + '@types/react': 19.2.2 html-url-attributes@3.0.1: {} @@ -4962,9 +4962,9 @@ snapshots: memorystream@0.3.1: {} - merge-refs@2.0.0(@types/react@19.2.0): + merge-refs@2.0.0(@types/react@19.2.2): optionalDependencies: - '@types/react': 19.2.0 + '@types/react': 19.2.2 micromark-core-commonmark@2.0.3: dependencies: @@ -5150,7 +5150,7 @@ snapshots: node-addon-api@7.1.1: optional: true - node-releases@2.0.21: {} + node-releases@2.0.23: {} normalize-package-data@2.5.0: dependencies: @@ -5293,7 +5293,7 @@ snapshots: react: 19.2.0 scheduler: 0.27.0 - react-hook-form@7.63.0(react@19.2.0): + react-hook-form@7.64.0(react@19.2.0): dependencies: react: 19.2.0 @@ -5305,11 +5305,11 @@ snapshots: dependencies: react: 19.2.0 - react-markdown@10.1.0(@types/react@19.2.0)(react@19.2.0): + react-markdown@10.1.0(@types/react@19.2.2)(react@19.2.0): dependencies: '@types/hast': 3.0.4 '@types/mdast': 4.0.4 - '@types/react': 19.2.0 + '@types/react': 19.2.2 devlop: 1.1.0 hast-util-to-jsx-runtime: 2.3.6 html-url-attributes: 3.0.1 @@ -5331,13 +5331,13 @@ snapshots: qr.js: 0.0.0 react: 19.2.0 - react-redux@9.2.0(@types/react@19.2.0)(react@19.2.0)(redux@5.0.1): + react-redux@9.2.0(@types/react@19.2.2)(react@19.2.0)(redux@5.0.1): dependencies: '@types/use-sync-external-store': 0.0.6 react: 19.2.0 use-sync-external-store: 1.6.0(react@19.2.0) optionalDependencies: - '@types/react': 19.2.0 + '@types/react': 19.2.2 redux: 5.0.1 react-refresh@0.17.0: {} @@ -5375,18 +5375,18 @@ snapshots: readdirp@4.1.2: {} - recharts@3.2.1(@types/react@19.2.0)(react-dom@19.2.0(react@19.2.0))(react-is@18.3.1)(react@19.2.0)(redux@5.0.1): + recharts@3.2.1(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react-is@18.3.1)(react@19.2.0)(redux@5.0.1): dependencies: - '@reduxjs/toolkit': 2.9.0(react-redux@9.2.0(@types/react@19.2.0)(react@19.2.0)(redux@5.0.1))(react@19.2.0) + '@reduxjs/toolkit': 2.9.0(react-redux@9.2.0(@types/react@19.2.2)(react@19.2.0)(redux@5.0.1))(react@19.2.0) clsx: 2.1.1 decimal.js-light: 2.5.1 - es-toolkit: 1.39.10 + es-toolkit: 1.40.0 eventemitter3: 5.0.1 immer: 10.1.3 react: 19.2.0 react-dom: 19.2.0(react@19.2.0) react-is: 18.3.1 - react-redux: 9.2.0(@types/react@19.2.0)(react@19.2.0)(redux@5.0.1) + react-redux: 9.2.0(@types/react@19.2.2)(react@19.2.0)(redux@5.0.1) reselect: 5.1.1 tiny-invariant: 1.3.3 use-sync-external-store: 1.6.0(react@19.2.0) @@ -5764,7 +5764,7 @@ snapshots: has-symbols: 1.1.0 which-boxed-primitive: 1.1.1 - undici-types@7.13.0: {} + undici-types@7.14.0: {} unified@11.0.5: dependencies: @@ -5854,7 +5854,7 @@ snapshots: d3-time: 3.1.0 d3-timer: 3.0.1 - vite@7.1.9(@types/node@24.6.2)(sass@1.92.1)(yaml@2.8.1): + vite@7.1.9(@types/node@24.7.0)(sass@1.92.1)(yaml@2.8.1): dependencies: esbuild: 0.25.10 fdir: 6.5.0(picomatch@4.0.3) @@ -5863,7 +5863,7 @@ snapshots: rollup: 4.52.4 tinyglobby: 0.2.15 optionalDependencies: - '@types/node': 24.6.2 + '@types/node': 24.7.0 fsevents: 2.3.3 sass: 1.92.1 yaml: 2.8.1 @@ -5943,9 +5943,9 @@ snapshots: zod@3.25.76: {} - zustand@5.0.8(@types/react@19.2.0)(immer@10.1.3)(react@19.2.0)(use-sync-external-store@1.6.0(react@19.2.0)): + zustand@5.0.8(@types/react@19.2.2)(immer@10.1.3)(react@19.2.0)(use-sync-external-store@1.6.0(react@19.2.0)): optionalDependencies: - '@types/react': 19.2.0 + '@types/react': 19.2.2 immer: 10.1.3 react: 19.2.0 use-sync-external-store: 1.6.0(react@19.2.0) diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index 0c97a857..768009b8 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -2,15 +2,6 @@ # It is not intended for manual editing. version = 3 -[[package]] -name = "addr2line" -version = "0.25.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b5d307320b3181d6d7954e663bd7c774a838b8220fe0593c86d9fb09f498b4b" -dependencies = [ - "gimli", -] - [[package]] name = "adler2" version = "2.0.1" @@ -550,21 +541,6 @@ dependencies = [ "tower-service", ] -[[package]] -name = "backtrace" -version = "0.3.76" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb531853791a215d7c62a30daf0dde835f381ab5de4589cfe7c649d2cbe92bd6" -dependencies = [ - "addr2line", - "cfg-if", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", - "windows-link 0.2.1", -] - [[package]] name = "base64" version = "0.21.7" @@ -866,14 +842,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "374b7c592d9c00c1f4972ea58390ac6b18cbb6ab79011f3bdc90a0b82ca06b77" dependencies = [ "serde", - "toml 0.9.7", + "toml 0.9.8", ] [[package]] name = "cc" -version = "1.2.40" +version = "1.2.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1d05d92f4b1fd76aad469d46cdd858ca761576082cd37df81416691e50199fb" +checksum = "ac9fe6cdbb24b6ade63616c0a0688e45bb56732262c158df3c0c4bea4ca47cb7" dependencies = [ "find-msvc-tools", "jobserver", @@ -910,9 +886,9 @@ dependencies = [ [[package]] name = "cfg-if" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] name = "cfg_aliases" @@ -971,9 +947,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.48" +version = "4.5.49" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2134bb3ea021b78629caa971416385309e0131b351b25e01dc16fb54e1b5fae" +checksum = "f4512b90fa68d3a9932cea5184017c5d200f5921df706d45e853537dea51508f" dependencies = [ "clap_builder", "clap_derive", @@ -981,9 +957,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.48" +version = "4.5.49" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2ba64afa3c0a6df7fa517765e31314e983f51dda798ffba27b988194fb65dc9" +checksum = "0025e98baa12e766c67ba13ff4695a887a1eba19569aad00a472546795bd6730" dependencies = [ "anstream", "anstyle", @@ -993,9 +969,9 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.47" +version = "4.5.49" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbfd7eae0b0f1a6e63d4b13c9c478de77c2eb546fba158ad50b4203dc24b9f9c" +checksum = "2a0b5487afeab2deb2ff4e03a807ad1a03ac532ff5a2cee5d86884440c7f7671" dependencies = [ "heck 0.5.0", "proc-macro2", @@ -1005,9 +981,9 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.7.5" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675" +checksum = "a1d728cc89cf3aee9ff92b05e62b19ee65a02b5702cff7d5a377e32c6ae29d8d" [[package]] name = "clipboard-win" @@ -1753,7 +1729,7 @@ dependencies = [ "cc", "memchr", "rustc_version", - "toml 0.9.7", + "toml 0.9.8", "vswhom", "winreg 0.55.0", ] @@ -1802,9 +1778,9 @@ dependencies = [ [[package]] name = "env_filter" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "186e05a59d4c50738528153b83b0b0194d3a29507dfec16eccd4b342903397d0" +checksum = "1bf3c259d255ca70051b30e2e95b5446cdb8949ac4cd22c0d7fd634d89f568e2" dependencies = [ "log", "regex", @@ -1943,9 +1919,9 @@ dependencies = [ [[package]] name = "find-msvc-tools" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0399f9d26e5191ce32c498bebd31e7a3ceabc2745f0ac54af3f335126c3f24b3" +checksum = "52051878f80a721bb68ebfbc930e07b65ba72f2da88968ea5c06fd6ca3d3a127" [[package]] name = "fixedbitset" @@ -2275,9 +2251,9 @@ dependencies = [ [[package]] name = "generic-array" -version = "0.14.7" +version = "0.14.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +checksum = "4bb6743198531e02858aeaea5398fcc883e71851fcbcb5a2f773e2fb6cb1edf2" dependencies = [ "typenum", "version_check", @@ -2285,12 +2261,12 @@ dependencies = [ [[package]] name = "gethostname" -version = "1.0.2" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc257fdb4038301ce4b9cd1b3b51704509692bb3ff716a410cbd07925d9dae55" +checksum = "1bd49230192a3797a9a4d6abe9b3eed6f7fa4c8a8a4947977c6f80025f92cbd8" dependencies = [ "rustix 1.1.2", - "windows-targets 0.52.6", + "windows-link 0.2.1", ] [[package]] @@ -2319,24 +2295,18 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.3.3" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" dependencies = [ "cfg-if", "js-sys", "libc", "r-efi", - "wasi 0.14.7+wasi-0.2.4", + "wasip2", "wasm-bindgen", ] -[[package]] -name = "gimli" -version = "0.32.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7" - [[package]] name = "gio" version = "0.18.4" @@ -2542,12 +2512,13 @@ dependencies = [ [[package]] name = "half" -version = "2.6.0" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "459196ed295495a68f7d7fe1d84f6c4b7ff0e21fe3017b2f283c6fac3ad803c9" +checksum = "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b" dependencies = [ "cfg-if", "crunchy", + "zerocopy", ] [[package]] @@ -2997,17 +2968,6 @@ dependencies = [ "generic-array", ] -[[package]] -name = "io-uring" -version = "0.7.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "046fa2d4d00aea763528b4950358d0ead425372445dc8ff86312b3c69ff7727b" -dependencies = [ - "bitflags 2.9.4", - "cfg-if", - "libc", -] - [[package]] name = "ip_network" version = "0.4.1" @@ -3137,7 +3097,7 @@ version = "0.1.34" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" dependencies = [ - "getrandom 0.3.3", + "getrandom 0.3.4", "libc", ] @@ -3240,9 +3200,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.176" +version = "0.2.177" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58f929b4d672ea937a23a1ab494143d968337a5f47e56d0815df1e0890ddf174" +checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976" [[package]] name = "libgit2-sys" @@ -3489,9 +3449,9 @@ dependencies = [ [[package]] name = "moxcms" -version = "0.7.6" +version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cc7d85f3d741164e8972ad355e26ac6e51b20fcae5f911c7da8f2d8bbbb3f33" +checksum = "c588e11a3082784af229e23e8e4ecf5bcc6fbe4f69101e0421ce8d79da7f0b40" dependencies = [ "num-traits", "pxfm", @@ -3686,11 +3646,11 @@ dependencies = [ [[package]] name = "nu-ansi-term" -version = "0.50.1" +version = "0.50.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4a28e057d01f97e61255210fcff094d74ed0466038633e95017f5beb68e4399" +checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] @@ -4041,15 +4001,6 @@ dependencies = [ "objc2-security", ] -[[package]] -name = "object" -version = "0.37.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe" -dependencies = [ - "memchr", -] - [[package]] name = "once_cell" version = "1.21.3" @@ -4174,12 +4125,12 @@ dependencies = [ [[package]] name = "os_pipe" -version = "1.2.2" +version = "1.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db335f4760b14ead6290116f2427bf33a14d4f0617d49f78a246de10c1831224" +checksum = "7d8fae84b431384b68627d0f9b3b1245fcf9f46f6c0e3dc902e9dce64edd1967" dependencies = [ "libc", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -4629,7 +4580,7 @@ version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "219cb19e96be00ab2e37d6e299658a0cfa83e52429179969b0f0121b4ac46983" dependencies = [ - "toml_edit 0.23.6", + "toml_edit 0.23.7", ] [[package]] @@ -4783,9 +4734,9 @@ dependencies = [ [[package]] name = "pxfm" -version = "0.1.24" +version = "0.1.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83f9b339b02259ada5c0f4a389b7fb472f933aa17ce176fd2ad98f28bb401fde" +checksum = "a3cbdf373972bf78df4d3b518d07003938e2c7d1fb5891e55f9cb6df57009d84" dependencies = [ "num-traits", ] @@ -4841,7 +4792,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1906b49b0c3bc04b5fe5d86a77925ae6524a19b816ae38ce1e426255f1d8a31" dependencies = [ "bytes", - "getrandom 0.3.3", + "getrandom 0.3.4", "lru-slab", "rand 0.9.2", "ring", @@ -4979,7 +4930,7 @@ version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" dependencies = [ - "getrandom 0.3.3", + "getrandom 0.3.4", ] [[package]] @@ -5059,9 +5010,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.11.3" +version = "1.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b5288124840bee7b386bc413c487869b360b2b4ec421ea56425128692f2a82c" +checksum = "843bc0191f75f3e22651ae5f1e72939ab2f72a4bc30fa80a066bd66edefc24d4" dependencies = [ "aho-corasick", "memchr", @@ -5071,9 +5022,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.11" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "833eb9ce86d40ef33cb1306d8accf7bc8ec2bfea4355cbdebb3df68b40925cad" +checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c" dependencies = [ "aho-corasick", "memchr", @@ -5082,9 +5033,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.6" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "caf4aa5b0f434c91fe5c7f1ecb6a5ece2130b02ad2a590589dda5146df959001" +checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" [[package]] name = "rend" @@ -5097,9 +5048,9 @@ dependencies = [ [[package]] name = "reqwest" -version = "0.12.23" +version = "0.12.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d429f34c8092b2d42c7c93cec323bb4adeb7c67698f70839adec842ec10c7ceb" +checksum = "9d0946410b9f7b082a427e4ef5c8ff541a88b357bc6c637c40db3a68ac70a36f" dependencies = [ "base64 0.22.1", "bytes", @@ -5245,9 +5196,9 @@ dependencies = [ [[package]] name = "rust_decimal" -version = "1.38.0" +version = "1.39.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8975fc98059f365204d635119cf9c5a60ae67b841ed49b5422a9a7e56cdfac0" +checksum = "35affe401787a9bd846712274d97654355d21b2a2c092a3139aabe31e9022282" dependencies = [ "arrayvec", "borsh", @@ -5259,12 +5210,6 @@ dependencies = [ "serde_json", ] -[[package]] -name = "rustc-demangle" -version = "0.1.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace" - [[package]] name = "rustc-hash" version = "2.1.1" @@ -5323,9 +5268,9 @@ dependencies = [ [[package]] name = "rustls-native-certs" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcff2dd52b58a8d98a70243663a0d234c4e2b79235637849d15913394a247d3" +checksum = "9980d917ebb0c0536119ba501e90834767bffc3d60641457fd84a1f3fd337923" dependencies = [ "openssl-probe", "rustls-pki-types", @@ -5625,9 +5570,9 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5417783452c2be558477e104686f7de5dae53dba813c28435e0e70f82d9b04ee" +checksum = "e24345aa0fe688594e73770a5f6d1b216508b4f93484c0026d521acd30134392" dependencies = [ "serde_core", ] @@ -5810,12 +5755,12 @@ checksum = "b7c388c1b5e93756d0c740965c41e8822f866621d41acbdf6336a6a168f8840c" [[package]] name = "socket2" -version = "0.6.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "233504af464074f9d066d7b5416c5f9b894a5862a6506e306f7b816cdd6f1807" +checksum = "17129e116933cf371d018bb80ae557e889637989d8638274fb25622827b03881" dependencies = [ "libc", - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] [[package]] @@ -6083,9 +6028,9 @@ dependencies = [ [[package]] name = "stable_deref_trait" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" [[package]] name = "static_assertions" @@ -6353,7 +6298,7 @@ dependencies = [ "dirs", "dunce", "embed_plist", - "getrandom 0.3.3", + "getrandom 0.3.4", "glob", "gtk", "heck 0.5.0", @@ -6412,7 +6357,7 @@ dependencies = [ "serde_json", "tauri-utils", "tauri-winres", - "toml 0.9.7", + "toml 0.9.8", "walkdir", ] @@ -6470,7 +6415,7 @@ dependencies = [ "serde", "serde_json", "tauri-utils", - "toml 0.9.7", + "toml 0.9.8", "walkdir", ] @@ -6546,7 +6491,7 @@ dependencies = [ "tauri-plugin", "tauri-utils", "thiserror 2.0.17", - "toml 0.9.7", + "toml 0.9.8", "url", ] @@ -6769,7 +6714,7 @@ dependencies = [ "serde_with", "swift-rs", "thiserror 2.0.17", - "toml 0.9.7", + "toml 0.9.8", "url", "urlpattern", "uuid", @@ -6783,7 +6728,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fd21509dd1fa9bd355dc29894a6ff10635880732396aa38c0066c1e6c1ab8074" dependencies = [ "embed-resource", - "toml 0.9.7", + "toml 0.9.8", ] [[package]] @@ -6805,7 +6750,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2d31c77bdf42a745371d260a26ca7163f1e0924b64afa0b688e61b5a9fa02f16" dependencies = [ "fastrand", - "getrandom 0.3.3", + "getrandom 0.3.4", "once_cell", "rustix 1.1.2", "windows-sys 0.61.2", @@ -6963,30 +6908,27 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.47.1" +version = "1.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89e49afdadebb872d3145a5638b59eb0691ea23e46ca484037cfab3b76b95038" +checksum = "ff360e02eab121e0bc37a2d3b4d4dc622e6eda3a8e5253d5435ecf5bd4c68408" dependencies = [ - "backtrace", "bytes", - "io-uring", "libc", "mio", "parking_lot", "pin-project-lite", "signal-hook-registry", - "slab", "socket2", "tokio-macros", "tracing", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] name = "tokio-macros" -version = "2.5.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" +checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5" dependencies = [ "proc-macro2", "quote", @@ -7060,14 +7002,14 @@ dependencies = [ [[package]] name = "toml" -version = "0.9.7" +version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00e5e5d9bf2475ac9d4f0d9edab68cc573dc2fd644b0dba36b0c30a92dd9eaa0" +checksum = "f0dc8b1fb61449e27716ec0e1bdf0f6b8f3e8f6b05391e8497b8b6d7804ea6d8" dependencies = [ "indexmap 2.11.4", "serde_core", - "serde_spanned 1.0.2", - "toml_datetime 0.7.2", + "serde_spanned 1.0.3", + "toml_datetime 0.7.3", "toml_parser", "toml_writer", "winnow 0.7.13", @@ -7084,9 +7026,9 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32f1085dec27c2b6632b04c80b3bb1b4300d6495d1e129693bdda7d91e72eec1" +checksum = "f2cdb639ebbc97961c51720f858597f7f24c4fc295327923af55b74c3c724533" dependencies = [ "serde_core", ] @@ -7117,30 +7059,30 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.23.6" +version = "0.23.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3effe7c0e86fdff4f69cdd2ccc1b96f933e24811c5441d44904e8683e27184b" +checksum = "6485ef6d0d9b5d0ec17244ff7eb05310113c3f316f2d14200d4de56b3cb98f8d" dependencies = [ "indexmap 2.11.4", - "toml_datetime 0.7.2", + "toml_datetime 0.7.3", "toml_parser", "winnow 0.7.13", ] [[package]] name = "toml_parser" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cf893c33be71572e0e9aa6dd15e6677937abd686b066eac3f8cd3531688a627" +checksum = "c0cbe268d35bdb4bb5a56a2de88d0ad0eb70af5384a99d648cd4b3d04039800e" dependencies = [ "winnow 0.7.13", ] [[package]] name = "toml_writer" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d163a63c116ce562a22cda521fcc4d79152e7aba014456fb5eb442f6d6a10109" +checksum = "df8b2b54733674ad286d16267dcfc7a71ed5c776e4ac7aa3c3e2561f7c637bf2" [[package]] name = "tonic" @@ -7701,7 +7643,7 @@ version = "1.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2f87b8aa10b915a06587d0dec516c282ff295b475d94abf425d62b57710070a2" dependencies = [ - "getrandom 0.3.3", + "getrandom 0.3.4", "js-sys", "serde", "wasm-bindgen", @@ -7827,15 +7769,6 @@ version = "0.11.1+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" -[[package]] -name = "wasi" -version = "0.14.7+wasi-0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "883478de20367e224c0090af9cf5f9fa85bed63a95c1abf3afc5c083ebc06e8c" -dependencies = [ - "wasip2", -] - [[package]] name = "wasip2" version = "1.0.1+wasi-0.2.4" @@ -8161,9 +8094,9 @@ dependencies = [ [[package]] name = "widestring" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd7cf3379ca1aac9eea11fba24fd7e315d621f8dfe35c8d7d2be8b793726e07d" +checksum = "72069c3113ab32ab29e5584db3c6ec55d416895e60715417b5b883a357c3e471" [[package]] name = "winapi" diff --git a/src-tauri/Client.entitlements b/src-tauri/Client.entitlements new file mode 100644 index 00000000..0402d920 --- /dev/null +++ b/src-tauri/Client.entitlements @@ -0,0 +1,12 @@ + + + + + com.apple.developer.networking.networkextension + + packet-tunnel-provider + + com.apple.security.app-sandbox + + + diff --git a/src-tauri/build.rs b/src-tauri/build.rs index 6145784e..deb2e438 100644 --- a/src-tauri/build.rs +++ b/src-tauri/build.rs @@ -28,10 +28,11 @@ fn main() -> Result<(), Box> { #[cfg(target_os = "macos")] SwiftLinker::new("13") .with_ios("15") - .with_package("defguard-vpn-extension", "../swift/") + .with_package("defguard-vpn-plugin", "../swift/plugin") .link(); println!("cargo:rerun-if-changed=proto"); + #[cfg(target_os = "macos")] println!("cargo:rerun-if-changed=../swift"); Ok(()) } diff --git a/swift/.gitignore b/swift/.gitignore index 5922fdaa..7507e0a8 100644 --- a/swift/.gitignore +++ b/swift/.gitignore @@ -1,5 +1,5 @@ .DS_Store -/.build +*/.build /Packages /*.xcodeproj xcuserdata/ diff --git a/swift/Sources/TunnelConfiguration.swift b/swift/Sources/TunnelConfiguration.swift deleted file mode 100644 index 01a002b1..00000000 --- a/swift/Sources/TunnelConfiguration.swift +++ /dev/null @@ -1,18 +0,0 @@ -import Foundation -import NetworkExtension - -final class TunnelConfiguration: Codable { - var name: String - var privateKey: String - var addresses: [IpAddrMask] = [] - var listenPort: UInt16? - var peers: [Peer] = [] - var mtu: UInt32? - var dns: [String] = [] - var dnsSearch: [String] = [] - - init(name: String, privateKey: String) { - self.name = name - self.privateKey = privateKey - } -} diff --git a/swift/plugin/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata b/swift/plugin/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata new file mode 100644 index 00000000..919434a6 --- /dev/null +++ b/swift/plugin/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/swift/Package.swift b/swift/plugin/Package.swift similarity index 81% rename from swift/Package.swift rename to swift/plugin/Package.swift index 224cdfc2..4e027349 100644 --- a/swift/Package.swift +++ b/swift/plugin/Package.swift @@ -4,7 +4,7 @@ import PackageDescription let package = Package( - name: "defguard-vpn-extension", + name: "defguard-vpn-plugin", platforms: [ .macOS("13.5"), .iOS("15.6"), @@ -12,16 +12,16 @@ let package = Package( products: [ // Products define the executables and libraries a package produces, and make them visible to other packages. .library( - name: "defguard-vpn-extension", + name: "defguard-vpn-plugin", type: .static, - targets: ["defguard-vpn-extension"]) + targets: ["defguard-vpn-plugin"]) ], dependencies: [ .package(url: "https://github.com/Brendonovich/swift-rs", from: "1.0.7") ], targets: [ .target( - name: "defguard-vpn-extension", + name: "defguard-vpn-plugin", dependencies: [ .product( name: "SwiftRs", diff --git a/swift/Sources/Decodabe+Encodable.swift b/swift/plugin/Sources/Decodabe+Encodable.swift similarity index 100% rename from swift/Sources/Decodabe+Encodable.swift rename to swift/plugin/Sources/Decodabe+Encodable.swift diff --git a/swift/Sources/Endpoint.swift b/swift/plugin/Sources/Endpoint.swift similarity index 100% rename from swift/Sources/Endpoint.swift rename to swift/plugin/Sources/Endpoint.swift diff --git a/swift/Sources/IpAddrMask.swift b/swift/plugin/Sources/IpAddrMask.swift similarity index 100% rename from swift/Sources/IpAddrMask.swift rename to swift/plugin/Sources/IpAddrMask.swift diff --git a/swift/Sources/Peer.swift b/swift/plugin/Sources/Peer.swift similarity index 100% rename from swift/Sources/Peer.swift rename to swift/plugin/Sources/Peer.swift diff --git a/swift/Sources/Shared.swift b/swift/plugin/Sources/Shared.swift similarity index 100% rename from swift/Sources/Shared.swift rename to swift/plugin/Sources/Shared.swift diff --git a/swift/plugin/Sources/TunnelConfiguration.swift b/swift/plugin/Sources/TunnelConfiguration.swift new file mode 100644 index 00000000..5b865512 --- /dev/null +++ b/swift/plugin/Sources/TunnelConfiguration.swift @@ -0,0 +1,112 @@ +import Foundation +import NetworkExtension + +final class TunnelConfiguration: Codable { + var name: String + var privateKey: String + var addresses: [IpAddrMask] = [] + var listenPort: UInt16? + var peers: [Peer] = [] + var mtu: UInt32? + var dns: [String] = [] + var dnsSearch: [String] = [] + + init(name: String, privateKey: String, peers: [Peer]) { + self.name = name + self.privateKey = privateKey + self.peers = peers + + let peerPublicKeysArray = peers.map { $0.publicKey } + let peerPublicKeysSet = Set(peerPublicKeysArray) + if peerPublicKeysArray.count != peerPublicKeysSet.count { + fatalError("Two or more peers cannot have the same public key") + } + } + + /// Only encode these properties. + enum CodingKeys: String, CodingKey { + case name + case privateKey + case addresses + case listenPort + case peers + case mtu + case dns + case dnsSearch + } + + func asNetworkSettings() -> NEPacketTunnelNetworkSettings { + // Keep 127.0.0.1 as remote address for WireGuard. + let networkSettings = NEPacketTunnelNetworkSettings(tunnelRemoteAddress: "127.0.0.1") + + let (ipv4IncludedRoutes, ipv6IncludedRoutes) = routes() + + // IPv4 addresses + let addrs_v4 = addresses.filter { $0.address is IPv4Address } + .map { String(describing: $0.address) } + let masks_v4 = addresses.filter { $0.address is IPv4Address } + .map { String(describing: $0.mask()) } + let ipv4Settings = NEIPv4Settings(addresses: addrs_v4, subnetMasks: masks_v4) + ipv4Settings.includedRoutes = ipv4IncludedRoutes + networkSettings.ipv4Settings = ipv4Settings + + // IPv6 addresses + let addrs_v6 = addresses.filter { $0.address is IPv6Address } + .map { String(describing: $0.address) } + let masks_v6 = addresses.filter { $0.address is IPv6Address } + .map { NSNumber(value: $0.cidr) } + let ipv6Settings = NEIPv6Settings(addresses: addrs_v6, networkPrefixLengths: masks_v6) + ipv6Settings.includedRoutes = ipv6IncludedRoutes + networkSettings.ipv6Settings = ipv6Settings + + networkSettings.mtu = mtu as NSNumber? + networkSettings.tunnelOverheadBytes = 80 + + let dnsServers = dns + let dnsSettings = NEDNSSettings(servers: dnsServers) + dnsSettings.searchDomains = dnsSearch + networkSettings.dnsSettings = dnsSettings + + return networkSettings + } + + /// Return array of routes for IPv4 and IPv6. + func routes() -> ([NEIPv4Route], [NEIPv6Route]) { + var ipv4IncludedRoutes = [NEIPv4Route]() + var ipv6IncludedRoutes = [NEIPv6Route]() + + // Routes to interface addresses. + for addr_mask in addresses { + if addr_mask.address is IPv4Address { + let route = NEIPv4Route(destinationAddress: "\(addr_mask.address)", + subnetMask: "\(addr_mask.mask())") + route.gatewayAddress = "\(addr_mask.address)" + ipv4IncludedRoutes.append(route) + } else if addr_mask.address is IPv6Address { + let route = NEIPv6Route( + destinationAddress: "\(addr_mask.address)", + networkPrefixLength: NSNumber(value: addr_mask.cidr) + ) + route.gatewayAddress = "\(addr_mask.address)" + ipv6IncludedRoutes.append(route) + } + } + + // Routes to peer's allowed IPs. + for peer in peers { + for addr_mask in peer.allowedIPs { + if addr_mask.address is IPv4Address { + ipv4IncludedRoutes.append( + NEIPv4Route(destinationAddress: "\(addr_mask.address)", + subnetMask: "\(addr_mask.mask())")) + } else if addr_mask.address is IPv6Address { + ipv6IncludedRoutes.append( + NEIPv6Route(destinationAddress: "\(addr_mask.address)", + networkPrefixLength: NSNumber(value: addr_mask.cidr))) + } + } + } + + return (ipv4IncludedRoutes, ipv6IncludedRoutes) + } +} diff --git a/swift/Sources/VPNError.swift b/swift/plugin/Sources/VPNError.swift similarity index 100% rename from swift/Sources/VPNError.swift rename to swift/plugin/Sources/VPNError.swift diff --git a/swift/Sources/VPNManager.swift b/swift/plugin/Sources/VPNManager.swift similarity index 100% rename from swift/Sources/VPNManager.swift rename to swift/plugin/Sources/VPNManager.swift diff --git a/swift/Sources/Wireguard.swift b/swift/plugin/Sources/Wireguard.swift similarity index 79% rename from swift/Sources/Wireguard.swift rename to swift/plugin/Sources/Wireguard.swift index e9f242df..0787498f 100644 --- a/swift/Sources/Wireguard.swift +++ b/swift/plugin/Sources/Wireguard.swift @@ -23,7 +23,11 @@ public func startTunnel(json: SRString) { } logger.log("Starting tunnel with config: \(String(describing: config))") - try? plugin.startTunnel(config: config) { result in - // nothing here for the time being + plugin.startTunnel(config: config) { result in + if result == nil { + logger.info("Tunnel started successfully") + } else { + logger.error("Tunnel failed to start with \(result)") + } } } diff --git a/swift/Sources/WireguardPlugin.swift b/swift/plugin/Sources/WireguardPlugin.swift similarity index 100% rename from swift/Sources/WireguardPlugin.swift rename to swift/plugin/Sources/WireguardPlugin.swift From 96cb3836e60de946cef13ef36bedd0d634f7fc52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adam=20Ciarcin=CC=81ski?= Date: Mon, 20 Oct 2025 09:52:34 +0200 Subject: [PATCH 05/28] Work in progress --- package.json | 24 +- pnpm-lock.yaml | 726 +++++++++--------- src-tauri/Cargo.lock | 323 ++++---- src-tauri/Client.entitlements | 2 + .../resources/net.defguard.plist | 22 - .../resources-macos/resources/uninstall.sh | 26 - src-tauri/resources-macos/scripts/postinstall | 24 - src-tauri/src/appstate.rs | 28 +- src-tauri/src/export.rs | 5 +- src-tauri/src/lib.rs | 2 +- src-tauri/src/utils.rs | 5 +- src-tauri/tauri.conf.json | 11 +- src-tauri/tauri.macos.conf.json | 8 - .../plugin/Sources/TunnelConfiguration.swift | 5 + swift/plugin/Sources/VPNError.swift | 41 +- swift/plugin/Sources/VPNManager.swift | 113 ++- swift/plugin/Sources/Wireguard.swift | 108 ++- swift/plugin/Sources/WireguardPlugin.swift | 78 +- 18 files changed, 829 insertions(+), 722 deletions(-) delete mode 100644 src-tauri/resources-macos/resources/net.defguard.plist delete mode 100644 src-tauri/resources-macos/resources/uninstall.sh delete mode 100755 src-tauri/resources-macos/scripts/postinstall delete mode 100644 src-tauri/tauri.macos.conf.json diff --git a/package.json b/package.json index c890a05d..b7cd41de 100644 --- a/package.json +++ b/package.json @@ -52,7 +52,7 @@ "@react-hook/resize-observer": "^2.0.2", "@stablelib/base64": "^2.0.1", "@stablelib/x25519": "^2.0.1", - "@tanstack/query-core": "^5.90.2", + "@tanstack/query-core": "^5.90.5", "@tanstack/react-virtual": "3.13.12", "@tauri-apps/api": "^2.8.0", "@tauri-apps/plugin-clipboard-manager": "^2.3.0", @@ -77,13 +77,13 @@ "fast-deep-equal": "^3.1.3", "file-saver": "^2.0.5", "get-text-width": "^1.0.3", - "html-react-parser": "^5.2.6", + "html-react-parser": "^5.2.7", "itertools": "^2.5.0", "js-base64": "^3.7.8", "lodash-es": "^4.17.21", "merge-refs": "^2.0.0", "millify": "^6.1.0", - "motion": "^12.23.22", + "motion": "^12.23.24", "p-timeout": "^6.1.4", "prop-types": "^15.8.1", "radash": "^12.1.1", @@ -91,32 +91,32 @@ "react-auth-code-input": "^3.2.1", "react-click-away-listener": "^2.4.0", "react-dom": "^19.2.0", - "react-hook-form": "^7.64.0", + "react-hook-form": "^7.65.0", "react-loading-skeleton": "^3.5.0", "react-markdown": "^10.1.0", "react-qr-code": "^2.0.18", "react-router-dom": "^6.30.1", "react-use-websocket": "^4.13.0", "react-virtualized-auto-sizer": "^1.0.26", - "recharts": "^3.2.1", + "recharts": "^3.3.0", "rehype-sanitize": "^6.0.0", "rxjs": "^7.8.2", - "use-breakpoint": "^4.0.6", + "use-breakpoint": "^4.0.10", "zod": "^3.25.76", "zustand": "^5.0.8" }, "devDependencies": { - "@biomejs/biome": "^2.2.5", + "@biomejs/biome": "^2.2.6", "@hookform/devtools": "^4.4.0", "@svgr/cli": "^8.1.0", - "@tanstack/react-query": "^5.90.2", + "@tanstack/react-query": "^5.90.5", "@tanstack/react-query-devtools": "^5.90.2", "@tauri-apps/cli": "^2.8.4", "@types/file-saver": "^2.0.7", "@types/lodash-es": "^4.17.12", - "@types/node": "^24.7.0", + "@types/node": "^24.8.1", "@types/react": "^19.2.2", - "@types/react-dom": "^19.2.1", + "@types/react-dom": "^19.2.2", "@vitejs/plugin-react": "^5.0.4", "@vitejs/plugin-react-swc": "^4.1.0", "autoprefixer": "^10.4.21", @@ -124,10 +124,10 @@ "postcss": "^8.5.6", "prettier": "^3.6.2", "sass": "~1.92.1", - "typedoc": "^0.28.13", + "typedoc": "^0.28.14", "typesafe-i18n": "^5.26.2", "typescript": "^5.9.3", - "vite": "^7.1.9" + "vite": "^7.1.11" }, "volta": { "node": "20.5.1" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2e2265e9..da04bbb4 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -13,7 +13,7 @@ importers: version: 0.27.16(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@hookform/resolvers': specifier: ^3.10.0 - version: 3.10.0(react-hook-form@7.64.0(react@19.2.0)) + version: 3.10.0(react-hook-form@7.65.0(react@19.2.0)) '@react-hook/resize-observer': specifier: ^2.0.2 version: 2.0.2(react@19.2.0) @@ -24,8 +24,8 @@ importers: specifier: ^2.0.1 version: 2.0.1 '@tanstack/query-core': - specifier: ^5.90.2 - version: 5.90.2 + specifier: ^5.90.5 + version: 5.90.5 '@tanstack/react-virtual': specifier: 3.13.12 version: 3.13.12(react-dom@19.2.0(react@19.2.0))(react@19.2.0) @@ -99,8 +99,8 @@ importers: specifier: ^1.0.3 version: 1.0.3 html-react-parser: - specifier: ^5.2.6 - version: 5.2.6(@types/react@19.2.2)(react@19.2.0) + specifier: ^5.2.7 + version: 5.2.7(@types/react@19.2.2)(react@19.2.0) itertools: specifier: ^2.5.0 version: 2.5.0 @@ -117,8 +117,8 @@ importers: specifier: ^6.1.0 version: 6.1.0 motion: - specifier: ^12.23.22 - version: 12.23.22(@emotion/is-prop-valid@1.4.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + specifier: ^12.23.24 + version: 12.23.24(@emotion/is-prop-valid@1.4.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) p-timeout: specifier: ^6.1.4 version: 6.1.4 @@ -141,8 +141,8 @@ importers: specifier: ^19.2.0 version: 19.2.0(react@19.2.0) react-hook-form: - specifier: ^7.64.0 - version: 7.64.0(react@19.2.0) + specifier: ^7.65.0 + version: 7.65.0(react@19.2.0) react-loading-skeleton: specifier: ^3.5.0 version: 3.5.0(react@19.2.0) @@ -162,8 +162,8 @@ importers: specifier: ^1.0.26 version: 1.0.26(react-dom@19.2.0(react@19.2.0))(react@19.2.0) recharts: - specifier: ^3.2.1 - version: 3.2.1(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react-is@18.3.1)(react@19.2.0)(redux@5.0.1) + specifier: ^3.3.0 + version: 3.3.0(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react-is@18.3.1)(react@19.2.0)(redux@5.0.1) rehype-sanitize: specifier: ^6.0.0 version: 6.0.0 @@ -171,8 +171,8 @@ importers: specifier: ^7.8.2 version: 7.8.2 use-breakpoint: - specifier: ^4.0.6 - version: 4.0.6(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + specifier: ^4.0.10 + version: 4.0.10(react-dom@19.2.0(react@19.2.0))(react@19.2.0) zod: specifier: ^3.25.76 version: 3.25.76 @@ -181,8 +181,8 @@ importers: version: 5.0.8(@types/react@19.2.2)(immer@10.1.3)(react@19.2.0)(use-sync-external-store@1.6.0(react@19.2.0)) devDependencies: '@biomejs/biome': - specifier: ^2.2.5 - version: 2.2.5 + specifier: ^2.2.6 + version: 2.2.6 '@hookform/devtools': specifier: ^4.4.0 version: 4.4.0(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) @@ -190,11 +190,11 @@ importers: specifier: ^8.1.0 version: 8.1.0(typescript@5.9.3) '@tanstack/react-query': - specifier: ^5.90.2 - version: 5.90.2(react@19.2.0) + specifier: ^5.90.5 + version: 5.90.5(react@19.2.0) '@tanstack/react-query-devtools': specifier: ^5.90.2 - version: 5.90.2(@tanstack/react-query@5.90.2(react@19.2.0))(react@19.2.0) + version: 5.90.2(@tanstack/react-query@5.90.5(react@19.2.0))(react@19.2.0) '@tauri-apps/cli': specifier: ^2.8.4 version: 2.8.4 @@ -205,20 +205,20 @@ importers: specifier: ^4.17.12 version: 4.17.12 '@types/node': - specifier: ^24.7.0 - version: 24.7.0 + specifier: ^24.8.1 + version: 24.8.1 '@types/react': specifier: ^19.2.2 version: 19.2.2 '@types/react-dom': - specifier: ^19.2.1 - version: 19.2.1(@types/react@19.2.2) + specifier: ^19.2.2 + version: 19.2.2(@types/react@19.2.2) '@vitejs/plugin-react': specifier: ^5.0.4 - version: 5.0.4(vite@7.1.9(@types/node@24.7.0)(sass@1.92.1)(yaml@2.8.1)) + version: 5.0.4(vite@7.1.11(@types/node@24.8.1)(sass@1.92.1)(yaml@2.8.1)) '@vitejs/plugin-react-swc': specifier: ^4.1.0 - version: 4.1.0(vite@7.1.9(@types/node@24.7.0)(sass@1.92.1)(yaml@2.8.1)) + version: 4.1.0(vite@7.1.11(@types/node@24.8.1)(sass@1.92.1)(yaml@2.8.1)) autoprefixer: specifier: ^10.4.21 version: 10.4.21(postcss@8.5.6) @@ -235,8 +235,8 @@ importers: specifier: ~1.92.1 version: 1.92.1 typedoc: - specifier: ^0.28.13 - version: 0.28.13(typescript@5.9.3) + specifier: ^0.28.14 + version: 0.28.14(typescript@5.9.3) typesafe-i18n: specifier: ^5.26.2 version: 5.26.2(typescript@5.9.3) @@ -244,8 +244,8 @@ importers: specifier: ^5.9.3 version: 5.9.3 vite: - specifier: ^7.1.9 - version: 7.1.9(@types/node@24.7.0)(sass@1.92.1)(yaml@2.8.1) + specifier: ^7.1.11 + version: 7.1.11(@types/node@24.8.1)(sass@1.92.1)(yaml@2.8.1) packages: @@ -336,55 +336,55 @@ packages: resolution: {integrity: sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q==} engines: {node: '>=6.9.0'} - '@biomejs/biome@2.2.5': - resolution: {integrity: sha512-zcIi+163Rc3HtyHbEO7CjeHq8DjQRs40HsGbW6vx2WI0tg8mYQOPouhvHSyEnCBAorfYNnKdR64/IxO7xQ5faw==} + '@biomejs/biome@2.2.6': + resolution: {integrity: sha512-yKTCNGhek0rL5OEW1jbLeZX8LHaM8yk7+3JRGv08my+gkpmtb5dDE+54r2ZjZx0ediFEn1pYBOJSmOdDP9xtFw==} engines: {node: '>=14.21.3'} hasBin: true - '@biomejs/cli-darwin-arm64@2.2.5': - resolution: {integrity: sha512-MYT+nZ38wEIWVcL5xLyOhYQQ7nlWD0b/4mgATW2c8dvq7R4OQjt/XGXFkXrmtWmQofaIM14L7V8qIz/M+bx5QQ==} + '@biomejs/cli-darwin-arm64@2.2.6': + resolution: {integrity: sha512-UZPmn3M45CjTYulgcrFJFZv7YmK3pTxTJDrFYlNElT2FNnkkX4fsxjExTSMeWKQYoZjvekpH5cvrYZZlWu3yfA==} engines: {node: '>=14.21.3'} cpu: [arm64] os: [darwin] - '@biomejs/cli-darwin-x64@2.2.5': - resolution: {integrity: sha512-FLIEl73fv0R7dI10EnEiZLw+IMz3mWLnF95ASDI0kbx6DDLJjWxE5JxxBfmG+udz1hIDd3fr5wsuP7nwuTRdAg==} + '@biomejs/cli-darwin-x64@2.2.6': + resolution: {integrity: sha512-HOUIquhHVgh/jvxyClpwlpl/oeMqntlteL89YqjuFDiZ091P0vhHccwz+8muu3nTyHWM5FQslt+4Jdcd67+xWQ==} engines: {node: '>=14.21.3'} cpu: [x64] os: [darwin] - '@biomejs/cli-linux-arm64-musl@2.2.5': - resolution: {integrity: sha512-5Ov2wgAFwqDvQiESnu7b9ufD1faRa+40uwrohgBopeY84El2TnBDoMNXx6iuQdreoFGjwW8vH6k68G21EpNERw==} + '@biomejs/cli-linux-arm64-musl@2.2.6': + resolution: {integrity: sha512-TjCenQq3N6g1C+5UT3jE1bIiJb5MWQvulpUngTIpFsL4StVAUXucWD0SL9MCW89Tm6awWfeXBbZBAhJwjyFbRQ==} engines: {node: '>=14.21.3'} cpu: [arm64] os: [linux] - '@biomejs/cli-linux-arm64@2.2.5': - resolution: {integrity: sha512-5DjiiDfHqGgR2MS9D+AZ8kOfrzTGqLKywn8hoXpXXlJXIECGQ32t+gt/uiS2XyGBM2XQhR6ztUvbjZWeccFMoQ==} + '@biomejs/cli-linux-arm64@2.2.6': + resolution: {integrity: sha512-BpGtuMJGN+o8pQjvYsUKZ+4JEErxdSmcRD/JG3mXoWc6zrcA7OkuyGFN1mDggO0Q1n7qXxo/PcupHk8gzijt5g==} engines: {node: '>=14.21.3'} cpu: [arm64] os: [linux] - '@biomejs/cli-linux-x64-musl@2.2.5': - resolution: {integrity: sha512-AVqLCDb/6K7aPNIcxHaTQj01sl1m989CJIQFQEaiQkGr2EQwyOpaATJ473h+nXDUuAcREhccfRpe/tu+0wu0eQ==} + '@biomejs/cli-linux-x64-musl@2.2.6': + resolution: {integrity: sha512-1ZcBux8zVM3JhWN2ZCPaYf0+ogxXG316uaoXJdgoPZcdK/rmRcRY7PqHdAos2ExzvjIdvhQp72UcveI98hgOog==} engines: {node: '>=14.21.3'} cpu: [x64] os: [linux] - '@biomejs/cli-linux-x64@2.2.5': - resolution: {integrity: sha512-fq9meKm1AEXeAWan3uCg6XSP5ObA6F/Ovm89TwaMiy1DNIwdgxPkNwxlXJX8iM6oRbFysYeGnT0OG8diCWb9ew==} + '@biomejs/cli-linux-x64@2.2.6': + resolution: {integrity: sha512-1HaM/dpI/1Z68zp8ZdT6EiBq+/O/z97a2AiHMl+VAdv5/ELckFt9EvRb8hDHpk8hUMoz03gXkC7VPXOVtU7faA==} engines: {node: '>=14.21.3'} cpu: [x64] os: [linux] - '@biomejs/cli-win32-arm64@2.2.5': - resolution: {integrity: sha512-xaOIad4wBambwJa6mdp1FigYSIF9i7PCqRbvBqtIi9y29QtPVQ13sDGtUnsRoe6SjL10auMzQ6YAe+B3RpZXVg==} + '@biomejs/cli-win32-arm64@2.2.6': + resolution: {integrity: sha512-h3A88G8PGM1ryTeZyLlSdfC/gz3e95EJw9BZmA6Po412DRqwqPBa2Y9U+4ZSGUAXCsnSQE00jLV8Pyrh0d+jQw==} engines: {node: '>=14.21.3'} cpu: [arm64] os: [win32] - '@biomejs/cli-win32-x64@2.2.5': - resolution: {integrity: sha512-F/jhuXCssPFAuciMhHKk00xnCAxJRS/pUzVfXYmOMUp//XW7mO6QeCjsjvnm8L4AO/dG2VOB0O+fJPiJ2uXtIw==} + '@biomejs/cli-win32-x64@2.2.6': + resolution: {integrity: sha512-yx0CqeOhPjYQ5ZXgPfu8QYkgBhVJyvWe36as7jRuPrKPO5ylVDfwVtPQ+K/mooNTADW0IhxOZm3aPu16dP8yNQ==} engines: {node: '>=14.21.3'} cpu: [x64] os: [win32] @@ -443,158 +443,158 @@ packages: '@emotion/weak-memoize@0.4.0': resolution: {integrity: sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==} - '@esbuild/aix-ppc64@0.25.10': - resolution: {integrity: sha512-0NFWnA+7l41irNuaSVlLfgNT12caWJVLzp5eAVhZ0z1qpxbockccEt3s+149rE64VUI3Ml2zt8Nv5JVc4QXTsw==} + '@esbuild/aix-ppc64@0.25.11': + resolution: {integrity: sha512-Xt1dOL13m8u0WE8iplx9Ibbm+hFAO0GsU2P34UNoDGvZYkY8ifSiy6Zuc1lYxfG7svWE2fzqCUmFp5HCn51gJg==} engines: {node: '>=18'} cpu: [ppc64] os: [aix] - '@esbuild/android-arm64@0.25.10': - resolution: {integrity: sha512-LSQa7eDahypv/VO6WKohZGPSJDq5OVOo3UoFR1E4t4Gj1W7zEQMUhI+lo81H+DtB+kP+tDgBp+M4oNCwp6kffg==} + '@esbuild/android-arm64@0.25.11': + resolution: {integrity: sha512-9slpyFBc4FPPz48+f6jyiXOx/Y4v34TUeDDXJpZqAWQn/08lKGeD8aDp9TMn9jDz2CiEuHwfhRmGBvpnd/PWIQ==} engines: {node: '>=18'} cpu: [arm64] os: [android] - '@esbuild/android-arm@0.25.10': - resolution: {integrity: sha512-dQAxF1dW1C3zpeCDc5KqIYuZ1tgAdRXNoZP7vkBIRtKZPYe2xVr/d3SkirklCHudW1B45tGiUlz2pUWDfbDD4w==} + '@esbuild/android-arm@0.25.11': + resolution: {integrity: sha512-uoa7dU+Dt3HYsethkJ1k6Z9YdcHjTrSb5NUy66ZfZaSV8hEYGD5ZHbEMXnqLFlbBflLsl89Zke7CAdDJ4JI+Gg==} engines: {node: '>=18'} cpu: [arm] os: [android] - '@esbuild/android-x64@0.25.10': - resolution: {integrity: sha512-MiC9CWdPrfhibcXwr39p9ha1x0lZJ9KaVfvzA0Wxwz9ETX4v5CHfF09bx935nHlhi+MxhA63dKRRQLiVgSUtEg==} + '@esbuild/android-x64@0.25.11': + resolution: {integrity: sha512-Sgiab4xBjPU1QoPEIqS3Xx+R2lezu0LKIEcYe6pftr56PqPygbB7+szVnzoShbx64MUupqoE0KyRlN7gezbl8g==} engines: {node: '>=18'} cpu: [x64] os: [android] - '@esbuild/darwin-arm64@0.25.10': - resolution: {integrity: sha512-JC74bdXcQEpW9KkV326WpZZjLguSZ3DfS8wrrvPMHgQOIEIG/sPXEN/V8IssoJhbefLRcRqw6RQH2NnpdprtMA==} + '@esbuild/darwin-arm64@0.25.11': + resolution: {integrity: sha512-VekY0PBCukppoQrycFxUqkCojnTQhdec0vevUL/EDOCnXd9LKWqD/bHwMPzigIJXPhC59Vd1WFIL57SKs2mg4w==} engines: {node: '>=18'} cpu: [arm64] os: [darwin] - '@esbuild/darwin-x64@0.25.10': - resolution: {integrity: sha512-tguWg1olF6DGqzws97pKZ8G2L7Ig1vjDmGTwcTuYHbuU6TTjJe5FXbgs5C1BBzHbJ2bo1m3WkQDbWO2PvamRcg==} + '@esbuild/darwin-x64@0.25.11': + resolution: {integrity: sha512-+hfp3yfBalNEpTGp9loYgbknjR695HkqtY3d3/JjSRUyPg/xd6q+mQqIb5qdywnDxRZykIHs3axEqU6l1+oWEQ==} engines: {node: '>=18'} cpu: [x64] os: [darwin] - '@esbuild/freebsd-arm64@0.25.10': - resolution: {integrity: sha512-3ZioSQSg1HT2N05YxeJWYR+Libe3bREVSdWhEEgExWaDtyFbbXWb49QgPvFH8u03vUPX10JhJPcz7s9t9+boWg==} + '@esbuild/freebsd-arm64@0.25.11': + resolution: {integrity: sha512-CmKjrnayyTJF2eVuO//uSjl/K3KsMIeYeyN7FyDBjsR3lnSJHaXlVoAK8DZa7lXWChbuOk7NjAc7ygAwrnPBhA==} engines: {node: '>=18'} cpu: [arm64] os: [freebsd] - '@esbuild/freebsd-x64@0.25.10': - resolution: {integrity: sha512-LLgJfHJk014Aa4anGDbh8bmI5Lk+QidDmGzuC2D+vP7mv/GeSN+H39zOf7pN5N8p059FcOfs2bVlrRr4SK9WxA==} + '@esbuild/freebsd-x64@0.25.11': + resolution: {integrity: sha512-Dyq+5oscTJvMaYPvW3x3FLpi2+gSZTCE/1ffdwuM6G1ARang/mb3jvjxs0mw6n3Lsw84ocfo9CrNMqc5lTfGOw==} engines: {node: '>=18'} cpu: [x64] os: [freebsd] - '@esbuild/linux-arm64@0.25.10': - resolution: {integrity: sha512-5luJWN6YKBsawd5f9i4+c+geYiVEw20FVW5x0v1kEMWNq8UctFjDiMATBxLvmmHA4bf7F6hTRaJgtghFr9iziQ==} + '@esbuild/linux-arm64@0.25.11': + resolution: {integrity: sha512-Qr8AzcplUhGvdyUF08A1kHU3Vr2O88xxP0Tm8GcdVOUm25XYcMPp2YqSVHbLuXzYQMf9Bh/iKx7YPqECs6ffLA==} engines: {node: '>=18'} cpu: [arm64] os: [linux] - '@esbuild/linux-arm@0.25.10': - resolution: {integrity: sha512-oR31GtBTFYCqEBALI9r6WxoU/ZofZl962pouZRTEYECvNF/dtXKku8YXcJkhgK/beU+zedXfIzHijSRapJY3vg==} + '@esbuild/linux-arm@0.25.11': + resolution: {integrity: sha512-TBMv6B4kCfrGJ8cUPo7vd6NECZH/8hPpBHHlYI3qzoYFvWu2AdTvZNuU/7hsbKWqu/COU7NIK12dHAAqBLLXgw==} engines: {node: '>=18'} cpu: [arm] os: [linux] - '@esbuild/linux-ia32@0.25.10': - resolution: {integrity: sha512-NrSCx2Kim3EnnWgS4Txn0QGt0Xipoumb6z6sUtl5bOEZIVKhzfyp/Lyw4C1DIYvzeW/5mWYPBFJU3a/8Yr75DQ==} + '@esbuild/linux-ia32@0.25.11': + resolution: {integrity: sha512-TmnJg8BMGPehs5JKrCLqyWTVAvielc615jbkOirATQvWWB1NMXY77oLMzsUjRLa0+ngecEmDGqt5jiDC6bfvOw==} engines: {node: '>=18'} cpu: [ia32] os: [linux] - '@esbuild/linux-loong64@0.25.10': - resolution: {integrity: sha512-xoSphrd4AZda8+rUDDfD9J6FUMjrkTz8itpTITM4/xgerAZZcFW7Dv+sun7333IfKxGG8gAq+3NbfEMJfiY+Eg==} + '@esbuild/linux-loong64@0.25.11': + resolution: {integrity: sha512-DIGXL2+gvDaXlaq8xruNXUJdT5tF+SBbJQKbWy/0J7OhU8gOHOzKmGIlfTTl6nHaCOoipxQbuJi7O++ldrxgMw==} engines: {node: '>=18'} cpu: [loong64] os: [linux] - '@esbuild/linux-mips64el@0.25.10': - resolution: {integrity: sha512-ab6eiuCwoMmYDyTnyptoKkVS3k8fy/1Uvq7Dj5czXI6DF2GqD2ToInBI0SHOp5/X1BdZ26RKc5+qjQNGRBelRA==} + '@esbuild/linux-mips64el@0.25.11': + resolution: {integrity: sha512-Osx1nALUJu4pU43o9OyjSCXokFkFbyzjXb6VhGIJZQ5JZi8ylCQ9/LFagolPsHtgw6himDSyb5ETSfmp4rpiKQ==} engines: {node: '>=18'} cpu: [mips64el] os: [linux] - '@esbuild/linux-ppc64@0.25.10': - resolution: {integrity: sha512-NLinzzOgZQsGpsTkEbdJTCanwA5/wozN9dSgEl12haXJBzMTpssebuXR42bthOF3z7zXFWH1AmvWunUCkBE4EA==} + '@esbuild/linux-ppc64@0.25.11': + resolution: {integrity: sha512-nbLFgsQQEsBa8XSgSTSlrnBSrpoWh7ioFDUmwo158gIm5NNP+17IYmNWzaIzWmgCxq56vfr34xGkOcZ7jX6CPw==} engines: {node: '>=18'} cpu: [ppc64] os: [linux] - '@esbuild/linux-riscv64@0.25.10': - resolution: {integrity: sha512-FE557XdZDrtX8NMIeA8LBJX3dC2M8VGXwfrQWU7LB5SLOajfJIxmSdyL/gU1m64Zs9CBKvm4UAuBp5aJ8OgnrA==} + '@esbuild/linux-riscv64@0.25.11': + resolution: {integrity: sha512-HfyAmqZi9uBAbgKYP1yGuI7tSREXwIb438q0nqvlpxAOs3XnZ8RsisRfmVsgV486NdjD7Mw2UrFSw51lzUk1ww==} engines: {node: '>=18'} cpu: [riscv64] os: [linux] - '@esbuild/linux-s390x@0.25.10': - resolution: {integrity: sha512-3BBSbgzuB9ajLoVZk0mGu+EHlBwkusRmeNYdqmznmMc9zGASFjSsxgkNsqmXugpPk00gJ0JNKh/97nxmjctdew==} + '@esbuild/linux-s390x@0.25.11': + resolution: {integrity: sha512-HjLqVgSSYnVXRisyfmzsH6mXqyvj0SA7pG5g+9W7ESgwA70AXYNpfKBqh1KbTxmQVaYxpzA/SvlB9oclGPbApw==} engines: {node: '>=18'} cpu: [s390x] os: [linux] - '@esbuild/linux-x64@0.25.10': - resolution: {integrity: sha512-QSX81KhFoZGwenVyPoberggdW1nrQZSvfVDAIUXr3WqLRZGZqWk/P4T8p2SP+de2Sr5HPcvjhcJzEiulKgnxtA==} + '@esbuild/linux-x64@0.25.11': + resolution: {integrity: sha512-HSFAT4+WYjIhrHxKBwGmOOSpphjYkcswF449j6EjsjbinTZbp8PJtjsVK1XFJStdzXdy/jaddAep2FGY+wyFAQ==} engines: {node: '>=18'} cpu: [x64] os: [linux] - '@esbuild/netbsd-arm64@0.25.10': - resolution: {integrity: sha512-AKQM3gfYfSW8XRk8DdMCzaLUFB15dTrZfnX8WXQoOUpUBQ+NaAFCP1kPS/ykbbGYz7rxn0WS48/81l9hFl3u4A==} + '@esbuild/netbsd-arm64@0.25.11': + resolution: {integrity: sha512-hr9Oxj1Fa4r04dNpWr3P8QKVVsjQhqrMSUzZzf+LZcYjZNqhA3IAfPQdEh1FLVUJSiu6sgAwp3OmwBfbFgG2Xg==} engines: {node: '>=18'} cpu: [arm64] os: [netbsd] - '@esbuild/netbsd-x64@0.25.10': - resolution: {integrity: sha512-7RTytDPGU6fek/hWuN9qQpeGPBZFfB4zZgcz2VK2Z5VpdUxEI8JKYsg3JfO0n/Z1E/6l05n0unDCNc4HnhQGig==} + '@esbuild/netbsd-x64@0.25.11': + resolution: {integrity: sha512-u7tKA+qbzBydyj0vgpu+5h5AeudxOAGncb8N6C9Kh1N4n7wU1Xw1JDApsRjpShRpXRQlJLb9wY28ELpwdPcZ7A==} engines: {node: '>=18'} cpu: [x64] os: [netbsd] - '@esbuild/openbsd-arm64@0.25.10': - resolution: {integrity: sha512-5Se0VM9Wtq797YFn+dLimf2Zx6McttsH2olUBsDml+lm0GOCRVebRWUvDtkY4BWYv/3NgzS8b/UM3jQNh5hYyw==} + '@esbuild/openbsd-arm64@0.25.11': + resolution: {integrity: sha512-Qq6YHhayieor3DxFOoYM1q0q1uMFYb7cSpLD2qzDSvK1NAvqFi8Xgivv0cFC6J+hWVw2teCYltyy9/m/14ryHg==} engines: {node: '>=18'} cpu: [arm64] os: [openbsd] - '@esbuild/openbsd-x64@0.25.10': - resolution: {integrity: sha512-XkA4frq1TLj4bEMB+2HnI0+4RnjbuGZfet2gs/LNs5Hc7D89ZQBHQ0gL2ND6Lzu1+QVkjp3x1gIcPKzRNP8bXw==} + '@esbuild/openbsd-x64@0.25.11': + resolution: {integrity: sha512-CN+7c++kkbrckTOz5hrehxWN7uIhFFlmS/hqziSFVWpAzpWrQoAG4chH+nN3Be+Kzv/uuo7zhX716x3Sn2Jduw==} engines: {node: '>=18'} cpu: [x64] os: [openbsd] - '@esbuild/openharmony-arm64@0.25.10': - resolution: {integrity: sha512-AVTSBhTX8Y/Fz6OmIVBip9tJzZEUcY8WLh7I59+upa5/GPhh2/aM6bvOMQySspnCCHvFi79kMtdJS1w0DXAeag==} + '@esbuild/openharmony-arm64@0.25.11': + resolution: {integrity: sha512-rOREuNIQgaiR+9QuNkbkxubbp8MSO9rONmwP5nKncnWJ9v5jQ4JxFnLu4zDSRPf3x4u+2VN4pM4RdyIzDty/wQ==} engines: {node: '>=18'} cpu: [arm64] os: [openharmony] - '@esbuild/sunos-x64@0.25.10': - resolution: {integrity: sha512-fswk3XT0Uf2pGJmOpDB7yknqhVkJQkAQOcW/ccVOtfx05LkbWOaRAtn5SaqXypeKQra1QaEa841PgrSL9ubSPQ==} + '@esbuild/sunos-x64@0.25.11': + resolution: {integrity: sha512-nq2xdYaWxyg9DcIyXkZhcYulC6pQ2FuCgem3LI92IwMgIZ69KHeY8T4Y88pcwoLIjbed8n36CyKoYRDygNSGhA==} engines: {node: '>=18'} cpu: [x64] os: [sunos] - '@esbuild/win32-arm64@0.25.10': - resolution: {integrity: sha512-ah+9b59KDTSfpaCg6VdJoOQvKjI33nTaQr4UluQwW7aEwZQsbMCfTmfEO4VyewOxx4RaDT/xCy9ra2GPWmO7Kw==} + '@esbuild/win32-arm64@0.25.11': + resolution: {integrity: sha512-3XxECOWJq1qMZ3MN8srCJ/QfoLpL+VaxD/WfNRm1O3B4+AZ/BnLVgFbUV3eiRYDMXetciH16dwPbbHqwe1uU0Q==} engines: {node: '>=18'} cpu: [arm64] os: [win32] - '@esbuild/win32-ia32@0.25.10': - resolution: {integrity: sha512-QHPDbKkrGO8/cz9LKVnJU22HOi4pxZnZhhA2HYHez5Pz4JeffhDjf85E57Oyco163GnzNCVkZK0b/n4Y0UHcSw==} + '@esbuild/win32-ia32@0.25.11': + resolution: {integrity: sha512-3ukss6gb9XZ8TlRyJlgLn17ecsK4NSQTmdIXRASVsiS2sQ6zPPZklNJT5GR5tE/MUarymmy8kCEf5xPCNCqVOA==} engines: {node: '>=18'} cpu: [ia32] os: [win32] - '@esbuild/win32-x64@0.25.10': - resolution: {integrity: sha512-9KpxSVFCu0iK1owoez6aC/s/EdUQLDN3adTxGCqxMVhrPDj6bt5dbrHDXUuq+Bs2vATFBBrQS5vdQ/Ed2P+nbw==} + '@esbuild/win32-x64@0.25.11': + resolution: {integrity: sha512-D7Hpz6A2L4hzsRpPaCYkQnGOotdUpDzSGRIv9I+1ITdHROSFUWW95ZPZWQmGka1Fg7W3zFJowyn9WGwMJ0+KPA==} engines: {node: '>=18'} cpu: [x64] os: [win32] @@ -620,8 +620,8 @@ packages: '@floating-ui/utils@0.2.10': resolution: {integrity: sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==} - '@gerrit0/mini-shiki@3.13.0': - resolution: {integrity: sha512-mCrNvZNYNrwKer5PWLF6cOc0OEe2eKzgy976x+IT2tynwJYl+7UpHTSeXQJGijgTcoOf+f359L946unWlYRnsg==} + '@gerrit0/mini-shiki@3.13.1': + resolution: {integrity: sha512-fDWM5QQc70jwBIt/WYMybdyXdyBmoJe7r1hpM+V/bHnyla79sygVDK2/LlVxIPc4n5FA3B5Wzt7AQH2+psNphg==} '@hookform/devtools@4.4.0': resolution: {integrity: sha512-Mtlic+uigoYBPXlfvPBfiYYUZuyMrD3pTjDpVIhL6eCZTvQkHsKBSKeZCvXWUZr8fqrkzDg27N+ZuazLKq6Vmg==} @@ -747,8 +747,8 @@ packages: peerDependencies: react: '>=18' - '@reduxjs/toolkit@2.9.0': - resolution: {integrity: sha512-fSfQlSRu9Z5yBkvsNhYF2rPS8cGXn/TZVrlwN1948QyZ8xMZ0JvP50S2acZNaf+o63u6aEeMjipFyksjIcWrog==} + '@reduxjs/toolkit@2.9.1': + resolution: {integrity: sha512-sETJ3qO72y7L7WiR5K54UFLT3jRzAtqeBPVO15xC3bGA6kDqCH8m/v7BKCPH4czydXzz/1lPEGLvew7GjOO3Qw==} peerDependencies: react: ^16.9.0 || ^17.0.0 || ^18 || ^19 react-redux: ^7.2.1 || ^8.1.3 || ^9.0.0 @@ -768,113 +768,113 @@ packages: '@rolldown/pluginutils@1.0.0-beta.38': resolution: {integrity: sha512-N/ICGKleNhA5nc9XXQG/kkKHJ7S55u0x0XUJbbkmdCnFuoRkM1Il12q9q0eX19+M7KKUEPw/daUPIRnxhcxAIw==} - '@rollup/rollup-android-arm-eabi@4.52.4': - resolution: {integrity: sha512-BTm2qKNnWIQ5auf4deoetINJm2JzvihvGb9R6K/ETwKLql/Bb3Eg2H1FBp1gUb4YGbydMA3jcmQTR73q7J+GAA==} + '@rollup/rollup-android-arm-eabi@4.52.5': + resolution: {integrity: sha512-8c1vW4ocv3UOMp9K+gToY5zL2XiiVw3k7f1ksf4yO1FlDFQ1C2u72iACFnSOceJFsWskc2WZNqeRhFRPzv+wtQ==} cpu: [arm] os: [android] - '@rollup/rollup-android-arm64@4.52.4': - resolution: {integrity: sha512-P9LDQiC5vpgGFgz7GSM6dKPCiqR3XYN1WwJKA4/BUVDjHpYsf3iBEmVz62uyq20NGYbiGPR5cNHI7T1HqxNs2w==} + '@rollup/rollup-android-arm64@4.52.5': + resolution: {integrity: sha512-mQGfsIEFcu21mvqkEKKu2dYmtuSZOBMmAl5CFlPGLY94Vlcm+zWApK7F/eocsNzp8tKmbeBP8yXyAbx0XHsFNA==} cpu: [arm64] os: [android] - '@rollup/rollup-darwin-arm64@4.52.4': - resolution: {integrity: sha512-QRWSW+bVccAvZF6cbNZBJwAehmvG9NwfWHwMy4GbWi/BQIA/laTIktebT2ipVjNncqE6GLPxOok5hsECgAxGZg==} + '@rollup/rollup-darwin-arm64@4.52.5': + resolution: {integrity: sha512-takF3CR71mCAGA+v794QUZ0b6ZSrgJkArC+gUiG6LB6TQty9T0Mqh3m2ImRBOxS2IeYBo4lKWIieSvnEk2OQWA==} cpu: [arm64] os: [darwin] - '@rollup/rollup-darwin-x64@4.52.4': - resolution: {integrity: sha512-hZgP05pResAkRJxL1b+7yxCnXPGsXU0fG9Yfd6dUaoGk+FhdPKCJ5L1Sumyxn8kvw8Qi5PvQ8ulenUbRjzeCTw==} + '@rollup/rollup-darwin-x64@4.52.5': + resolution: {integrity: sha512-W901Pla8Ya95WpxDn//VF9K9u2JbocwV/v75TE0YIHNTbhqUTv9w4VuQ9MaWlNOkkEfFwkdNhXgcLqPSmHy0fA==} cpu: [x64] os: [darwin] - '@rollup/rollup-freebsd-arm64@4.52.4': - resolution: {integrity: sha512-xmc30VshuBNUd58Xk4TKAEcRZHaXlV+tCxIXELiE9sQuK3kG8ZFgSPi57UBJt8/ogfhAF5Oz4ZSUBN77weM+mQ==} + '@rollup/rollup-freebsd-arm64@4.52.5': + resolution: {integrity: sha512-QofO7i7JycsYOWxe0GFqhLmF6l1TqBswJMvICnRUjqCx8b47MTo46W8AoeQwiokAx3zVryVnxtBMcGcnX12LvA==} cpu: [arm64] os: [freebsd] - '@rollup/rollup-freebsd-x64@4.52.4': - resolution: {integrity: sha512-WdSLpZFjOEqNZGmHflxyifolwAiZmDQzuOzIq9L27ButpCVpD7KzTRtEG1I0wMPFyiyUdOO+4t8GvrnBLQSwpw==} + '@rollup/rollup-freebsd-x64@4.52.5': + resolution: {integrity: sha512-jr21b/99ew8ujZubPo9skbrItHEIE50WdV86cdSoRkKtmWa+DDr6fu2c/xyRT0F/WazZpam6kk7IHBerSL7LDQ==} cpu: [x64] os: [freebsd] - '@rollup/rollup-linux-arm-gnueabihf@4.52.4': - resolution: {integrity: sha512-xRiOu9Of1FZ4SxVbB0iEDXc4ddIcjCv2aj03dmW8UrZIW7aIQ9jVJdLBIhxBI+MaTnGAKyvMwPwQnoOEvP7FgQ==} + '@rollup/rollup-linux-arm-gnueabihf@4.52.5': + resolution: {integrity: sha512-PsNAbcyv9CcecAUagQefwX8fQn9LQ4nZkpDboBOttmyffnInRy8R8dSg6hxxl2Re5QhHBf6FYIDhIj5v982ATQ==} cpu: [arm] os: [linux] - '@rollup/rollup-linux-arm-musleabihf@4.52.4': - resolution: {integrity: sha512-FbhM2p9TJAmEIEhIgzR4soUcsW49e9veAQCziwbR+XWB2zqJ12b4i/+hel9yLiD8pLncDH4fKIPIbt5238341Q==} + '@rollup/rollup-linux-arm-musleabihf@4.52.5': + resolution: {integrity: sha512-Fw4tysRutyQc/wwkmcyoqFtJhh0u31K+Q6jYjeicsGJJ7bbEq8LwPWV/w0cnzOqR2m694/Af6hpFayLJZkG2VQ==} cpu: [arm] os: [linux] - '@rollup/rollup-linux-arm64-gnu@4.52.4': - resolution: {integrity: sha512-4n4gVwhPHR9q/g8lKCyz0yuaD0MvDf7dV4f9tHt0C73Mp8h38UCtSCSE6R9iBlTbXlmA8CjpsZoujhszefqueg==} + '@rollup/rollup-linux-arm64-gnu@4.52.5': + resolution: {integrity: sha512-a+3wVnAYdQClOTlyapKmyI6BLPAFYs0JM8HRpgYZQO02rMR09ZcV9LbQB+NL6sljzG38869YqThrRnfPMCDtZg==} cpu: [arm64] os: [linux] - '@rollup/rollup-linux-arm64-musl@4.52.4': - resolution: {integrity: sha512-u0n17nGA0nvi/11gcZKsjkLj1QIpAuPFQbR48Subo7SmZJnGxDpspyw2kbpuoQnyK+9pwf3pAoEXerJs/8Mi9g==} + '@rollup/rollup-linux-arm64-musl@4.52.5': + resolution: {integrity: sha512-AvttBOMwO9Pcuuf7m9PkC1PUIKsfaAJ4AYhy944qeTJgQOqJYJ9oVl2nYgY7Rk0mkbsuOpCAYSs6wLYB2Xiw0Q==} cpu: [arm64] os: [linux] - '@rollup/rollup-linux-loong64-gnu@4.52.4': - resolution: {integrity: sha512-0G2c2lpYtbTuXo8KEJkDkClE/+/2AFPdPAbmaHoE870foRFs4pBrDehilMcrSScrN/fB/1HTaWO4bqw+ewBzMQ==} + '@rollup/rollup-linux-loong64-gnu@4.52.5': + resolution: {integrity: sha512-DkDk8pmXQV2wVrF6oq5tONK6UHLz/XcEVow4JTTerdeV1uqPeHxwcg7aFsfnSm9L+OO8WJsWotKM2JJPMWrQtA==} cpu: [loong64] os: [linux] - '@rollup/rollup-linux-ppc64-gnu@4.52.4': - resolution: {integrity: sha512-teSACug1GyZHmPDv14VNbvZFX779UqWTsd7KtTM9JIZRDI5NUwYSIS30kzI8m06gOPB//jtpqlhmraQ68b5X2g==} + '@rollup/rollup-linux-ppc64-gnu@4.52.5': + resolution: {integrity: sha512-W/b9ZN/U9+hPQVvlGwjzi+Wy4xdoH2I8EjaCkMvzpI7wJUs8sWJ03Rq96jRnHkSrcHTpQe8h5Tg3ZzUPGauvAw==} cpu: [ppc64] os: [linux] - '@rollup/rollup-linux-riscv64-gnu@4.52.4': - resolution: {integrity: sha512-/MOEW3aHjjs1p4Pw1Xk4+3egRevx8Ji9N6HUIA1Ifh8Q+cg9dremvFCUbOX2Zebz80BwJIgCBUemjqhU5XI5Eg==} + '@rollup/rollup-linux-riscv64-gnu@4.52.5': + resolution: {integrity: sha512-sjQLr9BW7R/ZiXnQiWPkErNfLMkkWIoCz7YMn27HldKsADEKa5WYdobaa1hmN6slu9oWQbB6/jFpJ+P2IkVrmw==} cpu: [riscv64] os: [linux] - '@rollup/rollup-linux-riscv64-musl@4.52.4': - resolution: {integrity: sha512-1HHmsRyh845QDpEWzOFtMCph5Ts+9+yllCrREuBR/vg2RogAQGGBRC8lDPrPOMnrdOJ+mt1WLMOC2Kao/UwcvA==} + '@rollup/rollup-linux-riscv64-musl@4.52.5': + resolution: {integrity: sha512-hq3jU/kGyjXWTvAh2awn8oHroCbrPm8JqM7RUpKjalIRWWXE01CQOf/tUNWNHjmbMHg/hmNCwc/Pz3k1T/j/Lg==} cpu: [riscv64] os: [linux] - '@rollup/rollup-linux-s390x-gnu@4.52.4': - resolution: {integrity: sha512-seoeZp4L/6D1MUyjWkOMRU6/iLmCU2EjbMTyAG4oIOs1/I82Y5lTeaxW0KBfkUdHAWN7j25bpkt0rjnOgAcQcA==} + '@rollup/rollup-linux-s390x-gnu@4.52.5': + resolution: {integrity: sha512-gn8kHOrku8D4NGHMK1Y7NA7INQTRdVOntt1OCYypZPRt6skGbddska44K8iocdpxHTMMNui5oH4elPH4QOLrFQ==} cpu: [s390x] os: [linux] - '@rollup/rollup-linux-x64-gnu@4.52.4': - resolution: {integrity: sha512-Wi6AXf0k0L7E2gteNsNHUs7UMwCIhsCTs6+tqQ5GPwVRWMaflqGec4Sd8n6+FNFDw9vGcReqk2KzBDhCa1DLYg==} + '@rollup/rollup-linux-x64-gnu@4.52.5': + resolution: {integrity: sha512-hXGLYpdhiNElzN770+H2nlx+jRog8TyynpTVzdlc6bndktjKWyZyiCsuDAlpd+j+W+WNqfcyAWz9HxxIGfZm1Q==} cpu: [x64] os: [linux] - '@rollup/rollup-linux-x64-musl@4.52.4': - resolution: {integrity: sha512-dtBZYjDmCQ9hW+WgEkaffvRRCKm767wWhxsFW3Lw86VXz/uJRuD438/XvbZT//B96Vs8oTA8Q4A0AfHbrxP9zw==} + '@rollup/rollup-linux-x64-musl@4.52.5': + resolution: {integrity: sha512-arCGIcuNKjBoKAXD+y7XomR9gY6Mw7HnFBv5Rw7wQRvwYLR7gBAgV7Mb2QTyjXfTveBNFAtPt46/36vV9STLNg==} cpu: [x64] os: [linux] - '@rollup/rollup-openharmony-arm64@4.52.4': - resolution: {integrity: sha512-1ox+GqgRWqaB1RnyZXL8PD6E5f7YyRUJYnCqKpNzxzP0TkaUh112NDrR9Tt+C8rJ4x5G9Mk8PQR3o7Ku2RKqKA==} + '@rollup/rollup-openharmony-arm64@4.52.5': + resolution: {integrity: sha512-QoFqB6+/9Rly/RiPjaomPLmR/13cgkIGfA40LHly9zcH1S0bN2HVFYk3a1eAyHQyjs3ZJYlXvIGtcCs5tko9Cw==} cpu: [arm64] os: [openharmony] - '@rollup/rollup-win32-arm64-msvc@4.52.4': - resolution: {integrity: sha512-8GKr640PdFNXwzIE0IrkMWUNUomILLkfeHjXBi/nUvFlpZP+FA8BKGKpacjW6OUUHaNI6sUURxR2U2g78FOHWQ==} + '@rollup/rollup-win32-arm64-msvc@4.52.5': + resolution: {integrity: sha512-w0cDWVR6MlTstla1cIfOGyl8+qb93FlAVutcor14Gf5Md5ap5ySfQ7R9S/NjNaMLSFdUnKGEasmVnu3lCMqB7w==} cpu: [arm64] os: [win32] - '@rollup/rollup-win32-ia32-msvc@4.52.4': - resolution: {integrity: sha512-AIy/jdJ7WtJ/F6EcfOb2GjR9UweO0n43jNObQMb6oGxkYTfLcnN7vYYpG+CN3lLxrQkzWnMOoNSHTW54pgbVxw==} + '@rollup/rollup-win32-ia32-msvc@4.52.5': + resolution: {integrity: sha512-Aufdpzp7DpOTULJCuvzqcItSGDH73pF3ko/f+ckJhxQyHtp67rHw3HMNxoIdDMUITJESNE6a8uh4Lo4SLouOUg==} cpu: [ia32] os: [win32] - '@rollup/rollup-win32-x64-gnu@4.52.4': - resolution: {integrity: sha512-UF9KfsH9yEam0UjTwAgdK0anlQ7c8/pWPU2yVjyWcF1I1thABt6WXE47cI71pGiZ8wGvxohBoLnxM04L/wj8mQ==} + '@rollup/rollup-win32-x64-gnu@4.52.5': + resolution: {integrity: sha512-UGBUGPFp1vkj6p8wCRraqNhqwX/4kNQPS57BCFc8wYh0g94iVIW33wJtQAx3G7vrjjNtRaxiMUylM0ktp/TRSQ==} cpu: [x64] os: [win32] - '@rollup/rollup-win32-x64-msvc@4.52.4': - resolution: {integrity: sha512-bf9PtUa0u8IXDVxzRToFQKsNCRz9qLYfR/MpECxl4mRoWYjAeFjgxj1XdZr2M/GNVpT05p+LgQOHopYDlUu6/w==} + '@rollup/rollup-win32-x64-msvc@4.52.5': + resolution: {integrity: sha512-TAcgQh2sSkykPRWLrdyy2AiceMckNf5loITqXxFI5VuQjS5tSuw3WlwdN8qv8vzjLAUTvYaH/mVjSFpbkFbpTg==} cpu: [x64] os: [win32] @@ -1083,8 +1083,8 @@ packages: '@swc/types@0.1.25': resolution: {integrity: sha512-iAoY/qRhNH8a/hBvm3zKj9qQ4oc2+3w1unPJa2XvTK3XjeLXtzcCingVPw/9e5mn1+0yPqxcBGp9Jf0pkfMb1g==} - '@tanstack/query-core@5.90.2': - resolution: {integrity: sha512-k/TcR3YalnzibscALLwxeiLUub6jN5EDLwKDiO7q5f4ICEoptJ+n9+7vcEFy5/x/i6Q+Lb/tXrsKCggf5uQJXQ==} + '@tanstack/query-core@5.90.5': + resolution: {integrity: sha512-wLamYp7FaDq6ZnNehypKI5fNvxHPfTYylE0m/ZpuuzJfJqhR5Pxg9gvGBHZx4n7J+V5Rg5mZxHHTlv25Zt5u+w==} '@tanstack/query-devtools@5.90.1': resolution: {integrity: sha512-GtINOPjPUH0OegJExZ70UahT9ykmAhmtNVcmtdnOZbxLwT7R5OmRztR5Ahe3/Cu7LArEmR6/588tAycuaWb1xQ==} @@ -1095,8 +1095,8 @@ packages: '@tanstack/react-query': ^5.90.2 react: ^18 || ^19 - '@tanstack/react-query@5.90.2': - resolution: {integrity: sha512-CLABiR+h5PYfOWr/z+vWFt5VsOA2ekQeRQBFSKlcoW6Ndx/f8rfyVmq4LbgOM4GG2qtxAxjLYLOpCNTYm4uKzw==} + '@tanstack/react-query@5.90.5': + resolution: {integrity: sha512-pN+8UWpxZkEJ/Rnnj2v2Sxpx1WFlaa9L6a4UO89p6tTQbeo+m0MS8oYDjbggrR8QcTyjKoYWKS3xJQGr3ExT8Q==} peerDependencies: react: ^18 || ^19 @@ -1286,14 +1286,14 @@ packages: '@types/ms@2.1.0': resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==} - '@types/node@24.7.0': - resolution: {integrity: sha512-IbKooQVqUBrlzWTi79E8Fw78l8k1RNtlDDNWsFZs7XonuQSJ8oNYfEeclhprUldXISRMLzBpILuKgPlIxm+/Yw==} + '@types/node@24.8.1': + resolution: {integrity: sha512-alv65KGRadQVfVcG69MuB4IzdYVpRwMG/mq8KWOaoOdyY617P5ivaDiMCGOFDWD2sAn5Q0mR3mRtUOgm99hL9Q==} '@types/parse-json@4.0.2': resolution: {integrity: sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==} - '@types/react-dom@19.2.1': - resolution: {integrity: sha512-/EEvYBdT3BflCWvTMO7YkYBHVE9Ci6XdqZciZANQgKpaiDRGOLIlRo91jbTNRQjgPFWVaRxcYc0luVNFitz57A==} + '@types/react-dom@19.2.2': + resolution: {integrity: sha512-9KQPoO6mZCi7jcIStSnlOWn2nEF3mNmyr3rIAsGnAbQKYbRLyqmeSc39EVgtxXVia+LMT8j3knZLAZAh+xLmrw==} peerDependencies: '@types/react': ^19.2.0 @@ -1380,8 +1380,8 @@ packages: balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} - baseline-browser-mapping@2.8.14: - resolution: {integrity: sha512-GM9c0cWWR8Ga7//Ves/9KRgTS8nLausCkP3CGiFLrnwA2CDUluXgaQqvrULoR2Ujrd/mz/lkX87F5BHFsNr5sQ==} + baseline-browser-mapping@2.8.18: + resolution: {integrity: sha512-UYmTpOBwgPScZpS4A+YbapwWuBwasxvO/2IOHArSsAhL/+ZdmATBXTex3t+l2hXwLVYK382ibr/nKoY9GKe86w==} hasBin: true boolbase@1.0.0: @@ -1431,8 +1431,8 @@ packages: resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} engines: {node: '>=10'} - caniuse-lite@1.0.30001749: - resolution: {integrity: sha512-0rw2fJOmLfnzCRbkm8EyHL8SvI2Apu5UbnQuTsJ0ClgrH8hcwFooJ1s5R0EP8o8aVrFu8++ae29Kt9/gZAZp/Q==} + caniuse-lite@1.0.30001751: + resolution: {integrity: sha512-A0QJhug0Ly64Ii3eIqHu5X51ebln3k4yTUkY1j8drqpWHVreg/VLijN48cZ1bYPiqOQuqpkIKnzr/Ul8V+p6Cw==} ccount@2.0.1: resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} @@ -1676,8 +1676,8 @@ packages: resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} engines: {node: '>= 0.4'} - electron-to-chromium@1.5.233: - resolution: {integrity: sha512-iUdTQSf7EFXsDdQsp8MwJz5SVk4APEFqXU/S47OtQ0YLqacSwPXdZ5vRlMX3neb07Cy2vgioNuRnWUXFwuslkg==} + electron-to-chromium@1.5.237: + resolution: {integrity: sha512-icUt1NvfhGLar5lSWH3tHNzablaA5js3HVHacQimfP8ViEBOQv+L7DKEuHdbTZ0SKCO1ogTJTIL1Gwk9S6Qvcg==} emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} @@ -1720,8 +1720,8 @@ packages: es-toolkit@1.40.0: resolution: {integrity: sha512-8o6w0KFmU0CiIl0/Q/BCEOabF2IJaELM1T2PWj6e8KqzHv1gdx+7JtFnDwOx1kJH/isJ5NwlDG1nCr1HrRF94Q==} - esbuild@0.25.10: - resolution: {integrity: sha512-9RiGKvCwaqxO2owP61uQ4BgNborAQskMR6QusfWzQqv7AZOg5oGehdY2pRJMTKuwxd1IDBP4rSbI5lHzU7SMsQ==} + esbuild@0.25.11: + resolution: {integrity: sha512-KohQwyzrKTQmhXDW1PjCv3Tyspn9n5GcY2RTDqeORIdIJY8yKIF7sTSopFmn/wpMPW4rdPXI0UE5LJLuq3bx0Q==} engines: {node: '>=18'} hasBin: true @@ -1775,8 +1775,8 @@ packages: fraction.js@4.3.7: resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==} - framer-motion@12.23.22: - resolution: {integrity: sha512-ZgGvdxXCw55ZYvhoZChTlG6pUuehecgvEAJz0BHoC5pQKW1EC5xf1Mul1ej5+ai+pVY0pylyFfdl45qnM1/GsA==} + framer-motion@12.23.24: + resolution: {integrity: sha512-HMi5HRoRCTou+3fb3h9oTLyJGBxHfW+HnNE25tAXOvVx/IvwMHK0cx7IR4a2ZU6sh3IX1Z+4ts32PcYBOqka8w==} peerDependencies: '@emotion/is-prop-valid': '*' react: ^18.0.0 || ^19.0.0 @@ -1899,8 +1899,8 @@ packages: html-dom-parser@5.1.1: resolution: {integrity: sha512-+o4Y4Z0CLuyemeccvGN4bAO20aauB2N9tFEAep5x4OW34kV4PTarBHm6RL02afYt2BMKcr0D2Agep8S3nJPIBg==} - html-react-parser@5.2.6: - resolution: {integrity: sha512-qcpPWLaSvqXi+TndiHbCa+z8qt0tVzjMwFGFBAa41ggC+ZA5BHaMIeMJla9g3VSp4SmiZb9qyQbmbpHYpIfPOg==} + html-react-parser@5.2.7: + resolution: {integrity: sha512-WzIAcqQoZoF49J9aev8NBDLz9TJvt2RmipeYA+/5+5x0sWCwFxqKiq0lysieiSA/G6dbUZ6KGGy65Cx2fjie5Q==} peerDependencies: '@types/react': 0.14 || 15 || 16 || 17 || 18 || 19 react: 0.14 || 15 || 16 || 17 || 18 || 19 @@ -1917,8 +1917,8 @@ packages: immer@10.1.3: resolution: {integrity: sha512-tmjF/k8QDKydUlm3mZU+tjM6zeq9/fFpPqH9SzWmBnVVKsPBg/V66qsMwb3/Bo90cgUN+ghdVBess+hPsxUyRw==} - immutable@5.1.3: - resolution: {integrity: sha512-+chQdDfvscSF1SJqv2gn4SRO2ZyS3xL3r7IW/wWEEzrzLisnOlKiQu5ytC/BVNcS15C39WT2Hg/bjKjDMcu+zg==} + immutable@5.1.4: + resolution: {integrity: sha512-p6u1bG3YSnINT5RQmx/yRZBpenIl30kVxkTLDyHLIMk0gict704Q9n+thfDI7lTRm9vXdDYutVzXhzcThxTnXA==} import-fresh@3.3.1: resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} @@ -2272,14 +2272,14 @@ packages: resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} engines: {node: '>=16 || 14 >=14.17'} - motion-dom@12.23.21: - resolution: {integrity: sha512-5xDXx/AbhrfgsQmSE7YESMn4Dpo6x5/DTZ4Iyy4xqDvVHWvFVoV+V2Ri2S/ksx+D40wrZ7gPYiMWshkdoqNgNQ==} + motion-dom@12.23.23: + resolution: {integrity: sha512-n5yolOs0TQQBRUFImrRfs/+6X4p3Q4n1dUEqt/H58Vx7OW6RF+foWEgmTVDhIWJIMXOuNNL0apKH2S16en9eiA==} motion-utils@12.23.6: resolution: {integrity: sha512-eAWoPgr4eFEOFfg2WjIsMoqJTW6Z8MTUCgn/GZ3VRpClWBdnbjryiA3ZSNLyxCTmCQx4RmYX6jX1iWHbenUPNQ==} - motion@12.23.22: - resolution: {integrity: sha512-iSq6X9vLHbeYwmHvhK//+U74ROaPnZmBuy60XZzqNl0QtZkWfoZyMDHYnpKuWFv0sNMqHgED8aCXk94LCoQPGg==} + motion@12.23.24: + resolution: {integrity: sha512-Rc5E7oe2YZ72N//S3QXGzbnXgqNrTESv8KKxABR20q2FLch9gHLo0JLyYo2hZ238bZ9Gx6cWhj9VO0IgwbMjCw==} peerDependencies: '@emotion/is-prop-valid': '*' react: ^18.0.0 || ^19.0.0 @@ -2309,8 +2309,8 @@ packages: node-addon-api@7.1.1: resolution: {integrity: sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==} - node-releases@2.0.23: - resolution: {integrity: sha512-cCmFDMSm26S6tQSDpBCg/NR8NENrVPhAJSf+XbxBG4rPFaaonlEoE9wHQmun+cls499TQGSb7ZyPBRlzgKfpeg==} + node-releases@2.0.25: + resolution: {integrity: sha512-4auku8B/vw5psvTiiN9j1dAOsXvMoGqJuKJcR+dTdqiXEK20mMTk1UEo3HS16LeGQsVG6+qKTPM9u/qQ2LqATA==} normalize-package-data@2.5.0: resolution: {integrity: sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==} @@ -2459,8 +2459,8 @@ packages: peerDependencies: react: ^19.2.0 - react-hook-form@7.64.0: - resolution: {integrity: sha512-fnN+vvTiMLnRqKNTVhDysdrUay0kUUAymQnFIznmgDvapjveUWOOPqMNzPg+A+0yf9DuE2h6xzBjN1s+Qx8wcg==} + react-hook-form@7.65.0: + resolution: {integrity: sha512-xtOzDz063WcXvGWaHgLNrNzlsdFgtUWcb32E6WFaGTd7kPZG3EeDusjdZfUsPwKCKVXy1ZlntifaHZ4l8pAsmw==} engines: {node: '>=18.0.0'} peerDependencies: react: ^16.8.0 || ^17 || ^18 || ^19 @@ -2545,8 +2545,8 @@ packages: resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==} engines: {node: '>= 14.18.0'} - recharts@3.2.1: - resolution: {integrity: sha512-0JKwHRiFZdmLq/6nmilxEZl3pqb4T+aKkOkOi/ZISRZwfBhVMgInxzlYU9D4KnCH3KINScLy68m/OvMXoYGZUw==} + recharts@3.3.0: + resolution: {integrity: sha512-Vi0qmTB0iz1+/Cz9o5B7irVyUjX2ynvEgImbgMt/3sKRREcUM07QiYjS1QpAVrkmVlXqy5gykq4nGWMz9AS4Rg==} engines: {node: '>=18'} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 @@ -2594,8 +2594,8 @@ packages: engines: {node: '>= 0.4'} hasBin: true - rollup@4.52.4: - resolution: {integrity: sha512-CLEVl+MnPAiKh5pl4dEWSyMTpuflgNQiLGhMv8ezD5W/qP8AKvmYpCOKRRNOh7oRKnauBZ4SyeYkMS+1VSyKwQ==} + rollup@4.52.5: + resolution: {integrity: sha512-3GuObel8h7Kqdjt0gxkEzaifHTqLVW56Y/bjN7PSQtkKr0w3V/QYSdt6QWYtd7A1xUtYQigtdUfgj1RvWVtorw==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true @@ -2731,11 +2731,11 @@ packages: resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} engines: {node: '>=4'} - style-to-js@1.1.17: - resolution: {integrity: sha512-xQcBGDxJb6jjFCTzvQtfiPn6YvvP2O8U1MDIPNfJQlWMYfktPy+iGsHE7cssjs7y84d9fQaK4UF3RIJaAHSoYA==} + style-to-js@1.1.18: + resolution: {integrity: sha512-JFPn62D4kJaPTnhFUI244MThx+FEGbi+9dw1b9yBBQ+1CZpV7QAT8kUtJ7b7EUNdHajjF/0x8fT+16oLJoojLg==} - style-to-object@1.0.9: - resolution: {integrity: sha512-G4qppLgKu/k6FwRpHiGiKPaPTFcG3g4wNVX/Qsfu+RqQM30E7Tyu/TEgxcL9PNLF5pdRLwQdE3YKKf+KF2Dzlw==} + style-to-object@1.0.11: + resolution: {integrity: sha512-5A560JmXr7wDyGLK12Nq/EYS38VkGlglVzkis1JEdbGWSnbQIEhZzTJhzURXN5/8WwwFCs/f/VVcmkTppbXLow==} stylis@4.2.0: resolution: {integrity: sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==} @@ -2799,8 +2799,8 @@ packages: resolution: {integrity: sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==} engines: {node: '>= 0.4'} - typedoc@0.28.13: - resolution: {integrity: sha512-dNWY8msnYB2a+7Audha+aTF1Pu3euiE7ySp53w8kEsXoYw7dMouV5A1UsTUY345aB152RHnmRMDiovuBi7BD+w==} + typedoc@0.28.14: + resolution: {integrity: sha512-ftJYPvpVfQvFzpkoSfHLkJybdA/geDJ8BGQt/ZnkkhnBYoYW6lBgPQXu6vqLxO4X75dA55hX8Af847H5KXlEFA==} engines: {node: '>= 18', pnpm: '>= 10'} hasBin: true peerDependencies: @@ -2830,8 +2830,8 @@ packages: unified@11.0.5: resolution: {integrity: sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==} - unist-util-is@6.0.0: - resolution: {integrity: sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==} + unist-util-is@6.0.1: + resolution: {integrity: sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==} unist-util-position@5.0.0: resolution: {integrity: sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==} @@ -2839,8 +2839,8 @@ packages: unist-util-stringify-position@4.0.0: resolution: {integrity: sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==} - unist-util-visit-parents@6.0.1: - resolution: {integrity: sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw==} + unist-util-visit-parents@6.0.2: + resolution: {integrity: sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ==} unist-util-visit@5.0.0: resolution: {integrity: sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==} @@ -2851,8 +2851,8 @@ packages: peerDependencies: browserslist: '>= 4.21.0' - use-breakpoint@4.0.6: - resolution: {integrity: sha512-1s7vUjf36eeZYTgY1KkmPNXrTbKJVRA9cjBFQdYjK8+pDr0qJgH6/cuX5qQ2zcfkqxN5LieVd/DTVK6ofnwRTQ==} + use-breakpoint@4.0.10: + resolution: {integrity: sha512-rnUpZwCQCTtexbpM8S5aiJrfIx6NTvt0WwATiH4hCBN6gQNgkYPFoFt6g/3pAuyqU9D9tLKwXfsVqEWMBnwo6A==} peerDependencies: react: '>=18' react-dom: '>=18' @@ -2884,8 +2884,8 @@ packages: victory-vendor@37.3.6: resolution: {integrity: sha512-SbPDPdDBYp+5MJHhBCAyI7wKM3d5ivekigc2Dk2s7pgbZ9wIgIBYGVw4zGHBml/qTFbexrofXW6Gu4noGxrOwQ==} - vite@7.1.9: - resolution: {integrity: sha512-4nVGliEpxmhCL8DslSAUdxlB6+SMrhB0a1v5ijlh1xB1nEPuy1mxaHxysVucLHuWryAxLWg6a5ei+U4TLn/rFg==} + vite@7.1.11: + resolution: {integrity: sha512-uzcxnSDVjAopEUjljkWh8EIrg6tlzrjFUfMcR1EVsRDGwf/ccef0qQPRyOrROwhrTDaApueq+ja+KLPlzR/zdg==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true peerDependencies: @@ -3115,39 +3115,39 @@ snapshots: '@babel/helper-string-parser': 7.27.1 '@babel/helper-validator-identifier': 7.27.1 - '@biomejs/biome@2.2.5': + '@biomejs/biome@2.2.6': optionalDependencies: - '@biomejs/cli-darwin-arm64': 2.2.5 - '@biomejs/cli-darwin-x64': 2.2.5 - '@biomejs/cli-linux-arm64': 2.2.5 - '@biomejs/cli-linux-arm64-musl': 2.2.5 - '@biomejs/cli-linux-x64': 2.2.5 - '@biomejs/cli-linux-x64-musl': 2.2.5 - '@biomejs/cli-win32-arm64': 2.2.5 - '@biomejs/cli-win32-x64': 2.2.5 - - '@biomejs/cli-darwin-arm64@2.2.5': + '@biomejs/cli-darwin-arm64': 2.2.6 + '@biomejs/cli-darwin-x64': 2.2.6 + '@biomejs/cli-linux-arm64': 2.2.6 + '@biomejs/cli-linux-arm64-musl': 2.2.6 + '@biomejs/cli-linux-x64': 2.2.6 + '@biomejs/cli-linux-x64-musl': 2.2.6 + '@biomejs/cli-win32-arm64': 2.2.6 + '@biomejs/cli-win32-x64': 2.2.6 + + '@biomejs/cli-darwin-arm64@2.2.6': optional: true - '@biomejs/cli-darwin-x64@2.2.5': + '@biomejs/cli-darwin-x64@2.2.6': optional: true - '@biomejs/cli-linux-arm64-musl@2.2.5': + '@biomejs/cli-linux-arm64-musl@2.2.6': optional: true - '@biomejs/cli-linux-arm64@2.2.5': + '@biomejs/cli-linux-arm64@2.2.6': optional: true - '@biomejs/cli-linux-x64-musl@2.2.5': + '@biomejs/cli-linux-x64-musl@2.2.6': optional: true - '@biomejs/cli-linux-x64@2.2.5': + '@biomejs/cli-linux-x64@2.2.6': optional: true - '@biomejs/cli-win32-arm64@2.2.5': + '@biomejs/cli-win32-arm64@2.2.6': optional: true - '@biomejs/cli-win32-x64@2.2.5': + '@biomejs/cli-win32-x64@2.2.6': optional: true '@emotion/babel-plugin@11.13.5': @@ -3233,82 +3233,82 @@ snapshots: '@emotion/weak-memoize@0.4.0': {} - '@esbuild/aix-ppc64@0.25.10': + '@esbuild/aix-ppc64@0.25.11': optional: true - '@esbuild/android-arm64@0.25.10': + '@esbuild/android-arm64@0.25.11': optional: true - '@esbuild/android-arm@0.25.10': + '@esbuild/android-arm@0.25.11': optional: true - '@esbuild/android-x64@0.25.10': + '@esbuild/android-x64@0.25.11': optional: true - '@esbuild/darwin-arm64@0.25.10': + '@esbuild/darwin-arm64@0.25.11': optional: true - '@esbuild/darwin-x64@0.25.10': + '@esbuild/darwin-x64@0.25.11': optional: true - '@esbuild/freebsd-arm64@0.25.10': + '@esbuild/freebsd-arm64@0.25.11': optional: true - '@esbuild/freebsd-x64@0.25.10': + '@esbuild/freebsd-x64@0.25.11': optional: true - '@esbuild/linux-arm64@0.25.10': + '@esbuild/linux-arm64@0.25.11': optional: true - '@esbuild/linux-arm@0.25.10': + '@esbuild/linux-arm@0.25.11': optional: true - '@esbuild/linux-ia32@0.25.10': + '@esbuild/linux-ia32@0.25.11': optional: true - '@esbuild/linux-loong64@0.25.10': + '@esbuild/linux-loong64@0.25.11': optional: true - '@esbuild/linux-mips64el@0.25.10': + '@esbuild/linux-mips64el@0.25.11': optional: true - '@esbuild/linux-ppc64@0.25.10': + '@esbuild/linux-ppc64@0.25.11': optional: true - '@esbuild/linux-riscv64@0.25.10': + '@esbuild/linux-riscv64@0.25.11': optional: true - '@esbuild/linux-s390x@0.25.10': + '@esbuild/linux-s390x@0.25.11': optional: true - '@esbuild/linux-x64@0.25.10': + '@esbuild/linux-x64@0.25.11': optional: true - '@esbuild/netbsd-arm64@0.25.10': + '@esbuild/netbsd-arm64@0.25.11': optional: true - '@esbuild/netbsd-x64@0.25.10': + '@esbuild/netbsd-x64@0.25.11': optional: true - '@esbuild/openbsd-arm64@0.25.10': + '@esbuild/openbsd-arm64@0.25.11': optional: true - '@esbuild/openbsd-x64@0.25.10': + '@esbuild/openbsd-x64@0.25.11': optional: true - '@esbuild/openharmony-arm64@0.25.10': + '@esbuild/openharmony-arm64@0.25.11': optional: true - '@esbuild/sunos-x64@0.25.10': + '@esbuild/sunos-x64@0.25.11': optional: true - '@esbuild/win32-arm64@0.25.10': + '@esbuild/win32-arm64@0.25.11': optional: true - '@esbuild/win32-ia32@0.25.10': + '@esbuild/win32-ia32@0.25.11': optional: true - '@esbuild/win32-x64@0.25.10': + '@esbuild/win32-x64@0.25.11': optional: true '@floating-ui/core@1.7.3': @@ -3336,7 +3336,7 @@ snapshots: '@floating-ui/utils@0.2.10': {} - '@gerrit0/mini-shiki@3.13.0': + '@gerrit0/mini-shiki@3.13.1': dependencies: '@shikijs/engine-oniguruma': 3.13.0 '@shikijs/langs': 3.13.0 @@ -3360,9 +3360,9 @@ snapshots: - '@types/react' - supports-color - '@hookform/resolvers@3.10.0(react-hook-form@7.64.0(react@19.2.0))': + '@hookform/resolvers@3.10.0(react-hook-form@7.65.0(react@19.2.0))': dependencies: - react-hook-form: 7.64.0(react@19.2.0) + react-hook-form: 7.65.0(react@19.2.0) '@jridgewell/gen-mapping@0.3.13': dependencies: @@ -3458,7 +3458,7 @@ snapshots: '@react-hook/passive-layout-effect': 1.2.1(react@19.2.0) react: 19.2.0 - '@reduxjs/toolkit@2.9.0(react-redux@9.2.0(@types/react@19.2.2)(react@19.2.0)(redux@5.0.1))(react@19.2.0)': + '@reduxjs/toolkit@2.9.1(react-redux@9.2.0(@types/react@19.2.2)(react@19.2.0)(redux@5.0.1))(react@19.2.0)': dependencies: '@standard-schema/spec': 1.0.0 '@standard-schema/utils': 0.3.0 @@ -3476,70 +3476,70 @@ snapshots: '@rolldown/pluginutils@1.0.0-beta.38': {} - '@rollup/rollup-android-arm-eabi@4.52.4': + '@rollup/rollup-android-arm-eabi@4.52.5': optional: true - '@rollup/rollup-android-arm64@4.52.4': + '@rollup/rollup-android-arm64@4.52.5': optional: true - '@rollup/rollup-darwin-arm64@4.52.4': + '@rollup/rollup-darwin-arm64@4.52.5': optional: true - '@rollup/rollup-darwin-x64@4.52.4': + '@rollup/rollup-darwin-x64@4.52.5': optional: true - '@rollup/rollup-freebsd-arm64@4.52.4': + '@rollup/rollup-freebsd-arm64@4.52.5': optional: true - '@rollup/rollup-freebsd-x64@4.52.4': + '@rollup/rollup-freebsd-x64@4.52.5': optional: true - '@rollup/rollup-linux-arm-gnueabihf@4.52.4': + '@rollup/rollup-linux-arm-gnueabihf@4.52.5': optional: true - '@rollup/rollup-linux-arm-musleabihf@4.52.4': + '@rollup/rollup-linux-arm-musleabihf@4.52.5': optional: true - '@rollup/rollup-linux-arm64-gnu@4.52.4': + '@rollup/rollup-linux-arm64-gnu@4.52.5': optional: true - '@rollup/rollup-linux-arm64-musl@4.52.4': + '@rollup/rollup-linux-arm64-musl@4.52.5': optional: true - '@rollup/rollup-linux-loong64-gnu@4.52.4': + '@rollup/rollup-linux-loong64-gnu@4.52.5': optional: true - '@rollup/rollup-linux-ppc64-gnu@4.52.4': + '@rollup/rollup-linux-ppc64-gnu@4.52.5': optional: true - '@rollup/rollup-linux-riscv64-gnu@4.52.4': + '@rollup/rollup-linux-riscv64-gnu@4.52.5': optional: true - '@rollup/rollup-linux-riscv64-musl@4.52.4': + '@rollup/rollup-linux-riscv64-musl@4.52.5': optional: true - '@rollup/rollup-linux-s390x-gnu@4.52.4': + '@rollup/rollup-linux-s390x-gnu@4.52.5': optional: true - '@rollup/rollup-linux-x64-gnu@4.52.4': + '@rollup/rollup-linux-x64-gnu@4.52.5': optional: true - '@rollup/rollup-linux-x64-musl@4.52.4': + '@rollup/rollup-linux-x64-musl@4.52.5': optional: true - '@rollup/rollup-openharmony-arm64@4.52.4': + '@rollup/rollup-openharmony-arm64@4.52.5': optional: true - '@rollup/rollup-win32-arm64-msvc@4.52.4': + '@rollup/rollup-win32-arm64-msvc@4.52.5': optional: true - '@rollup/rollup-win32-ia32-msvc@4.52.4': + '@rollup/rollup-win32-ia32-msvc@4.52.5': optional: true - '@rollup/rollup-win32-x64-gnu@4.52.4': + '@rollup/rollup-win32-x64-gnu@4.52.5': optional: true - '@rollup/rollup-win32-x64-msvc@4.52.4': + '@rollup/rollup-win32-x64-msvc@4.52.5': optional: true '@shikijs/engine-oniguruma@3.13.0': @@ -3746,19 +3746,19 @@ snapshots: dependencies: '@swc/counter': 0.1.3 - '@tanstack/query-core@5.90.2': {} + '@tanstack/query-core@5.90.5': {} '@tanstack/query-devtools@5.90.1': {} - '@tanstack/react-query-devtools@5.90.2(@tanstack/react-query@5.90.2(react@19.2.0))(react@19.2.0)': + '@tanstack/react-query-devtools@5.90.2(@tanstack/react-query@5.90.5(react@19.2.0))(react@19.2.0)': dependencies: '@tanstack/query-devtools': 5.90.1 - '@tanstack/react-query': 5.90.2(react@19.2.0) + '@tanstack/react-query': 5.90.5(react@19.2.0) react: 19.2.0 - '@tanstack/react-query@5.90.2(react@19.2.0)': + '@tanstack/react-query@5.90.5(react@19.2.0)': dependencies: - '@tanstack/query-core': 5.90.2 + '@tanstack/query-core': 5.90.5 react: 19.2.0 '@tanstack/react-virtual@3.13.12(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': @@ -3935,13 +3935,13 @@ snapshots: '@types/ms@2.1.0': {} - '@types/node@24.7.0': + '@types/node@24.8.1': dependencies: undici-types: 7.14.0 '@types/parse-json@4.0.2': {} - '@types/react-dom@19.2.1(@types/react@19.2.2)': + '@types/react-dom@19.2.2(@types/react@19.2.2)': dependencies: '@types/react': 19.2.2 @@ -3964,15 +3964,15 @@ snapshots: '@use-gesture/core': 10.3.1 react: 19.2.0 - '@vitejs/plugin-react-swc@4.1.0(vite@7.1.9(@types/node@24.7.0)(sass@1.92.1)(yaml@2.8.1))': + '@vitejs/plugin-react-swc@4.1.0(vite@7.1.11(@types/node@24.8.1)(sass@1.92.1)(yaml@2.8.1))': dependencies: '@rolldown/pluginutils': 1.0.0-beta.35 '@swc/core': 1.13.5 - vite: 7.1.9(@types/node@24.7.0)(sass@1.92.1)(yaml@2.8.1) + vite: 7.1.11(@types/node@24.8.1)(sass@1.92.1)(yaml@2.8.1) transitivePeerDependencies: - '@swc/helpers' - '@vitejs/plugin-react@5.0.4(vite@7.1.9(@types/node@24.7.0)(sass@1.92.1)(yaml@2.8.1))': + '@vitejs/plugin-react@5.0.4(vite@7.1.11(@types/node@24.8.1)(sass@1.92.1)(yaml@2.8.1))': dependencies: '@babel/core': 7.28.4 '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.28.4) @@ -3980,7 +3980,7 @@ snapshots: '@rolldown/pluginutils': 1.0.0-beta.38 '@types/babel__core': 7.20.5 react-refresh: 0.17.0 - vite: 7.1.9(@types/node@24.7.0)(sass@1.92.1)(yaml@2.8.1) + vite: 7.1.11(@types/node@24.8.1)(sass@1.92.1)(yaml@2.8.1) transitivePeerDependencies: - supports-color @@ -4016,7 +4016,7 @@ snapshots: autoprefixer@10.4.21(postcss@8.5.6): dependencies: browserslist: 4.26.3 - caniuse-lite: 1.0.30001749 + caniuse-lite: 1.0.30001751 fraction.js: 4.3.7 normalize-range: 0.1.2 picocolors: 1.1.1 @@ -4037,7 +4037,7 @@ snapshots: balanced-match@1.0.2: {} - baseline-browser-mapping@2.8.14: {} + baseline-browser-mapping@2.8.18: {} boolbase@1.0.0: {} @@ -4057,10 +4057,10 @@ snapshots: browserslist@4.26.3: dependencies: - baseline-browser-mapping: 2.8.14 - caniuse-lite: 1.0.30001749 - electron-to-chromium: 1.5.233 - node-releases: 2.0.23 + baseline-browser-mapping: 2.8.18 + caniuse-lite: 1.0.30001751 + electron-to-chromium: 1.5.237 + node-releases: 2.0.25 update-browserslist-db: 1.1.3(browserslist@4.26.3) byte-size@9.0.1: {} @@ -4086,7 +4086,7 @@ snapshots: camelcase@6.3.0: {} - caniuse-lite@1.0.30001749: {} + caniuse-lite@1.0.30001751: {} ccount@2.0.1: {} @@ -4326,7 +4326,7 @@ snapshots: es-errors: 1.3.0 gopd: 1.2.0 - electron-to-chromium@1.5.233: {} + electron-to-chromium@1.5.237: {} emoji-regex@8.0.0: {} @@ -4418,34 +4418,34 @@ snapshots: es-toolkit@1.40.0: {} - esbuild@0.25.10: + esbuild@0.25.11: optionalDependencies: - '@esbuild/aix-ppc64': 0.25.10 - '@esbuild/android-arm': 0.25.10 - '@esbuild/android-arm64': 0.25.10 - '@esbuild/android-x64': 0.25.10 - '@esbuild/darwin-arm64': 0.25.10 - '@esbuild/darwin-x64': 0.25.10 - '@esbuild/freebsd-arm64': 0.25.10 - '@esbuild/freebsd-x64': 0.25.10 - '@esbuild/linux-arm': 0.25.10 - '@esbuild/linux-arm64': 0.25.10 - '@esbuild/linux-ia32': 0.25.10 - '@esbuild/linux-loong64': 0.25.10 - '@esbuild/linux-mips64el': 0.25.10 - '@esbuild/linux-ppc64': 0.25.10 - '@esbuild/linux-riscv64': 0.25.10 - '@esbuild/linux-s390x': 0.25.10 - '@esbuild/linux-x64': 0.25.10 - '@esbuild/netbsd-arm64': 0.25.10 - '@esbuild/netbsd-x64': 0.25.10 - '@esbuild/openbsd-arm64': 0.25.10 - '@esbuild/openbsd-x64': 0.25.10 - '@esbuild/openharmony-arm64': 0.25.10 - '@esbuild/sunos-x64': 0.25.10 - '@esbuild/win32-arm64': 0.25.10 - '@esbuild/win32-ia32': 0.25.10 - '@esbuild/win32-x64': 0.25.10 + '@esbuild/aix-ppc64': 0.25.11 + '@esbuild/android-arm': 0.25.11 + '@esbuild/android-arm64': 0.25.11 + '@esbuild/android-x64': 0.25.11 + '@esbuild/darwin-arm64': 0.25.11 + '@esbuild/darwin-x64': 0.25.11 + '@esbuild/freebsd-arm64': 0.25.11 + '@esbuild/freebsd-x64': 0.25.11 + '@esbuild/linux-arm': 0.25.11 + '@esbuild/linux-arm64': 0.25.11 + '@esbuild/linux-ia32': 0.25.11 + '@esbuild/linux-loong64': 0.25.11 + '@esbuild/linux-mips64el': 0.25.11 + '@esbuild/linux-ppc64': 0.25.11 + '@esbuild/linux-riscv64': 0.25.11 + '@esbuild/linux-s390x': 0.25.11 + '@esbuild/linux-x64': 0.25.11 + '@esbuild/netbsd-arm64': 0.25.11 + '@esbuild/netbsd-x64': 0.25.11 + '@esbuild/openbsd-arm64': 0.25.11 + '@esbuild/openbsd-x64': 0.25.11 + '@esbuild/openharmony-arm64': 0.25.11 + '@esbuild/sunos-x64': 0.25.11 + '@esbuild/win32-arm64': 0.25.11 + '@esbuild/win32-ia32': 0.25.11 + '@esbuild/win32-x64': 0.25.11 escalade@3.2.0: {} @@ -4480,9 +4480,9 @@ snapshots: fraction.js@4.3.7: {} - framer-motion@12.23.22(@emotion/is-prop-valid@1.4.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0): + framer-motion@12.23.24(@emotion/is-prop-valid@1.4.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0): dependencies: - motion-dom: 12.23.21 + motion-dom: 12.23.23 motion-utils: 12.23.6 tslib: 2.8.1 optionalDependencies: @@ -4601,7 +4601,7 @@ snapshots: mdast-util-mdxjs-esm: 2.0.1 property-information: 7.1.0 space-separated-tokens: 2.0.2 - style-to-js: 1.1.17 + style-to-js: 1.1.18 unist-util-position: 5.0.0 vfile-message: 4.0.3 transitivePeerDependencies: @@ -4622,13 +4622,13 @@ snapshots: domhandler: 5.0.3 htmlparser2: 10.0.0 - html-react-parser@5.2.6(@types/react@19.2.2)(react@19.2.0): + html-react-parser@5.2.7(@types/react@19.2.2)(react@19.2.0): dependencies: domhandler: 5.0.3 html-dom-parser: 5.1.1 react: 19.2.0 react-property: 2.0.2 - style-to-js: 1.1.17 + style-to-js: 1.1.18 optionalDependencies: '@types/react': 19.2.2 @@ -4643,7 +4643,7 @@ snapshots: immer@10.1.3: {} - immutable@5.1.3: {} + immutable@5.1.4: {} import-fresh@3.3.1: dependencies: @@ -4924,7 +4924,7 @@ snapshots: mdast-util-phrasing@4.1.0: dependencies: '@types/mdast': 4.0.4 - unist-util-is: 6.0.0 + unist-util-is: 6.0.1 mdast-util-to-hast@13.2.0: dependencies: @@ -5121,15 +5121,15 @@ snapshots: dependencies: brace-expansion: 2.0.2 - motion-dom@12.23.21: + motion-dom@12.23.23: dependencies: motion-utils: 12.23.6 motion-utils@12.23.6: {} - motion@12.23.22(@emotion/is-prop-valid@1.4.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0): + motion@12.23.24(@emotion/is-prop-valid@1.4.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0): dependencies: - framer-motion: 12.23.22(@emotion/is-prop-valid@1.4.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + framer-motion: 12.23.24(@emotion/is-prop-valid@1.4.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) tslib: 2.8.1 optionalDependencies: '@emotion/is-prop-valid': 1.4.0 @@ -5150,7 +5150,7 @@ snapshots: node-addon-api@7.1.1: optional: true - node-releases@2.0.23: {} + node-releases@2.0.25: {} normalize-package-data@2.5.0: dependencies: @@ -5293,7 +5293,7 @@ snapshots: react: 19.2.0 scheduler: 0.27.0 - react-hook-form@7.64.0(react@19.2.0): + react-hook-form@7.65.0(react@19.2.0): dependencies: react: 19.2.0 @@ -5375,9 +5375,9 @@ snapshots: readdirp@4.1.2: {} - recharts@3.2.1(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react-is@18.3.1)(react@19.2.0)(redux@5.0.1): + recharts@3.3.0(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react-is@18.3.1)(react@19.2.0)(redux@5.0.1): dependencies: - '@reduxjs/toolkit': 2.9.0(react-redux@9.2.0(@types/react@19.2.2)(react@19.2.0)(redux@5.0.1))(react@19.2.0) + '@reduxjs/toolkit': 2.9.1(react-redux@9.2.0(@types/react@19.2.2)(react@19.2.0)(redux@5.0.1))(react@19.2.0) clsx: 2.1.1 decimal.js-light: 2.5.1 es-toolkit: 1.40.0 @@ -5455,32 +5455,32 @@ snapshots: path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 - rollup@4.52.4: + rollup@4.52.5: dependencies: '@types/estree': 1.0.8 optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.52.4 - '@rollup/rollup-android-arm64': 4.52.4 - '@rollup/rollup-darwin-arm64': 4.52.4 - '@rollup/rollup-darwin-x64': 4.52.4 - '@rollup/rollup-freebsd-arm64': 4.52.4 - '@rollup/rollup-freebsd-x64': 4.52.4 - '@rollup/rollup-linux-arm-gnueabihf': 4.52.4 - '@rollup/rollup-linux-arm-musleabihf': 4.52.4 - '@rollup/rollup-linux-arm64-gnu': 4.52.4 - '@rollup/rollup-linux-arm64-musl': 4.52.4 - '@rollup/rollup-linux-loong64-gnu': 4.52.4 - '@rollup/rollup-linux-ppc64-gnu': 4.52.4 - '@rollup/rollup-linux-riscv64-gnu': 4.52.4 - '@rollup/rollup-linux-riscv64-musl': 4.52.4 - '@rollup/rollup-linux-s390x-gnu': 4.52.4 - '@rollup/rollup-linux-x64-gnu': 4.52.4 - '@rollup/rollup-linux-x64-musl': 4.52.4 - '@rollup/rollup-openharmony-arm64': 4.52.4 - '@rollup/rollup-win32-arm64-msvc': 4.52.4 - '@rollup/rollup-win32-ia32-msvc': 4.52.4 - '@rollup/rollup-win32-x64-gnu': 4.52.4 - '@rollup/rollup-win32-x64-msvc': 4.52.4 + '@rollup/rollup-android-arm-eabi': 4.52.5 + '@rollup/rollup-android-arm64': 4.52.5 + '@rollup/rollup-darwin-arm64': 4.52.5 + '@rollup/rollup-darwin-x64': 4.52.5 + '@rollup/rollup-freebsd-arm64': 4.52.5 + '@rollup/rollup-freebsd-x64': 4.52.5 + '@rollup/rollup-linux-arm-gnueabihf': 4.52.5 + '@rollup/rollup-linux-arm-musleabihf': 4.52.5 + '@rollup/rollup-linux-arm64-gnu': 4.52.5 + '@rollup/rollup-linux-arm64-musl': 4.52.5 + '@rollup/rollup-linux-loong64-gnu': 4.52.5 + '@rollup/rollup-linux-ppc64-gnu': 4.52.5 + '@rollup/rollup-linux-riscv64-gnu': 4.52.5 + '@rollup/rollup-linux-riscv64-musl': 4.52.5 + '@rollup/rollup-linux-s390x-gnu': 4.52.5 + '@rollup/rollup-linux-x64-gnu': 4.52.5 + '@rollup/rollup-linux-x64-musl': 4.52.5 + '@rollup/rollup-openharmony-arm64': 4.52.5 + '@rollup/rollup-win32-arm64-msvc': 4.52.5 + '@rollup/rollup-win32-ia32-msvc': 4.52.5 + '@rollup/rollup-win32-x64-gnu': 4.52.5 + '@rollup/rollup-win32-x64-msvc': 4.52.5 fsevents: 2.3.3 rxjs@7.8.2: @@ -5509,7 +5509,7 @@ snapshots: sass@1.92.1: dependencies: chokidar: 4.0.3 - immutable: 5.1.3 + immutable: 5.1.4 source-map-js: 1.2.1 optionalDependencies: '@parcel/watcher': 2.5.1 @@ -5655,11 +5655,11 @@ snapshots: strip-bom@3.0.0: {} - style-to-js@1.1.17: + style-to-js@1.1.18: dependencies: - style-to-object: 1.0.9 + style-to-object: 1.0.11 - style-to-object@1.0.9: + style-to-object@1.0.11: dependencies: inline-style-parser: 0.2.4 @@ -5740,9 +5740,9 @@ snapshots: possible-typed-array-names: 1.1.0 reflect.getprototypeof: 1.0.10 - typedoc@0.28.13(typescript@5.9.3): + typedoc@0.28.14(typescript@5.9.3): dependencies: - '@gerrit0/mini-shiki': 3.13.0 + '@gerrit0/mini-shiki': 3.13.1 lunr: 2.3.9 markdown-it: 14.1.0 minimatch: 9.0.5 @@ -5776,7 +5776,7 @@ snapshots: trough: 2.2.0 vfile: 6.0.3 - unist-util-is@6.0.0: + unist-util-is@6.0.1: dependencies: '@types/unist': 3.0.3 @@ -5788,16 +5788,16 @@ snapshots: dependencies: '@types/unist': 3.0.3 - unist-util-visit-parents@6.0.1: + unist-util-visit-parents@6.0.2: dependencies: '@types/unist': 3.0.3 - unist-util-is: 6.0.0 + unist-util-is: 6.0.1 unist-util-visit@5.0.0: dependencies: '@types/unist': 3.0.3 - unist-util-is: 6.0.0 - unist-util-visit-parents: 6.0.1 + unist-util-is: 6.0.1 + unist-util-visit-parents: 6.0.2 update-browserslist-db@1.1.3(browserslist@4.26.3): dependencies: @@ -5805,7 +5805,7 @@ snapshots: escalade: 3.2.0 picocolors: 1.1.1 - use-breakpoint@4.0.6(react-dom@19.2.0(react@19.2.0))(react@19.2.0): + use-breakpoint@4.0.10(react-dom@19.2.0(react@19.2.0))(react@19.2.0): dependencies: react: 19.2.0 react-dom: 19.2.0(react@19.2.0) @@ -5854,16 +5854,16 @@ snapshots: d3-time: 3.1.0 d3-timer: 3.0.1 - vite@7.1.9(@types/node@24.7.0)(sass@1.92.1)(yaml@2.8.1): + vite@7.1.11(@types/node@24.8.1)(sass@1.92.1)(yaml@2.8.1): dependencies: - esbuild: 0.25.10 + esbuild: 0.25.11 fdir: 6.5.0(picomatch@4.0.3) picomatch: 4.0.3 postcss: 8.5.6 - rollup: 4.52.4 + rollup: 4.52.5 tinyglobby: 0.2.15 optionalDependencies: - '@types/node': 24.7.0 + '@types/node': 24.8.1 fsevents: 2.3.3 sass: 1.92.1 yaml: 2.8.1 diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index 768009b8..f8cca8ea 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -234,7 +234,7 @@ dependencies = [ "rustc-hash", "serde", "serde_derive", - "syn 2.0.106", + "syn 2.0.107", ] [[package]] @@ -390,7 +390,7 @@ checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.107", ] [[package]] @@ -451,7 +451,7 @@ checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.107", ] [[package]] @@ -576,11 +576,11 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.9.4" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2261d10cca569e4643e526d8dc2e62e433cc8aba21ab764233731f8d369bf394" +checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" dependencies = [ - "serde", + "serde_core", ] [[package]] @@ -688,7 +688,7 @@ dependencies = [ "proc-macro-crate 3.4.0", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.107", ] [[package]] @@ -784,7 +784,7 @@ version = "0.18.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ca26ef0159422fb77631dc9d17b102f253b876fe1586b03b803e63a309b4ee2" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "cairo-sys-rs", "glib", "libc", @@ -976,7 +976,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.107", ] [[package]] @@ -1119,7 +1119,7 @@ version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fa95a34622365fa5bbf40b20b75dba8dfa8c94c734aea8ac9a5ca38af14316f1" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "core-foundation 0.10.1", "core-graphics-types", "foreign-types 0.5.0", @@ -1132,7 +1132,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d44a101f213f6c4cdc1853d4b78aef6db6bdfa3468798cc1d9912f4735013eb" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "core-foundation 0.10.1", "libc", ] @@ -1235,7 +1235,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331" dependencies = [ "quote", - "syn 2.0.106", + "syn 2.0.107", ] [[package]] @@ -1245,7 +1245,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a2785755761f3ddc1492979ce1e48d2c00d09311c39e4466429188f3dd6501" dependencies = [ "quote", - "syn 2.0.106", + "syn 2.0.107", ] [[package]] @@ -1272,7 +1272,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.107", ] [[package]] @@ -1320,7 +1320,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.106", + "syn 2.0.107", ] [[package]] @@ -1334,7 +1334,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.106", + "syn 2.0.107", ] [[package]] @@ -1345,7 +1345,7 @@ checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" dependencies = [ "darling_core 0.20.11", "quote", - "syn 2.0.106", + "syn 2.0.107", ] [[package]] @@ -1356,7 +1356,7 @@ checksum = "d38308df82d1080de0afee5d069fa14b0326a88c14f15c5ccda35b4a6c414c81" dependencies = [ "darling_core 0.21.3", "quote", - "syn 2.0.106", + "syn 2.0.107", ] [[package]] @@ -1504,7 +1504,7 @@ dependencies = [ "darling 0.20.11", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.107", ] [[package]] @@ -1514,7 +1514,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c" dependencies = [ "derive_builder_core", - "syn 2.0.106", + "syn 2.0.107", ] [[package]] @@ -1527,7 +1527,7 @@ dependencies = [ "proc-macro2", "quote", "rustc_version", - "syn 2.0.106", + "syn 2.0.107", ] [[package]] @@ -1596,7 +1596,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "89a09f22a6c6069a18470eb92d2298acf25463f14256d24778e1230d789a2aec" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "block2 0.6.2", "libc", "objc2 0.6.3", @@ -1610,7 +1610,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.107", ] [[package]] @@ -1642,7 +1642,7 @@ checksum = "788160fb30de9cdd857af31c6a2675904b16ece8fc2737b2c7127ba368c9d0f4" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.107", ] [[package]] @@ -1773,7 +1773,7 @@ checksum = "67c78a4d8fdf9953a5c9d458f9efe940fd97a0cab0941c075a813ac594733827" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.107", ] [[package]] @@ -1880,7 +1880,7 @@ checksum = "a0aca10fb742cb43f9e7bb8467c91aa9bcb8e3ffbc6a6f7389bb93ffc920577d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.107", ] [[package]] @@ -1995,7 +1995,7 @@ checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.107", ] [[package]] @@ -2109,7 +2109,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.107", ] [[package]] @@ -2345,7 +2345,7 @@ version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2deb07a133b1520dc1a5690e9bd08950108873d7ed5de38dcc74d3b5ebffa110" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "libc", "libgit2-sys", "log", @@ -2358,7 +2358,7 @@ version = "0.18.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "233daaf6e83ae6a12a52055f568f9d7cf4671dabb78ff9560ab6da230ce00ee5" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "futures-channel", "futures-core", "futures-executor", @@ -2386,7 +2386,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.107", ] [[package]] @@ -2488,7 +2488,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.107", ] [[package]] @@ -2503,7 +2503,7 @@ dependencies = [ "futures-core", "futures-sink", "http", - "indexmap 2.11.4", + "indexmap 2.12.0", "slab", "tokio", "tokio-util", @@ -2940,9 +2940,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.11.4" +version = "2.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b0f83760fb341a774ed326568e19f5a863af4a952def8c39f9ab92fd95b88e5" +checksum = "6717a8d2a5a929a1a2eb43a12812498ed141a0bcfb7e8f7844fbdbe4303bba9f" dependencies = [ "equivalent", "hashbrown 0.16.0", @@ -3139,7 +3139,7 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b750dcadc39a09dbadd74e118f6dd6598df77fa01df0cfcdc52c28dece74528a" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "serde", "unicode-segmentation", ] @@ -3152,7 +3152,7 @@ checksum = "02cb977175687f33fa4afa0c95c112b987ea1443e5a51c8f8ff27dc618270cc2" dependencies = [ "cssparser", "html5ever", - "indexmap 2.11.4", + "indexmap 2.12.0", "selectors", ] @@ -3248,7 +3248,7 @@ version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "416f7e718bdb06000964960ffa43b4335ad4012ae8b99060261aa4a8088d5ccb" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "libc", "redox_syscall", ] @@ -3365,7 +3365,7 @@ checksum = "88a9689d8d44bf9964484516275f5cd4c9b59457a6940c1d5d0ecbb94510a36b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.107", ] [[package]] @@ -3438,13 +3438,13 @@ dependencies = [ [[package]] name = "mio" -version = "1.0.4" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c" +checksum = "69d83b0086dc8ecf3ce9ae2874b2d1290252e2a30720bea58a5c6639b0092873" dependencies = [ "libc", "wasi 0.11.1+wasi-snapshot-preview1", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -3507,7 +3507,7 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3f42e7bbe13d351b6bead8286a43aac9534b82bd3cc43e47037f012ebfd62d4" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "jni-sys", "log", "ndk-sys", @@ -3555,7 +3555,7 @@ version = "0.25.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3ec2f5b6839be2a19d7fa5aab5bc444380f6311c2b693551cb80f45caaa7b5ef" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "libc", "log", "netlink-packet-core", @@ -3607,7 +3607,7 @@ version = "0.30.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "74523f3a35e05aba87a1d978330aef40f67b0304ac79c1c00b294c9830543db6" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "cfg-if", "cfg_aliases", "libc", @@ -3708,9 +3708,9 @@ dependencies = [ [[package]] name = "num_enum" -version = "0.7.4" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a973b4e44ce6cad84ce69d797acf9a044532e4184c4f267913d1b546a0727b7a" +checksum = "b1207a7e20ad57b847bbddc6776b968420d38292bbfe2089accff5e19e82454c" dependencies = [ "num_enum_derive", "rustversion", @@ -3718,14 +3718,14 @@ dependencies = [ [[package]] name = "num_enum_derive" -version = "0.7.4" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77e878c846a8abae00dd069496dbe8751b16ac1c3d6bd2a7283a938e8228f90d" +checksum = "ff32365de1b6743cb203b710788263c44a03de03802daf96092f2da4fe6ba4d7" dependencies = [ "proc-macro-crate 3.4.0", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.107", ] [[package]] @@ -3769,7 +3769,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d49e936b501e5c5bf01fda3a9452ff86dc3ea98ad5f283e1455153142d97518c" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "block2 0.6.2", "libc", "objc2 0.6.3", @@ -3790,7 +3790,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73ad74d880bb43877038da939b7427bba67e9dd42004a18b809ba7d87cee241c" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "objc2 0.6.3", "objc2-foundation 0.3.2", ] @@ -3801,7 +3801,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b402a653efbb5e82ce4df10683b6b28027616a2715e90009947d50b8dd298fa" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "objc2 0.6.3", "objc2-foundation 0.3.2", ] @@ -3812,7 +3812,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "dispatch2", "objc2 0.6.3", ] @@ -3823,7 +3823,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e022c9d066895efa1345f8e33e584b9f958da2fd4cd116792e15e07e4720a807" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "dispatch2", "objc2 0.6.3", "objc2-core-foundation", @@ -3846,7 +3846,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0cde0dfb48d25d2b4862161a4d5fcc0e3c24367869ad306b0c9ec0073bfed92d" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "objc2 0.6.3", "objc2-core-foundation", "objc2-core-graphics", @@ -3858,7 +3858,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d425caf1df73233f29fd8a5c3e5edbc30d2d4307870f802d18f00d83dc5141a6" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "objc2 0.6.3", "objc2-core-foundation", "objc2-core-graphics", @@ -3886,7 +3886,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ee638a5da3799329310ad4cfa62fbf045d5f56e3ef5ba4149e7452dcf89d5a8" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "block2 0.5.1", "libc", "objc2 0.5.2", @@ -3898,7 +3898,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3e0adef53c21f888deb4fa59fc59f7eb17404926ee8a6f59f5df0fd7f9f3272" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "block2 0.6.2", "libc", "objc2 0.6.3", @@ -3911,7 +3911,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "180788110936d59bab6bd83b6060ffdfffb3b922ba1396b312ae795e1de9d81d" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "objc2 0.6.3", "objc2-core-foundation", ] @@ -3932,7 +3932,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd0cba1276f6023976a406a14ffa85e1fdd19df6b0f737b063b95f6c8c7aadd6" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "block2 0.5.1", "objc2 0.5.2", "objc2-foundation 0.2.2", @@ -3944,7 +3944,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e42bee7bff906b14b167da2bac5efe6b6a07e6f7c0a21a7308d40c960242dc7a" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "block2 0.5.1", "objc2 0.5.2", "objc2-foundation 0.2.2", @@ -3957,7 +3957,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96c1358452b371bf9f104e21ec536d37a650eb10f7ee379fff67d2e08d537f1f" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "objc2 0.6.3", "objc2-foundation 0.3.2", ] @@ -3968,7 +3968,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "709fe137109bd1e8b5a99390f77a7d8b2961dafc1a1c5db8f2e60329ad6d895a" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "objc2 0.6.3", "objc2-core-foundation", ] @@ -3979,7 +3979,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d87d638e33c06f577498cbcc50491496a3ed4246998a7fbba7ccb98b1e7eab22" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "objc2 0.6.3", "objc2-core-foundation", "objc2-foundation 0.3.2", @@ -3991,7 +3991,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b2e5aaab980c433cf470df9d7af96a7b46a9d892d521a2cbbb2f8a4c16751e7f" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "block2 0.6.2", "objc2 0.6.3", "objc2-app-kit", @@ -4033,11 +4033,11 @@ dependencies = [ [[package]] name = "openssl" -version = "0.10.73" +version = "0.10.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8505734d46c8ab1e19a1dce3aef597ad87dcb4c37e7188231769bd6bd51cebf8" +checksum = "24ad14dd45412269e1a30f52ad8f0664f0f4f4a89ee8fe28c3b3527021ebb654" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "cfg-if", "foreign-types 0.3.2", "libc", @@ -4054,7 +4054,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.107", ] [[package]] @@ -4074,9 +4074,9 @@ dependencies = [ [[package]] name = "openssl-sys" -version = "0.9.109" +version = "0.9.110" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90096e2e47630d78b7d1c20952dc621f957103f8bc2c8359ec81290d75238571" +checksum = "0a9f0075ba3c21b09f8e8b2026584b1d18d49388648f2fbbf3c97ea8deced8e2" dependencies = [ "cc", "libc", @@ -4227,7 +4227,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" dependencies = [ "fixedbitset 0.4.2", - "indexmap 2.11.4", + "indexmap 2.12.0", ] [[package]] @@ -4237,7 +4237,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3672b37090dbd86368a4145bc067582552b29c27377cad4e0a306c97f9bd7772" dependencies = [ "fixedbitset 0.5.7", - "indexmap 2.11.4", + "indexmap 2.12.0", ] [[package]] @@ -4344,7 +4344,7 @@ dependencies = [ "phf_shared 0.11.3", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.107", ] [[package]] @@ -4391,7 +4391,7 @@ checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.107", ] [[package]] @@ -4457,7 +4457,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "740ebea15c5d1428f910cd1a5f52cebf8d25006245ed8ade92702f4943d91e07" dependencies = [ "base64 0.22.1", - "indexmap 2.11.4", + "indexmap 2.12.0", "quick-xml 0.38.3", "serde", "time", @@ -4482,7 +4482,7 @@ version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97baced388464909d42d89643fe4361939af9b7ce7a31ee32a168f832a70f2a0" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "crc32fast", "fdeflate", "flate2", @@ -4551,7 +4551,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" dependencies = [ "proc-macro2", - "syn 2.0.106", + "syn 2.0.107", ] [[package]] @@ -4650,7 +4650,7 @@ dependencies = [ "pulldown-cmark", "pulldown-cmark-to-cmark", "regex", - "syn 2.0.106", + "syn 2.0.107", "tempfile", ] @@ -4664,7 +4664,7 @@ dependencies = [ "itertools", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.107", ] [[package]] @@ -4718,7 +4718,7 @@ version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e8bbe1a966bd2f362681a44f6edce3c2310ac21e4d5067a6e7ec396297a6ea0" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "memchr", "unicase", ] @@ -4963,7 +4963,7 @@ version = "0.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", ] [[package]] @@ -5005,7 +5005,7 @@ checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.107", ] [[package]] @@ -5231,7 +5231,7 @@ version = "0.38.44" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "errno", "libc", "linux-raw-sys 0.4.15", @@ -5244,7 +5244,7 @@ version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "errno", "libc", "linux-raw-sys 0.11.0", @@ -5253,9 +5253,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.32" +version = "0.23.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd3c25631629d034ce7cd9940adc9d45762d46de2b0f57193c4443b92c6d4d40" +checksum = "751e04a496ca00bb97a5e043158d23d66b5aabf2e1d5aa2a0aaebb1aafe6f82c" dependencies = [ "log", "once_cell", @@ -5377,7 +5377,7 @@ dependencies = [ "proc-macro2", "quote", "serde_derive_internals", - "syn 2.0.106", + "syn 2.0.107", ] [[package]] @@ -5409,7 +5409,7 @@ checksum = "1783eabc414609e28a5ba76aee5ddd52199f7107a0b24c2e9746a1ecc34a683d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.107", ] [[package]] @@ -5424,7 +5424,7 @@ version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "core-foundation 0.9.4", "core-foundation-sys", "libc", @@ -5437,7 +5437,7 @@ version = "3.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b3297343eaf830f66ede390ea39da1d462b6b0c1b000f420d0a83f898bbbe6ef" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "core-foundation 0.10.1", "core-foundation-sys", "libc", @@ -5521,7 +5521,7 @@ checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.107", ] [[package]] @@ -5532,7 +5532,7 @@ checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.107", ] [[package]] @@ -5556,7 +5556,7 @@ checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.107", ] [[package]] @@ -5599,7 +5599,7 @@ dependencies = [ "chrono", "hex", "indexmap 1.9.3", - "indexmap 2.11.4", + "indexmap 2.12.0", "schemars 0.9.0", "schemars 1.0.4", "serde_core", @@ -5617,7 +5617,7 @@ dependencies = [ "darling 0.21.3", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.107", ] [[package]] @@ -5639,7 +5639,7 @@ checksum = "772ee033c0916d670af7860b6e1ef7d658a4629a6d0b4c8c3e67f09b3765b75d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.107", ] [[package]] @@ -5862,7 +5862,7 @@ dependencies = [ "futures-util", "hashbrown 0.15.5", "hashlink", - "indexmap 2.11.4", + "indexmap 2.12.0", "log", "memchr", "once_cell", @@ -5889,7 +5889,7 @@ dependencies = [ "quote", "sqlx-core", "sqlx-macros-core", - "syn 2.0.106", + "syn 2.0.107", ] [[package]] @@ -5912,7 +5912,7 @@ dependencies = [ "sqlx-mysql", "sqlx-postgres", "sqlx-sqlite", - "syn 2.0.106", + "syn 2.0.107", "tokio", "url", ] @@ -5925,7 +5925,7 @@ checksum = "aa003f0038df784eb8fecbbac13affe3da23b45194bd57dba231c8f48199c526" dependencies = [ "atoi", "base64 0.22.1", - "bitflags 2.9.4", + "bitflags 2.10.0", "byteorder", "bytes", "chrono", @@ -5969,7 +5969,7 @@ checksum = "db58fcd5a53cf07c184b154801ff91347e4c30d17a3562a635ff028ad5deda46" dependencies = [ "atoi", "base64 0.22.1", - "bitflags 2.9.4", + "bitflags 2.10.0", "byteorder", "chrono", "crc", @@ -6097,7 +6097,7 @@ checksum = "68c6387c1c7b53060605101b63d93edca618c6cf7ce61839f2ec2a527419fdb5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.107", ] [[package]] @@ -6118,7 +6118,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.107", ] [[package]] @@ -6151,9 +6151,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.106" +version = "2.0.107" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" +checksum = "2a26dbd934e5451d21ef060c018dae56fc073894c5a7896f882928a76e6d081b" dependencies = [ "proc-macro2", "quote", @@ -6177,7 +6177,7 @@ checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.107", ] [[package]] @@ -6195,7 +6195,7 @@ version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "core-foundation 0.9.4", "system-configuration-sys", ] @@ -6225,11 +6225,11 @@ dependencies = [ [[package]] name = "tao" -version = "0.34.3" +version = "0.34.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "959469667dbcea91e5485fc48ba7dd6023face91bb0f1a14681a70f99847c3f7" +checksum = "6121216ff67fe4bcfe64508ea1700bc15f74937d835a07b4a209cc00a8926a84" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "block2 0.6.2", "core-foundation 0.10.1", "core-graphics", @@ -6271,7 +6271,7 @@ checksum = "f4e16beb8b2ac17db28eab8bca40e62dbfbb34c0fcdc6d9826b11b7b5d047dfd" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.107", ] [[package]] @@ -6379,7 +6379,7 @@ dependencies = [ "serde", "serde_json", "sha2", - "syn 2.0.106", + "syn 2.0.107", "tauri-utils", "thiserror 2.0.17", "time", @@ -6397,7 +6397,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.107", "tauri-codegen", "tauri-utils", ] @@ -6622,7 +6622,7 @@ version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2d5f6fe3291bfa609c7e0b0ee3bedac294d94c7018934086ce782c1d0f2a468e" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "log", "serde", "serde_json", @@ -6802,7 +6802,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.107", ] [[package]] @@ -6813,7 +6813,7 @@ checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.107", ] [[package]] @@ -6932,7 +6932,7 @@ checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.107", ] [[package]] @@ -7006,7 +7006,7 @@ version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0dc8b1fb61449e27716ec0e1bdf0f6b8f3e8f6b05391e8497b8b6d7804ea6d8" dependencies = [ - "indexmap 2.11.4", + "indexmap 2.12.0", "serde_core", "serde_spanned 1.0.3", "toml_datetime 0.7.3", @@ -7039,7 +7039,7 @@ version = "0.19.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" dependencies = [ - "indexmap 2.11.4", + "indexmap 2.12.0", "toml_datetime 0.6.3", "winnow 0.5.40", ] @@ -7050,7 +7050,7 @@ version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "396e4d48bbb2b7554c944bde63101b5ae446cff6ec4a24227428f15eb72ef338" dependencies = [ - "indexmap 2.11.4", + "indexmap 2.12.0", "serde", "serde_spanned 0.6.9", "toml_datetime 0.6.3", @@ -7063,7 +7063,7 @@ version = "0.23.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6485ef6d0d9b5d0ec17244ff7eb05310113c3f316f2d14200d4de56b3cb98f8d" dependencies = [ - "indexmap 2.11.4", + "indexmap 2.12.0", "toml_datetime 0.7.3", "toml_parser", "winnow 0.7.13", @@ -7125,7 +7125,7 @@ dependencies = [ "prettyplease", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.107", ] [[package]] @@ -7150,7 +7150,7 @@ dependencies = [ "prost-build", "prost-types", "quote", - "syn 2.0.106", + "syn 2.0.107", "tempfile", "tonic-build", ] @@ -7163,7 +7163,7 @@ checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" dependencies = [ "futures-core", "futures-util", - "indexmap 2.11.4", + "indexmap 2.12.0", "pin-project-lite", "slab", "sync_wrapper", @@ -7180,7 +7180,7 @@ version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "adc82fd73de2a9722ac5da747f12383d2bfdb93591ee6c58486e0097890f05f2" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "bytes", "futures-util", "http", @@ -7236,7 +7236,7 @@ checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.107", ] [[package]] @@ -7471,7 +7471,7 @@ dependencies = [ "glob", "goblin", "heck 0.5.0", - "indexmap 2.11.4", + "indexmap 2.12.0", "once_cell", "serde", "tempfile", @@ -7513,10 +7513,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04f4f224becf14885c10e6e400b95cc4d1985738140cb194ccc2044563f8a56b" dependencies = [ "anyhow", - "indexmap 2.11.4", + "indexmap 2.12.0", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.107", ] [[package]] @@ -7531,7 +7531,7 @@ dependencies = [ "proc-macro2", "quote", "serde", - "syn 2.0.106", + "syn 2.0.107", "toml 0.5.11", "uniffi_meta", ] @@ -7556,7 +7556,7 @@ checksum = "4b147e133ad7824e32426b90bc41fda584363563f2ba747f590eca1fd6fd14e6" dependencies = [ "anyhow", "heck 0.5.0", - "indexmap 2.11.4", + "indexmap 2.12.0", "tempfile", "uniffi_internal_macros", ] @@ -7807,7 +7807,7 @@ dependencies = [ "log", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.107", "wasm-bindgen-shared", ] @@ -7842,7 +7842,7 @@ checksum = "9f07d2f20d4da7b26400c9f4a0511e6e0345b040694e8a75bd41d578fa4421d7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.107", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -7889,7 +7889,7 @@ version = "0.31.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c66a47e840dc20793f2264eb4b3e4ecb4b75d91c0dd4af04b456128e0bdd449d" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "rustix 1.1.2", "wayland-backend", "wayland-scanner", @@ -7901,7 +7901,7 @@ version = "0.32.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "efa790ed75fbfd71283bd2521a1cfdc022aabcc28bdcff00851f9e4ae88d9901" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "wayland-backend", "wayland-client", "wayland-scanner", @@ -7913,7 +7913,7 @@ version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "efd94963ed43cf9938a090ca4f7da58eb55325ec8200c3848963e98dc25b78ec" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "wayland-backend", "wayland-client", "wayland-protocols", @@ -7964,9 +7964,9 @@ dependencies = [ [[package]] name = "webbrowser" -version = "1.0.5" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aaf4f3c0ba838e82b4e5ccc4157003fb8c324ee24c058470ffb82820becbde98" +checksum = "00f1243ef785213e3a32fa0396093424a3a6ea566f9948497e5a2309261a4c97" dependencies = [ "core-foundation 0.10.1", "jni", @@ -8053,7 +8053,7 @@ checksum = "1d228f15bba3b9d56dde8bddbee66fa24545bd17b48d5128ccf4a8742b18e431" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.107", ] [[package]] @@ -8211,7 +8211,7 @@ checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.107", ] [[package]] @@ -8222,7 +8222,7 @@ checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.107", ] [[package]] @@ -8282,7 +8282,7 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d24d6bcc7f734a4091ecf8d7a64c5f7d7066f45585c1861eba06449909609c8a" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "widestring", "windows-sys 0.52.0", ] @@ -8813,15 +8813,15 @@ checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.107", "synstructure", ] [[package]] name = "zbus" -version = "5.11.0" +version = "5.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d07e46d035fb8e375b2ce63ba4e4ff90a7f73cf2ffb0138b29e1158d2eaadf7" +checksum = "b622b18155f7a93d1cd2dc8c01d2d6a44e08fb9ebb7b3f9e6ed101488bad6c91" dependencies = [ "async-broadcast", "async-executor", @@ -8844,7 +8844,8 @@ dependencies = [ "tokio", "tracing", "uds_windows", - "windows-sys 0.60.2", + "uuid", + "windows-sys 0.61.2", "winnow 0.7.13", "zbus_macros", "zbus_names", @@ -8853,14 +8854,14 @@ dependencies = [ [[package]] name = "zbus_macros" -version = "5.11.0" +version = "5.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57e797a9c847ed3ccc5b6254e8bcce056494b375b511b3d6edcec0aeb4defaca" +checksum = "1cdb94821ca8a87ca9c298b5d1cbd80e2a8b67115d99f6e4551ac49e42b6a314" dependencies = [ "proc-macro-crate 3.4.0", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.107", "zbus_names", "zvariant", "zvariant_utils", @@ -8895,7 +8896,7 @@ checksum = "88d2b8d9c68ad2b9e4340d7832716a4d21a22a1154777ad56ea55c51a9cf3831" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.107", ] [[package]] @@ -8915,7 +8916,7 @@ checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.107", "synstructure", ] @@ -8936,7 +8937,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.107", ] [[package]] @@ -8969,7 +8970,7 @@ checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.107", ] [[package]] @@ -8989,9 +8990,9 @@ dependencies = [ [[package]] name = "zvariant" -version = "5.7.0" +version = "5.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "999dd3be73c52b1fccd109a4a81e4fcd20fab1d3599c8121b38d04e1419498db" +checksum = "2be61892e4f2b1772727be11630a62664a1826b62efa43a6fe7449521cb8744c" dependencies = [ "endi", "enumflags2", @@ -9004,14 +9005,14 @@ dependencies = [ [[package]] name = "zvariant_derive" -version = "5.7.0" +version = "5.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6643fd0b26a46d226bd90d3f07c1b5321fe9bb7f04673cb37ac6d6883885b68e" +checksum = "da58575a1b2b20766513b1ec59d8e2e68db2745379f961f86650655e862d2006" dependencies = [ "proc-macro-crate 3.4.0", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.107", "zvariant_utils", ] @@ -9024,6 +9025,6 @@ dependencies = [ "proc-macro2", "quote", "serde", - "syn 2.0.106", + "syn 2.0.107", "winnow 0.7.13", ] diff --git a/src-tauri/Client.entitlements b/src-tauri/Client.entitlements index 0402d920..af8c6f90 100644 --- a/src-tauri/Client.entitlements +++ b/src-tauri/Client.entitlements @@ -8,5 +8,7 @@ com.apple.security.app-sandbox + com.apple.security.network.client + diff --git a/src-tauri/resources-macos/resources/net.defguard.plist b/src-tauri/resources-macos/resources/net.defguard.plist deleted file mode 100644 index 479b9737..00000000 --- a/src-tauri/resources-macos/resources/net.defguard.plist +++ /dev/null @@ -1,22 +0,0 @@ - - - - - Label - net.defguard - EnvironmentVariables - - PATH - /usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/sbin - - Program - /usr/local/bin/defguard-service - KeepAlive - - RunAtLoad - - GroupName - staff - - diff --git a/src-tauri/resources-macos/resources/uninstall.sh b/src-tauri/resources-macos/resources/uninstall.sh deleted file mode 100644 index 629344c2..00000000 --- a/src-tauri/resources-macos/resources/uninstall.sh +++ /dev/null @@ -1,26 +0,0 @@ -#!/bin/bash - -SERVICE_BINARY=defguard-service -DAEMON_PROPERTY_FILE=net.defguard.plist -DAEMON_NAME=net.defguard -PACKAGE_ID=net.defguard - -#Check running user -if (( $EUID != 0 )); then - echo "Please run as root." - exit -fi - -# Remove service shortcut at /usr/local/bin -rm -f /usr/local/bin/${SERVICE_BINARY} - -# Remove daemon -launchctl stop ${DAEMON_NAME} -launchctl unload /Library/LaunchDaemons/${DAEMON_PROPERTY_FILE} -rm -f /Library/LaunchDaemons/${DAEMON_PROPERTY_FILE} - -pkgutil --forget ${PACKAGE_ID} > /dev/null 2>&1 - -rm -rf /Applications/defguard-client.app - -echo "Application uninstall process finished" diff --git a/src-tauri/resources-macos/scripts/postinstall b/src-tauri/resources-macos/scripts/postinstall deleted file mode 100755 index b1ed66ba..00000000 --- a/src-tauri/resources-macos/scripts/postinstall +++ /dev/null @@ -1,24 +0,0 @@ -#!/bin/bash - -SERVICE_BINARY=defguard-service -DAEMON_PROPERTY_FILE=net.defguard.plist -DAEMON_NAME=net.defguard -APP_BUNDLE=defguard-client.app -PRODUCT_HOME=/Applications/${APP_BUNDLE} -BINARY_PATH=${PRODUCT_HOME}/Contents/MacOS -RESOURCES_PATH=${PRODUCT_HOME}/Contents/Resources/resources-macos/resources - -echo "Post installation process started" - -mkdir -p /usr/local/bin - -# Add service shortcut to /usr/local/bin -ln -sf ${BINARY_PATH}/${SERVICE_BINARY} /usr/local/bin/${SERVICE_BINARY} - -# Launch daemon -ln -sf ${RESOURCES_PATH}/${DAEMON_PROPERTY_FILE} /Library/LaunchDaemons/${DAEMON_PROPERTY_FILE} -sudo launchctl load /Library/LaunchDaemons/${DAEMON_PROPERTY_FILE} -# Restart -sudo launchctl stop ${DAEMON_NAME} - -echo "Post installation process finished" diff --git a/src-tauri/src/appstate.rs b/src-tauri/src/appstate.rs index f8fa0d96..9b019c33 100644 --- a/src-tauri/src/appstate.rs +++ b/src-tauri/src/appstate.rs @@ -45,20 +45,20 @@ impl AppState { drop(connections); debug!("Spawning thread for network statistics for location ID {location_id}"); - let handle = spawn(stats_handler(DB_POOL.clone(), ifname, connection_type)); - let Some(old_handle) = self - .stat_threads - .lock() - .unwrap() - .insert(location_id, handle) - else { - return; - }; - warn!("Something went wrong: old network statistics thread still exists"); - old_handle.abort(); - if let Err(err) = old_handle.await { - debug!("Old network statistics thread for location ID {location_id} returned {err}"); - } + // let handle = spawn(stats_handler(DB_POOL.clone(), ifname, connection_type)); + // let Some(old_handle) = self + // .stat_threads + // .lock() + // .unwrap() + // .insert(location_id, handle) + // else { + return; + // }; + // warn!("Something went wrong: old network statistics thread still exists"); + // old_handle.abort(); + // if let Err(err) = old_handle.await { + // debug!("Old network statistics thread for location ID {location_id} returned {err}"); + // } } /// Try to remove a connection from the list of active connections. diff --git a/src-tauri/src/export.rs b/src-tauri/src/export.rs index 2878acbc..41b7e987 100644 --- a/src-tauri/src/export.rs +++ b/src-tauri/src/export.rs @@ -51,7 +51,6 @@ impl Location { pub(crate) async fn tunnel_configurarion<'e, E>( &self, executor: E, - name: String, preshared_key: Option, dns: Vec, dns_search: Vec, @@ -129,11 +128,11 @@ impl Location { Error::InternalError(msg) })?; let interface_config = TunnelConfiguration { - name, + name: self.name.clone(), private_key: keys.prvkey, addresses, listen_port: Some(0), - peers: vec![], + peers: vec![peer], mtu: None, dns, dns_search, diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index 16692304..bb5fe1ac 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -37,7 +37,7 @@ pub const VERSION: &str = concat!(env!("CARGO_PKG_VERSION"), "-", env!("VERGEN_G pub const MIN_CORE_VERSION: Version = Version::new(1, 5, 0); pub const MIN_PROXY_VERSION: Version = Version::new(1, 5, 0); // This must match tauri.bundle.identifier from tauri.conf.json. -const BUNDLE_IDENTIFIER: &str = "net.defguard"; +const BUNDLE_IDENTIFIER: &str = "net.defguard.client"; // Returns the path to the user’s data directory. #[must_use] pub fn app_data_dir() -> Option { diff --git a/src-tauri/src/utils.rs b/src-tauri/src/utils.rs index 532836a4..fb4ddf8e 100644 --- a/src-tauri/src/utils.rs +++ b/src-tauri/src/utils.rs @@ -69,7 +69,7 @@ pub(crate) async fn setup_interface( let (dns, dns_search) = location.dns(); let tunnel_config = location - .tunnel_configurarion(pool, interface_name, preshared_key, dns, dns_search) + .tunnel_configurarion(pool, preshared_key, dns, dns_search) .await?; // tunnel_config.port = port; @@ -79,7 +79,8 @@ pub(crate) async fn setup_interface( .unwrap() .as_str() .into(); - start_tunnel(&prvkey); + let result = start_tunnel(&prvkey); + error!("start_tunnel() returned {result:?}"); } Ok(()) diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index 9d071f3a..6ca8274e 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -36,11 +36,16 @@ } }, "macOS": { - "entitlements": null, + "entitlements": "./Client.entitlements", "exceptionDomain": "", + "files": { + "embedded.provisionprofile": "Adam_Apollo_Defguard.provisionprofile", + "PlugIns": "/Users/adam/Library/Developer/Xcode/DerivedData/NetExt-bpogxtiuhfulrpbbfnqblorodxcp/Build/Products/Release/NetExt.app/Contents/PlugIns" + }, "frameworks": [], + "minimumSystemVersion": "13.5", "providerShortName": null, - "signingIdentity": null + "signingIdentity": "692SQ9VLU5" }, "resources": [ "resources/icons/*" @@ -71,7 +76,7 @@ }, "productName": "defguard-client", "mainBinaryName": "defguard-client", - "identifier": "net.defguard", + "identifier": "net.defguard.client", "version": "1.5.2", "app": { "security": { diff --git a/src-tauri/tauri.macos.conf.json b/src-tauri/tauri.macos.conf.json deleted file mode 100644 index a724a03d..00000000 --- a/src-tauri/tauri.macos.conf.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "bundle": { - "resources": [ - "resources-macos/resources/*", - "resources/icons/*" - ] - } -} diff --git a/swift/plugin/Sources/TunnelConfiguration.swift b/swift/plugin/Sources/TunnelConfiguration.swift index 5b865512..a19c1e65 100644 --- a/swift/plugin/Sources/TunnelConfiguration.swift +++ b/swift/plugin/Sources/TunnelConfiguration.swift @@ -109,4 +109,9 @@ final class TunnelConfiguration: Codable { return (ipv4IncludedRoutes, ipv6IncludedRoutes) } + + /// Client connection expects one peer, so check for that. + func isValidForClientConnection() -> Bool { + return peers.count == 1 + } } diff --git a/swift/plugin/Sources/VPNError.swift b/swift/plugin/Sources/VPNError.swift index c448c944..213ed1af 100644 --- a/swift/plugin/Sources/VPNError.swift +++ b/swift/plugin/Sources/VPNError.swift @@ -8,29 +8,32 @@ enum VPNError: Error, LocalizedError { case saveError(Error) case startError(Error) case stopError(Error) + case invalidConfig var errorDescription: String? { switch self { - case .invalidArguments(let msg): return "Invalid arguments: \(msg)" - case .noManager(let msg): return "\(msg)" - case .configurationError(let error): - return "Configuration parsing error: \(error.localizedDescription)" - case .timeoutError(let msg): return "Timeout: \(msg)" - case .saveError(let error): return "Save error: \(error.localizedDescription)" - case .startError(let error): return "Start error: \(error.localizedDescription)" - case .stopError(let error): return "Stop error: \(error.localizedDescription)" + case .invalidArguments(let msg): return "Invalid arguments: \(msg)" + case .noManager(let msg): return "\(msg)" + case .configurationError(let error): + return "Configuration parsing error: \(error.localizedDescription)" + case .timeoutError(let msg): return "Timeout: \(msg)" + case .saveError(let error): return "Save error: \(error.localizedDescription)" + case .startError(let error): return "Start error: \(error.localizedDescription)" + case .stopError(let error): return "Stop error: \(error.localizedDescription)" + case .invalidConfig: return "Invalid configuration for client connection" } } - private var code: String { - switch self { - case .invalidArguments: return "INVALID_ARGUMENTS" - case .noManager: return "NO_MANAGER" - case .configurationError: return "CONFIG_ERROR" - case .timeoutError: return "TIMEOUT_ERROR" - case .saveError: return "SAVE_ERROR" - case .startError: return "START_ERROR" - case .stopError: return "STOP_ERROR" - } - } +// private var code: String { +// switch self { +// case .invalidArguments: return "INVALID_ARGUMENTS" +// case .noManager: return "NO_MANAGER" +// case .configurationError: return "CONFIG_ERROR" +// case .timeoutError: return "TIMEOUT_ERROR" +// case .saveError: return "SAVE_ERROR" +// case .startError: return "START_ERROR" +// case .stopError: return "STOP_ERROR" +// case .invalidConfig: return "INVALID_CONFIG" +// } +// } } diff --git a/swift/plugin/Sources/VPNManager.swift b/swift/plugin/Sources/VPNManager.swift index 47d7ddb1..8e5ec8ba 100644 --- a/swift/plugin/Sources/VPNManager.swift +++ b/swift/plugin/Sources/VPNManager.swift @@ -11,6 +11,7 @@ public protocol VPNManagement { var connectionStatus: NEVPNStatus? { get } func loadProviderManager( + name: String, completion: @escaping (NETunnelProviderManager?) -> Void ) func saveProviderManager( @@ -32,35 +33,96 @@ public class VPNManager: VPNManagement { providerManager?.connection.status } - /// Loads the provider manager from the system preferences. - public func loadProviderManager( - completion: @escaping (NETunnelProviderManager?) -> Void - ) { + func managerForConfig(_ config: TunnelConfiguration, + completion: @escaping (NETunnelProviderManager?) -> Void) { NETunnelProviderManager.loadAllFromPreferences { managers, error in - self.logger.log( - "Loaded \(managers?.count ?? 0, privacy: .public) tunnel provider managers.") + guard let managers = managers else { + self.logger.info("No tunnel managers in user's settings") + return + } guard error == nil else { - self.logger.log( - "Error loading managers: \(String(describing: error), privacy: .public)") + self.logger.warning( + "Error loading tunnel managers: \(error, privacy: .public)") self.providerManager = nil completion(nil) return } - guard let providerManager = managers?.first else { + self.logger.info("Loaded \(managers.count, privacy: .public) tunnel managers.") + + // Find the right protocol manager. + self.providerManager = nil + for manager in managers { + if manager.localizedDescription != config.name { + continue + } + guard let tunnelProtocol = manager.protocolConfiguration as? NETunnelProviderProtocol else { + continue + } + // Sometimes all managers from all apps come through, so filter by bundle ID. + if tunnelProtocol.providerBundleIdentifier == "\(appId).VPNExtension" { + self.providerManager = manager + break + } + } + if self.providerManager == nil { self.logger.log("No VPN manager found") + } + else { + self.logger.log( + "Loaded provider manager: \(String(describing: self.providerManager!.localizedDescription), privacy: .public)" + ) + } + completion(self.providerManager) + } + } + + /// Loads named provider manager from the system preferences. + public func loadProviderManager( + name: String, + completion: @escaping (NETunnelProviderManager?) -> Void + ) { + NETunnelProviderManager.loadAllFromPreferences { managers, error in + guard let managers = managers else { + self.logger.info("No tunnel managers in user's settings") + return + } + guard error == nil else { + self.logger.warning( + "Error loading tunnel managers: \(error, privacy: .public)") self.providerManager = nil completion(nil) return } + self.logger.info("Loaded \(managers.count, privacy: .public) tunnel managers.") - self.providerManager = providerManager - self.logger.log( - "Loaded provider manager: \(String(describing: providerManager.localizedDescription), privacy: .public)" - ) - completion(providerManager) + // Find the right protocol manager. + self.providerManager = nil + for manager in managers { + if manager.localizedDescription != name { + continue + } + guard let tunnelProtocol = manager.protocolConfiguration as? NETunnelProviderProtocol else { + continue + } + // Sometimes all managers from all apps come through, so filter by bundle ID. + if tunnelProtocol.providerBundleIdentifier == "\(appId).VPNExtension" { + self.providerManager = manager + break + } + } + if self.providerManager == nil { + self.logger.log("No VPN manager found") + } + else { + self.logger.log( + "Loaded provider manager: \(String(describing: self.providerManager!.localizedDescription), privacy: .public)" + ) + } + completion(self.providerManager) } } + /// Save the provider manager to system preferences. public func saveProviderManager( _ manager: NETunnelProviderManager, completion: @escaping (Error?) -> Void @@ -70,26 +132,21 @@ public class VPNManager: VPNManagement { self.logger.log("Failed to save provider manager: \(error, privacy: .public)") completion(error) } else { - self.logger.log("Provider manager saved successfully, reloading it") - self.loadProviderManager { providerManager in - self.providerManager = providerManager - self.logger.log("The provider manager has been reloaded.") - completion(nil) - } + self.providerManager = manager + completion(nil) } - } } public func handleVPNConfigurationChange() { logger.log("VPN configuration changed, updating provider manager") - loadProviderManager { providerManager in - guard let providerManager = providerManager else { - self.logger.log("No VPN manager found after configuration change") - return - } - self.providerManager = providerManager - } +// loadProviderManager { providerManager in +// guard let providerManager = providerManager else { +// self.logger.log("No VPN manager found after configuration change") +// return +// } +// self.providerManager = providerManager +// } } public func startTunnel() throws { diff --git a/swift/plugin/Sources/Wireguard.swift b/swift/plugin/Sources/Wireguard.swift index 0787498f..d2d57fe1 100644 --- a/swift/plugin/Sources/Wireguard.swift +++ b/swift/plugin/Sources/Wireguard.swift @@ -1,33 +1,123 @@ +// Functions to be called from Rust code. + import NetworkExtension import SwiftRs import os let appId = Bundle.main.bundleIdentifier ?? "net.defguard" -// let vpnManager = VPNManager.shared +let pluginAppId = "\(appId).VPNExtension" let plugin = WireguardPlugin() let logger = Logger(subsystem: appId, category: "WireguardPlugin") @_cdecl("start_tunnel") -public func startTunnel(json: SRString) { +public func startTunnel(json: SRString) -> Bool { let decoder = JSONDecoder() guard let json_data = json.toString().data(using: .utf8) else { logger.error("Failed to convert JSON string to data") - return + return false } let config: TunnelConfiguration do { config = try decoder.decode(TunnelConfiguration.self, from: json_data) } catch { logger.error( "Failed to decode tunnel configuration: \(error.localizedDescription, privacy: .public)" ) - return + return false + } + + if !config.isValidForClientConnection() { + logger.error("Invalid tunnel configuration: \(json.toString(), privacy: .public)") + return false } - logger.log("Starting tunnel with config: \(String(describing: config))") - plugin.startTunnel(config: config) { result in - if result == nil { - logger.info("Tunnel started successfully") + logger.log("Saving tunnel with config: \(String(describing: config))") +// plugin.startTunnel(config: config) { result in +// if result == nil { +// logger.info("Tunnel started successfully") +// } else { +// logger.error("Tunnel failed to start with \(result)") +// } +// } + saveConfig(config) + + return true +} + +func saveConfig(_ config: TunnelConfiguration) { + managerForConfig(config) { manager in + let providerManager = manager ?? NETunnelProviderManager() + let tunnelProtocol = NETunnelProviderProtocol() + tunnelProtocol.providerBundleIdentifier = pluginAppId + // `serverAddress` must have a non-nil string value for the protocol configuration to be valid. + if let endpoint = config.peers[0].endpoint { + tunnelProtocol.serverAddress = endpoint.toString() } else { - logger.error("Tunnel failed to start with \(result)") + tunnelProtocol.serverAddress = "" + } + let configDict: [String: Any] + do { + configDict = try config.toDictionary() + } catch { + logger.log( + "Failed to convert config to dictionary: \(error.localizedDescription, privacy: .public)" + ) + return + } + tunnelProtocol.providerConfiguration = configDict + providerManager.protocolConfiguration = tunnelProtocol + providerManager.localizedDescription = config.name + providerManager.isEnabled = true + + providerManager.saveToPreferences { error in + if let error = error { + logger.log("Failed to save provider manager: \(error, privacy: .public)") + } else { + logger.info("Config saved") + } + } + } +} + +func managerForConfig(_ config: TunnelConfiguration, + completion: @escaping (NETunnelProviderManager?) -> Void) { + var providerManager: NETunnelProviderManager? + NETunnelProviderManager.loadAllFromPreferences { managers, error in + guard let managers = managers else { + logger.info("No tunnel managers in user's settings") + return + } + guard error == nil else { + logger.warning( + "Error loading tunnel managers: \(error, privacy: .public)") + providerManager = nil + completion(nil) + return + } + logger.info("Loaded \(managers.count, privacy: .public) tunnel managers.") + + // Find the right protocol manager. + providerManager = nil + for manager in managers { + // Obtain named configuration. + if manager.localizedDescription != config.name { + continue + } + guard let tunnelProtocol = manager.protocolConfiguration as? NETunnelProviderProtocol else { + continue + } + // Sometimes all managers from all apps come through, so filter by bundle ID. + if tunnelProtocol.providerBundleIdentifier == "\(appId).VPNExtension" { + providerManager = manager + break + } + } + if providerManager == nil { + logger.log("No VPN manager found") + } + else { + logger.log( + "Loaded provider manager: \(String(describing: providerManager!.localizedDescription), privacy: .public)" + ) } + completion(providerManager) } } diff --git a/swift/plugin/Sources/WireguardPlugin.swift b/swift/plugin/Sources/WireguardPlugin.swift index 10ab28e5..6589a242 100644 --- a/swift/plugin/Sources/WireguardPlugin.swift +++ b/swift/plugin/Sources/WireguardPlugin.swift @@ -10,7 +10,7 @@ public class WireguardPlugin: NSObject { private var configurationObserver: NSObjectProtocol? private var vpnManager: VPNManagement private var logger = Logger( - subsystem: Bundle.main.bundleIdentifier ?? "net.defguard.WireguardPlugin", + subsystem: appId, category: "WireguardPlugin") public init(vpnManager: VPNManagement? = nil) { @@ -47,21 +47,21 @@ public class WireguardPlugin: NSObject { /// Loads the possibly already existing VPN manager and sets up observers for VPN connection status changes if its present. /// This is to ensure that the VPN status is observed and updated correctly when the app starts. - private func setupVPNManager( - completion: @escaping () -> Void - ) { - vpnManager.loadProviderManager { manager in - if manager == nil { - self.logger.log( - "No provider manager found, the VPN status won't be observed until the VPN is started." - ) - } else { - self.logger.log( - "VPN manager loaded successfully, the VPN status will be observed and updated.") - } - completion() - } - } +// private func setupVPNManager( +// completion: @escaping () -> Void +// ) { +// vpnManager.loadProviderManager { manager in +// if manager == nil { +// self.logger.log( +// "No provider manager found, the VPN status won't be observed until the VPN is started." +// ) +// } else { +// self.logger.log( +// "VPN manager loaded successfully, the VPN status will be observed and updated.") +// } +// completion() +// } +// } /// Sets up observers for VPN connection status changes. private func setupVPNObservers() { @@ -229,18 +229,42 @@ public class WireguardPlugin: NSObject { defaults?.removeObject(forKey: "lastTunnelError") } +// private func saveConfig(config: TunnelConfiguration, result: @escaping (VPNError?) -> Void) { +// logger.info("Saving tunnel config: \(String(describing: config))") +// +// vpnManager.saveProviderManager(providerManager) { saveError in +// if let saveError = saveError { +// self.logger.log("Failed to save preferences: \(saveError, privacy: .public)") +// result( +// VPNError.saveError( +// saveError +// ) +// ) +// return +// } +// } +// } + func startTunnel( config: TunnelConfiguration, - result: @escaping (VPNError?) -> Void + completion: @escaping (VPNError?) -> Void ) { logger.log("Starting tunnel with config: \(String(describing: config))") - vpnManager.loadProviderManager { manager in - let appId = Bundle.main.bundleIdentifier ?? "net.defguard.mobile" + if !config.isValidForClientConnection() { + completion(VPNError.invalidConfig) + } + + vpnManager.loadProviderManager(name: config.name) { manager in let providerManager = manager ?? NETunnelProviderManager() let tunnelProtocol = NETunnelProviderProtocol() tunnelProtocol.providerBundleIdentifier = "\(appId).VPNExtension" - tunnelProtocol.serverAddress = "" // config.endpoint + // `serverAddress` must have a non-nil string value for the protocol configuration to be valid. + if let endpoint = config.peers[0].endpoint { + tunnelProtocol.serverAddress = endpoint.toString() + } else { + tunnelProtocol.serverAddress = "" + } let configDict: [String: Any] do { configDict = try config.toDictionary() @@ -248,14 +272,14 @@ public class WireguardPlugin: NSObject { self.logger.log( "Failed to convert config to dictionary: \(error.localizedDescription, privacy: .public)" ) - result( + completion( VPNError.configurationError(error) ) return } tunnelProtocol.providerConfiguration = configDict providerManager.protocolConfiguration = tunnelProtocol - // providerManager.localizedDescription = config.locationName + providerManager.localizedDescription = config.name providerManager.isEnabled = true if let status = self.vpnManager.connectionStatus { @@ -264,7 +288,7 @@ public class WireguardPlugin: NSObject { try self.vpnManager.stopTunnel() } catch { self.logger.log("Failed to stop VPN tunnel: \(error, privacy: .public)") - result( + completion( VPNError.stopError( error ) @@ -277,7 +301,7 @@ public class WireguardPlugin: NSObject { ) { status in if let status = status { self.logger.log("Timeout waiting for tunnel to disconnect") - result( + completion( VPNError.timeoutError( "The tunnel disconnection has failed to complete in a specified amount of time (\(tunnelStatusTimeout) seconds). Please check your configuration and try again. Current status: \(status.rawValue)" ) @@ -287,7 +311,7 @@ public class WireguardPlugin: NSObject { self.saveAndStartTunnel( providerManager: providerManager, config: config, - result: result + result: completion ) return } @@ -296,7 +320,7 @@ public class WireguardPlugin: NSObject { self.saveAndStartTunnel( providerManager: providerManager, config: config, - result: result + result: completion ) } } @@ -346,7 +370,7 @@ public class WireguardPlugin: NSObject { config: TunnelConfiguration, result: @escaping (VPNError?) -> Void ) { - self.vpnManager.saveProviderManager(providerManager) { saveError in + vpnManager.saveProviderManager(providerManager) { saveError in if let saveError = saveError { self.logger.log("Failed to save preferences: \(saveError, privacy: .public)") result( From 0f434fcf5f2e45f9154bc474cb2396b597df729e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adam=20Ciarcin=CC=81ski?= Date: Tue, 21 Oct 2025 13:47:22 +0200 Subject: [PATCH 06/28] Buildable VPNExtension --- package.json | 6 +- pnpm-lock.yaml | 174 ++++---- src-tauri/Cargo.lock | 58 +-- src-tauri/src/export.rs | 20 - src-tauri/src/utils.rs | 68 +-- src-tauri/tauri.conf.json | 2 +- swift/.gitignore | 3 +- .../VPNExtension.xcodeproj/project.pbxproj | 397 ++++++++++++++++++ .../contents.xcworkspacedata | 7 + swift/extension/VPNExtension/Adapter.swift | 281 +++++++++++++ swift/extension/VPNExtension/Info.plist | 13 + .../VPNExtension/PacketTunnelProvider.swift | 70 +++ .../VPNExtension/VPNExtension.entitlements | 10 + .../{ => Defguard}/Decodabe+Encodable.swift | 0 .../Sources/{ => Defguard}/Endpoint.swift | 1 + .../Sources/{ => Defguard}/IpAddrMask.swift | 0 .../plugin/Sources/{ => Defguard}/Peer.swift | 0 .../{ => Defguard}/TunnelConfiguration.swift | 0 swift/plugin/Sources/Wireguard.swift | 51 ++- 19 files changed, 975 insertions(+), 186 deletions(-) create mode 100644 swift/extension/VPNExtension.xcodeproj/project.pbxproj create mode 100644 swift/extension/VPNExtension.xcodeproj/project.xcworkspace/contents.xcworkspacedata create mode 100644 swift/extension/VPNExtension/Adapter.swift create mode 100644 swift/extension/VPNExtension/Info.plist create mode 100644 swift/extension/VPNExtension/PacketTunnelProvider.swift create mode 100644 swift/extension/VPNExtension/VPNExtension.entitlements rename swift/plugin/Sources/{ => Defguard}/Decodabe+Encodable.swift (100%) rename swift/plugin/Sources/{ => Defguard}/Endpoint.swift (99%) rename swift/plugin/Sources/{ => Defguard}/IpAddrMask.swift (100%) rename swift/plugin/Sources/{ => Defguard}/Peer.swift (100%) rename swift/plugin/Sources/{ => Defguard}/TunnelConfiguration.swift (100%) diff --git a/package.json b/package.json index b7cd41de..0a0d5d9f 100644 --- a/package.json +++ b/package.json @@ -54,7 +54,7 @@ "@stablelib/x25519": "^2.0.1", "@tanstack/query-core": "^5.90.5", "@tanstack/react-virtual": "3.13.12", - "@tauri-apps/api": "^2.8.0", + "@tauri-apps/api": "^2.9.0", "@tauri-apps/plugin-clipboard-manager": "^2.3.0", "@tauri-apps/plugin-deep-link": "^2.4.3", "@tauri-apps/plugin-dialog": "^2.4.0", @@ -111,10 +111,10 @@ "@svgr/cli": "^8.1.0", "@tanstack/react-query": "^5.90.5", "@tanstack/react-query-devtools": "^5.90.2", - "@tauri-apps/cli": "^2.8.4", + "@tauri-apps/cli": "^2.9.0", "@types/file-saver": "^2.0.7", "@types/lodash-es": "^4.17.12", - "@types/node": "^24.8.1", + "@types/node": "^24.9.1", "@types/react": "^19.2.2", "@types/react-dom": "^19.2.2", "@vitejs/plugin-react": "^5.0.4", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index da04bbb4..33d4cc00 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -30,8 +30,8 @@ importers: specifier: 3.13.12 version: 3.13.12(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@tauri-apps/api': - specifier: ^2.8.0 - version: 2.8.0 + specifier: ^2.9.0 + version: 2.9.0 '@tauri-apps/plugin-clipboard-manager': specifier: ^2.3.0 version: 2.3.0 @@ -196,8 +196,8 @@ importers: specifier: ^5.90.2 version: 5.90.2(@tanstack/react-query@5.90.5(react@19.2.0))(react@19.2.0) '@tauri-apps/cli': - specifier: ^2.8.4 - version: 2.8.4 + specifier: ^2.9.0 + version: 2.9.0 '@types/file-saver': specifier: ^2.0.7 version: 2.0.7 @@ -205,8 +205,8 @@ importers: specifier: ^4.17.12 version: 4.17.12 '@types/node': - specifier: ^24.8.1 - version: 24.8.1 + specifier: ^24.9.1 + version: 24.9.1 '@types/react': specifier: ^19.2.2 version: 19.2.2 @@ -215,10 +215,10 @@ importers: version: 19.2.2(@types/react@19.2.2) '@vitejs/plugin-react': specifier: ^5.0.4 - version: 5.0.4(vite@7.1.11(@types/node@24.8.1)(sass@1.92.1)(yaml@2.8.1)) + version: 5.0.4(vite@7.1.11(@types/node@24.9.1)(sass@1.92.1)(yaml@2.8.1)) '@vitejs/plugin-react-swc': specifier: ^4.1.0 - version: 4.1.0(vite@7.1.11(@types/node@24.8.1)(sass@1.92.1)(yaml@2.8.1)) + version: 4.1.0(vite@7.1.11(@types/node@24.9.1)(sass@1.92.1)(yaml@2.8.1)) autoprefixer: specifier: ^10.4.21 version: 10.4.21(postcss@8.5.6) @@ -245,7 +245,7 @@ importers: version: 5.9.3 vite: specifier: ^7.1.11 - version: 7.1.11(@types/node@24.8.1)(sass@1.92.1)(yaml@2.8.1) + version: 7.1.11(@types/node@24.9.1)(sass@1.92.1)(yaml@2.8.1) packages: @@ -1109,77 +1109,77 @@ packages: '@tanstack/virtual-core@3.13.12': resolution: {integrity: sha512-1YBOJfRHV4sXUmWsFSf5rQor4Ss82G8dQWLRbnk3GA4jeP8hQt1hxXh0tmflpC0dz3VgEv/1+qwPyLeWkQuPFA==} - '@tauri-apps/api@2.8.0': - resolution: {integrity: sha512-ga7zdhbS2GXOMTIZRT0mYjKJtR9fivsXzsyq5U3vjDL0s6DTMwYRm0UHNjzTY5dh4+LSC68Sm/7WEiimbQNYlw==} + '@tauri-apps/api@2.9.0': + resolution: {integrity: sha512-qD5tMjh7utwBk9/5PrTA/aGr3i5QaJ/Mlt7p8NilQ45WgbifUNPyKWsA63iQ8YfQq6R8ajMapU+/Q8nMcPRLNw==} - '@tauri-apps/cli-darwin-arm64@2.8.4': - resolution: {integrity: sha512-BKu8HRkYV01SMTa7r4fLx+wjgtRK8Vep7lmBdHDioP6b8XH3q2KgsAyPWfEZaZIkZ2LY4SqqGARaE9oilNe0oA==} + '@tauri-apps/cli-darwin-arm64@2.9.0': + resolution: {integrity: sha512-A2Wo2gvtPDymSApnLlKGVuX/b6rvVtdlTh80qta7j0jgc+tK0dyX8+puDufthUR3VPBRsVmV+XWfEJKnaqMLjg==} engines: {node: '>= 10'} cpu: [arm64] os: [darwin] - '@tauri-apps/cli-darwin-x64@2.8.4': - resolution: {integrity: sha512-imb9PfSd/7G6VAO7v1bQ2A3ZH4NOCbhGJFLchxzepGcXf9NKkfun157JH9mko29K6sqAwuJ88qtzbKCbWJTH9g==} + '@tauri-apps/cli-darwin-x64@2.9.0': + resolution: {integrity: sha512-RfFB1BB7cqPuPWwKtROXYkN9F760jwYIHpxXgg5AocEQ0c6XynWPMLnYvy77jEyycbYt6cWeIwhiWQYsRbWESA==} engines: {node: '>= 10'} cpu: [x64] os: [darwin] - '@tauri-apps/cli-linux-arm-gnueabihf@2.8.4': - resolution: {integrity: sha512-Ml215UnDdl7/fpOrF1CNovym/KjtUbCuPgrcZ4IhqUCnhZdXuphud/JT3E8X97Y03TZ40Sjz8raXYI2ET0exzw==} + '@tauri-apps/cli-linux-arm-gnueabihf@2.9.0': + resolution: {integrity: sha512-n1Gs41458ktY6FMTow/M6AWzy5EYhH1vJ2rdkNAwgX1u086xHCM8PbnowQVgJbRjhrJCUoq7E36EjSy2awHTvA==} engines: {node: '>= 10'} cpu: [arm] os: [linux] - '@tauri-apps/cli-linux-arm64-gnu@2.8.4': - resolution: {integrity: sha512-pbcgBpMyI90C83CxE5REZ9ODyIlmmAPkkJXtV398X3SgZEIYy5TACYqlyyv2z5yKgD8F8WH4/2fek7+jH+ZXAw==} + '@tauri-apps/cli-linux-arm64-gnu@2.9.0': + resolution: {integrity: sha512-E2y+egQvm7nZbl6cv2Nt1kYw5H8rJG2IisGj9bzJbd8ygSsWJK4Rdw6KW9Ml9iZL7+GuYGihOtlMcyQ6uykw2g==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - '@tauri-apps/cli-linux-arm64-musl@2.8.4': - resolution: {integrity: sha512-zumFeaU1Ws5Ay872FTyIm7z8kfzEHu8NcIn8M6TxbJs0a7GRV21KBdpW1zNj2qy7HynnpQCqjAYXTUUmm9JAOw==} + '@tauri-apps/cli-linux-arm64-musl@2.9.0': + resolution: {integrity: sha512-TH09uepDx3LE7+DSzn9x04ilM0pouguwD6Cjq+A2NdDOu2UkZ3rWux77lMiiuO5fQAGYQAs0BtLjkzcTDoUHTQ==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - '@tauri-apps/cli-linux-riscv64-gnu@2.8.4': - resolution: {integrity: sha512-qiqbB3Zz6IyO201f+1ojxLj65WYj8mixL5cOMo63nlg8CIzsP23cPYUrx1YaDPsCLszKZo7tVs14pc7BWf+/aQ==} + '@tauri-apps/cli-linux-riscv64-gnu@2.9.0': + resolution: {integrity: sha512-s0ENNDStw8tLScc/K5gS4xE8VrDaFbyCCgYHylrBsIqKQT4rYZLHH3WyzWxxLXIOhPzkczw6MPxt0GdUVPH97A==} engines: {node: '>= 10'} cpu: [riscv64] os: [linux] - '@tauri-apps/cli-linux-x64-gnu@2.8.4': - resolution: {integrity: sha512-TaqaDd9Oy6k45Hotx3pOf+pkbsxLaApv4rGd9mLuRM1k6YS/aw81YrsMryYPThrxrScEIUcmNIHaHsLiU4GMkw==} + '@tauri-apps/cli-linux-x64-gnu@2.9.0': + resolution: {integrity: sha512-stBAjrxfcrJLdmvF3jQskq/Ks/ar4TRyk45kfpD9/0c/8WWDKKWu+z6+ynGNkDYfm9GpbQOQDAjfX0BPWodZZw==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - '@tauri-apps/cli-linux-x64-musl@2.8.4': - resolution: {integrity: sha512-ot9STAwyezN8w+bBHZ+bqSQIJ0qPZFlz/AyscpGqB/JnJQVDFQcRDmUPFEaAtt2UUHSWzN3GoTJ5ypqLBp2WQA==} + '@tauri-apps/cli-linux-x64-musl@2.9.0': + resolution: {integrity: sha512-fxR/cG3DVuVFDoBCvAGzbVdNfHAdMfNG32aBR1j6y+0+Ys4ZF+a4SNBbMNGdJ2gQc6/QVciswYMSfSs9hP3GZA==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - '@tauri-apps/cli-win32-arm64-msvc@2.8.4': - resolution: {integrity: sha512-+2aJ/g90dhLiOLFSD1PbElXX3SoMdpO7HFPAZB+xot3CWlAZD1tReUFy7xe0L5GAR16ZmrxpIDM9v9gn5xRy/w==} + '@tauri-apps/cli-win32-arm64-msvc@2.9.0': + resolution: {integrity: sha512-YIyRvIaYyPRlf1XB0HOLI3q9rkBpb9a8Cl6+PRopTsnXQqlfZIBG5A2KmQO90PkvmyVC6CprGcvK0U28l4MUow==} engines: {node: '>= 10'} cpu: [arm64] os: [win32] - '@tauri-apps/cli-win32-ia32-msvc@2.8.4': - resolution: {integrity: sha512-yj7WDxkL1t9Uzr2gufQ1Hl7hrHuFKTNEOyascbc109EoiAqCp0tgZ2IykQqOZmZOHU884UAWI1pVMqBhS/BfhA==} + '@tauri-apps/cli-win32-ia32-msvc@2.9.0': + resolution: {integrity: sha512-Z6a6J+KT0DvjoWSz/R0EDRUCr0DDl/sp10sL1OuJLGnsl36lXWF10YuhJua3dQHizzJzkHpWAV/k1EBxjf10fQ==} engines: {node: '>= 10'} cpu: [ia32] os: [win32] - '@tauri-apps/cli-win32-x64-msvc@2.8.4': - resolution: {integrity: sha512-XuvGB4ehBdd7QhMZ9qbj/8icGEatDuBNxyYHbLKsTYh90ggUlPa/AtaqcC1Fo69lGkTmq9BOKrs1aWSi7xDonA==} + '@tauri-apps/cli-win32-x64-msvc@2.9.0': + resolution: {integrity: sha512-Ja2LCRGhEBV/FxRF3ofGGO8ZAVrZt5P0MKkAyJ2wQGRB7xcFoadmnkKwpF0uFOjT/6ygh4f/RV46cjo3pbZxyA==} engines: {node: '>= 10'} cpu: [x64] os: [win32] - '@tauri-apps/cli@2.8.4': - resolution: {integrity: sha512-ejUZBzuQRcjFV+v/gdj/DcbyX/6T4unZQjMSBZwLzP/CymEjKcc2+Fc8xTORThebHDUvqoXMdsCZt8r+hyN15g==} + '@tauri-apps/cli@2.9.0': + resolution: {integrity: sha512-Rq67+sgiiUot95kjn+6eP8gTRw9YL839gutPx5bAsGtlQ8n9S6qo2VSQkogYsiHlJs14hQpYACn/EIswH6sHzw==} engines: {node: '>= 10'} hasBin: true @@ -1286,8 +1286,8 @@ packages: '@types/ms@2.1.0': resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==} - '@types/node@24.8.1': - resolution: {integrity: sha512-alv65KGRadQVfVcG69MuB4IzdYVpRwMG/mq8KWOaoOdyY617P5ivaDiMCGOFDWD2sAn5Q0mR3mRtUOgm99hL9Q==} + '@types/node@24.9.1': + resolution: {integrity: sha512-QoiaXANRkSXK6p0Duvt56W208du4P9Uye9hWLWgGMDTEoKPhuenzNcC4vGUmrNkiOKTlIrBoyNQYNpSwfEZXSg==} '@types/parse-json@4.0.2': resolution: {integrity: sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==} @@ -2589,8 +2589,8 @@ packages: resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} engines: {node: '>=4'} - resolve@1.22.10: - resolution: {integrity: sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==} + resolve@1.22.11: + resolution: {integrity: sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==} engines: {node: '>= 0.4'} hasBin: true @@ -2824,8 +2824,8 @@ packages: resolution: {integrity: sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==} engines: {node: '>= 0.4'} - undici-types@7.14.0: - resolution: {integrity: sha512-QQiYxHuyZ9gQUIrmPo3IA+hUl4KYk8uSA7cHrcKd/l3p1OTpZcM0Tbp9x7FAtXdAYhlasd60ncPpgu6ihG6TOA==} + undici-types@7.16.0: + resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==} unified@11.0.5: resolution: {integrity: sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==} @@ -3769,94 +3769,94 @@ snapshots: '@tanstack/virtual-core@3.13.12': {} - '@tauri-apps/api@2.8.0': {} + '@tauri-apps/api@2.9.0': {} - '@tauri-apps/cli-darwin-arm64@2.8.4': + '@tauri-apps/cli-darwin-arm64@2.9.0': optional: true - '@tauri-apps/cli-darwin-x64@2.8.4': + '@tauri-apps/cli-darwin-x64@2.9.0': optional: true - '@tauri-apps/cli-linux-arm-gnueabihf@2.8.4': + '@tauri-apps/cli-linux-arm-gnueabihf@2.9.0': optional: true - '@tauri-apps/cli-linux-arm64-gnu@2.8.4': + '@tauri-apps/cli-linux-arm64-gnu@2.9.0': optional: true - '@tauri-apps/cli-linux-arm64-musl@2.8.4': + '@tauri-apps/cli-linux-arm64-musl@2.9.0': optional: true - '@tauri-apps/cli-linux-riscv64-gnu@2.8.4': + '@tauri-apps/cli-linux-riscv64-gnu@2.9.0': optional: true - '@tauri-apps/cli-linux-x64-gnu@2.8.4': + '@tauri-apps/cli-linux-x64-gnu@2.9.0': optional: true - '@tauri-apps/cli-linux-x64-musl@2.8.4': + '@tauri-apps/cli-linux-x64-musl@2.9.0': optional: true - '@tauri-apps/cli-win32-arm64-msvc@2.8.4': + '@tauri-apps/cli-win32-arm64-msvc@2.9.0': optional: true - '@tauri-apps/cli-win32-ia32-msvc@2.8.4': + '@tauri-apps/cli-win32-ia32-msvc@2.9.0': optional: true - '@tauri-apps/cli-win32-x64-msvc@2.8.4': + '@tauri-apps/cli-win32-x64-msvc@2.9.0': optional: true - '@tauri-apps/cli@2.8.4': + '@tauri-apps/cli@2.9.0': optionalDependencies: - '@tauri-apps/cli-darwin-arm64': 2.8.4 - '@tauri-apps/cli-darwin-x64': 2.8.4 - '@tauri-apps/cli-linux-arm-gnueabihf': 2.8.4 - '@tauri-apps/cli-linux-arm64-gnu': 2.8.4 - '@tauri-apps/cli-linux-arm64-musl': 2.8.4 - '@tauri-apps/cli-linux-riscv64-gnu': 2.8.4 - '@tauri-apps/cli-linux-x64-gnu': 2.8.4 - '@tauri-apps/cli-linux-x64-musl': 2.8.4 - '@tauri-apps/cli-win32-arm64-msvc': 2.8.4 - '@tauri-apps/cli-win32-ia32-msvc': 2.8.4 - '@tauri-apps/cli-win32-x64-msvc': 2.8.4 + '@tauri-apps/cli-darwin-arm64': 2.9.0 + '@tauri-apps/cli-darwin-x64': 2.9.0 + '@tauri-apps/cli-linux-arm-gnueabihf': 2.9.0 + '@tauri-apps/cli-linux-arm64-gnu': 2.9.0 + '@tauri-apps/cli-linux-arm64-musl': 2.9.0 + '@tauri-apps/cli-linux-riscv64-gnu': 2.9.0 + '@tauri-apps/cli-linux-x64-gnu': 2.9.0 + '@tauri-apps/cli-linux-x64-musl': 2.9.0 + '@tauri-apps/cli-win32-arm64-msvc': 2.9.0 + '@tauri-apps/cli-win32-ia32-msvc': 2.9.0 + '@tauri-apps/cli-win32-x64-msvc': 2.9.0 '@tauri-apps/plugin-clipboard-manager@2.3.0': dependencies: - '@tauri-apps/api': 2.8.0 + '@tauri-apps/api': 2.9.0 '@tauri-apps/plugin-deep-link@2.4.3': dependencies: - '@tauri-apps/api': 2.8.0 + '@tauri-apps/api': 2.9.0 '@tauri-apps/plugin-dialog@2.4.0': dependencies: - '@tauri-apps/api': 2.8.0 + '@tauri-apps/api': 2.9.0 '@tauri-apps/plugin-fs@2.4.2': dependencies: - '@tauri-apps/api': 2.8.0 + '@tauri-apps/api': 2.9.0 '@tauri-apps/plugin-http@2.5.2': dependencies: - '@tauri-apps/api': 2.8.0 + '@tauri-apps/api': 2.9.0 '@tauri-apps/plugin-log@2.7.0': dependencies: - '@tauri-apps/api': 2.8.0 + '@tauri-apps/api': 2.9.0 '@tauri-apps/plugin-notification@2.3.1': dependencies: - '@tauri-apps/api': 2.8.0 + '@tauri-apps/api': 2.9.0 '@tauri-apps/plugin-opener@2.5.0': dependencies: - '@tauri-apps/api': 2.8.0 + '@tauri-apps/api': 2.9.0 '@tauri-apps/plugin-os@2.3.1': dependencies: - '@tauri-apps/api': 2.8.0 + '@tauri-apps/api': 2.9.0 '@tauri-apps/plugin-window-state@2.4.0': dependencies: - '@tauri-apps/api': 2.8.0 + '@tauri-apps/api': 2.9.0 '@trysound/sax@0.2.0': {} @@ -3935,9 +3935,9 @@ snapshots: '@types/ms@2.1.0': {} - '@types/node@24.8.1': + '@types/node@24.9.1': dependencies: - undici-types: 7.14.0 + undici-types: 7.16.0 '@types/parse-json@4.0.2': {} @@ -3964,15 +3964,15 @@ snapshots: '@use-gesture/core': 10.3.1 react: 19.2.0 - '@vitejs/plugin-react-swc@4.1.0(vite@7.1.11(@types/node@24.8.1)(sass@1.92.1)(yaml@2.8.1))': + '@vitejs/plugin-react-swc@4.1.0(vite@7.1.11(@types/node@24.9.1)(sass@1.92.1)(yaml@2.8.1))': dependencies: '@rolldown/pluginutils': 1.0.0-beta.35 '@swc/core': 1.13.5 - vite: 7.1.11(@types/node@24.8.1)(sass@1.92.1)(yaml@2.8.1) + vite: 7.1.11(@types/node@24.9.1)(sass@1.92.1)(yaml@2.8.1) transitivePeerDependencies: - '@swc/helpers' - '@vitejs/plugin-react@5.0.4(vite@7.1.11(@types/node@24.8.1)(sass@1.92.1)(yaml@2.8.1))': + '@vitejs/plugin-react@5.0.4(vite@7.1.11(@types/node@24.9.1)(sass@1.92.1)(yaml@2.8.1))': dependencies: '@babel/core': 7.28.4 '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.28.4) @@ -3980,7 +3980,7 @@ snapshots: '@rolldown/pluginutils': 1.0.0-beta.38 '@types/babel__core': 7.20.5 react-refresh: 0.17.0 - vite: 7.1.11(@types/node@24.8.1)(sass@1.92.1)(yaml@2.8.1) + vite: 7.1.11(@types/node@24.9.1)(sass@1.92.1)(yaml@2.8.1) transitivePeerDependencies: - supports-color @@ -4031,7 +4031,7 @@ snapshots: dependencies: '@babel/runtime': 7.28.4 cosmiconfig: 7.1.0 - resolve: 1.22.10 + resolve: 1.22.11 bail@2.0.2: {} @@ -5155,7 +5155,7 @@ snapshots: normalize-package-data@2.5.0: dependencies: hosted-git-info: 2.8.9 - resolve: 1.22.10 + resolve: 1.22.11 semver: 5.7.2 validate-npm-package-license: 3.0.4 @@ -5449,7 +5449,7 @@ snapshots: resolve-from@4.0.0: {} - resolve@1.22.10: + resolve@1.22.11: dependencies: is-core-module: 2.16.1 path-parse: 1.0.7 @@ -5764,7 +5764,7 @@ snapshots: has-symbols: 1.1.0 which-boxed-primitive: 1.1.1 - undici-types@7.14.0: {} + undici-types@7.16.0: {} unified@11.0.5: dependencies: @@ -5854,7 +5854,7 @@ snapshots: d3-time: 3.1.0 d3-timer: 3.0.1 - vite@7.1.11(@types/node@24.8.1)(sass@1.92.1)(yaml@2.8.1): + vite@7.1.11(@types/node@24.9.1)(sass@1.92.1)(yaml@2.8.1): dependencies: esbuild: 0.25.11 fdir: 6.5.0(picomatch@4.0.3) @@ -5863,7 +5863,7 @@ snapshots: rollup: 4.52.5 tinyglobby: 0.2.15 optionalDependencies: - '@types/node': 24.8.1 + '@types/node': 24.9.1 fsevents: 2.3.3 sass: 1.92.1 yaml: 2.8.1 diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index f8cca8ea..3e769883 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -947,9 +947,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.49" +version = "4.5.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4512b90fa68d3a9932cea5184017c5d200f5921df706d45e853537dea51508f" +checksum = "0c2cfd7bf8a6017ddaa4e32ffe7403d547790db06bd171c1c53926faab501623" dependencies = [ "clap_builder", "clap_derive", @@ -957,9 +957,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.49" +version = "4.5.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0025e98baa12e766c67ba13ff4695a887a1eba19569aad00a472546795bd6730" +checksum = "0a4c05b9e80c5ccd3a7ef080ad7b6ba7d6fc00a985b8b157197075677c82c7a0" dependencies = [ "anstream", "anstyle", @@ -4065,9 +4065,9 @@ checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" [[package]] name = "openssl-src" -version = "300.5.3+3.5.4" +version = "300.5.4+3.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc6bad8cd0233b63971e232cc9c5e83039375b8586d2312f31fda85db8f888c2" +checksum = "a507b3792995dae9b0df8a1c1e3771e8418b7c2d9f0baeba32e6fe8b06c7cb72" dependencies = [ "cc", ] @@ -6225,9 +6225,9 @@ dependencies = [ [[package]] name = "tao" -version = "0.34.4" +version = "0.34.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6121216ff67fe4bcfe64508ea1700bc15f74937d835a07b4a209cc00a8926a84" +checksum = "f3a753bdc39c07b192151523a3f77cd0394aa75413802c883a0f6f6a0e5ee2e7" dependencies = [ "bitflags 2.10.0", "block2 0.6.2", @@ -6288,9 +6288,9 @@ checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" [[package]] name = "tauri" -version = "2.8.5" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4d1d3b3dc4c101ac989fd7db77e045cc6d91a25349cd410455cb5c57d510c1c" +checksum = "7f07c6590706b2fc0ab287b041cf5ce9c435b3850bdae5571e19d9d27584e89d" dependencies = [ "anyhow", "bytes", @@ -6341,9 +6341,9 @@ dependencies = [ [[package]] name = "tauri-build" -version = "2.4.1" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c432ccc9ff661803dab74c6cd78de11026a578a9307610bbc39d3c55be7943f" +checksum = "f71be1f494b683ac439e6d61c16ab5c472c6f9c6ee78995b29556d9067c021a1" dependencies = [ "anyhow", "cargo_toml", @@ -6363,9 +6363,9 @@ dependencies = [ [[package]] name = "tauri-codegen" -version = "2.4.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ab3a62cf2e6253936a8b267c2e95839674e7439f104fa96ad0025e149d54d8a" +checksum = "6c1fe64c74cc40f90848281a90058a6db931eb400b60205840e09801ee30f190" dependencies = [ "base64 0.22.1", "brotli", @@ -6390,9 +6390,9 @@ dependencies = [ [[package]] name = "tauri-macros" -version = "2.4.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4368ea8094e7045217edb690f493b55b30caf9f3e61f79b4c24b6db91f07995e" +checksum = "260c5d2eb036b76206b9fca20b7be3614cfd21046c5396f7959e0e64a4b07f2f" dependencies = [ "heck 0.5.0", "proc-macro2", @@ -6404,9 +6404,9 @@ dependencies = [ [[package]] name = "tauri-plugin" -version = "2.4.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9946a3cede302eac0c6eb6c6070ac47b1768e326092d32efbb91f21ed58d978f" +checksum = "3d7ce9aab979296b2f91e6fbf154207c2e3512b12ddca0b24bfa0e0cde6b2976" dependencies = [ "anyhow", "glob", @@ -6633,9 +6633,9 @@ dependencies = [ [[package]] name = "tauri-runtime" -version = "2.8.0" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4cfc9ad45b487d3fded5a4731a567872a4812e9552e3964161b08edabf93846" +checksum = "3367f0b47df90e9195cd9f04a56b0055a2cba45aa11923c6c253d748778176fc" dependencies = [ "cookie", "dpi", @@ -6658,9 +6658,9 @@ dependencies = [ [[package]] name = "tauri-runtime-wry" -version = "2.8.1" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1fe9d48bd122ff002064e88cfcd7027090d789c4302714e68fcccba0f4b7807" +checksum = "80d91d29ca680c545364cf75ba2f2e3c7ea2ab6376bfa3be26b56fa2463a5b5e" dependencies = [ "gtk", "http", @@ -6685,9 +6685,9 @@ dependencies = [ [[package]] name = "tauri-utils" -version = "2.7.0" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41a3852fdf9a4f8fbeaa63dc3e9a85284dd6ef7200751f0bd66ceee30c93f212" +checksum = "f6b8bbe426abdbf52d050e52ed693130dbd68375b9ad82a3fb17efb4c8d85673" dependencies = [ "anyhow", "brotli", @@ -7293,9 +7293,9 @@ dependencies = [ [[package]] name = "tray-icon" -version = "0.21.1" +version = "0.21.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0d92153331e7d02ec09137538996a7786fe679c629c279e82a6be762b7e6fe2" +checksum = "e3d5572781bee8e3f994d7467084e1b1fd7a93ce66bd480f8156ba89dee55a2b" dependencies = [ "crossbeam-channel", "dirs", @@ -7310,7 +7310,7 @@ dependencies = [ "png 0.17.16", "serde", "thiserror 2.0.17", - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] [[package]] @@ -7415,9 +7415,9 @@ checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5" [[package]] name = "unicode-ident" -version = "1.0.19" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d" +checksum = "462eeb75aeb73aea900253ce739c8e18a67423fadf006037cd3ff27e82748a06" [[package]] name = "unicode-normalization" diff --git a/src-tauri/src/export.rs b/src-tauri/src/export.rs index 41b7e987..37a51284 100644 --- a/src-tauri/src/export.rs +++ b/src-tauri/src/export.rs @@ -27,26 +27,6 @@ pub(crate) struct TunnelConfiguration { dns_search: Vec, } -// impl TunnelConfiguration { -// #[must_use] -// pub(crate) fn new( -// interface_configuration: InterfaceConfiguration, -// dns: Vec, -// dns_search: Vec, -// ) -> Self { -// Self { -// name: interface_configuration.name, -// private_key: interface_configuration.prvkey, -// addresses: interface_configuration.addresses, -// listen_port: Some(interface_configuration.port), -// peers: interface_configuration.peers, -// mtu: interface_configuration.mtu, -// dns, -// dns_search, -// } -// } -// } - impl Location { pub(crate) async fn tunnel_configurarion<'e, E>( &self, diff --git a/src-tauri/src/utils.rs b/src-tauri/src/utils.rs index fb4ddf8e..2b6bde5e 100644 --- a/src-tauri/src/utils.rs +++ b/src-tauri/src/utils.rs @@ -73,13 +73,13 @@ pub(crate) async fn setup_interface( .await?; // tunnel_config.port = port; - swift!(fn start_tunnel(prvkey: &SRString)); + swift!(fn start_tunnel(json: &SRString) -> bool); unsafe { - let prvkey: SRString = serde_json::to_string(&tunnel_config) + let json: SRString = serde_json::to_string(&tunnel_config) .unwrap() .as_str() .into(); - let result = start_tunnel(&prvkey); + let result = start_tunnel(&json); error!("start_tunnel() returned {result:?}"); } Ok(()) @@ -261,10 +261,10 @@ pub fn load_log_targets() -> Vec { // helper function to get log file directory for the defguard-service daemon #[must_use] pub fn get_service_log_dir() -> &'static Path { - #[cfg(target_os = "windows")] + #[cfg(windows)] let path = "/Logs/defguard-service"; - #[cfg(not(target_os = "windows"))] + #[cfg(not(windows))] let path = "/var/log/defguard-service"; Path::new(path) @@ -644,30 +644,40 @@ pub(crate) async fn disconnect_interface( ); return Err(Error::NotFound); }; - let request = RemoveInterfaceRequest { - interface_name, - endpoint: location.endpoint.clone(), - }; - debug!( - "Sending request to the background service to remove interface {} for location \ - {}...", - active_connection.interface_name, location.name - ); - if let Err(error) = client.remove_interface(request).await { - let msg = if error.code() == Code::Unavailable { - format!( - "Couldn't remove interface {}. Background service is unavailable. \ - Please make sure the service is running. Error: {error}.", - active_connection.interface_name - ) - } else { - format!( - "Failed to send a request to the background service to remove interface \ - {}. Error: {error}.", - active_connection.interface_name - ) - }; - error!("{msg}"); + + let mut result = false; + swift!(fn stop_tunnel(name: &SRString) -> bool); + unsafe { + let name: SRString = location.name.as_str().into(); + result = stop_tunnel(&name); + error!("stop_tunnel() returned {result:?}"); + } + if !result { + let msg = String::from("Error from Swift"); + // let request = RemoveInterfaceRequest { + // interface_name, + // endpoint: location.endpoint.clone(), + // }; + // debug!( + // "Sending request to the background service to remove interface {} for location \ + // {}...", + // active_connection.interface_name, location.name + // ); + // if let Err(error) = client.remove_interface(request).await { + // let msg = if error.code() == Code::Unavailable { + // format!( + // "Couldn't remove interface {}. Background service is unavailable. \ + // Please make sure the service is running. Error: {error}.", + // active_connection.interface_name + // ) + // } else { + // format!( + // "Failed to send a request to the background service to remove interface \ + // {}. Error: {error}.", + // active_connection.interface_name + // ) + // }; + // error!("{msg}"); return Err(Error::InternalError(msg)); } let connection: Connection = active_connection.into(); diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index 6ca8274e..2b83bf39 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -40,7 +40,7 @@ "exceptionDomain": "", "files": { "embedded.provisionprofile": "Adam_Apollo_Defguard.provisionprofile", - "PlugIns": "/Users/adam/Library/Developer/Xcode/DerivedData/NetExt-bpogxtiuhfulrpbbfnqblorodxcp/Build/Products/Release/NetExt.app/Contents/PlugIns" + "PlugIns/VPNExtension.appex": "../swift/extension/build/Debug/VPNExtension.appex" }, "frameworks": [], "minimumSystemVersion": "13.5", diff --git a/swift/.gitignore b/swift/.gitignore index 7507e0a8..9ca7835c 100644 --- a/swift/.gitignore +++ b/swift/.gitignore @@ -1,7 +1,8 @@ .DS_Store */.build +build +Boringtun /Packages -/*.xcodeproj xcuserdata/ DerivedData/ .swiftpm/config/registries.json diff --git a/swift/extension/VPNExtension.xcodeproj/project.pbxproj b/swift/extension/VPNExtension.xcodeproj/project.pbxproj new file mode 100644 index 00000000..bec82c49 --- /dev/null +++ b/swift/extension/VPNExtension.xcodeproj/project.pbxproj @@ -0,0 +1,397 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 77; + objects = { + +/* Begin PBXBuildFile section */ + 66CABCD82EA76D070057D1AF /* NetworkExtension.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 66CABCD72EA76D060057D1AF /* NetworkExtension.framework */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 66CABCD42EA76D060057D1AF /* VPNExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = VPNExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; }; + 66CABCD72EA76D060057D1AF /* NetworkExtension.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = NetworkExtension.framework; path = System/Library/Frameworks/NetworkExtension.framework; sourceTree = SDKROOT; }; +/* End PBXFileReference section */ + +/* Begin PBXFileSystemSynchronizedBuildFileExceptionSet section */ + 66CABCDE2EA76D070057D1AF /* Exceptions for "VPNExtension" folder in "VPNExtension" target */ = { + isa = PBXFileSystemSynchronizedBuildFileExceptionSet; + membershipExceptions = ( + Info.plist, + ); + target = 66CABCD32EA76D060057D1AF /* VPNExtension */; + }; +/* End PBXFileSystemSynchronizedBuildFileExceptionSet section */ + +/* Begin PBXFileSystemSynchronizedRootGroup section */ + 660FE5002EA779E8006A7447 /* Defguard */ = { + isa = PBXFileSystemSynchronizedRootGroup; + name = Defguard; + path = ../plugin/Sources/Defguard; + sourceTree = SOURCE_ROOT; + }; + 660FE50B2EA77C68006A7447 /* BoringTun */ = { + isa = PBXFileSystemSynchronizedRootGroup; + path = BoringTun; + sourceTree = ""; + }; + 66CABCD92EA76D070057D1AF /* VPNExtension */ = { + isa = PBXFileSystemSynchronizedRootGroup; + exceptions = ( + 66CABCDE2EA76D070057D1AF /* Exceptions for "VPNExtension" folder in "VPNExtension" target */, + ); + path = VPNExtension; + sourceTree = ""; + }; +/* End PBXFileSystemSynchronizedRootGroup section */ + +/* Begin PBXFrameworksBuildPhase section */ + 66CABCD12EA76D060057D1AF /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 66CABCD82EA76D070057D1AF /* NetworkExtension.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 66CABCC92EA76CD80057D1AF = { + isa = PBXGroup; + children = ( + 660FE50B2EA77C68006A7447 /* BoringTun */, + 660FE5002EA779E8006A7447 /* Defguard */, + 66CABCD92EA76D070057D1AF /* VPNExtension */, + 66CABCD62EA76D060057D1AF /* Frameworks */, + 66CABCD52EA76D060057D1AF /* Products */, + ); + sourceTree = ""; + }; + 66CABCD52EA76D060057D1AF /* Products */ = { + isa = PBXGroup; + children = ( + 66CABCD42EA76D060057D1AF /* VPNExtension.appex */, + ); + name = Products; + sourceTree = ""; + }; + 66CABCD62EA76D060057D1AF /* Frameworks */ = { + isa = PBXGroup; + children = ( + 66CABCD72EA76D060057D1AF /* NetworkExtension.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 66CABCD32EA76D060057D1AF /* VPNExtension */ = { + isa = PBXNativeTarget; + buildConfigurationList = 66CABCDF2EA76D070057D1AF /* Build configuration list for PBXNativeTarget "VPNExtension" */; + buildPhases = ( + 66CABCD02EA76D060057D1AF /* Sources */, + 66CABCD12EA76D060057D1AF /* Frameworks */, + 66CABCD22EA76D060057D1AF /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + fileSystemSynchronizedGroups = ( + 660FE5002EA779E8006A7447 /* Defguard */, + 660FE50B2EA77C68006A7447 /* BoringTun */, + 66CABCD92EA76D070057D1AF /* VPNExtension */, + ); + name = VPNExtension; + packageProductDependencies = ( + ); + productName = VPNExtension; + productReference = 66CABCD42EA76D060057D1AF /* VPNExtension.appex */; + productType = "com.apple.product-type.app-extension"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 66CABCCA2EA76CD80057D1AF /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = 1; + LastSwiftUpdateCheck = 2600; + LastUpgradeCheck = 2600; + TargetAttributes = { + 66CABCD32EA76D060057D1AF = { + CreatedOnToolsVersion = 26.0.1; + }; + }; + }; + buildConfigurationList = 66CABCCD2EA76CD80057D1AF /* Build configuration list for PBXProject "VPNExtension" */; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 66CABCC92EA76CD80057D1AF; + minimizedProjectReferenceProxies = 1; + preferredProjectObjectVersion = 77; + productRefGroup = 66CABCD52EA76D060057D1AF /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 66CABCD32EA76D060057D1AF /* VPNExtension */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 66CABCD22EA76D060057D1AF /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 66CABCD02EA76D060057D1AF /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 66CABCCE2EA76CD80057D1AF /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + DEVELOPMENT_TEAM = 82GZ7KN29J; + SWIFT_OBJC_BRIDGING_HEADER = "$(PROJECT_DIR)/BoringTun/boringtunFFI.h"; + }; + name = Debug; + }; + 66CABCCF2EA76CD80057D1AF /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + DEVELOPMENT_TEAM = 82GZ7KN29J; + SWIFT_OBJC_BRIDGING_HEADER = "$(PROJECT_DIR)/BoringTun/boringtunFFI.h"; + }; + name = Release; + }; + 66CABCE02EA76D070057D1AF /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_ENTITLEMENTS = VPNExtension/VPNExtension.entitlements; + CODE_SIGN_STYLE = Automatic; + COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = dwarf; + DEVELOPMENT_TEAM = 82GZ7KN29J; + ENABLE_APP_SANDBOX = YES; + ENABLE_HARDENED_RUNTIME = YES; + ENABLE_INCOMING_NETWORK_CONNECTIONS = YES; + ENABLE_OUTGOING_NETWORK_CONNECTIONS = YES; + ENABLE_RESOURCE_ACCESS_AUDIO_INPUT = NO; + ENABLE_RESOURCE_ACCESS_BLUETOOTH = NO; + ENABLE_RESOURCE_ACCESS_CALENDARS = NO; + ENABLE_RESOURCE_ACCESS_CAMERA = NO; + ENABLE_RESOURCE_ACCESS_CONTACTS = NO; + ENABLE_RESOURCE_ACCESS_LOCATION = NO; + ENABLE_RESOURCE_ACCESS_PRINTING = NO; + ENABLE_RESOURCE_ACCESS_USB = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = VPNExtension/Info.plist; + INFOPLIST_KEY_CFBundleDisplayName = VPNExtension; + INFOPLIST_KEY_NSHumanReadableCopyright = ""; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + "@executable_path/../../../../Frameworks", + ); + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MACOSX_DEPLOYMENT_TARGET = 13.5; + MARKETING_VERSION = 1.0; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + PRODUCT_BUNDLE_IDENTIFIER = net.defguard.client.VPNExtension; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + SKIP_INSTALL = YES; + STRING_CATALOG_GENERATE_SYMBOLS = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)"; + SWIFT_APPROACHABLE_CONCURRENCY = YES; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_UPCOMING_FEATURE_MEMBER_IMPORT_VISIBILITY = YES; + SWIFT_VERSION = 5.0; + }; + name = Debug; + }; + 66CABCE12EA76D070057D1AF /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_ENTITLEMENTS = VPNExtension/VPNExtension.entitlements; + CODE_SIGN_STYLE = Automatic; + COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DEVELOPMENT_TEAM = 82GZ7KN29J; + ENABLE_APP_SANDBOX = YES; + ENABLE_HARDENED_RUNTIME = YES; + ENABLE_INCOMING_NETWORK_CONNECTIONS = YES; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_OUTGOING_NETWORK_CONNECTIONS = YES; + ENABLE_RESOURCE_ACCESS_AUDIO_INPUT = NO; + ENABLE_RESOURCE_ACCESS_BLUETOOTH = NO; + ENABLE_RESOURCE_ACCESS_CALENDARS = NO; + ENABLE_RESOURCE_ACCESS_CAMERA = NO; + ENABLE_RESOURCE_ACCESS_CONTACTS = NO; + ENABLE_RESOURCE_ACCESS_LOCATION = NO; + ENABLE_RESOURCE_ACCESS_PRINTING = NO; + ENABLE_RESOURCE_ACCESS_USB = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = VPNExtension/Info.plist; + INFOPLIST_KEY_CFBundleDisplayName = VPNExtension; + INFOPLIST_KEY_NSHumanReadableCopyright = ""; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + "@executable_path/../../../../Frameworks", + ); + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MACOSX_DEPLOYMENT_TARGET = 13.5; + MARKETING_VERSION = 1.0; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + PRODUCT_BUNDLE_IDENTIFIER = net.defguard.client.VPNExtension; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + SKIP_INSTALL = YES; + STRING_CATALOG_GENERATE_SYMBOLS = YES; + SWIFT_APPROACHABLE_CONCURRENCY = YES; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_UPCOMING_FEATURE_MEMBER_IMPORT_VISIBILITY = YES; + SWIFT_VERSION = 5.0; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 66CABCCD2EA76CD80057D1AF /* Build configuration list for PBXProject "VPNExtension" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 66CABCCE2EA76CD80057D1AF /* Debug */, + 66CABCCF2EA76CD80057D1AF /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 66CABCDF2EA76D070057D1AF /* Build configuration list for PBXNativeTarget "VPNExtension" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 66CABCE02EA76D070057D1AF /* Debug */, + 66CABCE12EA76D070057D1AF /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 66CABCCA2EA76CD80057D1AF /* Project object */; +} diff --git a/swift/extension/VPNExtension.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/swift/extension/VPNExtension.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 00000000..919434a6 --- /dev/null +++ b/swift/extension/VPNExtension.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/swift/extension/VPNExtension/Adapter.swift b/swift/extension/VPNExtension/Adapter.swift new file mode 100644 index 00000000..0e00cbd1 --- /dev/null +++ b/swift/extension/VPNExtension/Adapter.swift @@ -0,0 +1,281 @@ +import Foundation +import Network +import NetworkExtension +import os + +/// State of Adapter. +enum State { + /// Tunnel is running. + case running + /// Tunnel is stopped. + case stopped + /// Tunnel is temporary unavaiable due to device being offline. + case dormant +} + +@preconcurrency final class Adapter /*: Sendable*/ { + /// Packet tunnel provider. + private weak var packetTunnelProvider: NEPacketTunnelProvider? + /// BortingTun tunnel + private var tunnel: Tunnel? + /// UDP endpoint + private var endpoint: Network.NWEndpoint? + /// Server connection + private var connection: NWConnection? + /// Network routes monitor. + private var networkMonitor: NWPathMonitor? + /// Keep alive timer + private var keepAliveTimer: Timer? + /// Logging + private lazy var logger = Logger(subsystem: Bundle.main.bundleIdentifier!, category: "Adapter") + /// Adapter state. + private var state: State = .stopped + + private let notificationCenter = CFNotificationCenterGetDarwinNotifyCenter() + + + /// Designated initializer. + /// - Parameter packetTunnelProvider: an instance of `NEPacketTunnelProvider`. Internally stored + init(with packetTunnelProvider: NEPacketTunnelProvider) { + self.packetTunnelProvider = packetTunnelProvider + } + + deinit { + self.stop() + } + + func start(tunnelConfiguration: TunnelConfiguration) throws { + guard case .stopped = self.state else { + logger.error("Invalid state") + // TODO: throw invalid state + return + } + + if let _ = tunnel { + logger.info("Cleaning exiting Tunnel") + tunnel = nil + connection = nil + } + + let networkMonitor = NWPathMonitor() + networkMonitor.pathUpdateHandler = { [weak self] path in + self?.networkPathUpdate(path: path) + } + networkMonitor.start(queue: .main) + self.networkMonitor = networkMonitor + + logger.info("Initializing Tunnel") + tunnel = try Tunnel.init( + privateKey: tunnelConfiguration.privateKey, + serverPublicKey: tunnelConfiguration.peers[0].publicKey, + presharedKey: tunnelConfiguration.peers[0].preSharedKey, + keepAlive: tunnelConfiguration.peers[0].persistentKeepAlive, + index: 0 + ) + + logger.info("Connecting to endpoint") + guard let endpoint = tunnelConfiguration.peers[0].endpoint else { + logger.error("Endpoint is nil") + return + } + self.endpoint = endpoint.asNWEndpoint() + initEndpoint() + + logger.info("Sniffing packets") + readPackets() + + state = .running + + // Test notifications + let notificationName = CFNotificationName("net.defguard.NetExt.start" as CFString) + CFNotificationCenterPostNotification(notificationCenter, notificationName, nil, nil, false) + } + + func stop() { + logger.info("Stopping Adapter") + connection?.cancel() + connection = nil + tunnel = nil + keepAliveTimer?.invalidate() + keepAliveTimer = nil + // Cancel network monitor + networkMonitor?.cancel() + networkMonitor = nil + + state = .stopped + logger.info("Tunnel stopped") + + // Test notifications + let notificationName = CFNotificationName("net.defguard.NetExt.stop" as CFString) + CFNotificationCenterPostNotification(notificationCenter, notificationName, nil, nil, false) + } + + private func handleTunnelResult(_ result: TunnelResult) { + switch result { + case .done: + // Nothing to do. + break + case .err(let error): + logger.error("Tunnel error \(error, privacy: .public)") + switch error { + case .InvalidAeadTag: + logger.error("Invalid pre-shared key; stopping tunnel") + // The correct way is to call the packet tunnel provider, if there is one. + if let provider = packetTunnelProvider { + provider.cancelTunnelWithError(error) + } else { + stop() + } + case .ConnectionExpired: + logger.error("Connecion has expired; re-connecting") + packetTunnelProvider?.reasserting = true + initEndpoint() + packetTunnelProvider?.reasserting = false + default: + break + } + case .writeToNetwork(let data): + sendToEndpoint(data: data) + case .writeToTunnelV4(let data): + packetTunnelProvider?.packetFlow.writePacketObjects([ + NEPacket(data: data,protocolFamily: sa_family_t(AF_INET))]) + case .writeToTunnelV6(let data): + packetTunnelProvider?.packetFlow.writePacketObjects([ + NEPacket(data: data, protocolFamily: sa_family_t(AF_INET6))]) + } + } + + /// Initialise UDP connection to endpoint. + private func initEndpoint() { + guard let endpoint = endpoint else { return } + + logger.info("Init Endpoint") + // Cancel previous connection + connection?.cancel() + connection = nil + + let params = NWParameters.udp + params.allowLocalEndpointReuse = true + let connection = NWConnection.init(to: endpoint, using: params) + connection.stateUpdateHandler = { [weak self] state in + self?.endpointStateChange(state: state) + } + + connection.start(queue: .main) + self.connection = connection + } + + /// Setup UDP connection to endpoint. This method should be called when UDP connection is ready to send and receive. + private func setupEndpoint() { + logger.info("Setup endpoint") + + // Send initial handshake packet + if let tunnel = self.tunnel { + handleTunnelResult(tunnel.forceHandshake()) + } + logger.info("Receiving UDP from endpoint") + logger.debug("NWConnection path \(String(describing: self.connection?.currentPath), privacy: .public)") + receive() + + // Use Timer to send keep-alive packets. + keepAliveTimer?.invalidate() + logger.info("Creating keep-alive timer") + let timer = Timer(timeInterval: 0.25, repeats: true) { [weak self] timer in + guard let self = self, let tunnel = self.tunnel else { return } + self.handleTunnelResult(tunnel.tick()) + } + keepAliveTimer = timer + RunLoop.main.add(timer, forMode: .common) + } + + /// Send packets to UDP endpoint. + private func sendToEndpoint(data: Data) { + guard let connection = connection else { return } + if connection.state == .ready { + connection.send(content: data, completion: .contentProcessed { error in + if let error = error { + self.logger.error("UDP connection send error: \(error, privacy: .public)") + } + }) + } else { + logger.warning("UDP connection not ready to send") + } + } + + /// Handle UDP packets from the endpoint. + private func receive() { + connection?.receiveMessage { [weak self] data, context, isComplete, error in + guard let self = self else { return } + if let data = data, let tunnel = self.tunnel { + self.handleTunnelResult(tunnel.read(src: data)) + } + if error == nil { + // continue receiving + self.receive() + } else { + logger.error("receive() error: \(error)") + } + } + } + + /// Read tunnel packets. + private func readPackets() { + guard let tunnel = self.tunnel else { return } + + // Packets received to the tunnel's virtual interface. + packetTunnelProvider?.packetFlow.readPacketObjects { packets in + for packet in packets { + self.handleTunnelResult(tunnel.write(src: packet.data)) + } + // continue reading + self.readPackets() + } + } + + /// Handle UDP connection state changes. + private func endpointStateChange(state: NWConnection.State) { + logger.debug("UDP connection state: \(String(describing: state), privacy: .public)") + switch state { + case .ready: + setupEndpoint() + //case .waiting(let error): + // switch error { + // case .posix(_): + // connection?.restart() + // default: + // self.stop() + // } + case .failed(let error): + logger.error("Failed to establish endpoint connection: \(error)") + // The correct way is to call the packet tunnel provider, if there is one. + if let provider = packetTunnelProvider { + provider.cancelTunnelWithError(error) + } else { + stop() + } + default: + break + } + } + + /// Handle network path updates. + private func networkPathUpdate(path: Network.NWPath) { + logger + .debug("Network path status \(String(describing: path.status), privacy: .public); interfaces \(path.availableInterfaces, privacy: .public)" + ) + if path.status == .unsatisfied { + if state == .running { + logger.warning("Unsatisfied network path: going dormant") + connection?.cancel() + connection = nil + state = .dormant + } + } else { + if state == .dormant { + logger.warning("Satisfied network path: going running") + initEndpoint() + state = .running + } + } + } +} diff --git a/swift/extension/VPNExtension/Info.plist b/swift/extension/VPNExtension/Info.plist new file mode 100644 index 00000000..3059459e --- /dev/null +++ b/swift/extension/VPNExtension/Info.plist @@ -0,0 +1,13 @@ + + + + + NSExtension + + NSExtensionPointIdentifier + com.apple.networkextension.packet-tunnel + NSExtensionPrincipalClass + $(PRODUCT_MODULE_NAME).PacketTunnelProvider + + + diff --git a/swift/extension/VPNExtension/PacketTunnelProvider.swift b/swift/extension/VPNExtension/PacketTunnelProvider.swift new file mode 100644 index 00000000..f45f5d11 --- /dev/null +++ b/swift/extension/VPNExtension/PacketTunnelProvider.swift @@ -0,0 +1,70 @@ +import NetworkExtension +import os + +enum WireGuardTunnelError: Error { + case invalidTunnelConfiguration +} + +class PacketTunnelProvider: NEPacketTunnelProvider { + /// Logging + private var logger = Logger(subsystem: Bundle.main.bundleIdentifier!, category: "PacketTunnelProvider") + + private lazy var adapter: Adapter = { + return Adapter(with: self) + }() + + override func startTunnel(options: [String : NSObject]?, completionHandler: @escaping (Error?) -> Void) { + logger.debug("\(#function)") + if let options = options { + logger.log("Options: \(options)") + } + + guard let protocolConfig = self.protocolConfiguration as? NETunnelProviderProtocol, + let providerConfig = protocolConfig.providerConfiguration, + let tunnelConfig = try? TunnelConfiguration.from(dictionary: providerConfig) else { + completionHandler(WireGuardTunnelError.invalidTunnelConfiguration) + return + } + + let networkSettings = tunnelConfig.asNetworkSettings() + self.setTunnelNetworkSettings(networkSettings) { error in + self.logger.log("Set tunnel network settings returned \(error)") + completionHandler(error) + return + } + + do { + try adapter.start(tunnelConfiguration: tunnelConfig) + } catch { + logger.error("Failed to start tunnel") + completionHandler(error) + } + + completionHandler(nil) + } + + override func stopTunnel(with reason: NEProviderStopReason, completionHandler: @escaping () -> Void) { + logger.debug("\(#function)") + adapter.stop() + completionHandler() + } + + override func handleAppMessage(_ messageData: Data, completionHandler: ((Data?) -> Void)?) { + logger.debug("\(#function)") + // Add code here to handle the message. + if let handler = completionHandler { + handler(messageData) + } + } + + override func sleep(completionHandler: @escaping () -> Void) { + logger.debug("\(#function)") + // Add code here to get ready to sleep. + completionHandler() + } + + override func wake() { + logger.debug("\(#function)") + // Add code here to wake up. + } +} diff --git a/swift/extension/VPNExtension/VPNExtension.entitlements b/swift/extension/VPNExtension/VPNExtension.entitlements new file mode 100644 index 00000000..ffab33e0 --- /dev/null +++ b/swift/extension/VPNExtension/VPNExtension.entitlements @@ -0,0 +1,10 @@ + + + + + com.apple.developer.networking.networkextension + + packet-tunnel-provider + + + diff --git a/swift/plugin/Sources/Decodabe+Encodable.swift b/swift/plugin/Sources/Defguard/Decodabe+Encodable.swift similarity index 100% rename from swift/plugin/Sources/Decodabe+Encodable.swift rename to swift/plugin/Sources/Defguard/Decodabe+Encodable.swift diff --git a/swift/plugin/Sources/Endpoint.swift b/swift/plugin/Sources/Defguard/Endpoint.swift similarity index 99% rename from swift/plugin/Sources/Endpoint.swift rename to swift/plugin/Sources/Defguard/Endpoint.swift index bb218061..64f50a40 100644 --- a/swift/plugin/Sources/Endpoint.swift +++ b/swift/plugin/Sources/Defguard/Endpoint.swift @@ -1,3 +1,4 @@ +import Foundation import Network struct Endpoint: Codable, CustomStringConvertible { diff --git a/swift/plugin/Sources/IpAddrMask.swift b/swift/plugin/Sources/Defguard/IpAddrMask.swift similarity index 100% rename from swift/plugin/Sources/IpAddrMask.swift rename to swift/plugin/Sources/Defguard/IpAddrMask.swift diff --git a/swift/plugin/Sources/Peer.swift b/swift/plugin/Sources/Defguard/Peer.swift similarity index 100% rename from swift/plugin/Sources/Peer.swift rename to swift/plugin/Sources/Defguard/Peer.swift diff --git a/swift/plugin/Sources/TunnelConfiguration.swift b/swift/plugin/Sources/Defguard/TunnelConfiguration.swift similarity index 100% rename from swift/plugin/Sources/TunnelConfiguration.swift rename to swift/plugin/Sources/Defguard/TunnelConfiguration.swift diff --git a/swift/plugin/Sources/Wireguard.swift b/swift/plugin/Sources/Wireguard.swift index d2d57fe1..8d3c8351 100644 --- a/swift/plugin/Sources/Wireguard.swift +++ b/swift/plugin/Sources/Wireguard.swift @@ -4,7 +4,7 @@ import NetworkExtension import SwiftRs import os -let appId = Bundle.main.bundleIdentifier ?? "net.defguard" +let appId = Bundle.main.bundleIdentifier ?? "net.defguard.client" let pluginAppId = "\(appId).VPNExtension" let plugin = WireguardPlugin() let logger = Logger(subsystem: appId, category: "WireguardPlugin") @@ -29,21 +29,30 @@ public func startTunnel(json: SRString) -> Bool { return false } - logger.log("Saving tunnel with config: \(String(describing: config))") -// plugin.startTunnel(config: config) { result in -// if result == nil { -// logger.info("Tunnel started successfully") -// } else { -// logger.error("Tunnel failed to start with \(result)") -// } -// } + logger.info("Saving tunnel with config: \(String(describing: config))") saveConfig(config) return true } +@_cdecl("stop_tunnel") +public func stopTunnel(name: SRString) -> Bool { + managerForName(name.toString()) { manager in + if let providerManager = manager { + // TEST + do { + try providerManager.connection.stopVPNTunnel() + logger.info("VPN stopped") + } catch { + logger.error("Failed to stop VPN") + } + } + } + return true +} + func saveConfig(_ config: TunnelConfiguration) { - managerForConfig(config) { manager in + managerForName(config.name) { manager in let providerManager = manager ?? NETunnelProviderManager() let tunnelProtocol = NETunnelProviderProtocol() tunnelProtocol.providerBundleIdentifier = pluginAppId @@ -74,11 +83,21 @@ func saveConfig(_ config: TunnelConfiguration) { logger.info("Config saved") } } + + // TEST + do { + try providerManager.connection.startVPNTunnel() + logger.info("VPN started") + } catch { + logger.error("Failed to start VPN") + } } } -func managerForConfig(_ config: TunnelConfiguration, - completion: @escaping (NETunnelProviderManager?) -> Void) { +func managerForName( + _ name: String, + completion: @escaping (NETunnelProviderManager?) -> Void +) { var providerManager: NETunnelProviderManager? NETunnelProviderManager.loadAllFromPreferences { managers, error in guard let managers = managers else { @@ -98,10 +117,11 @@ func managerForConfig(_ config: TunnelConfiguration, providerManager = nil for manager in managers { // Obtain named configuration. - if manager.localizedDescription != config.name { + if manager.localizedDescription != name { continue } - guard let tunnelProtocol = manager.protocolConfiguration as? NETunnelProviderProtocol else { + guard let tunnelProtocol = manager.protocolConfiguration as? NETunnelProviderProtocol + else { continue } // Sometimes all managers from all apps come through, so filter by bundle ID. @@ -112,8 +132,7 @@ func managerForConfig(_ config: TunnelConfiguration, } if providerManager == nil { logger.log("No VPN manager found") - } - else { + } else { logger.log( "Loaded provider manager: \(String(describing: providerManager!.localizedDescription), privacy: .public)" ) From 0bbdebc9b6bd54444226ba776ffe32901cf827ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adam=20Ciarcin=CC=81ski?= Date: Thu, 23 Oct 2025 16:34:17 +0200 Subject: [PATCH 07/28] Work in progress --- package.json | 4 +- pnpm-lock.yaml | 218 +++++++++--------- src-tauri/Cargo.lock | 189 ++++++++------- src-tauri/Client.entitlements | 2 +- src-tauri/resources-macos/binaries/.gitkeep | 0 src-tauri/src/appstate.rs | 28 +-- src-tauri/src/export.rs | 5 + src-tauri/src/lib.rs | 2 +- src-tauri/src/periodic/mod.rs | 2 +- src-tauri/src/utils.rs | 37 ++- .../VPNExtension/PacketTunnelProvider.swift | 4 +- swift/plugin/Sources/VPNManager.swift | 38 +-- swift/plugin/Sources/Wireguard.swift | 33 ++- swift/plugin/Sources/WireguardPlugin.swift | 62 ++--- 14 files changed, 332 insertions(+), 292 deletions(-) delete mode 100644 src-tauri/resources-macos/binaries/.gitkeep diff --git a/package.json b/package.json index 81829fe5..b4d18788 100644 --- a/package.json +++ b/package.json @@ -106,12 +106,12 @@ "zustand": "^5.0.8" }, "devDependencies": { - "@biomejs/biome": "^2.2.6", + "@biomejs/biome": "^2.2.7", "@hookform/devtools": "^4.4.0", "@svgr/cli": "^8.1.0", "@tanstack/react-query": "^5.90.5", "@tanstack/react-query-devtools": "^5.90.2", - "@tauri-apps/cli": "^2.9.0", + "@tauri-apps/cli": "^2.9.1", "@types/file-saver": "^2.0.7", "@types/lodash-es": "^4.17.12", "@types/node": "^24.9.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 33d4cc00..a348b2bf 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -181,8 +181,8 @@ importers: version: 5.0.8(@types/react@19.2.2)(immer@10.1.3)(react@19.2.0)(use-sync-external-store@1.6.0(react@19.2.0)) devDependencies: '@biomejs/biome': - specifier: ^2.2.6 - version: 2.2.6 + specifier: ^2.2.7 + version: 2.2.7 '@hookform/devtools': specifier: ^4.4.0 version: 4.4.0(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) @@ -196,8 +196,8 @@ importers: specifier: ^5.90.2 version: 5.90.2(@tanstack/react-query@5.90.5(react@19.2.0))(react@19.2.0) '@tauri-apps/cli': - specifier: ^2.9.0 - version: 2.9.0 + specifier: ^2.9.1 + version: 2.9.1 '@types/file-saver': specifier: ^2.0.7 version: 2.0.7 @@ -336,55 +336,55 @@ packages: resolution: {integrity: sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q==} engines: {node: '>=6.9.0'} - '@biomejs/biome@2.2.6': - resolution: {integrity: sha512-yKTCNGhek0rL5OEW1jbLeZX8LHaM8yk7+3JRGv08my+gkpmtb5dDE+54r2ZjZx0ediFEn1pYBOJSmOdDP9xtFw==} + '@biomejs/biome@2.2.7': + resolution: {integrity: sha512-1a8j0UP1vXVUf3UzMZEJ/zS2VgAG6wU6Cuh/I764sUGI+MCnJs/9WaojHYBDCxCMLTgU60/WqnYof85emXmSBA==} engines: {node: '>=14.21.3'} hasBin: true - '@biomejs/cli-darwin-arm64@2.2.6': - resolution: {integrity: sha512-UZPmn3M45CjTYulgcrFJFZv7YmK3pTxTJDrFYlNElT2FNnkkX4fsxjExTSMeWKQYoZjvekpH5cvrYZZlWu3yfA==} + '@biomejs/cli-darwin-arm64@2.2.7': + resolution: {integrity: sha512-xBUUsebnO2/Qj1v7eZmKUy2ZcFkZ4/jLUkxN02Qup1RPoRaiW9AKXHrqS3L7iX6PzofHY2xuZ+Pb9kAcpoe0qA==} engines: {node: '>=14.21.3'} cpu: [arm64] os: [darwin] - '@biomejs/cli-darwin-x64@2.2.6': - resolution: {integrity: sha512-HOUIquhHVgh/jvxyClpwlpl/oeMqntlteL89YqjuFDiZ091P0vhHccwz+8muu3nTyHWM5FQslt+4Jdcd67+xWQ==} + '@biomejs/cli-darwin-x64@2.2.7': + resolution: {integrity: sha512-vsY4NhmxqgfLJufr9XUnC+yGUPJiXAc1mz6FcjaAmuIuLwfghN4uQO7hnW2AneGyoi2mNe9Jbvf6Qtq4AjzrFg==} engines: {node: '>=14.21.3'} cpu: [x64] os: [darwin] - '@biomejs/cli-linux-arm64-musl@2.2.6': - resolution: {integrity: sha512-TjCenQq3N6g1C+5UT3jE1bIiJb5MWQvulpUngTIpFsL4StVAUXucWD0SL9MCW89Tm6awWfeXBbZBAhJwjyFbRQ==} + '@biomejs/cli-linux-arm64-musl@2.2.7': + resolution: {integrity: sha512-FrTwvKO/7t5HbVTvhlMOTOVQLAcR7r4O4iFQhEpZXUtBfosHqrX/JJlX7daPawoe14MDcCu9CDg0zLVpTuDvuQ==} engines: {node: '>=14.21.3'} cpu: [arm64] os: [linux] - '@biomejs/cli-linux-arm64@2.2.6': - resolution: {integrity: sha512-BpGtuMJGN+o8pQjvYsUKZ+4JEErxdSmcRD/JG3mXoWc6zrcA7OkuyGFN1mDggO0Q1n7qXxo/PcupHk8gzijt5g==} + '@biomejs/cli-linux-arm64@2.2.7': + resolution: {integrity: sha512-nUdco104rjV9dULi1VssQ5R/kX2jE/Z2sDjyqS+siV9sTQda0DwmEUixFNRCWvZJRRiZUWhgiDFJ4n7RowO8Mg==} engines: {node: '>=14.21.3'} cpu: [arm64] os: [linux] - '@biomejs/cli-linux-x64-musl@2.2.6': - resolution: {integrity: sha512-1ZcBux8zVM3JhWN2ZCPaYf0+ogxXG316uaoXJdgoPZcdK/rmRcRY7PqHdAos2ExzvjIdvhQp72UcveI98hgOog==} + '@biomejs/cli-linux-x64-musl@2.2.7': + resolution: {integrity: sha512-MnsysF5s/iLC5wnYvuMseOy+m8Pd4bWG1uwlVyy2AUbfjAVUgtbYbboc5wMXljFrDY7e6rLjLTR4S2xqDpGlQg==} engines: {node: '>=14.21.3'} cpu: [x64] os: [linux] - '@biomejs/cli-linux-x64@2.2.6': - resolution: {integrity: sha512-1HaM/dpI/1Z68zp8ZdT6EiBq+/O/z97a2AiHMl+VAdv5/ELckFt9EvRb8hDHpk8hUMoz03gXkC7VPXOVtU7faA==} + '@biomejs/cli-linux-x64@2.2.7': + resolution: {integrity: sha512-tPTcGAIEOOZrj2tQ7fdraWlaxNKApBw6l4In8wQQV1IyxnAexqi0hykHzKEX8hKKctf5gxGBfNCzyIvqpj4CFQ==} engines: {node: '>=14.21.3'} cpu: [x64] os: [linux] - '@biomejs/cli-win32-arm64@2.2.6': - resolution: {integrity: sha512-h3A88G8PGM1ryTeZyLlSdfC/gz3e95EJw9BZmA6Po412DRqwqPBa2Y9U+4ZSGUAXCsnSQE00jLV8Pyrh0d+jQw==} + '@biomejs/cli-win32-arm64@2.2.7': + resolution: {integrity: sha512-h5D1jhwA2b7cFXerYiJfXHSzzAMFFoEDL5Mc2BgiaEw0iaSgSso/3Nc6FbOR55aTQISql+IpB4PS7JoV26Gdbw==} engines: {node: '>=14.21.3'} cpu: [arm64] os: [win32] - '@biomejs/cli-win32-x64@2.2.6': - resolution: {integrity: sha512-yx0CqeOhPjYQ5ZXgPfu8QYkgBhVJyvWe36as7jRuPrKPO5ylVDfwVtPQ+K/mooNTADW0IhxOZm3aPu16dP8yNQ==} + '@biomejs/cli-win32-x64@2.2.7': + resolution: {integrity: sha512-URqAJi0kONyBKG4V9NVafHLDtm6IHmF4qPYi/b6x7MD6jxpWeJiTCO6R5+xDlWckX2T/OGv6Yq3nkz6s0M8Ykw==} engines: {node: '>=14.21.3'} cpu: [x64] os: [win32] @@ -1112,74 +1112,74 @@ packages: '@tauri-apps/api@2.9.0': resolution: {integrity: sha512-qD5tMjh7utwBk9/5PrTA/aGr3i5QaJ/Mlt7p8NilQ45WgbifUNPyKWsA63iQ8YfQq6R8ajMapU+/Q8nMcPRLNw==} - '@tauri-apps/cli-darwin-arm64@2.9.0': - resolution: {integrity: sha512-A2Wo2gvtPDymSApnLlKGVuX/b6rvVtdlTh80qta7j0jgc+tK0dyX8+puDufthUR3VPBRsVmV+XWfEJKnaqMLjg==} + '@tauri-apps/cli-darwin-arm64@2.9.1': + resolution: {integrity: sha512-sdwhtsE/6njD0AjgfYEj1JyxZH4SBmCJSXpRm6Ph5fQeuZD6MyjzjdVOrrtFguyREVQ7xn0Ujkwvbo01ULthNg==} engines: {node: '>= 10'} cpu: [arm64] os: [darwin] - '@tauri-apps/cli-darwin-x64@2.9.0': - resolution: {integrity: sha512-RfFB1BB7cqPuPWwKtROXYkN9F760jwYIHpxXgg5AocEQ0c6XynWPMLnYvy77jEyycbYt6cWeIwhiWQYsRbWESA==} + '@tauri-apps/cli-darwin-x64@2.9.1': + resolution: {integrity: sha512-c86g+67wTdI4TUCD7CaSd/13+oYuLQxVST4ZNJ5C+6i1kdnU3Us1L68N9MvbDLDQGJc9eo0pvuK6sCWkee+BzA==} engines: {node: '>= 10'} cpu: [x64] os: [darwin] - '@tauri-apps/cli-linux-arm-gnueabihf@2.9.0': - resolution: {integrity: sha512-n1Gs41458ktY6FMTow/M6AWzy5EYhH1vJ2rdkNAwgX1u086xHCM8PbnowQVgJbRjhrJCUoq7E36EjSy2awHTvA==} + '@tauri-apps/cli-linux-arm-gnueabihf@2.9.1': + resolution: {integrity: sha512-IrB3gFQmueQKJjjisOcMktW/Gh6gxgqYO419doA3YZ7yIV5rbE8ZW52Q3I4AO+SlFEyVYer5kpi066p0JBlLGw==} engines: {node: '>= 10'} cpu: [arm] os: [linux] - '@tauri-apps/cli-linux-arm64-gnu@2.9.0': - resolution: {integrity: sha512-E2y+egQvm7nZbl6cv2Nt1kYw5H8rJG2IisGj9bzJbd8ygSsWJK4Rdw6KW9Ml9iZL7+GuYGihOtlMcyQ6uykw2g==} + '@tauri-apps/cli-linux-arm64-gnu@2.9.1': + resolution: {integrity: sha512-Ke7TyXvu6HbWSkmVkFbbH19D3cLsd117YtXP/u9NIvSpYwKeFtnbpirrIUfPm44Q+PZFZ2Hvg8X9qoUiAK0zKw==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - '@tauri-apps/cli-linux-arm64-musl@2.9.0': - resolution: {integrity: sha512-TH09uepDx3LE7+DSzn9x04ilM0pouguwD6Cjq+A2NdDOu2UkZ3rWux77lMiiuO5fQAGYQAs0BtLjkzcTDoUHTQ==} + '@tauri-apps/cli-linux-arm64-musl@2.9.1': + resolution: {integrity: sha512-sGvy75sv55oeMulR5ArwPD28DsDQxqTzLhXCrpU9/nbFg/JImmI7k994YE9fr3V0qE3Cjk5gjLldRNv7I9sjwQ==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - '@tauri-apps/cli-linux-riscv64-gnu@2.9.0': - resolution: {integrity: sha512-s0ENNDStw8tLScc/K5gS4xE8VrDaFbyCCgYHylrBsIqKQT4rYZLHH3WyzWxxLXIOhPzkczw6MPxt0GdUVPH97A==} + '@tauri-apps/cli-linux-riscv64-gnu@2.9.1': + resolution: {integrity: sha512-tEKbJydV3BdIxpAx8aGHW6VDg1xW4LlQuRD/QeFZdZNTreHJpMbJEcdvAcI+Hg6vgQpVpaoEldR9W4F6dYSLqQ==} engines: {node: '>= 10'} cpu: [riscv64] os: [linux] - '@tauri-apps/cli-linux-x64-gnu@2.9.0': - resolution: {integrity: sha512-stBAjrxfcrJLdmvF3jQskq/Ks/ar4TRyk45kfpD9/0c/8WWDKKWu+z6+ynGNkDYfm9GpbQOQDAjfX0BPWodZZw==} + '@tauri-apps/cli-linux-x64-gnu@2.9.1': + resolution: {integrity: sha512-mg5msXHagtHpyCVWgI01M26JeSrgE/otWyGdYcuTwyRYZYEJRTbcNt7hscOkdNlPBe7isScW7PVKbxmAjJJl4g==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - '@tauri-apps/cli-linux-x64-musl@2.9.0': - resolution: {integrity: sha512-fxR/cG3DVuVFDoBCvAGzbVdNfHAdMfNG32aBR1j6y+0+Ys4ZF+a4SNBbMNGdJ2gQc6/QVciswYMSfSs9hP3GZA==} + '@tauri-apps/cli-linux-x64-musl@2.9.1': + resolution: {integrity: sha512-lFZEXkpDreUe3zKilvnMsrnKP9gwQudaEjDnOz/GMzbzNceIuPfFZz0cR/ky1Aoq4eSvZonPKHhROq4owz4fzg==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - '@tauri-apps/cli-win32-arm64-msvc@2.9.0': - resolution: {integrity: sha512-YIyRvIaYyPRlf1XB0HOLI3q9rkBpb9a8Cl6+PRopTsnXQqlfZIBG5A2KmQO90PkvmyVC6CprGcvK0U28l4MUow==} + '@tauri-apps/cli-win32-arm64-msvc@2.9.1': + resolution: {integrity: sha512-ejc5RAp/Lm1Aj0EQHaT+Wdt5PHfdgQV5hIDV00MV6HNbIb5W4ZUFxMDaRkAg65gl9MvY2fH396riePW3RoKXDw==} engines: {node: '>= 10'} cpu: [arm64] os: [win32] - '@tauri-apps/cli-win32-ia32-msvc@2.9.0': - resolution: {integrity: sha512-Z6a6J+KT0DvjoWSz/R0EDRUCr0DDl/sp10sL1OuJLGnsl36lXWF10YuhJua3dQHizzJzkHpWAV/k1EBxjf10fQ==} + '@tauri-apps/cli-win32-ia32-msvc@2.9.1': + resolution: {integrity: sha512-fSATtJDc0fNjVB6ystyi8NbwhNFk8i8E05h6KrsC8Fio5eaJIJvPCbC9pdrPl6kkxN1X7fj25ErBbgfqgcK8Fg==} engines: {node: '>= 10'} cpu: [ia32] os: [win32] - '@tauri-apps/cli-win32-x64-msvc@2.9.0': - resolution: {integrity: sha512-Ja2LCRGhEBV/FxRF3ofGGO8ZAVrZt5P0MKkAyJ2wQGRB7xcFoadmnkKwpF0uFOjT/6ygh4f/RV46cjo3pbZxyA==} + '@tauri-apps/cli-win32-x64-msvc@2.9.1': + resolution: {integrity: sha512-/JHlOzpUDhjBOO9w167bcYxfJbcMQv7ykS/Y07xjtcga8np0rzUzVGWYmLMH7orKcDMC7wjhheEW1x8cbGma/Q==} engines: {node: '>= 10'} cpu: [x64] os: [win32] - '@tauri-apps/cli@2.9.0': - resolution: {integrity: sha512-Rq67+sgiiUot95kjn+6eP8gTRw9YL839gutPx5bAsGtlQ8n9S6qo2VSQkogYsiHlJs14hQpYACn/EIswH6sHzw==} + '@tauri-apps/cli@2.9.1': + resolution: {integrity: sha512-kKi2/WWsNXKoMdatBl4xrT7e1Ce27JvsetBVfWuIb6D3ep/Y0WO5SIr70yarXOSWam8NyDur4ipzjZkg6m7VDg==} engines: {node: '>= 10'} hasBin: true @@ -1380,8 +1380,8 @@ packages: balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} - baseline-browser-mapping@2.8.18: - resolution: {integrity: sha512-UYmTpOBwgPScZpS4A+YbapwWuBwasxvO/2IOHArSsAhL/+ZdmATBXTex3t+l2hXwLVYK382ibr/nKoY9GKe86w==} + baseline-browser-mapping@2.8.19: + resolution: {integrity: sha512-zoKGUdu6vb2jd3YOq0nnhEDQVbPcHhco3UImJrv5dSkvxTc2pl2WjOPsjZXDwPDSl5eghIMuY3R6J9NDKF3KcQ==} hasBin: true boolbase@1.0.0: @@ -1397,8 +1397,8 @@ packages: resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} engines: {node: '>=8'} - browserslist@4.26.3: - resolution: {integrity: sha512-lAUU+02RFBuCKQPj/P6NgjlbCnLBMp4UtgTx7vNHd3XSIJF87s9a5rA3aH2yw3GS9DqZAUbOtZdCCiZeVRqt0w==} + browserslist@4.27.0: + resolution: {integrity: sha512-AXVQwdhot1eqLihwasPElhX2tAZiBjWdJ9i/Zcj2S6QYIjkx62OKSfnobkriB81C3l4w0rVy3Nt4jaTBltYEpw==} engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true @@ -1676,8 +1676,8 @@ packages: resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} engines: {node: '>= 0.4'} - electron-to-chromium@1.5.237: - resolution: {integrity: sha512-icUt1NvfhGLar5lSWH3tHNzablaA5js3HVHacQimfP8ViEBOQv+L7DKEuHdbTZ0SKCO1ogTJTIL1Gwk9S6Qvcg==} + electron-to-chromium@1.5.238: + resolution: {integrity: sha512-khBdc+w/Gv+cS8e/Pbnaw/FXcBUeKrRVik9IxfXtgREOWyJhR4tj43n3amkVogJ/yeQUqzkrZcFhtIxIdqmmcQ==} emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} @@ -2309,8 +2309,8 @@ packages: node-addon-api@7.1.1: resolution: {integrity: sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==} - node-releases@2.0.25: - resolution: {integrity: sha512-4auku8B/vw5psvTiiN9j1dAOsXvMoGqJuKJcR+dTdqiXEK20mMTk1UEo3HS16LeGQsVG6+qKTPM9u/qQ2LqATA==} + node-releases@2.0.26: + resolution: {integrity: sha512-S2M9YimhSjBSvYnlr5/+umAnPHE++ODwt5e2Ij6FoX45HA/s4vHdkDx1eax2pAPeAOqu4s9b7ppahsyEFdVqQA==} normalize-package-data@2.5.0: resolution: {integrity: sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==} @@ -2845,8 +2845,8 @@ packages: unist-util-visit@5.0.0: resolution: {integrity: sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==} - update-browserslist-db@1.1.3: - resolution: {integrity: sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==} + update-browserslist-db@1.1.4: + resolution: {integrity: sha512-q0SPT4xyU84saUX+tomz1WLkxUbuaJnR1xWt17M7fJtEJigJeWUNGUqrauFXsHnqev9y9JTRGwk13tFBuKby4A==} hasBin: true peerDependencies: browserslist: '>= 4.21.0' @@ -3041,7 +3041,7 @@ snapshots: dependencies: '@babel/compat-data': 7.28.4 '@babel/helper-validator-option': 7.27.1 - browserslist: 4.26.3 + browserslist: 4.27.0 lru-cache: 5.1.1 semver: 6.3.1 @@ -3115,39 +3115,39 @@ snapshots: '@babel/helper-string-parser': 7.27.1 '@babel/helper-validator-identifier': 7.27.1 - '@biomejs/biome@2.2.6': + '@biomejs/biome@2.2.7': optionalDependencies: - '@biomejs/cli-darwin-arm64': 2.2.6 - '@biomejs/cli-darwin-x64': 2.2.6 - '@biomejs/cli-linux-arm64': 2.2.6 - '@biomejs/cli-linux-arm64-musl': 2.2.6 - '@biomejs/cli-linux-x64': 2.2.6 - '@biomejs/cli-linux-x64-musl': 2.2.6 - '@biomejs/cli-win32-arm64': 2.2.6 - '@biomejs/cli-win32-x64': 2.2.6 - - '@biomejs/cli-darwin-arm64@2.2.6': + '@biomejs/cli-darwin-arm64': 2.2.7 + '@biomejs/cli-darwin-x64': 2.2.7 + '@biomejs/cli-linux-arm64': 2.2.7 + '@biomejs/cli-linux-arm64-musl': 2.2.7 + '@biomejs/cli-linux-x64': 2.2.7 + '@biomejs/cli-linux-x64-musl': 2.2.7 + '@biomejs/cli-win32-arm64': 2.2.7 + '@biomejs/cli-win32-x64': 2.2.7 + + '@biomejs/cli-darwin-arm64@2.2.7': optional: true - '@biomejs/cli-darwin-x64@2.2.6': + '@biomejs/cli-darwin-x64@2.2.7': optional: true - '@biomejs/cli-linux-arm64-musl@2.2.6': + '@biomejs/cli-linux-arm64-musl@2.2.7': optional: true - '@biomejs/cli-linux-arm64@2.2.6': + '@biomejs/cli-linux-arm64@2.2.7': optional: true - '@biomejs/cli-linux-x64-musl@2.2.6': + '@biomejs/cli-linux-x64-musl@2.2.7': optional: true - '@biomejs/cli-linux-x64@2.2.6': + '@biomejs/cli-linux-x64@2.2.7': optional: true - '@biomejs/cli-win32-arm64@2.2.6': + '@biomejs/cli-win32-arm64@2.2.7': optional: true - '@biomejs/cli-win32-x64@2.2.6': + '@biomejs/cli-win32-x64@2.2.7': optional: true '@emotion/babel-plugin@11.13.5': @@ -3771,52 +3771,52 @@ snapshots: '@tauri-apps/api@2.9.0': {} - '@tauri-apps/cli-darwin-arm64@2.9.0': + '@tauri-apps/cli-darwin-arm64@2.9.1': optional: true - '@tauri-apps/cli-darwin-x64@2.9.0': + '@tauri-apps/cli-darwin-x64@2.9.1': optional: true - '@tauri-apps/cli-linux-arm-gnueabihf@2.9.0': + '@tauri-apps/cli-linux-arm-gnueabihf@2.9.1': optional: true - '@tauri-apps/cli-linux-arm64-gnu@2.9.0': + '@tauri-apps/cli-linux-arm64-gnu@2.9.1': optional: true - '@tauri-apps/cli-linux-arm64-musl@2.9.0': + '@tauri-apps/cli-linux-arm64-musl@2.9.1': optional: true - '@tauri-apps/cli-linux-riscv64-gnu@2.9.0': + '@tauri-apps/cli-linux-riscv64-gnu@2.9.1': optional: true - '@tauri-apps/cli-linux-x64-gnu@2.9.0': + '@tauri-apps/cli-linux-x64-gnu@2.9.1': optional: true - '@tauri-apps/cli-linux-x64-musl@2.9.0': + '@tauri-apps/cli-linux-x64-musl@2.9.1': optional: true - '@tauri-apps/cli-win32-arm64-msvc@2.9.0': + '@tauri-apps/cli-win32-arm64-msvc@2.9.1': optional: true - '@tauri-apps/cli-win32-ia32-msvc@2.9.0': + '@tauri-apps/cli-win32-ia32-msvc@2.9.1': optional: true - '@tauri-apps/cli-win32-x64-msvc@2.9.0': + '@tauri-apps/cli-win32-x64-msvc@2.9.1': optional: true - '@tauri-apps/cli@2.9.0': + '@tauri-apps/cli@2.9.1': optionalDependencies: - '@tauri-apps/cli-darwin-arm64': 2.9.0 - '@tauri-apps/cli-darwin-x64': 2.9.0 - '@tauri-apps/cli-linux-arm-gnueabihf': 2.9.0 - '@tauri-apps/cli-linux-arm64-gnu': 2.9.0 - '@tauri-apps/cli-linux-arm64-musl': 2.9.0 - '@tauri-apps/cli-linux-riscv64-gnu': 2.9.0 - '@tauri-apps/cli-linux-x64-gnu': 2.9.0 - '@tauri-apps/cli-linux-x64-musl': 2.9.0 - '@tauri-apps/cli-win32-arm64-msvc': 2.9.0 - '@tauri-apps/cli-win32-ia32-msvc': 2.9.0 - '@tauri-apps/cli-win32-x64-msvc': 2.9.0 + '@tauri-apps/cli-darwin-arm64': 2.9.1 + '@tauri-apps/cli-darwin-x64': 2.9.1 + '@tauri-apps/cli-linux-arm-gnueabihf': 2.9.1 + '@tauri-apps/cli-linux-arm64-gnu': 2.9.1 + '@tauri-apps/cli-linux-arm64-musl': 2.9.1 + '@tauri-apps/cli-linux-riscv64-gnu': 2.9.1 + '@tauri-apps/cli-linux-x64-gnu': 2.9.1 + '@tauri-apps/cli-linux-x64-musl': 2.9.1 + '@tauri-apps/cli-win32-arm64-msvc': 2.9.1 + '@tauri-apps/cli-win32-ia32-msvc': 2.9.1 + '@tauri-apps/cli-win32-x64-msvc': 2.9.1 '@tauri-apps/plugin-clipboard-manager@2.3.0': dependencies: @@ -4015,7 +4015,7 @@ snapshots: autoprefixer@10.4.21(postcss@8.5.6): dependencies: - browserslist: 4.26.3 + browserslist: 4.27.0 caniuse-lite: 1.0.30001751 fraction.js: 4.3.7 normalize-range: 0.1.2 @@ -4037,7 +4037,7 @@ snapshots: balanced-match@1.0.2: {} - baseline-browser-mapping@2.8.18: {} + baseline-browser-mapping@2.8.19: {} boolbase@1.0.0: {} @@ -4055,13 +4055,13 @@ snapshots: fill-range: 7.1.1 optional: true - browserslist@4.26.3: + browserslist@4.27.0: dependencies: - baseline-browser-mapping: 2.8.18 + baseline-browser-mapping: 2.8.19 caniuse-lite: 1.0.30001751 - electron-to-chromium: 1.5.237 - node-releases: 2.0.25 - update-browserslist-db: 1.1.3(browserslist@4.26.3) + electron-to-chromium: 1.5.238 + node-releases: 2.0.26 + update-browserslist-db: 1.1.4(browserslist@4.27.0) byte-size@9.0.1: {} @@ -4326,7 +4326,7 @@ snapshots: es-errors: 1.3.0 gopd: 1.2.0 - electron-to-chromium@1.5.237: {} + electron-to-chromium@1.5.238: {} emoji-regex@8.0.0: {} @@ -5150,7 +5150,7 @@ snapshots: node-addon-api@7.1.1: optional: true - node-releases@2.0.25: {} + node-releases@2.0.26: {} normalize-package-data@2.5.0: dependencies: @@ -5799,9 +5799,9 @@ snapshots: unist-util-is: 6.0.1 unist-util-visit-parents: 6.0.2 - update-browserslist-db@1.1.3(browserslist@4.26.3): + update-browserslist-db@1.1.4(browserslist@4.27.0): dependencies: - browserslist: 4.26.3 + browserslist: 4.27.0 escalade: 3.2.0 picocolors: 1.1.1 diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index 8daef15f..d0c76b90 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -234,7 +234,7 @@ dependencies = [ "rustc-hash", "serde", "serde_derive", - "syn 2.0.107", + "syn 2.0.108", ] [[package]] @@ -390,7 +390,7 @@ checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11" dependencies = [ "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.108", ] [[package]] @@ -451,7 +451,7 @@ checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.108", ] [[package]] @@ -688,7 +688,7 @@ dependencies = [ "proc-macro-crate 3.4.0", "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.108", ] [[package]] @@ -976,7 +976,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.108", ] [[package]] @@ -1235,7 +1235,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331" dependencies = [ "quote", - "syn 2.0.107", + "syn 2.0.108", ] [[package]] @@ -1245,7 +1245,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a2785755761f3ddc1492979ce1e48d2c00d09311c39e4466429188f3dd6501" dependencies = [ "quote", - "syn 2.0.107", + "syn 2.0.108", ] [[package]] @@ -1272,7 +1272,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.108", ] [[package]] @@ -1320,7 +1320,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.107", + "syn 2.0.108", ] [[package]] @@ -1334,7 +1334,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.107", + "syn 2.0.108", ] [[package]] @@ -1345,7 +1345,7 @@ checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" dependencies = [ "darling_core 0.20.11", "quote", - "syn 2.0.107", + "syn 2.0.108", ] [[package]] @@ -1356,7 +1356,7 @@ checksum = "d38308df82d1080de0afee5d069fa14b0326a88c14f15c5ccda35b4a6c414c81" dependencies = [ "darling_core 0.21.3", "quote", - "syn 2.0.107", + "syn 2.0.108", ] [[package]] @@ -1504,7 +1504,7 @@ dependencies = [ "darling 0.20.11", "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.108", ] [[package]] @@ -1514,7 +1514,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c" dependencies = [ "derive_builder_core", - "syn 2.0.107", + "syn 2.0.108", ] [[package]] @@ -1527,7 +1527,7 @@ dependencies = [ "proc-macro2", "quote", "rustc_version", - "syn 2.0.107", + "syn 2.0.108", ] [[package]] @@ -1610,7 +1610,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.108", ] [[package]] @@ -1642,7 +1642,7 @@ checksum = "788160fb30de9cdd857af31c6a2675904b16ece8fc2737b2c7127ba368c9d0f4" dependencies = [ "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.108", ] [[package]] @@ -1773,7 +1773,7 @@ checksum = "67c78a4d8fdf9953a5c9d458f9efe940fd97a0cab0941c075a813ac594733827" dependencies = [ "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.108", ] [[package]] @@ -1880,7 +1880,7 @@ checksum = "a0aca10fb742cb43f9e7bb8467c91aa9bcb8e3ffbc6a6f7389bb93ffc920577d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.108", ] [[package]] @@ -1995,7 +1995,7 @@ checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" dependencies = [ "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.108", ] [[package]] @@ -2109,7 +2109,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.108", ] [[package]] @@ -2386,7 +2386,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.108", ] [[package]] @@ -2488,7 +2488,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.108", ] [[package]] @@ -3027,9 +3027,9 @@ dependencies = [ [[package]] name = "is_terminal_polyfill" -version = "1.70.1" +version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" +checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" [[package]] name = "itertools" @@ -3365,7 +3365,7 @@ checksum = "88a9689d8d44bf9964484516275f5cd4c9b59457a6940c1d5d0ecbb94510a36b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.108", ] [[package]] @@ -3725,7 +3725,7 @@ dependencies = [ "proc-macro-crate 3.4.0", "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.108", ] [[package]] @@ -4009,9 +4009,9 @@ checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" [[package]] name = "once_cell_polyfill" -version = "1.70.1" +version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad" +checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" [[package]] name = "opaque-debug" @@ -4054,7 +4054,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.108", ] [[package]] @@ -4344,7 +4344,7 @@ dependencies = [ "phf_shared 0.11.3", "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.108", ] [[package]] @@ -4391,7 +4391,7 @@ checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" dependencies = [ "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.108", ] [[package]] @@ -4551,7 +4551,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" dependencies = [ "proc-macro2", - "syn 2.0.107", + "syn 2.0.108", ] [[package]] @@ -4615,9 +4615,9 @@ checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" [[package]] name = "proc-macro2" -version = "1.0.101" +version = "1.0.102" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" +checksum = "8e0f6df8eaa422d97d72edcd152e1451618fed47fabbdbd5a8864167b1d4aff7" dependencies = [ "unicode-ident", ] @@ -4650,7 +4650,7 @@ dependencies = [ "pulldown-cmark", "pulldown-cmark-to-cmark", "regex", - "syn 2.0.107", + "syn 2.0.108", "tempfile", ] @@ -4664,7 +4664,7 @@ dependencies = [ "itertools", "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.108", ] [[package]] @@ -5005,7 +5005,7 @@ checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da" dependencies = [ "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.108", ] [[package]] @@ -5253,9 +5253,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.33" +version = "0.23.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "751e04a496ca00bb97a5e043158d23d66b5aabf2e1d5aa2a0aaebb1aafe6f82c" +checksum = "6a9586e9ee2b4f8fab52a0048ca7334d7024eef48e2cb9407e3497bb7cab7fa7" dependencies = [ "log", "once_cell", @@ -5377,7 +5377,7 @@ dependencies = [ "proc-macro2", "quote", "serde_derive_internals", - "syn 2.0.107", + "syn 2.0.108", ] [[package]] @@ -5409,7 +5409,7 @@ checksum = "1783eabc414609e28a5ba76aee5ddd52199f7107a0b24c2e9746a1ecc34a683d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.108", ] [[package]] @@ -5521,7 +5521,7 @@ checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.108", ] [[package]] @@ -5532,7 +5532,7 @@ checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" dependencies = [ "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.108", ] [[package]] @@ -5556,7 +5556,7 @@ checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.108", ] [[package]] @@ -5591,9 +5591,9 @@ dependencies = [ [[package]] name = "serde_with" -version = "3.15.0" +version = "3.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6093cd8c01b25262b84927e0f7151692158fab02d961e04c979d3903eba7ecc5" +checksum = "aa66c845eee442168b2c8134fec70ac50dc20e760769c8ba0ad1319ca1959b04" dependencies = [ "base64 0.22.1", "chrono", @@ -5610,14 +5610,14 @@ dependencies = [ [[package]] name = "serde_with_macros" -version = "3.15.0" +version = "3.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7e6c180db0816026a61afa1cff5344fb7ebded7e4d3062772179f2501481c27" +checksum = "b91a903660542fced4e99881aa481bdbaec1634568ee02e0b8bd57c64cb38955" dependencies = [ "darling 0.21.3", "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.108", ] [[package]] @@ -5639,7 +5639,7 @@ checksum = "772ee033c0916d670af7860b6e1ef7d658a4629a6d0b4c8c3e67f09b3765b75d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.108", ] [[package]] @@ -5889,7 +5889,7 @@ dependencies = [ "quote", "sqlx-core", "sqlx-macros-core", - "syn 2.0.107", + "syn 2.0.108", ] [[package]] @@ -5912,7 +5912,7 @@ dependencies = [ "sqlx-mysql", "sqlx-postgres", "sqlx-sqlite", - "syn 2.0.107", + "syn 2.0.108", "tokio", "url", ] @@ -6097,7 +6097,7 @@ checksum = "68c6387c1c7b53060605101b63d93edca618c6cf7ce61839f2ec2a527419fdb5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.108", ] [[package]] @@ -6118,7 +6118,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.108", ] [[package]] @@ -6151,9 +6151,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.107" +version = "2.0.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a26dbd934e5451d21ef060c018dae56fc073894c5a7896f882928a76e6d081b" +checksum = "da58917d35242480a05c2897064da0a80589a2a0476c9a3f2fdc83b53502e917" dependencies = [ "proc-macro2", "quote", @@ -6177,7 +6177,7 @@ checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.108", ] [[package]] @@ -6271,7 +6271,7 @@ checksum = "f4e16beb8b2ac17db28eab8bca40e62dbfbb34c0fcdc6d9826b11b7b5d047dfd" dependencies = [ "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.108", ] [[package]] @@ -6288,9 +6288,9 @@ checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" [[package]] name = "tauri" -version = "2.9.0" +version = "2.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f07c6590706b2fc0ab287b041cf5ce9c435b3850bdae5571e19d9d27584e89d" +checksum = "c9871670c6711f50fddd4e20350be6b9dd6e6c2b5d77d8ee8900eb0d58cd837a" dependencies = [ "anyhow", "bytes", @@ -6332,7 +6332,6 @@ dependencies = [ "tokio", "tray-icon", "url", - "urlpattern", "webkit2gtk", "webview2-com", "window-vibrancy", @@ -6341,9 +6340,9 @@ dependencies = [ [[package]] name = "tauri-build" -version = "2.5.0" +version = "2.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f71be1f494b683ac439e6d61c16ab5c472c6f9c6ee78995b29556d9067c021a1" +checksum = "a924b6c50fe83193f0f8b14072afa7c25b7a72752a2a73d9549b463f5fe91a38" dependencies = [ "anyhow", "cargo_toml", @@ -6379,7 +6378,7 @@ dependencies = [ "serde", "serde_json", "sha2", - "syn 2.0.107", + "syn 2.0.108", "tauri-utils", "thiserror 2.0.17", "time", @@ -6397,16 +6396,16 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.108", "tauri-codegen", "tauri-utils", ] [[package]] name = "tauri-plugin" -version = "2.5.0" +version = "2.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d7ce9aab979296b2f91e6fbf154207c2e3512b12ddca0b24bfa0e0cde6b2976" +checksum = "076c78a474a7247c90cad0b6e87e593c4c620ed4efdb79cbe0214f0021f6c39d" dependencies = [ "anyhow", "glob", @@ -6633,9 +6632,9 @@ dependencies = [ [[package]] name = "tauri-runtime" -version = "2.9.0" +version = "2.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3367f0b47df90e9195cd9f04a56b0055a2cba45aa11923c6c253d748778176fc" +checksum = "9368f09358496f2229313fccb37682ad116b7f46fa76981efe116994a0628926" dependencies = [ "cookie", "dpi", @@ -6658,9 +6657,9 @@ dependencies = [ [[package]] name = "tauri-runtime-wry" -version = "2.9.0" +version = "2.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80d91d29ca680c545364cf75ba2f2e3c7ea2ab6376bfa3be26b56fa2463a5b5e" +checksum = "929f5df216f5c02a9e894554401bcdab6eec3e39ec6a4a7731c7067fc8688a93" dependencies = [ "gtk", "http", @@ -6802,7 +6801,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.108", ] [[package]] @@ -6813,7 +6812,7 @@ checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" dependencies = [ "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.108", ] [[package]] @@ -6932,7 +6931,7 @@ checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.108", ] [[package]] @@ -7125,7 +7124,7 @@ dependencies = [ "prettyplease", "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.108", ] [[package]] @@ -7150,7 +7149,7 @@ dependencies = [ "prost-build", "prost-types", "quote", - "syn 2.0.107", + "syn 2.0.108", "tempfile", "tonic-build", ] @@ -7236,7 +7235,7 @@ checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903" dependencies = [ "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.108", ] [[package]] @@ -7516,7 +7515,7 @@ dependencies = [ "indexmap 2.12.0", "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.108", ] [[package]] @@ -7531,7 +7530,7 @@ dependencies = [ "proc-macro2", "quote", "serde", - "syn 2.0.107", + "syn 2.0.108", "toml 0.5.11", "uniffi_meta", ] @@ -7807,7 +7806,7 @@ dependencies = [ "log", "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.108", "wasm-bindgen-shared", ] @@ -7842,7 +7841,7 @@ checksum = "9f07d2f20d4da7b26400c9f4a0511e6e0345b040694e8a75bd41d578fa4421d7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.108", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -8053,7 +8052,7 @@ checksum = "1d228f15bba3b9d56dde8bddbee66fa24545bd17b48d5128ccf4a8742b18e431" dependencies = [ "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.108", ] [[package]] @@ -8211,7 +8210,7 @@ checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" dependencies = [ "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.108", ] [[package]] @@ -8222,7 +8221,7 @@ checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" dependencies = [ "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.108", ] [[package]] @@ -8691,9 +8690,9 @@ checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" [[package]] name = "wry" -version = "0.53.4" +version = "0.53.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d78ec082b80fa088569a970d043bb3050abaabf4454101d44514ee8d9a8c9f6" +checksum = "728b7d4c8ec8d81cab295e0b5b8a4c263c0d41a785fb8f8c4df284e5411140a2" dependencies = [ "base64 0.22.1", "block2 0.6.2", @@ -8813,7 +8812,7 @@ checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.108", "synstructure", ] @@ -8861,7 +8860,7 @@ dependencies = [ "proc-macro-crate 3.4.0", "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.108", "zbus_names", "zvariant", "zvariant_utils", @@ -8896,7 +8895,7 @@ checksum = "88d2b8d9c68ad2b9e4340d7832716a4d21a22a1154777ad56ea55c51a9cf3831" dependencies = [ "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.108", ] [[package]] @@ -8916,7 +8915,7 @@ checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" dependencies = [ "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.108", "synstructure", ] @@ -8937,7 +8936,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.108", ] [[package]] @@ -8970,7 +8969,7 @@ checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.108", ] [[package]] @@ -9012,7 +9011,7 @@ dependencies = [ "proc-macro-crate 3.4.0", "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.108", "zvariant_utils", ] @@ -9025,6 +9024,6 @@ dependencies = [ "proc-macro2", "quote", "serde", - "syn 2.0.107", + "syn 2.0.108", "winnow 0.7.13", ] diff --git a/src-tauri/Client.entitlements b/src-tauri/Client.entitlements index af8c6f90..4e920afc 100644 --- a/src-tauri/Client.entitlements +++ b/src-tauri/Client.entitlements @@ -9,6 +9,6 @@ com.apple.security.app-sandbox com.apple.security.network.client - + diff --git a/src-tauri/resources-macos/binaries/.gitkeep b/src-tauri/resources-macos/binaries/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/src-tauri/src/appstate.rs b/src-tauri/src/appstate.rs index d2912b75..578ef4f0 100644 --- a/src-tauri/src/appstate.rs +++ b/src-tauri/src/appstate.rs @@ -48,20 +48,20 @@ impl AppState { drop(connections); debug!("Spawning thread for network statistics for location ID {location_id}"); - // let handle = spawn(stats_handler(DB_POOL.clone(), ifname, connection_type)); - // let Some(old_handle) = self - // .stat_threads - // .lock() - // .unwrap() - // .insert(location_id, handle) - // else { - return; - // }; - // warn!("Something went wrong: old network statistics thread still exists"); - // old_handle.abort(); - // if let Err(err) = old_handle.await { - // debug!("Old network statistics thread for location ID {location_id} returned {err}"); - // } + let handle = spawn(stats_handler(DB_POOL.clone(), ifname, connection_type)); + let Some(old_handle) = self + .stat_threads + .lock() + .unwrap() + .insert(location_id, handle) + else { + return; + }; + warn!("Something went wrong: old network statistics thread still exists"); + old_handle.abort(); + if let Err(err) = old_handle.await { + debug!("Old network statistics thread for location ID {location_id} returned {err}"); + } } /// Try to remove a connection from the list of active connections. diff --git a/src-tauri/src/export.rs b/src-tauri/src/export.rs index 37a51284..dead0b3b 100644 --- a/src-tauri/src/export.rs +++ b/src-tauri/src/export.rs @@ -5,6 +5,11 @@ use std::{net::IpAddr, str::FromStr}; use defguard_wireguard_rs::{host::Peer, key::Key, net::IpAddrMask}; use serde::Serialize; use sqlx::SqliteExecutor; +use swift_rs::{swift, SRString}; + +swift!(pub(crate) fn start_tunnel(json: &SRString) -> bool); +swift!(pub(crate) fn stop_tunnel(name: &SRString) -> bool); +swift!(pub(crate) fn tunnel_stats(name: &SRString)); use crate::{ database::models::{location::Location, wireguard_keys::WireguardKeys, Id}, diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index bb5fe1ac..16692304 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -37,7 +37,7 @@ pub const VERSION: &str = concat!(env!("CARGO_PKG_VERSION"), "-", env!("VERGEN_G pub const MIN_CORE_VERSION: Version = Version::new(1, 5, 0); pub const MIN_PROXY_VERSION: Version = Version::new(1, 5, 0); // This must match tauri.bundle.identifier from tauri.conf.json. -const BUNDLE_IDENTIFIER: &str = "net.defguard.client"; +const BUNDLE_IDENTIFIER: &str = "net.defguard"; // Returns the path to the user’s data directory. #[must_use] pub fn app_data_dir() -> Option { diff --git a/src-tauri/src/periodic/mod.rs b/src-tauri/src/periodic/mod.rs index 0b4fab97..dad8bd3d 100644 --- a/src-tauri/src/periodic/mod.rs +++ b/src-tauri/src/periodic/mod.rs @@ -22,7 +22,7 @@ pub async fn run_periodic_tasks(app_handle: &AppHandle) { () = poll_config(app_handle.clone()) => { error!("Config polling task has stopped unexpectedly"); } - () = verify_active_connections(app_handle.clone()) => { + () = verify_active_connections(app_handle.clone()), if cfg!(not(target_os = "macos")) => { error!("Active connection verification task has stopped unexpectedly"); } () = purge_stats() => { diff --git a/src-tauri/src/utils.rs b/src-tauri/src/utils.rs index 2b6bde5e..5ab1c3e8 100644 --- a/src-tauri/src/utils.rs +++ b/src-tauri/src/utils.rs @@ -4,7 +4,7 @@ use common::{find_free_tcp_port, get_interface_name}; use defguard_wireguard_rs::{host::Peer, key::Key, net::IpAddrMask, InterfaceConfiguration}; use sqlx::query; #[cfg(target_os = "macos")] -use swift_rs::{swift, SRString}; +use swift_rs::SRString; use tauri::{AppHandle, Emitter, Manager}; use tonic::Code; use tracing::Level; @@ -16,6 +16,10 @@ use windows_service::{ service_manager::{ServiceManager, ServiceManagerAccess}, }; +#[cfg(target_os = "windows")] +use crate::active_connections::find_connection; +#[cfg(target_os = "macos")] +use crate::export::{start_tunnel, stop_tunnel, tunnel_stats}; use crate::{ appstate::AppState, commands::LocationInterfaceDetails, @@ -40,9 +44,6 @@ use crate::{ ConnectionType, }; -#[cfg(target_os = "windows")] -use crate::active_connections::find_connection; - pub(crate) static DEFAULT_ROUTE_IPV4: &str = "0.0.0.0/0"; pub(crate) static DEFAULT_ROUTE_IPV6: &str = "::/0"; @@ -73,7 +74,6 @@ pub(crate) async fn setup_interface( .await?; // tunnel_config.port = port; - swift!(fn start_tunnel(json: &SRString) -> bool); unsafe { let json: SRString = serde_json::to_string(&tunnel_config) .unwrap() @@ -120,6 +120,21 @@ pub(crate) async fn setup_interface( // } } +#[cfg(target_os = "macos")] +pub(crate) async fn stats_handler(pool: DbPool, ifname: String, connection_type: ConnectionType) { + const CHECK_INTERVAL: std::time::Duration = std::time::Duration::from_secs(5); + let mut interval = tokio::time::interval(CHECK_INTERVAL); + + loop { + interval.tick().await; + info!("stats_handler :)"); + unsafe { + tunnel_stats(&"Szczecin".into()); + } + } +} + +#[cfg(not(target_os = "macos"))] pub(crate) async fn stats_handler( pool: DbPool, interface_name: String, @@ -361,7 +376,7 @@ pub async fn setup_interface_tunnel( name: interface_name, prvkey: tunnel.prvkey.clone(), addresses, - port: port.into(), + port, peers: vec![peer.clone()], mtu: None, }; @@ -645,13 +660,11 @@ pub(crate) async fn disconnect_interface( return Err(Error::NotFound); }; - let mut result = false; - swift!(fn stop_tunnel(name: &SRString) -> bool); - unsafe { + let result = unsafe { let name: SRString = location.name.as_str().into(); - result = stop_tunnel(&name); - error!("stop_tunnel() returned {result:?}"); - } + stop_tunnel(&name) + }; + error!("stop_tunnel() returned {result:?}"); if !result { let msg = String::from("Error from Swift"); // let request = RemoveInterfaceRequest { diff --git a/swift/extension/VPNExtension/PacketTunnelProvider.swift b/swift/extension/VPNExtension/PacketTunnelProvider.swift index f45f5d11..2dce14c8 100644 --- a/swift/extension/VPNExtension/PacketTunnelProvider.swift +++ b/swift/extension/VPNExtension/PacketTunnelProvider.swift @@ -28,7 +28,9 @@ class PacketTunnelProvider: NEPacketTunnelProvider { let networkSettings = tunnelConfig.asNetworkSettings() self.setTunnelNetworkSettings(networkSettings) { error in - self.logger.log("Set tunnel network settings returned \(error)") + if error != nil { + self.logger.error("Set tunnel network settings returned \(error)") + } completionHandler(error) return } diff --git a/swift/plugin/Sources/VPNManager.swift b/swift/plugin/Sources/VPNManager.swift index 8e5ec8ba..e6627337 100644 --- a/swift/plugin/Sources/VPNManager.swift +++ b/swift/plugin/Sources/VPNManager.swift @@ -33,8 +33,10 @@ public class VPNManager: VPNManagement { providerManager?.connection.status } - func managerForConfig(_ config: TunnelConfiguration, - completion: @escaping (NETunnelProviderManager?) -> Void) { + func managerForConfig( + _ config: TunnelConfiguration, + completion: @escaping (NETunnelProviderManager?) -> Void + ) { NETunnelProviderManager.loadAllFromPreferences { managers, error in guard let managers = managers else { self.logger.info("No tunnel managers in user's settings") @@ -55,19 +57,20 @@ public class VPNManager: VPNManagement { if manager.localizedDescription != config.name { continue } - guard let tunnelProtocol = manager.protocolConfiguration as? NETunnelProviderProtocol else { + guard + let tunnelProtocol = manager.protocolConfiguration as? NETunnelProviderProtocol + else { continue } // Sometimes all managers from all apps come through, so filter by bundle ID. - if tunnelProtocol.providerBundleIdentifier == "\(appId).VPNExtension" { + if tunnelProtocol.providerBundleIdentifier == pluginAppId { self.providerManager = manager break } } if self.providerManager == nil { self.logger.log("No VPN manager found") - } - else { + } else { self.logger.log( "Loaded provider manager: \(String(describing: self.providerManager!.localizedDescription), privacy: .public)" ) @@ -101,19 +104,20 @@ public class VPNManager: VPNManagement { if manager.localizedDescription != name { continue } - guard let tunnelProtocol = manager.protocolConfiguration as? NETunnelProviderProtocol else { + guard + let tunnelProtocol = manager.protocolConfiguration as? NETunnelProviderProtocol + else { continue } // Sometimes all managers from all apps come through, so filter by bundle ID. - if tunnelProtocol.providerBundleIdentifier == "\(appId).VPNExtension" { + if tunnelProtocol.providerBundleIdentifier == pluginAppId { self.providerManager = manager break } } if self.providerManager == nil { self.logger.log("No VPN manager found") - } - else { + } else { self.logger.log( "Loaded provider manager: \(String(describing: self.providerManager!.localizedDescription), privacy: .public)" ) @@ -140,13 +144,13 @@ public class VPNManager: VPNManagement { public func handleVPNConfigurationChange() { logger.log("VPN configuration changed, updating provider manager") -// loadProviderManager { providerManager in -// guard let providerManager = providerManager else { -// self.logger.log("No VPN manager found after configuration change") -// return -// } -// self.providerManager = providerManager -// } + // loadProviderManager { providerManager in + // guard let providerManager = providerManager else { + // self.logger.log("No VPN manager found after configuration change") + // return + // } + // self.providerManager = providerManager + // } } public func startTunnel() throws { diff --git a/swift/plugin/Sources/Wireguard.swift b/swift/plugin/Sources/Wireguard.swift index 8d3c8351..108367fc 100644 --- a/swift/plugin/Sources/Wireguard.swift +++ b/swift/plugin/Sources/Wireguard.swift @@ -4,8 +4,8 @@ import NetworkExtension import SwiftRs import os -let appId = Bundle.main.bundleIdentifier ?? "net.defguard.client" -let pluginAppId = "\(appId).VPNExtension" +let appId = Bundle.main.bundleIdentifier ?? "net.defguard" +let pluginAppId = "\(appId).client.VPNExtension" let plugin = WireguardPlugin() let logger = Logger(subsystem: appId, category: "WireguardPlugin") @@ -39,16 +39,33 @@ public func startTunnel(json: SRString) -> Bool { public func stopTunnel(name: SRString) -> Bool { managerForName(name.toString()) { manager in if let providerManager = manager { - // TEST + providerManager.connection.stopVPNTunnel() + logger.info("VPN stopped") + } + } + return true +} + +@_cdecl("tunnel_stats") +public func tunnelStats(name: SRString) { + managerForName(name.toString()) { manager in + if let providerManager = manager as NETunnelProviderManager? { + let session = providerManager.connection as! NETunnelProviderSession do { - try providerManager.connection.stopVPNTunnel() - logger.info("VPN stopped") + let data = Data(count: 8) + try session.sendProviderMessage(data) { response in + if response != nil { + logger.info("Tunnel extension sent some data") + } else { + logger.info("Tunnel extension sent nothing") + } + } + logger.info("Send message to tunnel extension") } catch { - logger.error("Failed to stop VPN") + logger.error("Failed to send message to tunnel extension \(error)") } } } - return true } func saveConfig(_ config: TunnelConfiguration) { @@ -125,7 +142,7 @@ func managerForName( continue } // Sometimes all managers from all apps come through, so filter by bundle ID. - if tunnelProtocol.providerBundleIdentifier == "\(appId).VPNExtension" { + if tunnelProtocol.providerBundleIdentifier == pluginAppId { providerManager = manager break } diff --git a/swift/plugin/Sources/WireguardPlugin.swift b/swift/plugin/Sources/WireguardPlugin.swift index 6589a242..357273b5 100644 --- a/swift/plugin/Sources/WireguardPlugin.swift +++ b/swift/plugin/Sources/WireguardPlugin.swift @@ -47,21 +47,21 @@ public class WireguardPlugin: NSObject { /// Loads the possibly already existing VPN manager and sets up observers for VPN connection status changes if its present. /// This is to ensure that the VPN status is observed and updated correctly when the app starts. -// private func setupVPNManager( -// completion: @escaping () -> Void -// ) { -// vpnManager.loadProviderManager { manager in -// if manager == nil { -// self.logger.log( -// "No provider manager found, the VPN status won't be observed until the VPN is started." -// ) -// } else { -// self.logger.log( -// "VPN manager loaded successfully, the VPN status will be observed and updated.") -// } -// completion() -// } -// } + // private func setupVPNManager( + // completion: @escaping () -> Void + // ) { + // vpnManager.loadProviderManager { manager in + // if manager == nil { + // self.logger.log( + // "No provider manager found, the VPN status won't be observed until the VPN is started." + // ) + // } else { + // self.logger.log( + // "VPN manager loaded successfully, the VPN status will be observed and updated.") + // } + // completion() + // } + // } /// Sets up observers for VPN connection status changes. private func setupVPNObservers() { @@ -229,21 +229,21 @@ public class WireguardPlugin: NSObject { defaults?.removeObject(forKey: "lastTunnelError") } -// private func saveConfig(config: TunnelConfiguration, result: @escaping (VPNError?) -> Void) { -// logger.info("Saving tunnel config: \(String(describing: config))") -// -// vpnManager.saveProviderManager(providerManager) { saveError in -// if let saveError = saveError { -// self.logger.log("Failed to save preferences: \(saveError, privacy: .public)") -// result( -// VPNError.saveError( -// saveError -// ) -// ) -// return -// } -// } -// } + // private func saveConfig(config: TunnelConfiguration, result: @escaping (VPNError?) -> Void) { + // logger.info("Saving tunnel config: \(String(describing: config))") + // + // vpnManager.saveProviderManager(providerManager) { saveError in + // if let saveError = saveError { + // self.logger.log("Failed to save preferences: \(saveError, privacy: .public)") + // result( + // VPNError.saveError( + // saveError + // ) + // ) + // return + // } + // } + // } func startTunnel( config: TunnelConfiguration, @@ -258,7 +258,7 @@ public class WireguardPlugin: NSObject { vpnManager.loadProviderManager(name: config.name) { manager in let providerManager = manager ?? NETunnelProviderManager() let tunnelProtocol = NETunnelProviderProtocol() - tunnelProtocol.providerBundleIdentifier = "\(appId).VPNExtension" + tunnelProtocol.providerBundleIdentifier = pluginAppId // `serverAddress` must have a non-nil string value for the protocol configuration to be valid. if let endpoint = config.peers[0].endpoint { tunnelProtocol.serverAddress = endpoint.toString() From 40ae746d2b3744e0b13586e38e00e7d5af81a74d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adam=20Ciarcin=CC=81ski?= Date: Mon, 27 Oct 2025 09:21:17 +0100 Subject: [PATCH 08/28] Message network extension --- package.json | 22 +- pnpm-lock.yaml | 481 +++++++++--------- src-tauri/Cargo.lock | 70 +-- src-tauri/Client.entitlements | 8 + src-tauri/build.rs | 4 +- src-tauri/common/src/lib.rs | 11 +- src-tauri/src/export.rs | 11 +- src-tauri/src/utils.rs | 219 ++++---- src-tauri/tauri.conf.json | 8 +- .../VPNExtension.xcodeproj/project.pbxproj | 6 +- swift/extension/VPNExtension/Adapter.swift | 138 ++--- .../VPNExtension/PacketTunnelProvider.swift | 11 +- .../VPNExtension/VPNExtension.entitlements | 10 + swift/plugin/Sources/Defguard/Stats.swift | 11 + swift/plugin/Sources/Wireguard.swift | 27 +- 15 files changed, 559 insertions(+), 478 deletions(-) create mode 100644 swift/plugin/Sources/Defguard/Stats.swift diff --git a/package.json b/package.json index b4d18788..542189b4 100644 --- a/package.json +++ b/package.json @@ -55,14 +55,14 @@ "@tanstack/query-core": "^5.90.5", "@tanstack/react-virtual": "3.13.12", "@tauri-apps/api": "^2.9.0", - "@tauri-apps/plugin-clipboard-manager": "^2.3.0", - "@tauri-apps/plugin-deep-link": "^2.4.3", - "@tauri-apps/plugin-dialog": "^2.4.0", - "@tauri-apps/plugin-fs": "^2.4.2", - "@tauri-apps/plugin-http": "^2.5.2", + "@tauri-apps/plugin-clipboard-manager": "^2.3.1", + "@tauri-apps/plugin-deep-link": "^2.4.4", + "@tauri-apps/plugin-dialog": "^2.4.1", + "@tauri-apps/plugin-fs": "^2.4.3", + "@tauri-apps/plugin-http": "^2.5.3", "@tauri-apps/plugin-log": "^2.7.0", - "@tauri-apps/plugin-notification": "^2.3.1", - "@tauri-apps/plugin-opener": "^2.5.0", + "@tauri-apps/plugin-notification": "^2.3.2", + "@tauri-apps/plugin-opener": "^2.5.1", "@tauri-apps/plugin-os": "^2.3.1", "@tauri-apps/plugin-window-state": "^2.4.0", "@types/byte-size": "^8.1.2", @@ -106,7 +106,7 @@ "zustand": "^5.0.8" }, "devDependencies": { - "@biomejs/biome": "^2.2.7", + "@biomejs/biome": "^2.3.1", "@hookform/devtools": "^4.4.0", "@svgr/cli": "^8.1.0", "@tanstack/react-query": "^5.90.5", @@ -117,8 +117,8 @@ "@types/node": "^24.9.1", "@types/react": "^19.2.2", "@types/react-dom": "^19.2.2", - "@vitejs/plugin-react": "^5.0.4", - "@vitejs/plugin-react-swc": "^4.1.0", + "@vitejs/plugin-react": "^5.1.0", + "@vitejs/plugin-react-swc": "^4.2.0", "autoprefixer": "^10.4.21", "npm-run-all": "^4.1.5", "postcss": "^8.5.6", @@ -127,7 +127,7 @@ "typedoc": "^0.28.14", "typesafe-i18n": "^5.26.2", "typescript": "^5.9.3", - "vite": "^7.1.11" + "vite": "^7.1.12" }, "volta": { "node": "20.5.1" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a348b2bf..6a99b85f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -33,29 +33,29 @@ importers: specifier: ^2.9.0 version: 2.9.0 '@tauri-apps/plugin-clipboard-manager': - specifier: ^2.3.0 - version: 2.3.0 + specifier: ^2.3.1 + version: 2.3.1 '@tauri-apps/plugin-deep-link': - specifier: ^2.4.3 - version: 2.4.3 + specifier: ^2.4.4 + version: 2.4.4 '@tauri-apps/plugin-dialog': - specifier: ^2.4.0 - version: 2.4.0 + specifier: ^2.4.1 + version: 2.4.1 '@tauri-apps/plugin-fs': - specifier: ^2.4.2 - version: 2.4.2 + specifier: ^2.4.3 + version: 2.4.3 '@tauri-apps/plugin-http': - specifier: ^2.5.2 - version: 2.5.2 + specifier: ^2.5.3 + version: 2.5.3 '@tauri-apps/plugin-log': specifier: ^2.7.0 version: 2.7.0 '@tauri-apps/plugin-notification': - specifier: ^2.3.1 - version: 2.3.1 + specifier: ^2.3.2 + version: 2.3.2 '@tauri-apps/plugin-opener': - specifier: ^2.5.0 - version: 2.5.0 + specifier: ^2.5.1 + version: 2.5.1 '@tauri-apps/plugin-os': specifier: ^2.3.1 version: 2.3.1 @@ -178,11 +178,11 @@ importers: version: 3.25.76 zustand: specifier: ^5.0.8 - version: 5.0.8(@types/react@19.2.2)(immer@10.1.3)(react@19.2.0)(use-sync-external-store@1.6.0(react@19.2.0)) + version: 5.0.8(@types/react@19.2.2)(immer@10.2.0)(react@19.2.0)(use-sync-external-store@1.6.0(react@19.2.0)) devDependencies: '@biomejs/biome': - specifier: ^2.2.7 - version: 2.2.7 + specifier: ^2.3.1 + version: 2.3.1 '@hookform/devtools': specifier: ^4.4.0 version: 4.4.0(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) @@ -214,11 +214,11 @@ importers: specifier: ^19.2.2 version: 19.2.2(@types/react@19.2.2) '@vitejs/plugin-react': - specifier: ^5.0.4 - version: 5.0.4(vite@7.1.11(@types/node@24.9.1)(sass@1.92.1)(yaml@2.8.1)) + specifier: ^5.1.0 + version: 5.1.0(vite@7.1.12(@types/node@24.9.1)(sass@1.92.1)(yaml@2.8.1)) '@vitejs/plugin-react-swc': - specifier: ^4.1.0 - version: 4.1.0(vite@7.1.11(@types/node@24.9.1)(sass@1.92.1)(yaml@2.8.1)) + specifier: ^4.2.0 + version: 4.2.0(vite@7.1.12(@types/node@24.9.1)(sass@1.92.1)(yaml@2.8.1)) autoprefixer: specifier: ^10.4.21 version: 10.4.21(postcss@8.5.6) @@ -244,8 +244,8 @@ importers: specifier: ^5.9.3 version: 5.9.3 vite: - specifier: ^7.1.11 - version: 7.1.11(@types/node@24.9.1)(sass@1.92.1)(yaml@2.8.1) + specifier: ^7.1.12 + version: 7.1.12(@types/node@24.9.1)(sass@1.92.1)(yaml@2.8.1) packages: @@ -253,16 +253,16 @@ packages: resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==} engines: {node: '>=6.9.0'} - '@babel/compat-data@7.28.4': - resolution: {integrity: sha512-YsmSKC29MJwf0gF8Rjjrg5LQCmyh+j/nD8/eP7f+BeoQTKYqs9RoWbjGOdy0+1Ekr68RJZMUOPVQaQisnIo4Rw==} + '@babel/compat-data@7.28.5': + resolution: {integrity: sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA==} engines: {node: '>=6.9.0'} - '@babel/core@7.28.4': - resolution: {integrity: sha512-2BCOP7TN8M+gVDj7/ht3hsaO/B/n5oDbiAyyvnRlNOs+u1o+JWNYTQrmpuNp1/Wq2gcFrI01JAW+paEKDMx/CA==} + '@babel/core@7.28.5': + resolution: {integrity: sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==} engines: {node: '>=6.9.0'} - '@babel/generator@7.28.3': - resolution: {integrity: sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw==} + '@babel/generator@7.28.5': + resolution: {integrity: sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==} engines: {node: '>=6.9.0'} '@babel/helper-compilation-targets@7.27.2': @@ -291,8 +291,8 @@ packages: resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} engines: {node: '>=6.9.0'} - '@babel/helper-validator-identifier@7.27.1': - resolution: {integrity: sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==} + '@babel/helper-validator-identifier@7.28.5': + resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==} engines: {node: '>=6.9.0'} '@babel/helper-validator-option@7.27.1': @@ -303,8 +303,8 @@ packages: resolution: {integrity: sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==} engines: {node: '>=6.9.0'} - '@babel/parser@7.28.4': - resolution: {integrity: sha512-yZbBqeM6TkpP9du/I2pUZnJsRMGGvOuIrhjzC1AwHwW+6he4mni6Bp/m8ijn0iOuZuPI2BfkCoSRunpyjnrQKg==} + '@babel/parser@7.28.5': + resolution: {integrity: sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==} engines: {node: '>=6.0.0'} hasBin: true @@ -328,63 +328,63 @@ packages: resolution: {integrity: sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==} engines: {node: '>=6.9.0'} - '@babel/traverse@7.28.4': - resolution: {integrity: sha512-YEzuboP2qvQavAcjgQNVgsvHIDv6ZpwXvcvjmyySP2DIMuByS/6ioU5G9pYrWHM6T2YDfc7xga9iNzYOs12CFQ==} + '@babel/traverse@7.28.5': + resolution: {integrity: sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ==} engines: {node: '>=6.9.0'} - '@babel/types@7.28.4': - resolution: {integrity: sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q==} + '@babel/types@7.28.5': + resolution: {integrity: sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==} engines: {node: '>=6.9.0'} - '@biomejs/biome@2.2.7': - resolution: {integrity: sha512-1a8j0UP1vXVUf3UzMZEJ/zS2VgAG6wU6Cuh/I764sUGI+MCnJs/9WaojHYBDCxCMLTgU60/WqnYof85emXmSBA==} + '@biomejs/biome@2.3.1': + resolution: {integrity: sha512-A29evf1R72V5bo4o2EPxYMm5mtyGvzp2g+biZvRFx29nWebGyyeOSsDWGx3tuNNMFRepGwxmA9ZQ15mzfabK2w==} engines: {node: '>=14.21.3'} hasBin: true - '@biomejs/cli-darwin-arm64@2.2.7': - resolution: {integrity: sha512-xBUUsebnO2/Qj1v7eZmKUy2ZcFkZ4/jLUkxN02Qup1RPoRaiW9AKXHrqS3L7iX6PzofHY2xuZ+Pb9kAcpoe0qA==} + '@biomejs/cli-darwin-arm64@2.3.1': + resolution: {integrity: sha512-ombSf3MnTUueiYGN1SeI9tBCsDUhpWzOwS63Dove42osNh0PfE1cUtHFx6eZ1+MYCCLwXzlFlYFdrJ+U7h6LcA==} engines: {node: '>=14.21.3'} cpu: [arm64] os: [darwin] - '@biomejs/cli-darwin-x64@2.2.7': - resolution: {integrity: sha512-vsY4NhmxqgfLJufr9XUnC+yGUPJiXAc1mz6FcjaAmuIuLwfghN4uQO7hnW2AneGyoi2mNe9Jbvf6Qtq4AjzrFg==} + '@biomejs/cli-darwin-x64@2.3.1': + resolution: {integrity: sha512-pcOfwyoQkrkbGvXxRvZNe5qgD797IowpJPovPX5biPk2FwMEV+INZqfCaz4G5bVq9hYnjwhRMamg11U4QsRXrQ==} engines: {node: '>=14.21.3'} cpu: [x64] os: [darwin] - '@biomejs/cli-linux-arm64-musl@2.2.7': - resolution: {integrity: sha512-FrTwvKO/7t5HbVTvhlMOTOVQLAcR7r4O4iFQhEpZXUtBfosHqrX/JJlX7daPawoe14MDcCu9CDg0zLVpTuDvuQ==} + '@biomejs/cli-linux-arm64-musl@2.3.1': + resolution: {integrity: sha512-+DZYv8l7FlUtTrWs1Tdt1KcNCAmRO87PyOnxKGunbWm5HKg1oZBSbIIPkjrCtDZaeqSG1DiGx7qF+CPsquQRcg==} engines: {node: '>=14.21.3'} cpu: [arm64] os: [linux] - '@biomejs/cli-linux-arm64@2.2.7': - resolution: {integrity: sha512-nUdco104rjV9dULi1VssQ5R/kX2jE/Z2sDjyqS+siV9sTQda0DwmEUixFNRCWvZJRRiZUWhgiDFJ4n7RowO8Mg==} + '@biomejs/cli-linux-arm64@2.3.1': + resolution: {integrity: sha512-td5O8pFIgLs8H1sAZsD6v+5quODihyEw4nv2R8z7swUfIK1FKk+15e4eiYVLcAE4jUqngvh4j3JCNgg0Y4o4IQ==} engines: {node: '>=14.21.3'} cpu: [arm64] os: [linux] - '@biomejs/cli-linux-x64-musl@2.2.7': - resolution: {integrity: sha512-MnsysF5s/iLC5wnYvuMseOy+m8Pd4bWG1uwlVyy2AUbfjAVUgtbYbboc5wMXljFrDY7e6rLjLTR4S2xqDpGlQg==} + '@biomejs/cli-linux-x64-musl@2.3.1': + resolution: {integrity: sha512-Y3Ob4nqgv38Mh+6EGHltuN+Cq8aj/gyMTJYzkFZV2AEj+9XzoXB9VNljz9pjfFNHUxvLEV4b55VWyxozQTBaUQ==} engines: {node: '>=14.21.3'} cpu: [x64] os: [linux] - '@biomejs/cli-linux-x64@2.2.7': - resolution: {integrity: sha512-tPTcGAIEOOZrj2tQ7fdraWlaxNKApBw6l4In8wQQV1IyxnAexqi0hykHzKEX8hKKctf5gxGBfNCzyIvqpj4CFQ==} + '@biomejs/cli-linux-x64@2.3.1': + resolution: {integrity: sha512-PYWgEO7up7XYwSAArOpzsVCiqxBCXy53gsReAb1kKYIyXaoAlhBaBMvxR/k2Rm9aTuZ662locXUmPk/Aj+Xu+Q==} engines: {node: '>=14.21.3'} cpu: [x64] os: [linux] - '@biomejs/cli-win32-arm64@2.2.7': - resolution: {integrity: sha512-h5D1jhwA2b7cFXerYiJfXHSzzAMFFoEDL5Mc2BgiaEw0iaSgSso/3Nc6FbOR55aTQISql+IpB4PS7JoV26Gdbw==} + '@biomejs/cli-win32-arm64@2.3.1': + resolution: {integrity: sha512-RHIG/zgo+69idUqVvV3n8+j58dKYABRpMyDmfWu2TITC+jwGPiEaT0Q3RKD+kQHiS80mpBrST0iUGeEXT0bU9A==} engines: {node: '>=14.21.3'} cpu: [arm64] os: [win32] - '@biomejs/cli-win32-x64@2.2.7': - resolution: {integrity: sha512-URqAJi0kONyBKG4V9NVafHLDtm6IHmF4qPYi/b6x7MD6jxpWeJiTCO6R5+xDlWckX2T/OGv6Yq3nkz6s0M8Ykw==} + '@biomejs/cli-win32-x64@2.3.1': + resolution: {integrity: sha512-izl30JJ5Dp10mi90Eko47zhxE6pYyWPcnX1NQxKpL/yMhXxf95oLTzfpu4q+MDBh/gemNqyJEwjBpe0MT5iWPA==} engines: {node: '>=14.21.3'} cpu: [x64] os: [win32] @@ -620,8 +620,8 @@ packages: '@floating-ui/utils@0.2.10': resolution: {integrity: sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==} - '@gerrit0/mini-shiki@3.13.1': - resolution: {integrity: sha512-fDWM5QQc70jwBIt/WYMybdyXdyBmoJe7r1hpM+V/bHnyla79sygVDK2/LlVxIPc4n5FA3B5Wzt7AQH2+psNphg==} + '@gerrit0/mini-shiki@3.14.0': + resolution: {integrity: sha512-c5X8fwPLOtUS8TVdqhynz9iV0GlOtFUT1ppXYzUUlEXe4kbZ/mvMT8wXoT8kCwUka+zsiloq7sD3pZ3+QVTuNQ==} '@hookform/devtools@4.4.0': resolution: {integrity: sha512-Mtlic+uigoYBPXlfvPBfiYYUZuyMrD3pTjDpVIhL6eCZTvQkHsKBSKeZCvXWUZr8fqrkzDg27N+ZuazLKq6Vmg==} @@ -747,8 +747,8 @@ packages: peerDependencies: react: '>=18' - '@reduxjs/toolkit@2.9.1': - resolution: {integrity: sha512-sETJ3qO72y7L7WiR5K54UFLT3jRzAtqeBPVO15xC3bGA6kDqCH8m/v7BKCPH4czydXzz/1lPEGLvew7GjOO3Qw==} + '@reduxjs/toolkit@2.9.2': + resolution: {integrity: sha512-ZAYu/NXkl/OhqTz7rfPaAhY0+e8Fr15jqNxte/2exKUxvHyQ/hcqmdekiN1f+Lcw3pE+34FCgX+26zcUE3duCg==} peerDependencies: react: ^16.9.0 || ^17.0.0 || ^18 || ^19 react-redux: ^7.2.1 || ^8.1.3 || ^9.0.0 @@ -762,11 +762,8 @@ packages: resolution: {integrity: sha512-O3rHJzAQKamUz1fvE0Qaw0xSFqsA/yafi2iqeE0pvdFtCO1viYx8QL6f3Ln/aCCTLxs68SLf0KPM9eSeM8yBnA==} engines: {node: '>=14.0.0'} - '@rolldown/pluginutils@1.0.0-beta.35': - resolution: {integrity: sha512-slYrCpoxJUqzFDDNlvrOYRazQUNRvWPjXA17dAOISY3rDMxX6k8K4cj2H+hEYMHF81HO3uNd5rHVigAWRM5dSg==} - - '@rolldown/pluginutils@1.0.0-beta.38': - resolution: {integrity: sha512-N/ICGKleNhA5nc9XXQG/kkKHJ7S55u0x0XUJbbkmdCnFuoRkM1Il12q9q0eX19+M7KKUEPw/daUPIRnxhcxAIw==} + '@rolldown/pluginutils@1.0.0-beta.43': + resolution: {integrity: sha512-5Uxg7fQUCmfhax7FJke2+8B6cqgeUJUD9o2uXIKXhD+mG0mL6NObmVoi9wXEU1tY89mZKgAYA6fTbftx3q2ZPQ==} '@rollup/rollup-android-arm-eabi@4.52.5': resolution: {integrity: sha512-8c1vW4ocv3UOMp9K+gToY5zL2XiiVw3k7f1ksf4yO1FlDFQ1C2u72iACFnSOceJFsWskc2WZNqeRhFRPzv+wtQ==} @@ -878,17 +875,17 @@ packages: cpu: [x64] os: [win32] - '@shikijs/engine-oniguruma@3.13.0': - resolution: {integrity: sha512-O42rBGr4UDSlhT2ZFMxqM7QzIU+IcpoTMzb3W7AlziI1ZF7R8eS2M0yt5Ry35nnnTX/LTLXFPUjRFCIW+Operg==} + '@shikijs/engine-oniguruma@3.14.0': + resolution: {integrity: sha512-TNcYTYMbJyy+ZjzWtt0bG5y4YyMIWC2nyePz+CFMWqm+HnZZyy9SWMgo8Z6KBJVIZnx8XUXS8U2afO6Y0g1Oug==} - '@shikijs/langs@3.13.0': - resolution: {integrity: sha512-672c3WAETDYHwrRP0yLy3W1QYB89Hbpj+pO4KhxK6FzIrDI2FoEXNiNCut6BQmEApYLfuYfpgOZaqbY+E9b8wQ==} + '@shikijs/langs@3.14.0': + resolution: {integrity: sha512-DIB2EQY7yPX1/ZH7lMcwrK5pl+ZkP/xoSpUzg9YC8R+evRCCiSQ7yyrvEyBsMnfZq4eBzLzBlugMyTAf13+pzg==} - '@shikijs/themes@3.13.0': - resolution: {integrity: sha512-Vxw1Nm1/Od8jyA7QuAenaV78BG2nSr3/gCGdBkLpfLscddCkzkL36Q5b67SrLLfvAJTOUzW39x4FHVCFriPVgg==} + '@shikijs/themes@3.14.0': + resolution: {integrity: sha512-fAo/OnfWckNmv4uBoUu6dSlkcBc+SA1xzj5oUSaz5z3KqHtEbUypg/9xxgJARtM6+7RVm0Q6Xnty41xA1ma1IA==} - '@shikijs/types@3.13.0': - resolution: {integrity: sha512-oM9P+NCFri/mmQ8LoFGVfVyemm5Hi27330zuOBp0annwJdKH1kOLndw3zCtAVDehPLg9fKqoEx3Ht/wNZxolfw==} + '@shikijs/types@3.14.0': + resolution: {integrity: sha512-bQGgC6vrY8U/9ObG1Z/vTro+uclbjjD/uG58RvfxKZVD5p9Yc1ka3tVyEFy7BNJLzxuWyHH5NWynP9zZZS59eQ==} '@shikijs/vscode-textmate@10.0.2': resolution: {integrity: sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==} @@ -1183,29 +1180,29 @@ packages: engines: {node: '>= 10'} hasBin: true - '@tauri-apps/plugin-clipboard-manager@2.3.0': - resolution: {integrity: sha512-81NOBA2P+OTY8RLkBwyl9ZR/0CeggLub4F6zxcxUIfFOAqtky7J61+K/MkH2SC1FMxNBxrX0swDuKvkjkHadlA==} + '@tauri-apps/plugin-clipboard-manager@2.3.1': + resolution: {integrity: sha512-lQMaUSFs5my8oEHuvQOLJoPHfxRJNn0gwXyTsyMhtQZBD4sYLiDux8p+EsagY6vv5SkSYWVViJYvlcPIjJ+Dog==} - '@tauri-apps/plugin-deep-link@2.4.3': - resolution: {integrity: sha512-yVCZpVG1ZrtfCvE7K5LRSrGqlyPlCrqlKgoREJHnfjyYdDtUhFmZqScOXpL8XL2PizJHDsoahEweuTaUPEokPA==} + '@tauri-apps/plugin-deep-link@2.4.4': + resolution: {integrity: sha512-xdDOIW5RHTyU+9CJFFrojQgDN2rd9FDU9II2suNOQauPP/YZ6CLldyQj5YFtKGyCX6+jYNymOEq5oYR7MKrsoQ==} - '@tauri-apps/plugin-dialog@2.4.0': - resolution: {integrity: sha512-OvXkrEBfWwtd8tzVCEXIvRfNEX87qs2jv6SqmVPiHcJjBhSF/GUvjqUNIDmKByb5N8nvDqVUM7+g1sXwdC/S9w==} + '@tauri-apps/plugin-dialog@2.4.1': + resolution: {integrity: sha512-2eAueoxstrUnAf5cZWT9A/jzh4mTdUu646Q8zEX0a3RQmht7fQhdhxWfgQH4/of8iy1etDLKzokXbF2CxdBFHg==} - '@tauri-apps/plugin-fs@2.4.2': - resolution: {integrity: sha512-YGhmYuTgXGsi6AjoV+5mh2NvicgWBfVJHHheuck6oHD+HC9bVWPaHvCP0/Aw4pHDejwrvT8hE3+zZAaWf+hrig==} + '@tauri-apps/plugin-fs@2.4.3': + resolution: {integrity: sha512-/ZVHrwf/FTMSReWgMfiraeJjBcIr4QrDQC5BalvSSLXgtEiELPjQkRaXox7zG7z5nB04m/TwTLqfeeBROg0LLQ==} - '@tauri-apps/plugin-http@2.5.2': - resolution: {integrity: sha512-x1mQKHSLDk4mS2S938OTeyk8L7QyLpCrKZCZcjkljGsvTvRMojCvI9SeJ1kaxc7t8xSilkC7WdId8xER9TIGLg==} + '@tauri-apps/plugin-http@2.5.3': + resolution: {integrity: sha512-YiizgUWd9jQBPGX2x3k1l6qdBiDYOo3FjqMEjkeJ0I8IRIkp6OQ8ff6fRcaiUt0sl8+h3r4983+6O/m+//PMVQ==} '@tauri-apps/plugin-log@2.7.0': resolution: {integrity: sha512-81XQ2f93x4vmIB5OY0XlYAxy60cHdYLs0Ki8Qp38tNATRiuBit+Orh3frpY3qfYQnqEvYVyRub7YRJWlmW2RRA==} - '@tauri-apps/plugin-notification@2.3.1': - resolution: {integrity: sha512-7gqgfANSREKhh35fY1L4j3TUjUdePmU735FYDqRGeIf8nMXWpcx6j4FhN9/4nYz+m0mv79DCTPLqIPTySggGgg==} + '@tauri-apps/plugin-notification@2.3.2': + resolution: {integrity: sha512-xJV7NxBYFD65nnFzYiR9gloT1yFIyGYQav5z7od2+JRlJF968ZYbVFHPkyy6h9yYjvGh2FQKsn45E5xlXTJl7A==} - '@tauri-apps/plugin-opener@2.5.0': - resolution: {integrity: sha512-B0LShOYae4CZjN8leiNDbnfjSrTwoZakqKaWpfoH6nXiJwt6Rgj6RnVIffG3DoJiKsffRhMkjmBV9VeilSb4TA==} + '@tauri-apps/plugin-opener@2.5.1': + resolution: {integrity: sha512-nyT6oW4ibyXJN2duVBZlPhPmN/+jViOtX0B95f7j5W3R493wEyCNRgjL6YXUp7cB1pKKG6spk7/Q46ZKuzeeBQ==} '@tauri-apps/plugin-os@2.3.1': resolution: {integrity: sha512-ty5V8XDUIFbSnrk3zsFoP3kzN+vAufYzalJSlmrVhQTImIZa1aL1a03bOaP2vuBvfR+WDRC6NgV2xBl8G07d+w==} @@ -1320,14 +1317,14 @@ packages: peerDependencies: react: '>= 16.8.0' - '@vitejs/plugin-react-swc@4.1.0': - resolution: {integrity: sha512-Ff690TUck0Anlh7wdIcnsVMhofeEVgm44Y4OYdeeEEPSKyZHzDI9gfVBvySEhDfXtBp8tLCbfsVKPWEMEjq8/g==} + '@vitejs/plugin-react-swc@4.2.0': + resolution: {integrity: sha512-/tesahXD1qpkGC6FzMoFOJj0RyZdw9xLELOL+6jbElwmWfwOnIVy+IfpY+o9JfD9PKaR/Eyb6DNrvbXpuvA+8Q==} engines: {node: ^20.19.0 || >=22.12.0} peerDependencies: vite: ^4 || ^5 || ^6 || ^7 - '@vitejs/plugin-react@5.0.4': - resolution: {integrity: sha512-La0KD0vGkVkSk6K+piWDKRUyg8Rl5iAIKRMH0vMJI0Eg47bq1eOxmoObAaQG37WMW9MSyk7Cs8EIWwJC1PtzKA==} + '@vitejs/plugin-react@5.1.0': + resolution: {integrity: sha512-4LuWrg7EKWgQaMJfnN+wcmbAW+VSsCmqGohftWjuct47bv8uE4n/nPpq4XjJPsxgq00GGG5J8dvBczp8uxScew==} engines: {node: ^20.19.0 || >=22.12.0} peerDependencies: vite: ^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 @@ -1380,8 +1377,8 @@ packages: balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} - baseline-browser-mapping@2.8.19: - resolution: {integrity: sha512-zoKGUdu6vb2jd3YOq0nnhEDQVbPcHhco3UImJrv5dSkvxTc2pl2WjOPsjZXDwPDSl5eghIMuY3R6J9NDKF3KcQ==} + baseline-browser-mapping@2.8.20: + resolution: {integrity: sha512-JMWsdF+O8Orq3EMukbUN1QfbLK9mX2CkUmQBcW2T0s8OmdAUL5LLM/6wFwSrqXzlXB13yhyK9gTKS1rIizOduQ==} hasBin: true boolbase@1.0.0: @@ -1676,8 +1673,8 @@ packages: resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} engines: {node: '>= 0.4'} - electron-to-chromium@1.5.238: - resolution: {integrity: sha512-khBdc+w/Gv+cS8e/Pbnaw/FXcBUeKrRVik9IxfXtgREOWyJhR4tj43n3amkVogJ/yeQUqzkrZcFhtIxIdqmmcQ==} + electron-to-chromium@1.5.240: + resolution: {integrity: sha512-OBwbZjWgrCOH+g6uJsA2/7Twpas2OlepS9uvByJjR2datRDuKGYeD+nP8lBBks2qnB7bGJNHDUx7c/YLaT3QMQ==} emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} @@ -1717,8 +1714,8 @@ packages: resolution: {integrity: sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==} engines: {node: '>= 0.4'} - es-toolkit@1.40.0: - resolution: {integrity: sha512-8o6w0KFmU0CiIl0/Q/BCEOabF2IJaELM1T2PWj6e8KqzHv1gdx+7JtFnDwOx1kJH/isJ5NwlDG1nCr1HrRF94Q==} + es-toolkit@1.41.0: + resolution: {integrity: sha512-bDd3oRmbVgqZCJS6WmeQieOrzpl3URcWBUVDXxOELlUW2FuW+0glPOz1n0KnRie+PdyvUZcXz2sOn00c6pPRIA==} esbuild@0.25.11: resolution: {integrity: sha512-KohQwyzrKTQmhXDW1PjCv3Tyspn9n5GcY2RTDqeORIdIJY8yKIF7sTSopFmn/wpMPW4rdPXI0UE5LJLuq3bx0Q==} @@ -1914,8 +1911,8 @@ packages: htmlparser2@10.0.0: resolution: {integrity: sha512-TwAZM+zE5Tq3lrEHvOlvwgj1XLWQCtaaibSN11Q+gGBAS7Y1uZSWwXXRe4iF6OXnaq1riyQAPFOBtYc77Mxq0g==} - immer@10.1.3: - resolution: {integrity: sha512-tmjF/k8QDKydUlm3mZU+tjM6zeq9/fFpPqH9SzWmBnVVKsPBg/V66qsMwb3/Bo90cgUN+ghdVBess+hPsxUyRw==} + immer@10.2.0: + resolution: {integrity: sha512-d/+XTN3zfODyjr89gM3mPq1WNX2B8pYsu7eORitdwyA2sBubnTl3laYlBk4sXY5FUa5qTZGBDPJICVbvqzjlbw==} immutable@5.1.4: resolution: {integrity: sha512-p6u1bG3YSnINT5RQmx/yRZBpenIl30kVxkTLDyHLIMk0gict704Q9n+thfDI7lTRm9vXdDYutVzXhzcThxTnXA==} @@ -2502,8 +2499,8 @@ packages: redux: optional: true - react-refresh@0.17.0: - resolution: {integrity: sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==} + react-refresh@0.18.0: + resolution: {integrity: sha512-QgT5//D3jfjJb6Gsjxv0Slpj23ip+HtOpnNgnb2S5zU3CB26G/IDPGoy4RJB42wzFE46DRsstbW6tKHoKbhAxw==} engines: {node: '>=0.10.0'} react-router-dom@6.30.1: @@ -2760,8 +2757,8 @@ packages: engines: {node: '>=14.0.0'} hasBin: true - tabbable@6.2.0: - resolution: {integrity: sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew==} + tabbable@6.3.0: + resolution: {integrity: sha512-EIHvdY5bPLuWForiR/AN2Bxngzpuwn1is4asboytXtpTgsArc+WmSJKVLlhdh71u7jFcryDqB2A8lQvj78MkyQ==} tiny-invariant@1.3.3: resolution: {integrity: sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==} @@ -2884,8 +2881,8 @@ packages: victory-vendor@37.3.6: resolution: {integrity: sha512-SbPDPdDBYp+5MJHhBCAyI7wKM3d5ivekigc2Dk2s7pgbZ9wIgIBYGVw4zGHBml/qTFbexrofXW6Gu4noGxrOwQ==} - vite@7.1.11: - resolution: {integrity: sha512-uzcxnSDVjAopEUjljkWh8EIrg6tlzrjFUfMcR1EVsRDGwf/ccef0qQPRyOrROwhrTDaApueq+ja+KLPlzR/zdg==} + vite@7.1.12: + resolution: {integrity: sha512-ZWyE8YXEXqJrrSLvYgrRP7p62OziLW7xI5HYGWFzOvupfAlrLvURSzv/FyGyy0eidogEM3ujU+kUG1zuHgb6Ug==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true peerDependencies: @@ -3003,23 +3000,23 @@ snapshots: '@babel/code-frame@7.27.1': dependencies: - '@babel/helper-validator-identifier': 7.27.1 + '@babel/helper-validator-identifier': 7.28.5 js-tokens: 4.0.0 picocolors: 1.1.1 - '@babel/compat-data@7.28.4': {} + '@babel/compat-data@7.28.5': {} - '@babel/core@7.28.4': + '@babel/core@7.28.5': dependencies: '@babel/code-frame': 7.27.1 - '@babel/generator': 7.28.3 + '@babel/generator': 7.28.5 '@babel/helper-compilation-targets': 7.27.2 - '@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.4) + '@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.5) '@babel/helpers': 7.28.4 - '@babel/parser': 7.28.4 + '@babel/parser': 7.28.5 '@babel/template': 7.27.2 - '@babel/traverse': 7.28.4 - '@babel/types': 7.28.4 + '@babel/traverse': 7.28.5 + '@babel/types': 7.28.5 '@jridgewell/remapping': 2.3.5 convert-source-map: 2.0.0 debug: 4.4.3 @@ -3029,17 +3026,17 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/generator@7.28.3': + '@babel/generator@7.28.5': dependencies: - '@babel/parser': 7.28.4 - '@babel/types': 7.28.4 + '@babel/parser': 7.28.5 + '@babel/types': 7.28.5 '@jridgewell/gen-mapping': 0.3.13 '@jridgewell/trace-mapping': 0.3.31 jsesc: 3.1.0 '@babel/helper-compilation-targets@7.27.2': dependencies: - '@babel/compat-data': 7.28.4 + '@babel/compat-data': 7.28.5 '@babel/helper-validator-option': 7.27.1 browserslist: 4.27.0 lru-cache: 5.1.1 @@ -3049,17 +3046,17 @@ snapshots: '@babel/helper-module-imports@7.27.1': dependencies: - '@babel/traverse': 7.28.4 - '@babel/types': 7.28.4 + '@babel/traverse': 7.28.5 + '@babel/types': 7.28.5 transitivePeerDependencies: - supports-color - '@babel/helper-module-transforms@7.28.3(@babel/core@7.28.4)': + '@babel/helper-module-transforms@7.28.3(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 + '@babel/core': 7.28.5 '@babel/helper-module-imports': 7.27.1 - '@babel/helper-validator-identifier': 7.27.1 - '@babel/traverse': 7.28.4 + '@babel/helper-validator-identifier': 7.28.5 + '@babel/traverse': 7.28.5 transitivePeerDependencies: - supports-color @@ -3067,27 +3064,27 @@ snapshots: '@babel/helper-string-parser@7.27.1': {} - '@babel/helper-validator-identifier@7.27.1': {} + '@babel/helper-validator-identifier@7.28.5': {} '@babel/helper-validator-option@7.27.1': {} '@babel/helpers@7.28.4': dependencies: '@babel/template': 7.27.2 - '@babel/types': 7.28.4 + '@babel/types': 7.28.5 - '@babel/parser@7.28.4': + '@babel/parser@7.28.5': dependencies: - '@babel/types': 7.28.4 + '@babel/types': 7.28.5 - '@babel/plugin-transform-react-jsx-self@7.27.1(@babel/core@7.28.4)': + '@babel/plugin-transform-react-jsx-self@7.27.1(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 + '@babel/core': 7.28.5 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-react-jsx-source@7.27.1(@babel/core@7.28.4)': + '@babel/plugin-transform-react-jsx-source@7.27.1(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 + '@babel/core': 7.28.5 '@babel/helper-plugin-utils': 7.27.1 '@babel/runtime@7.28.4': {} @@ -3095,59 +3092,59 @@ snapshots: '@babel/template@7.27.2': dependencies: '@babel/code-frame': 7.27.1 - '@babel/parser': 7.28.4 - '@babel/types': 7.28.4 + '@babel/parser': 7.28.5 + '@babel/types': 7.28.5 - '@babel/traverse@7.28.4': + '@babel/traverse@7.28.5': dependencies: '@babel/code-frame': 7.27.1 - '@babel/generator': 7.28.3 + '@babel/generator': 7.28.5 '@babel/helper-globals': 7.28.0 - '@babel/parser': 7.28.4 + '@babel/parser': 7.28.5 '@babel/template': 7.27.2 - '@babel/types': 7.28.4 + '@babel/types': 7.28.5 debug: 4.4.3 transitivePeerDependencies: - supports-color - '@babel/types@7.28.4': + '@babel/types@7.28.5': dependencies: '@babel/helper-string-parser': 7.27.1 - '@babel/helper-validator-identifier': 7.27.1 + '@babel/helper-validator-identifier': 7.28.5 - '@biomejs/biome@2.2.7': + '@biomejs/biome@2.3.1': optionalDependencies: - '@biomejs/cli-darwin-arm64': 2.2.7 - '@biomejs/cli-darwin-x64': 2.2.7 - '@biomejs/cli-linux-arm64': 2.2.7 - '@biomejs/cli-linux-arm64-musl': 2.2.7 - '@biomejs/cli-linux-x64': 2.2.7 - '@biomejs/cli-linux-x64-musl': 2.2.7 - '@biomejs/cli-win32-arm64': 2.2.7 - '@biomejs/cli-win32-x64': 2.2.7 - - '@biomejs/cli-darwin-arm64@2.2.7': + '@biomejs/cli-darwin-arm64': 2.3.1 + '@biomejs/cli-darwin-x64': 2.3.1 + '@biomejs/cli-linux-arm64': 2.3.1 + '@biomejs/cli-linux-arm64-musl': 2.3.1 + '@biomejs/cli-linux-x64': 2.3.1 + '@biomejs/cli-linux-x64-musl': 2.3.1 + '@biomejs/cli-win32-arm64': 2.3.1 + '@biomejs/cli-win32-x64': 2.3.1 + + '@biomejs/cli-darwin-arm64@2.3.1': optional: true - '@biomejs/cli-darwin-x64@2.2.7': + '@biomejs/cli-darwin-x64@2.3.1': optional: true - '@biomejs/cli-linux-arm64-musl@2.2.7': + '@biomejs/cli-linux-arm64-musl@2.3.1': optional: true - '@biomejs/cli-linux-arm64@2.2.7': + '@biomejs/cli-linux-arm64@2.3.1': optional: true - '@biomejs/cli-linux-x64-musl@2.2.7': + '@biomejs/cli-linux-x64-musl@2.3.1': optional: true - '@biomejs/cli-linux-x64@2.2.7': + '@biomejs/cli-linux-x64@2.3.1': optional: true - '@biomejs/cli-win32-arm64@2.2.7': + '@biomejs/cli-win32-arm64@2.3.1': optional: true - '@biomejs/cli-win32-x64@2.2.7': + '@biomejs/cli-win32-x64@2.3.1': optional: true '@emotion/babel-plugin@11.13.5': @@ -3332,16 +3329,16 @@ snapshots: '@floating-ui/utils': 0.2.10 react: 19.2.0 react-dom: 19.2.0(react@19.2.0) - tabbable: 6.2.0 + tabbable: 6.3.0 '@floating-ui/utils@0.2.10': {} - '@gerrit0/mini-shiki@3.13.1': + '@gerrit0/mini-shiki@3.14.0': dependencies: - '@shikijs/engine-oniguruma': 3.13.0 - '@shikijs/langs': 3.13.0 - '@shikijs/themes': 3.13.0 - '@shikijs/types': 3.13.0 + '@shikijs/engine-oniguruma': 3.14.0 + '@shikijs/langs': 3.14.0 + '@shikijs/themes': 3.14.0 + '@shikijs/types': 3.14.0 '@shikijs/vscode-textmate': 10.0.2 '@hookform/devtools@4.4.0(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': @@ -3458,11 +3455,11 @@ snapshots: '@react-hook/passive-layout-effect': 1.2.1(react@19.2.0) react: 19.2.0 - '@reduxjs/toolkit@2.9.1(react-redux@9.2.0(@types/react@19.2.2)(react@19.2.0)(redux@5.0.1))(react@19.2.0)': + '@reduxjs/toolkit@2.9.2(react-redux@9.2.0(@types/react@19.2.2)(react@19.2.0)(redux@5.0.1))(react@19.2.0)': dependencies: '@standard-schema/spec': 1.0.0 '@standard-schema/utils': 0.3.0 - immer: 10.1.3 + immer: 10.2.0 redux: 5.0.1 redux-thunk: 3.1.0(redux@5.0.1) reselect: 5.1.1 @@ -3472,9 +3469,7 @@ snapshots: '@remix-run/router@1.23.0': {} - '@rolldown/pluginutils@1.0.0-beta.35': {} - - '@rolldown/pluginutils@1.0.0-beta.38': {} + '@rolldown/pluginutils@1.0.0-beta.43': {} '@rollup/rollup-android-arm-eabi@4.52.5': optional: true @@ -3542,20 +3537,20 @@ snapshots: '@rollup/rollup-win32-x64-msvc@4.52.5': optional: true - '@shikijs/engine-oniguruma@3.13.0': + '@shikijs/engine-oniguruma@3.14.0': dependencies: - '@shikijs/types': 3.13.0 + '@shikijs/types': 3.14.0 '@shikijs/vscode-textmate': 10.0.2 - '@shikijs/langs@3.13.0': + '@shikijs/langs@3.14.0': dependencies: - '@shikijs/types': 3.13.0 + '@shikijs/types': 3.14.0 - '@shikijs/themes@3.13.0': + '@shikijs/themes@3.14.0': dependencies: - '@shikijs/types': 3.13.0 + '@shikijs/types': 3.14.0 - '@shikijs/types@3.13.0': + '@shikijs/types@3.14.0': dependencies: '@shikijs/vscode-textmate': 10.0.2 '@types/hast': 3.0.4 @@ -3593,49 +3588,49 @@ snapshots: '@standard-schema/utils@0.3.0': {} - '@svgr/babel-plugin-add-jsx-attribute@8.0.0(@babel/core@7.28.4)': + '@svgr/babel-plugin-add-jsx-attribute@8.0.0(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 + '@babel/core': 7.28.5 - '@svgr/babel-plugin-remove-jsx-attribute@8.0.0(@babel/core@7.28.4)': + '@svgr/babel-plugin-remove-jsx-attribute@8.0.0(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 + '@babel/core': 7.28.5 - '@svgr/babel-plugin-remove-jsx-empty-expression@8.0.0(@babel/core@7.28.4)': + '@svgr/babel-plugin-remove-jsx-empty-expression@8.0.0(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 + '@babel/core': 7.28.5 - '@svgr/babel-plugin-replace-jsx-attribute-value@8.0.0(@babel/core@7.28.4)': + '@svgr/babel-plugin-replace-jsx-attribute-value@8.0.0(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 + '@babel/core': 7.28.5 - '@svgr/babel-plugin-svg-dynamic-title@8.0.0(@babel/core@7.28.4)': + '@svgr/babel-plugin-svg-dynamic-title@8.0.0(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 + '@babel/core': 7.28.5 - '@svgr/babel-plugin-svg-em-dimensions@8.0.0(@babel/core@7.28.4)': + '@svgr/babel-plugin-svg-em-dimensions@8.0.0(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 + '@babel/core': 7.28.5 - '@svgr/babel-plugin-transform-react-native-svg@8.1.0(@babel/core@7.28.4)': + '@svgr/babel-plugin-transform-react-native-svg@8.1.0(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 + '@babel/core': 7.28.5 - '@svgr/babel-plugin-transform-svg-component@8.0.0(@babel/core@7.28.4)': + '@svgr/babel-plugin-transform-svg-component@8.0.0(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 + '@babel/core': 7.28.5 - '@svgr/babel-preset@8.1.0(@babel/core@7.28.4)': + '@svgr/babel-preset@8.1.0(@babel/core@7.28.5)': dependencies: - '@babel/core': 7.28.4 - '@svgr/babel-plugin-add-jsx-attribute': 8.0.0(@babel/core@7.28.4) - '@svgr/babel-plugin-remove-jsx-attribute': 8.0.0(@babel/core@7.28.4) - '@svgr/babel-plugin-remove-jsx-empty-expression': 8.0.0(@babel/core@7.28.4) - '@svgr/babel-plugin-replace-jsx-attribute-value': 8.0.0(@babel/core@7.28.4) - '@svgr/babel-plugin-svg-dynamic-title': 8.0.0(@babel/core@7.28.4) - '@svgr/babel-plugin-svg-em-dimensions': 8.0.0(@babel/core@7.28.4) - '@svgr/babel-plugin-transform-react-native-svg': 8.1.0(@babel/core@7.28.4) - '@svgr/babel-plugin-transform-svg-component': 8.0.0(@babel/core@7.28.4) + '@babel/core': 7.28.5 + '@svgr/babel-plugin-add-jsx-attribute': 8.0.0(@babel/core@7.28.5) + '@svgr/babel-plugin-remove-jsx-attribute': 8.0.0(@babel/core@7.28.5) + '@svgr/babel-plugin-remove-jsx-empty-expression': 8.0.0(@babel/core@7.28.5) + '@svgr/babel-plugin-replace-jsx-attribute-value': 8.0.0(@babel/core@7.28.5) + '@svgr/babel-plugin-svg-dynamic-title': 8.0.0(@babel/core@7.28.5) + '@svgr/babel-plugin-svg-em-dimensions': 8.0.0(@babel/core@7.28.5) + '@svgr/babel-plugin-transform-react-native-svg': 8.1.0(@babel/core@7.28.5) + '@svgr/babel-plugin-transform-svg-component': 8.0.0(@babel/core@7.28.5) '@svgr/cli@8.1.0(typescript@5.9.3)': dependencies: @@ -3655,8 +3650,8 @@ snapshots: '@svgr/core@8.1.0(typescript@5.9.3)': dependencies: - '@babel/core': 7.28.4 - '@svgr/babel-preset': 8.1.0(@babel/core@7.28.4) + '@babel/core': 7.28.5 + '@svgr/babel-preset': 8.1.0(@babel/core@7.28.5) camelcase: 6.3.0 cosmiconfig: 8.3.6(typescript@5.9.3) snake-case: 3.0.4 @@ -3666,13 +3661,13 @@ snapshots: '@svgr/hast-util-to-babel-ast@8.0.0': dependencies: - '@babel/types': 7.28.4 + '@babel/types': 7.28.5 entities: 4.5.0 '@svgr/plugin-jsx@8.1.0(@svgr/core@8.1.0(typescript@5.9.3))': dependencies: - '@babel/core': 7.28.4 - '@svgr/babel-preset': 8.1.0(@babel/core@7.28.4) + '@babel/core': 7.28.5 + '@svgr/babel-preset': 8.1.0(@babel/core@7.28.5) '@svgr/core': 8.1.0(typescript@5.9.3) '@svgr/hast-util-to-babel-ast': 8.0.0 svg-parser: 2.0.4 @@ -3818,23 +3813,23 @@ snapshots: '@tauri-apps/cli-win32-ia32-msvc': 2.9.1 '@tauri-apps/cli-win32-x64-msvc': 2.9.1 - '@tauri-apps/plugin-clipboard-manager@2.3.0': + '@tauri-apps/plugin-clipboard-manager@2.3.1': dependencies: '@tauri-apps/api': 2.9.0 - '@tauri-apps/plugin-deep-link@2.4.3': + '@tauri-apps/plugin-deep-link@2.4.4': dependencies: '@tauri-apps/api': 2.9.0 - '@tauri-apps/plugin-dialog@2.4.0': + '@tauri-apps/plugin-dialog@2.4.1': dependencies: '@tauri-apps/api': 2.9.0 - '@tauri-apps/plugin-fs@2.4.2': + '@tauri-apps/plugin-fs@2.4.3': dependencies: '@tauri-apps/api': 2.9.0 - '@tauri-apps/plugin-http@2.5.2': + '@tauri-apps/plugin-http@2.5.3': dependencies: '@tauri-apps/api': 2.9.0 @@ -3842,11 +3837,11 @@ snapshots: dependencies: '@tauri-apps/api': 2.9.0 - '@tauri-apps/plugin-notification@2.3.1': + '@tauri-apps/plugin-notification@2.3.2': dependencies: '@tauri-apps/api': 2.9.0 - '@tauri-apps/plugin-opener@2.5.0': + '@tauri-apps/plugin-opener@2.5.1': dependencies: '@tauri-apps/api': 2.9.0 @@ -3862,24 +3857,24 @@ snapshots: '@types/babel__core@7.20.5': dependencies: - '@babel/parser': 7.28.4 - '@babel/types': 7.28.4 + '@babel/parser': 7.28.5 + '@babel/types': 7.28.5 '@types/babel__generator': 7.27.0 '@types/babel__template': 7.4.4 '@types/babel__traverse': 7.28.0 '@types/babel__generator@7.27.0': dependencies: - '@babel/types': 7.28.4 + '@babel/types': 7.28.5 '@types/babel__template@7.4.4': dependencies: - '@babel/parser': 7.28.4 - '@babel/types': 7.28.4 + '@babel/parser': 7.28.5 + '@babel/types': 7.28.5 '@types/babel__traverse@7.28.0': dependencies: - '@babel/types': 7.28.4 + '@babel/types': 7.28.5 '@types/byte-size@8.1.2': {} @@ -3964,23 +3959,23 @@ snapshots: '@use-gesture/core': 10.3.1 react: 19.2.0 - '@vitejs/plugin-react-swc@4.1.0(vite@7.1.11(@types/node@24.9.1)(sass@1.92.1)(yaml@2.8.1))': + '@vitejs/plugin-react-swc@4.2.0(vite@7.1.12(@types/node@24.9.1)(sass@1.92.1)(yaml@2.8.1))': dependencies: - '@rolldown/pluginutils': 1.0.0-beta.35 + '@rolldown/pluginutils': 1.0.0-beta.43 '@swc/core': 1.13.5 - vite: 7.1.11(@types/node@24.9.1)(sass@1.92.1)(yaml@2.8.1) + vite: 7.1.12(@types/node@24.9.1)(sass@1.92.1)(yaml@2.8.1) transitivePeerDependencies: - '@swc/helpers' - '@vitejs/plugin-react@5.0.4(vite@7.1.11(@types/node@24.9.1)(sass@1.92.1)(yaml@2.8.1))': + '@vitejs/plugin-react@5.1.0(vite@7.1.12(@types/node@24.9.1)(sass@1.92.1)(yaml@2.8.1))': dependencies: - '@babel/core': 7.28.4 - '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.28.4) - '@babel/plugin-transform-react-jsx-source': 7.27.1(@babel/core@7.28.4) - '@rolldown/pluginutils': 1.0.0-beta.38 + '@babel/core': 7.28.5 + '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.28.5) + '@babel/plugin-transform-react-jsx-source': 7.27.1(@babel/core@7.28.5) + '@rolldown/pluginutils': 1.0.0-beta.43 '@types/babel__core': 7.20.5 - react-refresh: 0.17.0 - vite: 7.1.11(@types/node@24.9.1)(sass@1.92.1)(yaml@2.8.1) + react-refresh: 0.18.0 + vite: 7.1.12(@types/node@24.9.1)(sass@1.92.1)(yaml@2.8.1) transitivePeerDependencies: - supports-color @@ -4037,7 +4032,7 @@ snapshots: balanced-match@1.0.2: {} - baseline-browser-mapping@2.8.19: {} + baseline-browser-mapping@2.8.20: {} boolbase@1.0.0: {} @@ -4057,9 +4052,9 @@ snapshots: browserslist@4.27.0: dependencies: - baseline-browser-mapping: 2.8.19 + baseline-browser-mapping: 2.8.20 caniuse-lite: 1.0.30001751 - electron-to-chromium: 1.5.238 + electron-to-chromium: 1.5.240 node-releases: 2.0.26 update-browserslist-db: 1.1.4(browserslist@4.27.0) @@ -4326,7 +4321,7 @@ snapshots: es-errors: 1.3.0 gopd: 1.2.0 - electron-to-chromium@1.5.238: {} + electron-to-chromium@1.5.240: {} emoji-regex@8.0.0: {} @@ -4416,7 +4411,7 @@ snapshots: is-date-object: 1.1.0 is-symbol: 1.1.1 - es-toolkit@1.40.0: {} + es-toolkit@1.41.0: {} esbuild@0.25.11: optionalDependencies: @@ -4641,7 +4636,7 @@ snapshots: domutils: 3.2.2 entities: 6.0.1 - immer@10.1.3: {} + immer@10.2.0: {} immutable@5.1.4: {} @@ -5340,7 +5335,7 @@ snapshots: '@types/react': 19.2.2 redux: 5.0.1 - react-refresh@0.17.0: {} + react-refresh@0.18.0: {} react-router-dom@6.30.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0): dependencies: @@ -5377,12 +5372,12 @@ snapshots: recharts@3.3.0(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react-is@18.3.1)(react@19.2.0)(redux@5.0.1): dependencies: - '@reduxjs/toolkit': 2.9.1(react-redux@9.2.0(@types/react@19.2.2)(react@19.2.0)(redux@5.0.1))(react@19.2.0) + '@reduxjs/toolkit': 2.9.2(react-redux@9.2.0(@types/react@19.2.2)(react@19.2.0)(redux@5.0.1))(react@19.2.0) clsx: 2.1.1 decimal.js-light: 2.5.1 - es-toolkit: 1.40.0 + es-toolkit: 1.41.0 eventemitter3: 5.0.1 - immer: 10.1.3 + immer: 10.2.0 react: 19.2.0 react-dom: 19.2.0(react@19.2.0) react-is: 18.3.1 @@ -5687,7 +5682,7 @@ snapshots: csso: 5.0.5 picocolors: 1.1.1 - tabbable@6.2.0: {} + tabbable@6.3.0: {} tiny-invariant@1.3.3: {} @@ -5742,7 +5737,7 @@ snapshots: typedoc@0.28.14(typescript@5.9.3): dependencies: - '@gerrit0/mini-shiki': 3.13.1 + '@gerrit0/mini-shiki': 3.14.0 lunr: 2.3.9 markdown-it: 14.1.0 minimatch: 9.0.5 @@ -5854,7 +5849,7 @@ snapshots: d3-time: 3.1.0 d3-timer: 3.0.1 - vite@7.1.11(@types/node@24.9.1)(sass@1.92.1)(yaml@2.8.1): + vite@7.1.12(@types/node@24.9.1)(sass@1.92.1)(yaml@2.8.1): dependencies: esbuild: 0.25.11 fdir: 6.5.0(picomatch@4.0.3) @@ -5943,10 +5938,10 @@ snapshots: zod@3.25.76: {} - zustand@5.0.8(@types/react@19.2.2)(immer@10.1.3)(react@19.2.0)(use-sync-external-store@1.6.0(react@19.2.0)): + zustand@5.0.8(@types/react@19.2.2)(immer@10.2.0)(react@19.2.0)(use-sync-external-store@1.6.0(react@19.2.0)): optionalDependencies: '@types/react': 19.2.2 - immer: 10.1.3 + immer: 10.2.0 react: 19.2.0 use-sync-external-store: 1.6.0(react@19.2.0) diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index d0c76b90..8718b389 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -847,9 +847,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.41" +version = "1.2.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac9fe6cdbb24b6ade63616c0a0688e45bb56732262c158df3c0c4bea4ca47cb7" +checksum = "739eb0f94557554b3ca9a86d2d37bebd49c5e6d0c1d2bda35ba5bdac830befc2" dependencies = [ "find-msvc-tools", "jobserver", @@ -1478,9 +1478,9 @@ dependencies = [ [[package]] name = "deranged" -version = "0.5.4" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a41953f86f8a05768a6cda24def994fd2f424b04ec5c719cf89989779f199071" +checksum = "ececcb659e7ba858fb4f10388c250a7252eb0a27373f1a72b8748afdd248e587" dependencies = [ "powerfmt", "serde_core", @@ -1656,9 +1656,9 @@ dependencies = [ [[package]] name = "document-features" -version = "0.2.11" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95249b50c6c185bee49034bcb378a49dc2b5dff0be90ff6616d31d64febab05d" +checksum = "d4b8a88685455ed29a21542a33abd9cb6510b6b129abadabdcef0f4c55bc8f61" dependencies = [ "litrs", ] @@ -1937,9 +1937,9 @@ checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99" [[package]] name = "flate2" -version = "1.1.4" +version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc5a4e564e38c699f2880d3fda590bedc2e69f3f84cd48b457bd892ce61d0aa9" +checksum = "bfe33edd8e85a12a67454e37f8c75e730830d83e313556ab9ebf9ee7fbeb3bfb" dependencies = [ "crc32fast", "miniz_oxide", @@ -2606,11 +2606,11 @@ dependencies = [ [[package]] name = "home" -version = "0.5.11" +version = "0.5.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589533453244b0995c858700322199b2becb13b627df2851f64a2775d024abcf" +checksum = "cc627f471c528ff0c4a49e1d5e60450c8f6461dd6d10ba9dcd3a61d3dff7728d" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -3296,9 +3296,9 @@ checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" [[package]] name = "litrs" -version = "0.4.2" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5e54036fe321fd421e10d732f155734c4e4afd610dd556d9a82833ab3ee0bed" +checksum = "11d3d7f243d5c5a8b9bb5d6dd2b1602c0cb0b9db1621bafc7ed66e35ff9fe092" [[package]] name = "lock_api" @@ -3333,9 +3333,9 @@ checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4" [[package]] name = "mac-notification-sys" -version = "0.6.6" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "119c8490084af61b44c9eda9d626475847a186737c0378c85e32d77c33a01cd4" +checksum = "4ee70bb2bba058d58e252d2944582d634fc884fc9c489a966d428dedcf653e97" dependencies = [ "cc", "objc2 0.6.3", @@ -3449,9 +3449,9 @@ dependencies = [ [[package]] name = "moxcms" -version = "0.7.7" +version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c588e11a3082784af229e23e8e4ecf5bcc6fbe4f69101e0421ce8d79da7f0b40" +checksum = "692af879e4d9383c0fd9dec15524af6b6977c8bf1c6b278a4526d5341347c574" dependencies = [ "num-traits", "pxfm", @@ -4615,9 +4615,9 @@ checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" [[package]] name = "proc-macro2" -version = "1.0.102" +version = "1.0.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e0f6df8eaa422d97d72edcd152e1451618fed47fabbdbd5a8864167b1d4aff7" +checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8" dependencies = [ "unicode-ident", ] @@ -6420,9 +6420,9 @@ dependencies = [ [[package]] name = "tauri-plugin-clipboard-manager" -version = "2.3.0" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adddd9e9275b20e77af3061d100a25a884cced3c4c9ef680bd94dd0f7e26c1ca" +checksum = "97386ff464c30f491847e56355e9f3bd7ce82726c8c51c4ca93dc6bdb7993751" dependencies = [ "arboard", "log", @@ -6435,9 +6435,9 @@ dependencies = [ [[package]] name = "tauri-plugin-deep-link" -version = "2.4.3" +version = "2.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd67112fb1131834c2a7398ffcba520dbbf62c17de3b10329acd1a3554b1a9bb" +checksum = "bd913b8b96627ec87a847ee4fe101427d95100f6c565768c2361c47b70d02bff" dependencies = [ "dunce", "plist", @@ -6456,9 +6456,9 @@ dependencies = [ [[package]] name = "tauri-plugin-dialog" -version = "2.4.0" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0beee42a4002bc695550599b011728d9dfabf82f767f134754ed6655e434824e" +checksum = "e34cadb63450580599193ebe3d69ce292888f1b56c26ea63563ff302f8fdf1f7" dependencies = [ "log", "raw-window-handle", @@ -6474,9 +6474,9 @@ dependencies = [ [[package]] name = "tauri-plugin-fs" -version = "2.4.2" +version = "2.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "315784ec4be45e90a987687bae7235e6be3d6e9e350d2b75c16b8a4bf22c1db7" +checksum = "2864ee9907a87907ad710b5eab081a34c3c812af961d154976dab87f1fe39d12" dependencies = [ "anyhow", "dunce", @@ -6496,9 +6496,9 @@ dependencies = [ [[package]] name = "tauri-plugin-http" -version = "2.5.2" +version = "2.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "938a3d7051c9a82b431e3a0f3468f85715b3442b3c3a3913095e9fa509e2652c" +checksum = "3c51b7e91dd890ba1951c17ad35fd78eebb4da4fdd55347898faef546794e20f" dependencies = [ "bytes", "cookie_store", @@ -6542,9 +6542,9 @@ dependencies = [ [[package]] name = "tauri-plugin-notification" -version = "2.3.1" +version = "2.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2fbc86b929b5376ab84b25c060f966d146b2fbd59b6af8264027b343c82c219" +checksum = "5ec42df990633cbe5148ae502b06421ab2851b890f1655965c7413fb4eb11f73" dependencies = [ "log", "notify-rust", @@ -6561,9 +6561,9 @@ dependencies = [ [[package]] name = "tauri-plugin-opener" -version = "2.5.0" +version = "2.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "786156aa8e89e03d271fbd3fe642207da8e65f3c961baa9e2930f332bf80a1f5" +checksum = "dd354191c4b4606fe4d82332937bc63736e2a261ea39dcdcce4be17064cd8766" dependencies = [ "dunce", "glob", @@ -6601,9 +6601,9 @@ dependencies = [ [[package]] name = "tauri-plugin-single-instance" -version = "2.3.4" +version = "2.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb9cac815bf11c4a80fb498666bcdad66d65b89e3ae24669e47806febb76389c" +checksum = "d09255a1cd942cdff57c7a1ce5e6022cd68ce1b8714b98ad2f1ff0a8a747a4fa" dependencies = [ "serde", "serde_json", diff --git a/src-tauri/Client.entitlements b/src-tauri/Client.entitlements index 4e920afc..055a82c8 100644 --- a/src-tauri/Client.entitlements +++ b/src-tauri/Client.entitlements @@ -6,9 +6,17 @@ packet-tunnel-provider + com.apple.security.application-groups + + group.net.defguard + com.apple.security.app-sandbox com.apple.security.network.client + com.apple.application-identifier + 82GZ7KN29J.net.defguard + com.apple.developer.team-identifier + 82GZ7KN29J diff --git a/src-tauri/build.rs b/src-tauri/build.rs index deb2e438..dd438547 100644 --- a/src-tauri/build.rs +++ b/src-tauri/build.rs @@ -1,5 +1,3 @@ -#[cfg(target_os = "macos")] -use swift_rs::SwiftLinker; use vergen_git2::{Emitter, Git2Builder}; fn main() -> Result<(), Box> { @@ -26,7 +24,7 @@ fn main() -> Result<(), Box> { tauri_build::build(); #[cfg(target_os = "macos")] - SwiftLinker::new("13") + swift_rs::SwiftLinker::new("13") .with_ios("15") .with_package("defguard-vpn-plugin", "../swift/plugin") .link(); diff --git a/src-tauri/common/src/lib.rs b/src-tauri/common/src/lib.rs index bd4a0117..4d2f836b 100644 --- a/src-tauri/common/src/lib.rs +++ b/src-tauri/common/src/lib.rs @@ -11,14 +11,11 @@ pub fn find_free_tcp_port() -> Option { .map(|local_addr| local_addr.port()) } -#[cfg(not(windows))] -/// Find next available interface. On macOS, search for available `utun` interface. -/// On other UNIX, search for available `wg` interface. +#[cfg(not(any(windows, target_os = "macos")))] +/// Find next available interface. +/// Search for available `wg` interface. #[must_use] pub fn get_interface_name(_name: &str) -> String { - #[cfg(target_os = "macos")] - let base_ifname = "utun"; - #[cfg(not(target_os = "macos"))] let base_ifname = "wg"; if let Ok(interfaces) = nix::net::if_::if_nameindex() { for index in 0..=u16::MAX { @@ -36,7 +33,7 @@ pub fn get_interface_name(_name: &str) -> String { } /// Strips location name of all non-alphanumeric characters returning usable interface name. -#[cfg(windows)] +#[cfg(any(windows, target_os = "macos"))] #[must_use] pub fn get_interface_name(name: &str) -> String { name.chars().filter(|c| c.is_alphanumeric()).collect() diff --git a/src-tauri/src/export.rs b/src-tauri/src/export.rs index dead0b3b..ec89fd35 100644 --- a/src-tauri/src/export.rs +++ b/src-tauri/src/export.rs @@ -5,11 +5,18 @@ use std::{net::IpAddr, str::FromStr}; use defguard_wireguard_rs::{host::Peer, key::Key, net::IpAddrMask}; use serde::Serialize; use sqlx::SqliteExecutor; -use swift_rs::{swift, SRString}; +use swift_rs::{swift, SRObject, SRString}; + +#[repr(C)] +// Should match the declaration in Swift. +pub(crate) struct Stats { + pub(crate) tx_bytes: u64, + pub(crate) rx_bytes: u64, +} swift!(pub(crate) fn start_tunnel(json: &SRString) -> bool); swift!(pub(crate) fn stop_tunnel(name: &SRString) -> bool); -swift!(pub(crate) fn tunnel_stats(name: &SRString)); +swift!(pub(crate) fn tunnel_stats(name: &SRString) -> Option>); use crate::{ database::models::{location::Location, wireguard_keys::WireguardKeys, Id}, diff --git a/src-tauri/src/utils.rs b/src-tauri/src/utils.rs index 5ab1c3e8..d4bd9db4 100644 --- a/src-tauri/src/utils.rs +++ b/src-tauri/src/utils.rs @@ -1,4 +1,4 @@ -use std::{env, path::Path, process::Command, str::FromStr}; +use std::{env, path::Path, process::Command, str::FromStr, time::Duration}; use common::{find_free_tcp_port, get_interface_name}; use defguard_wireguard_rs::{host::Peer, key::Key, net::IpAddrMask, InterfaceConfiguration}; @@ -6,6 +6,7 @@ use sqlx::query; #[cfg(target_os = "macos")] use swift_rs::SRString; use tauri::{AppHandle, Emitter, Manager}; +#[cfg(not(target_os = "macos"))] use tonic::Code; use tracing::Level; #[cfg(target_os = "windows")] @@ -48,31 +49,20 @@ pub(crate) static DEFAULT_ROUTE_IPV4: &str = "0.0.0.0/0"; pub(crate) static DEFAULT_ROUTE_IPV6: &str = "::/0"; /// Setup client interface for `Instance`. +#[cfg(target_os = "macos")] pub(crate) async fn setup_interface( location: &Location, - interface_name: String, + name: &str, preshared_key: Option, pool: &DbPool, -) -> Result<(), Error> { +) -> Result { debug!("Setting up interface for location: {location}"); - - // request interface configuration - // debug!("Looking for a free port for interface {interface_name}."); - // let Some(port) = find_free_tcp_port() else { - // let msg = format!( - // "Couldn't find free port during interface {interface_name} setup for location \ - // {location}" - // ); - // error!("{msg}"); - // return Err(Error::InternalError(msg)); - // }; - // debug!("Found free port: {port} for interface {interface_name}."); + let interface_name = get_interface_name(name); let (dns, dns_search) = location.dns(); let tunnel_config = location .tunnel_configurarion(pool, preshared_key, dns, dns_search) .await?; - // tunnel_config.port = port; unsafe { let json: SRString = serde_json::to_string(&tunnel_config) @@ -82,54 +72,83 @@ pub(crate) async fn setup_interface( let result = start_tunnel(&json); error!("start_tunnel() returned {result:?}"); } - Ok(()) + Ok(interface_name) +} + +#[cfg(not(target_os = "macos"))] +pub(crate) async fn setup_interface( + location: &Location, + name: &str, + preshared_key: Option, + pool: &DbPool, +) -> Result { + debug!("Setting up interface for location: {location}"); + let interface_name = get_interface_name(name); + + // request interface configuration + debug!("Looking for a free port for interface {interface_name}."); + let Some(port) = find_free_tcp_port() else { + let msg = format!( + "Couldn't find free port during interface {interface_name} setup for location \ + {location}" + ); + error!("{msg}"); + return Err(Error::InternalError(msg)); + }; + debug!("Found free port: {port} for interface {interface_name}."); + + let (dns, dns_search) = location.dns(); + let tunnel_config = location + .tunnel_configurarion(pool, preshared_key, dns, dns_search) + .await?; + tunnel_config.port = port; - // debug!("Creating interface for location {location} with configuration {interface_config:?}"); - // let request = CreateInterfaceRequest { - // config: Some(interface_config.clone().into()), - // dns: location.dns.clone(), - // }; - // if let Err(error) = DAEMON_CLIENT.clone().create_interface(request).await { - // if error.code() == Code::Unavailable { - // error!( - // "Failed to set up connection for location {location}; background service is \ - // unavailable. Make sure the service is running. Error: {error}, Interface \ - // configuration: {interface_config:?}" - // ); - // Err(Error::InternalError( - // "Background service is unavailable. Make sure the service is running.".into(), - // )) - // } else { - // error!( - // "Failed to send a request to the background service to create an interface for \ - // location {location} with the following configuration: {interface_config:?}. \ - // Error: {error}" - // ); - // Err(Error::InternalError(format!( - // "Failed to send a request to the background service to create an interface for \ - // location {location}. Error: {error}. Check logs for details." - // ))) - // } - // } else { - // info!( - // "The interface for location {location} has been created successfully, interface \ - // name: {}.", - // interface_config.name - // ); - // Ok(()) - // } + debug!("Creating interface for location {location} with configuration {interface_config:?}"); + let request = CreateInterfaceRequest { + config: Some(interface_config.clone().into()), + dns: location.dns.clone(), + }; + if let Err(error) = DAEMON_CLIENT.clone().create_interface(request).await { + if error.code() == Code::Unavailable { + error!( + "Failed to set up connection for location {location}; background service is \ + unavailable. Make sure the service is running. Error: {error}, Interface \ + configuration: {interface_config:?}" + ); + Err(Error::InternalError( + "Background service is unavailable. Make sure the service is running.".into(), + )) + } else { + error!( + "Failed to send a request to the background service to create an interface for \ + location {location} with the following configuration: {interface_config:?}. \ + Error: {error}" + ); + Err(Error::InternalError(format!( + "Failed to send a request to the background service to create an interface for \ + location {location}. Error: {error}. Check logs for details." + ))) + } + } else { + info!( + "The interface for location {location} has been created successfully, interface \ + name: {}.", + interface_config.name + ); + Ok(interface_name) + } } #[cfg(target_os = "macos")] -pub(crate) async fn stats_handler(pool: DbPool, ifname: String, connection_type: ConnectionType) { - const CHECK_INTERVAL: std::time::Duration = std::time::Duration::from_secs(5); +pub(crate) async fn stats_handler(pool: DbPool, name: String, connection_type: ConnectionType) { + const CHECK_INTERVAL: Duration = Duration::from_secs(5); let mut interval = tokio::time::interval(CHECK_INTERVAL); loop { interval.tick().await; - info!("stats_handler :)"); - unsafe { - tunnel_stats(&"Szczecin".into()); + // TODO: check all known localtions/tunnels, not just `name`. + if let Some(stats) = unsafe { tunnel_stats(&name.as_str().into()) } { + info!("Tunnel stats: {} {}", stats.tx_bytes, stats.rx_bytes); } } } @@ -286,11 +305,9 @@ pub fn get_service_log_dir() -> &'static Path { } /// Setup client interface -pub async fn setup_interface_tunnel( - tunnel: &Tunnel, - interface_name: String, -) -> Result<(), Error> { +pub async fn setup_interface_tunnel(tunnel: &Tunnel, name: &str) -> Result { debug!("Setting up interface for tunnel {tunnel}"); + let interface_name = get_interface_name(name); // prepare peer config debug!( "Decoding tunnel {tunnel} public key: {}.", @@ -373,7 +390,7 @@ pub async fn setup_interface_tunnel( Error::InternalError(msg) })?; let interface_config = InterfaceConfiguration { - name: interface_name, + name: interface_name.clone(), prvkey: tunnel.prvkey.clone(), addresses, port, @@ -431,7 +448,7 @@ pub async fn setup_interface_tunnel( "Created interface {} with config: {interface_config:?}", interface_config.name ); - Ok(()) + Ok(interface_name) } } @@ -557,8 +574,7 @@ pub(crate) async fn handle_connection_for_location( ) -> Result<(), Error> { debug!("Setting up the connection for location {}", location.name); let state = handle.state::(); - let interface_name = get_interface_name(&location.name); - setup_interface(location, interface_name.clone(), preshared_key, &DB_POOL).await?; + let interface_name = setup_interface(location, &location.name, preshared_key, &DB_POOL).await?; state .add_connection(location.id, &interface_name, ConnectionType::Location) .await; @@ -589,8 +605,7 @@ pub(crate) async fn handle_connection_for_tunnel( ) -> Result<(), Error> { debug!("Setting up the connection for tunnel: {}", tunnel.name); let state = handle.state::(); - let interface_name = get_interface_name(&tunnel.name); - setup_interface_tunnel(tunnel, interface_name.clone()).await?; + let interface_name = setup_interface_tunnel(tunnel, &tunnel.name).await?; state .add_connection(tunnel.id, &interface_name, ConnectionType::Tunnel) .await; @@ -660,39 +675,47 @@ pub(crate) async fn disconnect_interface( return Err(Error::NotFound); }; - let result = unsafe { - let name: SRString = location.name.as_str().into(); - stop_tunnel(&name) - }; - error!("stop_tunnel() returned {result:?}"); - if !result { - let msg = String::from("Error from Swift"); - // let request = RemoveInterfaceRequest { - // interface_name, - // endpoint: location.endpoint.clone(), - // }; - // debug!( - // "Sending request to the background service to remove interface {} for location \ - // {}...", - // active_connection.interface_name, location.name - // ); - // if let Err(error) = client.remove_interface(request).await { - // let msg = if error.code() == Code::Unavailable { - // format!( - // "Couldn't remove interface {}. Background service is unavailable. \ - // Please make sure the service is running. Error: {error}.", - // active_connection.interface_name - // ) - // } else { - // format!( - // "Failed to send a request to the background service to remove interface \ - // {}. Error: {error}.", - // active_connection.interface_name - // ) - // }; - // error!("{msg}"); - return Err(Error::InternalError(msg)); + #[cfg(target_os = "macos")] + { + let result = unsafe { + let name: SRString = location.name.as_str().into(); + stop_tunnel(&name) + }; + error!("stop_tunnel() returned {result:?}"); + if !result { + return Err(Error::InternalError("Error from Swift".into())); + } + } + + #[cfg(not(target_os = "macos"))] + { + let request = RemoveInterfaceRequest { + interface_name, + endpoint: location.endpoint.clone(), + }; + debug!( + "Sending request to the background service to remove interface {} for location \ + {}...", + active_connection.interface_name, location.name + ); + if let Err(error) = client.remove_interface(request).await { + let msg = if error.code() == Code::Unavailable { + format!( + "Couldn't remove interface {}. Background service is unavailable. \ + Please make sure the service is running. Error: {error}.", + active_connection.interface_name + ) + } else { + format!( + "Failed to send a request to the background service to remove interface \ + {}. Error: {error}.", + active_connection.interface_name + ) + }; + error!("{msg}"); + } } + let connection: Connection = active_connection.into(); let connection = connection.save(&*DB_POOL).await?; debug!( diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index 025da5a3..5737f17f 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -39,13 +39,11 @@ "entitlements": "./Client.entitlements", "exceptionDomain": "", "files": { - "embedded.provisionprofile": "Adam_Apollo_Defguard.provisionprofile", - "PlugIns/VPNExtension.appex": "../swift/extension/build/Debug/VPNExtension.appex" + "embedded.provisionprofile": "Adam_Apollo_Desktop.provisionprofile", + "PlugIns/VPNExtension.appex": "../swift/extension/build/Release/VPNExtension.appex" }, "frameworks": [], - "minimumSystemVersion": "13.5", - "providerShortName": null, - "signingIdentity": "692SQ9VLU5" + "minimumSystemVersion": "13.5" }, "resources": [ "resources/icons/*" diff --git a/swift/extension/VPNExtension.xcodeproj/project.pbxproj b/swift/extension/VPNExtension.xcodeproj/project.pbxproj index bec82c49..51380492 100644 --- a/swift/extension/VPNExtension.xcodeproj/project.pbxproj +++ b/swift/extension/VPNExtension.xcodeproj/project.pbxproj @@ -267,8 +267,9 @@ MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; ONLY_ACTIVE_ARCH = YES; - PRODUCT_BUNDLE_IDENTIFIER = net.defguard.client.VPNExtension; + PRODUCT_BUNDLE_IDENTIFIER = net.defguard.VPNExtension; PRODUCT_NAME = "$(TARGET_NAME)"; + REGISTER_APP_GROUPS = YES; SDKROOT = macosx; SKIP_INSTALL = YES; STRING_CATALOG_GENERATE_SYMBOLS = YES; @@ -357,8 +358,9 @@ MARKETING_VERSION = 1.0; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; - PRODUCT_BUNDLE_IDENTIFIER = net.defguard.client.VPNExtension; + PRODUCT_BUNDLE_IDENTIFIER = net.defguard.VPNExtension; PRODUCT_NAME = "$(TARGET_NAME)"; + REGISTER_APP_GROUPS = YES; SDKROOT = macosx; SKIP_INSTALL = YES; STRING_CATALOG_GENERATE_SYMBOLS = YES; diff --git a/swift/extension/VPNExtension/Adapter.swift b/swift/extension/VPNExtension/Adapter.swift index 0e00cbd1..f60864c7 100644 --- a/swift/extension/VPNExtension/Adapter.swift +++ b/swift/extension/VPNExtension/Adapter.swift @@ -33,7 +33,6 @@ enum State { private let notificationCenter = CFNotificationCenterGetDarwinNotifyCenter() - /// Designated initializer. /// - Parameter packetTunnelProvider: an instance of `NEPacketTunnelProvider`. Internally stored init(with packetTunnelProvider: NEPacketTunnelProvider) { @@ -51,7 +50,7 @@ enum State { return } - if let _ = tunnel { + if tunnel != nil { logger.info("Cleaning exiting Tunnel") tunnel = nil connection = nil @@ -87,8 +86,8 @@ enum State { state = .running // Test notifications - let notificationName = CFNotificationName("net.defguard.NetExt.start" as CFString) - CFNotificationCenterPostNotification(notificationCenter, notificationName, nil, nil, false) + // let notificationName = CFNotificationName("net.defguard.client.start" as CFString) + // CFNotificationCenterPostNotification(notificationCenter, notificationName, nil, nil, false) } func stop() { @@ -106,42 +105,52 @@ enum State { logger.info("Tunnel stopped") // Test notifications - let notificationName = CFNotificationName("net.defguard.NetExt.stop" as CFString) - CFNotificationCenterPostNotification(notificationCenter, notificationName, nil, nil, false) + // let notificationName = CFNotificationName("net.defguard.client.stop" as CFString) + // CFNotificationCenterPostNotification(notificationCenter, notificationName, nil, nil, false) + } + + // Obtain tunnel statistics. + func stats() -> Stats? { + if let stats = tunnel?.stats() { + return Stats(txBytes: stats.txBytes, rxBytes: stats.rxBytes) + } + return nil } private func handleTunnelResult(_ result: TunnelResult) { switch result { - case .done: - // Nothing to do. - break - case .err(let error): - logger.error("Tunnel error \(error, privacy: .public)") - switch error { - case .InvalidAeadTag: - logger.error("Invalid pre-shared key; stopping tunnel") - // The correct way is to call the packet tunnel provider, if there is one. - if let provider = packetTunnelProvider { - provider.cancelTunnelWithError(error) - } else { - stop() - } - case .ConnectionExpired: - logger.error("Connecion has expired; re-connecting") - packetTunnelProvider?.reasserting = true - initEndpoint() - packetTunnelProvider?.reasserting = false - default: - break + case .done: + // Nothing to do. + break + case .err(let error): + logger.error("Tunnel error \(error, privacy: .public)") + switch error { + case .InvalidAeadTag: + logger.error("Invalid pre-shared key; stopping tunnel") + // The correct way is to call the packet tunnel provider, if there is one. + if let provider = packetTunnelProvider { + provider.cancelTunnelWithError(error) + } else { + stop() } - case .writeToNetwork(let data): - sendToEndpoint(data: data) - case .writeToTunnelV4(let data): - packetTunnelProvider?.packetFlow.writePacketObjects([ - NEPacket(data: data,protocolFamily: sa_family_t(AF_INET))]) - case .writeToTunnelV6(let data): - packetTunnelProvider?.packetFlow.writePacketObjects([ - NEPacket(data: data, protocolFamily: sa_family_t(AF_INET6))]) + case .ConnectionExpired: + logger.error("Connecion has expired; re-connecting") + packetTunnelProvider?.reasserting = true + initEndpoint() + packetTunnelProvider?.reasserting = false + default: + break + } + case .writeToNetwork(let data): + sendToEndpoint(data: data) + case .writeToTunnelV4(let data): + packetTunnelProvider?.packetFlow.writePacketObjects([ + NEPacket(data: data, protocolFamily: sa_family_t(AF_INET)) + ]) + case .writeToTunnelV6(let data): + packetTunnelProvider?.packetFlow.writePacketObjects([ + NEPacket(data: data, protocolFamily: sa_family_t(AF_INET6)) + ]) } } @@ -174,7 +183,9 @@ enum State { handleTunnelResult(tunnel.forceHandshake()) } logger.info("Receiving UDP from endpoint") - logger.debug("NWConnection path \(String(describing: self.connection?.currentPath), privacy: .public)") + logger.debug( + "NWConnection path \(String(describing: self.connection?.currentPath), privacy: .public)" + ) receive() // Use Timer to send keep-alive packets. @@ -192,11 +203,13 @@ enum State { private func sendToEndpoint(data: Data) { guard let connection = connection else { return } if connection.state == .ready { - connection.send(content: data, completion: .contentProcessed { error in - if let error = error { - self.logger.error("UDP connection send error: \(error, privacy: .public)") - } - }) + connection.send( + content: data, + completion: .contentProcessed { error in + if let error = error { + self.logger.error("UDP connection send error: \(error, privacy: .public)") + } + }) } else { logger.warning("UDP connection not ready to send") } @@ -224,7 +237,7 @@ enum State { // Packets received to the tunnel's virtual interface. packetTunnelProvider?.packetFlow.readPacketObjects { packets in - for packet in packets { + for packet in packets { self.handleTunnelResult(tunnel.write(src: packet.data)) } // continue reading @@ -236,32 +249,33 @@ enum State { private func endpointStateChange(state: NWConnection.State) { logger.debug("UDP connection state: \(String(describing: state), privacy: .public)") switch state { - case .ready: - setupEndpoint() - //case .waiting(let error): - // switch error { - // case .posix(_): - // connection?.restart() - // default: - // self.stop() - // } - case .failed(let error): - logger.error("Failed to establish endpoint connection: \(error)") - // The correct way is to call the packet tunnel provider, if there is one. - if let provider = packetTunnelProvider { - provider.cancelTunnelWithError(error) - } else { - stop() - } - default: - break + case .ready: + setupEndpoint() + //case .waiting(let error): + // switch error { + // case .posix(_): + // connection?.restart() + // default: + // self.stop() + // } + case .failed(let error): + logger.error("Failed to establish endpoint connection: \(error)") + // The correct way is to call the packet tunnel provider, if there is one. + if let provider = packetTunnelProvider { + provider.cancelTunnelWithError(error) + } else { + stop() + } + default: + break } } /// Handle network path updates. private func networkPathUpdate(path: Network.NWPath) { logger - .debug("Network path status \(String(describing: path.status), privacy: .public); interfaces \(path.availableInterfaces, privacy: .public)" + .debug( + "Network path status \(String(describing: path.status), privacy: .public); interfaces \(path.availableInterfaces, privacy: .public)" ) if path.status == .unsatisfied { if state == .running { diff --git a/swift/extension/VPNExtension/PacketTunnelProvider.swift b/swift/extension/VPNExtension/PacketTunnelProvider.swift index 2dce14c8..addccb60 100644 --- a/swift/extension/VPNExtension/PacketTunnelProvider.swift +++ b/swift/extension/VPNExtension/PacketTunnelProvider.swift @@ -41,6 +41,7 @@ class PacketTunnelProvider: NEPacketTunnelProvider { logger.error("Failed to start tunnel") completionHandler(error) } + logger.info("Tunnel started") completionHandler(nil) } @@ -48,14 +49,20 @@ class PacketTunnelProvider: NEPacketTunnelProvider { override func stopTunnel(with reason: NEProviderStopReason, completionHandler: @escaping () -> Void) { logger.debug("\(#function)") adapter.stop() + logger.info("Tunnel stopped") completionHandler() } override func handleAppMessage(_ messageData: Data, completionHandler: ((Data?) -> Void)?) { logger.debug("\(#function)") - // Add code here to handle the message. + // TODO: messageData should contain a valid message. if let handler = completionHandler { - handler(messageData) + if let stats = adapter.stats() { + let data = try? JSONEncoder().encode(stats) + handler(data) + } else { + handler(nil) + } } } diff --git a/swift/extension/VPNExtension/VPNExtension.entitlements b/swift/extension/VPNExtension/VPNExtension.entitlements index ffab33e0..5b4eb027 100644 --- a/swift/extension/VPNExtension/VPNExtension.entitlements +++ b/swift/extension/VPNExtension/VPNExtension.entitlements @@ -6,5 +6,15 @@ packet-tunnel-provider + com.apple.security.app-sandbox + + com.apple.security.application-groups + + group.net.defguard + + com.apple.security.network.client + + com.apple.security.network.server + diff --git a/swift/plugin/Sources/Defguard/Stats.swift b/swift/plugin/Sources/Defguard/Stats.swift new file mode 100644 index 00000000..b7f97569 --- /dev/null +++ b/swift/plugin/Sources/Defguard/Stats.swift @@ -0,0 +1,11 @@ +import ObjectiveC + +public class Stats: NSObject, Codable { + var txBytes: UInt64 + var rxBytes: UInt64 + + init(txBytes: UInt64, rxBytes: UInt64) { + self.txBytes = txBytes + self.rxBytes = rxBytes + } +} diff --git a/swift/plugin/Sources/Wireguard.swift b/swift/plugin/Sources/Wireguard.swift index 108367fc..c21485e0 100644 --- a/swift/plugin/Sources/Wireguard.swift +++ b/swift/plugin/Sources/Wireguard.swift @@ -5,7 +5,7 @@ import SwiftRs import os let appId = Bundle.main.bundleIdentifier ?? "net.defguard" -let pluginAppId = "\(appId).client.VPNExtension" +let pluginAppId = "\(appId).VPNExtension" let plugin = WireguardPlugin() let logger = Logger(subsystem: appId, category: "WireguardPlugin") @@ -47,25 +47,34 @@ public func stopTunnel(name: SRString) -> Bool { } @_cdecl("tunnel_stats") -public func tunnelStats(name: SRString) { +public func tunnelStats(name: SRString) -> Stats? { + // Blocking + let semaphore = DispatchSemaphore(value: 0) + var result: Stats? = nil + managerForName(name.toString()) { manager in if let providerManager = manager as NETunnelProviderManager? { let session = providerManager.connection as! NETunnelProviderSession do { - let data = Data(count: 8) + // TODO: data should contain a valid message. + let data = Data() try session.sendProviderMessage(data) { response in - if response != nil { - logger.info("Tunnel extension sent some data") - } else { - logger.info("Tunnel extension sent nothing") + if let data = response { + let decoder = JSONDecoder() + result = try? decoder.decode(Stats.self, from: data) } + semaphore.signal() } - logger.info("Send message to tunnel extension") } catch { logger.error("Failed to send message to tunnel extension \(error)") + semaphore.signal() } } } + + semaphore.wait() + logger.info("Tunnel stats done") + return result } func saveConfig(_ config: TunnelConfiguration) { @@ -102,6 +111,8 @@ func saveConfig(_ config: TunnelConfiguration) { } // TEST + // MFA is not that fast to propagate pre-shared key, so wait a moment here. + Thread.sleep(forTimeInterval: 1) do { try providerManager.connection.startVPNTunnel() logger.info("VPN started") From c09bc239bf086d052af3ec578aca364eda63b0b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adam=20Ciarcin=CC=81ski?= Date: Mon, 27 Oct 2025 11:18:50 +0100 Subject: [PATCH 09/28] Restore non-macos build --- src-tauri/src/database/models/location.rs | 1 + src-tauri/src/utils.rs | 61 +++++++++++------------ 2 files changed, 31 insertions(+), 31 deletions(-) diff --git a/src-tauri/src/database/models/location.rs b/src-tauri/src/database/models/location.rs index 94c78ad8..cab64634 100644 --- a/src-tauri/src/database/models/location.rs +++ b/src-tauri/src/database/models/location.rs @@ -215,6 +215,7 @@ impl Location { (dns, dns_search) } + #[cfg(not(target_os = "macos"))] pub(crate) async fn interface_configurarion<'e, E>( &self, executor: E, diff --git a/src-tauri/src/utils.rs b/src-tauri/src/utils.rs index d4bd9db4..d9df385f 100644 --- a/src-tauri/src/utils.rs +++ b/src-tauri/src/utils.rs @@ -49,32 +49,6 @@ pub(crate) static DEFAULT_ROUTE_IPV4: &str = "0.0.0.0/0"; pub(crate) static DEFAULT_ROUTE_IPV6: &str = "::/0"; /// Setup client interface for `Instance`. -#[cfg(target_os = "macos")] -pub(crate) async fn setup_interface( - location: &Location, - name: &str, - preshared_key: Option, - pool: &DbPool, -) -> Result { - debug!("Setting up interface for location: {location}"); - let interface_name = get_interface_name(name); - - let (dns, dns_search) = location.dns(); - let tunnel_config = location - .tunnel_configurarion(pool, preshared_key, dns, dns_search) - .await?; - - unsafe { - let json: SRString = serde_json::to_string(&tunnel_config) - .unwrap() - .as_str() - .into(); - let result = start_tunnel(&json); - error!("start_tunnel() returned {result:?}"); - } - Ok(interface_name) -} - #[cfg(not(target_os = "macos"))] pub(crate) async fn setup_interface( location: &Location, @@ -98,11 +72,10 @@ pub(crate) async fn setup_interface( debug!("Found free port: {port} for interface {interface_name}."); let (dns, dns_search) = location.dns(); - let tunnel_config = location - .tunnel_configurarion(pool, preshared_key, dns, dns_search) - .await?; - tunnel_config.port = port; + let interface_config = location + .interface_configurarion(&*DB_POOL, interface_name.clone(), preshared_key) + .await?; debug!("Creating interface for location {location} with configuration {interface_config:?}"); let request = CreateInterfaceRequest { config: Some(interface_config.clone().into()), @@ -140,7 +113,33 @@ pub(crate) async fn setup_interface( } #[cfg(target_os = "macos")] -pub(crate) async fn stats_handler(pool: DbPool, name: String, connection_type: ConnectionType) { +pub(crate) async fn setup_interface( + location: &Location, + name: &str, + preshared_key: Option, + pool: &DbPool, +) -> Result { + debug!("Setting up interface for location: {location}"); + let interface_name = get_interface_name(name); + + let (dns, dns_search) = location.dns(); + let tunnel_config = location + .tunnel_configurarion(pool, preshared_key, dns, dns_search) + .await?; + + unsafe { + let json: SRString = serde_json::to_string(&tunnel_config) + .unwrap() + .as_str() + .into(); + let result = start_tunnel(&json); + error!("start_tunnel() returned {result:?}"); + } + Ok(interface_name) +} + +#[cfg(target_os = "macos")] +pub(crate) async fn stats_handler(_pool: DbPool, name: String, _connection_type: ConnectionType) { const CHECK_INTERVAL: Duration = Duration::from_secs(5); let mut interval = tokio::time::interval(CHECK_INTERVAL); From 2ab6a606d0e7d56591f53d541e6943604aeb8950 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adam=20Ciarcin=CC=81ski?= Date: Tue, 28 Oct 2025 13:58:31 +0100 Subject: [PATCH 10/28] Get ready for building and distributing --- package.json | 20 ++-- pnpm-lock.yaml | 100 +++++++++--------- src-tauri/Cargo.lock | 96 +++++++---------- src-tauri/Cargo.toml | 9 ++ src-tauri/Client.entitlements | 4 - src-tauri/tauri.conf.json | 4 +- .../VPNExtension.xcodeproj/project.pbxproj | 12 ++- .../VPNExtension/VPNExtension.entitlements | 4 - 8 files changed, 119 insertions(+), 130 deletions(-) diff --git a/package.json b/package.json index 542189b4..b61db577 100644 --- a/package.json +++ b/package.json @@ -55,16 +55,16 @@ "@tanstack/query-core": "^5.90.5", "@tanstack/react-virtual": "3.13.12", "@tauri-apps/api": "^2.9.0", - "@tauri-apps/plugin-clipboard-manager": "^2.3.1", - "@tauri-apps/plugin-deep-link": "^2.4.4", - "@tauri-apps/plugin-dialog": "^2.4.1", - "@tauri-apps/plugin-fs": "^2.4.3", - "@tauri-apps/plugin-http": "^2.5.3", - "@tauri-apps/plugin-log": "^2.7.0", - "@tauri-apps/plugin-notification": "^2.3.2", - "@tauri-apps/plugin-opener": "^2.5.1", - "@tauri-apps/plugin-os": "^2.3.1", - "@tauri-apps/plugin-window-state": "^2.4.0", + "@tauri-apps/plugin-clipboard-manager": "^2.3.2", + "@tauri-apps/plugin-deep-link": "^2.4.5", + "@tauri-apps/plugin-dialog": "^2.4.2", + "@tauri-apps/plugin-fs": "^2.4.4", + "@tauri-apps/plugin-http": "^2.5.4", + "@tauri-apps/plugin-log": "^2.7.1", + "@tauri-apps/plugin-notification": "^2.3.3", + "@tauri-apps/plugin-opener": "^2.5.2", + "@tauri-apps/plugin-os": "^2.3.2", + "@tauri-apps/plugin-window-state": "^2.4.1", "@types/byte-size": "^8.1.2", "@use-gesture/react": "^10.3.1", "byte-size": "^9.0.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6a99b85f..a999d82c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -33,35 +33,35 @@ importers: specifier: ^2.9.0 version: 2.9.0 '@tauri-apps/plugin-clipboard-manager': - specifier: ^2.3.1 - version: 2.3.1 + specifier: ^2.3.2 + version: 2.3.2 '@tauri-apps/plugin-deep-link': - specifier: ^2.4.4 - version: 2.4.4 + specifier: ^2.4.5 + version: 2.4.5 '@tauri-apps/plugin-dialog': - specifier: ^2.4.1 - version: 2.4.1 + specifier: ^2.4.2 + version: 2.4.2 '@tauri-apps/plugin-fs': - specifier: ^2.4.3 - version: 2.4.3 + specifier: ^2.4.4 + version: 2.4.4 '@tauri-apps/plugin-http': - specifier: ^2.5.3 - version: 2.5.3 + specifier: ^2.5.4 + version: 2.5.4 '@tauri-apps/plugin-log': - specifier: ^2.7.0 - version: 2.7.0 + specifier: ^2.7.1 + version: 2.7.1 '@tauri-apps/plugin-notification': - specifier: ^2.3.2 - version: 2.3.2 + specifier: ^2.3.3 + version: 2.3.3 '@tauri-apps/plugin-opener': - specifier: ^2.5.1 - version: 2.5.1 + specifier: ^2.5.2 + version: 2.5.2 '@tauri-apps/plugin-os': - specifier: ^2.3.1 - version: 2.3.1 + specifier: ^2.3.2 + version: 2.3.2 '@tauri-apps/plugin-window-state': - specifier: ^2.4.0 - version: 2.4.0 + specifier: ^2.4.1 + version: 2.4.1 '@types/byte-size': specifier: ^8.1.2 version: 8.1.2 @@ -1180,35 +1180,35 @@ packages: engines: {node: '>= 10'} hasBin: true - '@tauri-apps/plugin-clipboard-manager@2.3.1': - resolution: {integrity: sha512-lQMaUSFs5my8oEHuvQOLJoPHfxRJNn0gwXyTsyMhtQZBD4sYLiDux8p+EsagY6vv5SkSYWVViJYvlcPIjJ+Dog==} + '@tauri-apps/plugin-clipboard-manager@2.3.2': + resolution: {integrity: sha512-CUlb5Hqi2oZbcZf4VUyUH53XWPPdtpw43EUpCza5HWZJwxEoDowFzNUDt1tRUXA8Uq+XPn17Ysfptip33sG4eQ==} - '@tauri-apps/plugin-deep-link@2.4.4': - resolution: {integrity: sha512-xdDOIW5RHTyU+9CJFFrojQgDN2rd9FDU9II2suNOQauPP/YZ6CLldyQj5YFtKGyCX6+jYNymOEq5oYR7MKrsoQ==} + '@tauri-apps/plugin-deep-link@2.4.5': + resolution: {integrity: sha512-Zf2RTj1D9IQQ45/jqW8XTKvql24HqlPjcpv0mV/O2jHQkNe11HOTZBVj6IK37qs+MWV7xZzcmazx/QVZnhAwaQ==} - '@tauri-apps/plugin-dialog@2.4.1': - resolution: {integrity: sha512-2eAueoxstrUnAf5cZWT9A/jzh4mTdUu646Q8zEX0a3RQmht7fQhdhxWfgQH4/of8iy1etDLKzokXbF2CxdBFHg==} + '@tauri-apps/plugin-dialog@2.4.2': + resolution: {integrity: sha512-lNIn5CZuw8WZOn8zHzmFmDSzg5zfohWoa3mdULP0YFh/VogVdMVWZPcWSHlydsiJhRQYaTNSYKN7RmZKE2lCYQ==} - '@tauri-apps/plugin-fs@2.4.3': - resolution: {integrity: sha512-/ZVHrwf/FTMSReWgMfiraeJjBcIr4QrDQC5BalvSSLXgtEiELPjQkRaXox7zG7z5nB04m/TwTLqfeeBROg0LLQ==} + '@tauri-apps/plugin-fs@2.4.4': + resolution: {integrity: sha512-MTorXxIRmOnOPT1jZ3w96vjSuScER38ryXY88vl5F0uiKdnvTKKTtaEjTEo8uPbl4e3gnUtfsDVwC7h77GQLvQ==} - '@tauri-apps/plugin-http@2.5.3': - resolution: {integrity: sha512-YiizgUWd9jQBPGX2x3k1l6qdBiDYOo3FjqMEjkeJ0I8IRIkp6OQ8ff6fRcaiUt0sl8+h3r4983+6O/m+//PMVQ==} + '@tauri-apps/plugin-http@2.5.4': + resolution: {integrity: sha512-/i4U/9za3mrytTgfRn5RHneKubZE/dwRmshYwyMvNRlkWjvu1m4Ma72kcbVJMZFGXpkbl+qLyWMGrihtWB76Zg==} - '@tauri-apps/plugin-log@2.7.0': - resolution: {integrity: sha512-81XQ2f93x4vmIB5OY0XlYAxy60cHdYLs0Ki8Qp38tNATRiuBit+Orh3frpY3qfYQnqEvYVyRub7YRJWlmW2RRA==} + '@tauri-apps/plugin-log@2.7.1': + resolution: {integrity: sha512-jdb+o0wxQc8PjnLktgGpOs9Dh1YupaOGDXzO+Y8peA1UZ1ep3eXv4E1oiJ7nIQVN0XUFDDhnn3aBszl8ijhR+A==} - '@tauri-apps/plugin-notification@2.3.2': - resolution: {integrity: sha512-xJV7NxBYFD65nnFzYiR9gloT1yFIyGYQav5z7od2+JRlJF968ZYbVFHPkyy6h9yYjvGh2FQKsn45E5xlXTJl7A==} + '@tauri-apps/plugin-notification@2.3.3': + resolution: {integrity: sha512-Zw+ZH18RJb41G4NrfHgIuofJiymusqN+q8fGUIIV7vyCH+5sSn5coqRv/MWB9qETsUs97vmU045q7OyseCV3Qg==} - '@tauri-apps/plugin-opener@2.5.1': - resolution: {integrity: sha512-nyT6oW4ibyXJN2duVBZlPhPmN/+jViOtX0B95f7j5W3R493wEyCNRgjL6YXUp7cB1pKKG6spk7/Q46ZKuzeeBQ==} + '@tauri-apps/plugin-opener@2.5.2': + resolution: {integrity: sha512-ei/yRRoCklWHImwpCcDK3VhNXx+QXM9793aQ64YxpqVF0BDuuIlXhZgiAkc15wnPVav+IbkYhmDJIv5R326Mew==} - '@tauri-apps/plugin-os@2.3.1': - resolution: {integrity: sha512-ty5V8XDUIFbSnrk3zsFoP3kzN+vAufYzalJSlmrVhQTImIZa1aL1a03bOaP2vuBvfR+WDRC6NgV2xBl8G07d+w==} + '@tauri-apps/plugin-os@2.3.2': + resolution: {integrity: sha512-n+nXWeuSeF9wcEsSPmRnBEGrRgOy6jjkSU+UVCOV8YUGKb2erhDOxis7IqRXiRVHhY8XMKks00BJ0OAdkpf6+A==} - '@tauri-apps/plugin-window-state@2.4.0': - resolution: {integrity: sha512-hRSzPNi2NG0lPFthfVY0V5C1MyWN/gGaQtQYw7i9zZhLzrhZveHZ2omHG1rIiIsjfTGbO7fhjydSoeTTK9GqLw==} + '@tauri-apps/plugin-window-state@2.4.1': + resolution: {integrity: sha512-OuvdrzyY8Q5Dbzpj+GcrnV1iCeoZbcFdzMjanZMMcAEUNy/6PH5pxZPXpaZLOR7whlzXiuzx0L9EKZbH7zpdRw==} '@trysound/sax@0.2.0': resolution: {integrity: sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==} @@ -3813,43 +3813,43 @@ snapshots: '@tauri-apps/cli-win32-ia32-msvc': 2.9.1 '@tauri-apps/cli-win32-x64-msvc': 2.9.1 - '@tauri-apps/plugin-clipboard-manager@2.3.1': + '@tauri-apps/plugin-clipboard-manager@2.3.2': dependencies: '@tauri-apps/api': 2.9.0 - '@tauri-apps/plugin-deep-link@2.4.4': + '@tauri-apps/plugin-deep-link@2.4.5': dependencies: '@tauri-apps/api': 2.9.0 - '@tauri-apps/plugin-dialog@2.4.1': + '@tauri-apps/plugin-dialog@2.4.2': dependencies: '@tauri-apps/api': 2.9.0 - '@tauri-apps/plugin-fs@2.4.3': + '@tauri-apps/plugin-fs@2.4.4': dependencies: '@tauri-apps/api': 2.9.0 - '@tauri-apps/plugin-http@2.5.3': + '@tauri-apps/plugin-http@2.5.4': dependencies: '@tauri-apps/api': 2.9.0 - '@tauri-apps/plugin-log@2.7.0': + '@tauri-apps/plugin-log@2.7.1': dependencies: '@tauri-apps/api': 2.9.0 - '@tauri-apps/plugin-notification@2.3.2': + '@tauri-apps/plugin-notification@2.3.3': dependencies: '@tauri-apps/api': 2.9.0 - '@tauri-apps/plugin-opener@2.5.1': + '@tauri-apps/plugin-opener@2.5.2': dependencies: '@tauri-apps/api': 2.9.0 - '@tauri-apps/plugin-os@2.3.1': + '@tauri-apps/plugin-os@2.3.2': dependencies: '@tauri-apps/api': 2.9.0 - '@tauri-apps/plugin-window-state@2.4.0': + '@tauri-apps/plugin-window-state@2.4.1': dependencies: '@tauri-apps/api': 2.9.0 diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index 8718b389..a232a7c6 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -3103,9 +3103,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.81" +version = "0.3.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec48937a97411dcb524a265206ccd4c90bb711fca92b2792c407f268825b9305" +checksum = "b011eec8cc36da2aab2d5cff675ec18454fad408585853910a202391cf9f8e65" dependencies = [ "once_cell", "wasm-bindgen", @@ -3449,9 +3449,9 @@ dependencies = [ [[package]] name = "moxcms" -version = "0.7.8" +version = "0.7.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "692af879e4d9383c0fd9dec15524af6b6977c8bf1c6b278a4526d5341347c574" +checksum = "0fbdd3d7436f8b5e892b8b7ea114271ff0fa00bc5acae845d53b07d498616ef6" dependencies = [ "num-traits", "pxfm", @@ -5280,9 +5280,9 @@ dependencies = [ [[package]] name = "rustls-pki-types" -version = "1.12.0" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "229a4a4c221013e7e1f1a043678c5cc39fe5171437c88fb47151a21e6f5b5c79" +checksum = "94182ad936a0c91c324cd46c6511b9510ed16af436d7b5bab34beab0afd55f7a" dependencies = [ "web-time", "zeroize", @@ -6420,9 +6420,9 @@ dependencies = [ [[package]] name = "tauri-plugin-clipboard-manager" -version = "2.3.1" +version = "2.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97386ff464c30f491847e56355e9f3bd7ce82726c8c51c4ca93dc6bdb7993751" +checksum = "206dc20af4ed210748ba945c2774e60fd0acd52b9a73a028402caf809e9b6ecf" dependencies = [ "arboard", "log", @@ -6435,9 +6435,9 @@ dependencies = [ [[package]] name = "tauri-plugin-deep-link" -version = "2.4.4" +version = "2.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd913b8b96627ec87a847ee4fe101427d95100f6c565768c2361c47b70d02bff" +checksum = "6e82759f7c7d51de3cbde51c04b3f2332de52436ed84541182cd8944b04e9e73" dependencies = [ "dunce", "plist", @@ -6456,9 +6456,9 @@ dependencies = [ [[package]] name = "tauri-plugin-dialog" -version = "2.4.1" +version = "2.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e34cadb63450580599193ebe3d69ce292888f1b56c26ea63563ff302f8fdf1f7" +checksum = "313f8138692ddc4a2127c4c9607d616a46f5c042e77b3722450866da0aad2f19" dependencies = [ "log", "raw-window-handle", @@ -6474,9 +6474,9 @@ dependencies = [ [[package]] name = "tauri-plugin-fs" -version = "2.4.3" +version = "2.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2864ee9907a87907ad710b5eab081a34c3c812af961d154976dab87f1fe39d12" +checksum = "47df422695255ecbe7bac7012440eddaeefd026656171eac9559f5243d3230d9" dependencies = [ "anyhow", "dunce", @@ -6496,9 +6496,9 @@ dependencies = [ [[package]] name = "tauri-plugin-http" -version = "2.5.3" +version = "2.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c51b7e91dd890ba1951c17ad35fd78eebb4da4fdd55347898faef546794e20f" +checksum = "c00685aceab12643cf024f712ab0448ba8fcadf86f2391d49d2e5aa732aacc70" dependencies = [ "bytes", "cookie_store", @@ -6520,9 +6520,9 @@ dependencies = [ [[package]] name = "tauri-plugin-log" -version = "2.7.0" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61c1438bc7662acd16d508c919b3c087efd63669a4c75625dff829b1c75975ec" +checksum = "d5709c792b8630290b5d9811a1f8fe983dd925fc87c7fc7f4923616458cd00b6" dependencies = [ "android_logger", "byte-unit", @@ -6542,9 +6542,9 @@ dependencies = [ [[package]] name = "tauri-plugin-notification" -version = "2.3.2" +version = "2.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ec42df990633cbe5148ae502b06421ab2851b890f1655965c7413fb4eb11f73" +checksum = "01fc2c5ff41105bd1f7242d8201fdf3efd70749b82fa013a17f2126357d194cc" dependencies = [ "log", "notify-rust", @@ -6561,9 +6561,9 @@ dependencies = [ [[package]] name = "tauri-plugin-opener" -version = "2.5.1" +version = "2.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd354191c4b4606fe4d82332937bc63736e2a261ea39dcdcce4be17064cd8766" +checksum = "c26b72571d25dee25667940027114e60f569fc3974f8cefbe50c2cbc5fd65e3b" dependencies = [ "dunce", "glob", @@ -6583,9 +6583,9 @@ dependencies = [ [[package]] name = "tauri-plugin-os" -version = "2.3.1" +version = "2.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77a1c77ebf6f20417ab2a74e8c310820ba52151406d0c80fbcea7df232e3f6ba" +checksum = "d8f08346c8deb39e96f86973da0e2d76cbb933d7ac9b750f6dc4daf955a6f997" dependencies = [ "gethostname", "log", @@ -6601,9 +6601,9 @@ dependencies = [ [[package]] name = "tauri-plugin-single-instance" -version = "2.3.5" +version = "2.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d09255a1cd942cdff57c7a1ce5e6022cd68ce1b8714b98ad2f1ff0a8a747a4fa" +checksum = "dd707f8c86b4e3004e2c141fa24351f1909ba40ce1b8437e30d5ed5277dd3710" dependencies = [ "serde", "serde_json", @@ -6617,9 +6617,9 @@ dependencies = [ [[package]] name = "tauri-plugin-window-state" -version = "2.4.0" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d5f6fe3291bfa609c7e0b0ee3bedac294d94c7018934086ce782c1d0f2a468e" +checksum = "73736611e14142408d15353e21e3cca2f12a3cfb523ad0ce85999b6d2ef1a704" dependencies = [ "bitflags 2.10.0", "log", @@ -7785,9 +7785,9 @@ checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b" [[package]] name = "wasm-bindgen" -version = "0.2.104" +version = "0.2.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1da10c01ae9f1ae40cbfac0bac3b1e724b320abfcf52229f80b547c0d250e2d" +checksum = "da95793dfc411fbbd93f5be7715b0578ec61fe87cb1a42b12eb625caa5c5ea60" dependencies = [ "cfg-if", "once_cell", @@ -7796,25 +7796,11 @@ dependencies = [ "wasm-bindgen-shared", ] -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.104" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "671c9a5a66f49d8a47345ab942e2cb93c7d1d0339065d4f8139c486121b43b19" -dependencies = [ - "bumpalo", - "log", - "proc-macro2", - "quote", - "syn 2.0.108", - "wasm-bindgen-shared", -] - [[package]] name = "wasm-bindgen-futures" -version = "0.4.54" +version = "0.4.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e038d41e478cc73bae0ff9b36c60cff1c98b8f38f8d7e8061e79ee63608ac5c" +checksum = "551f88106c6d5e7ccc7cd9a16f312dd3b5d36ea8b4954304657d5dfba115d4a0" dependencies = [ "cfg-if", "js-sys", @@ -7825,9 +7811,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.104" +version = "0.2.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ca60477e4c59f5f2986c50191cd972e3a50d8a95603bc9434501cf156a9a119" +checksum = "04264334509e04a7bf8690f2384ef5265f05143a4bff3889ab7a3269adab59c2" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -7835,22 +7821,22 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.104" +version = "0.2.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f07d2f20d4da7b26400c9f4a0511e6e0345b040694e8a75bd41d578fa4421d7" +checksum = "420bc339d9f322e562942d52e115d57e950d12d88983a14c79b86859ee6c7ebc" dependencies = [ + "bumpalo", "proc-macro2", "quote", "syn 2.0.108", - "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.104" +version = "0.2.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bad67dc8b2a1a6e5448428adec4c3e84c43e561d8c9ee8a9e5aabeb193ec41d1" +checksum = "76f218a38c84bcb33c25ec7059b07847d465ce0e0a76b995e134a45adcb6af76" dependencies = [ "unicode-ident", ] @@ -7943,9 +7929,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.81" +version = "0.3.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9367c417a924a74cae129e6a2ae3b47fabb1f8995595ab474029da749a8be120" +checksum = "3a1f95c0d03a47f4ae1f7a64643a6bb97465d9b740f0fa8f90ea33915c99a9a1" dependencies = [ "js-sys", "wasm-bindgen", diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 6edff813..e8b86ce3 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -39,6 +39,7 @@ name = "defguard-client" description = "Defguard desktop client" repository = "https://github.com/DefGuard/client" default-run = "defguard-client" +autobins = false authors.workspace = true edition.workspace = true homepage.workspace = true @@ -46,6 +47,13 @@ license-file.workspace = true rust-version.workspace = true version.workspace = true +[[bin]] +name = "defguard-client" + +[[bin]] +name = "defguard-service" +required-features = ["service"] + [build-dependencies] tauri-build = { version = "2", features = [] } tonic-prost-build.workspace = true @@ -133,6 +141,7 @@ windows-service = "0.7" # If you use cargo directly instead of tauri's cli you can use this feature flag to switch between tauri's `dev` and `build` modes. # DO NOT REMOVE!! custom-protocol = ["tauri/custom-protocol"] +service = [] [dev-dependencies] tokio = { version = "1", features = ["full"] } diff --git a/src-tauri/Client.entitlements b/src-tauri/Client.entitlements index 055a82c8..552baf4b 100644 --- a/src-tauri/Client.entitlements +++ b/src-tauri/Client.entitlements @@ -6,10 +6,6 @@ packet-tunnel-provider - com.apple.security.application-groups - - group.net.defguard - com.apple.security.app-sandbox com.apple.security.network.client diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index 5737f17f..0780a1aa 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -37,12 +37,10 @@ }, "macOS": { "entitlements": "./Client.entitlements", - "exceptionDomain": "", "files": { - "embedded.provisionprofile": "Adam_Apollo_Desktop.provisionprofile", + "embedded.provisionprofile": "Defguard_Client_Mac_App_Store.provisionprofile", "PlugIns/VPNExtension.appex": "../swift/extension/build/Release/VPNExtension.appex" }, - "frameworks": [], "minimumSystemVersion": "13.5" }, "resources": [ diff --git a/swift/extension/VPNExtension.xcodeproj/project.pbxproj b/swift/extension/VPNExtension.xcodeproj/project.pbxproj index 51380492..9f9e267a 100644 --- a/swift/extension/VPNExtension.xcodeproj/project.pbxproj +++ b/swift/extension/VPNExtension.xcodeproj/project.pbxproj @@ -263,7 +263,7 @@ ); LOCALIZATION_PREFERS_STRING_CATALOGS = YES; MACOSX_DEPLOYMENT_TARGET = 13.5; - MARKETING_VERSION = 1.0; + MARKETING_VERSION = 1.6.0; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; ONLY_ACTIVE_ARCH = YES; @@ -316,11 +316,13 @@ CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_ENTITLEMENTS = VPNExtension/VPNExtension.entitlements; - CODE_SIGN_STYLE = Automatic; + "CODE_SIGN_IDENTITY[sdk=macosx*]" = "3rd Party Mac Developer Application"; + CODE_SIGN_STYLE = Manual; COPY_PHASE_STRIP = NO; CURRENT_PROJECT_VERSION = 1; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - DEVELOPMENT_TEAM = 82GZ7KN29J; + DEVELOPMENT_TEAM = ""; + "DEVELOPMENT_TEAM[sdk=macosx*]" = 82GZ7KN29J; ENABLE_APP_SANDBOX = YES; ENABLE_HARDENED_RUNTIME = YES; ENABLE_INCOMING_NETWORK_CONNECTIONS = YES; @@ -355,11 +357,13 @@ ); LOCALIZATION_PREFERS_STRING_CATALOGS = YES; MACOSX_DEPLOYMENT_TARGET = 13.5; - MARKETING_VERSION = 1.0; + MARKETING_VERSION = 1.6.0; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = net.defguard.VPNExtension; PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = ""; + "PROVISIONING_PROFILE_SPECIFIER[sdk=macosx*]" = "Defguard VPNExtension Mac App Store"; REGISTER_APP_GROUPS = YES; SDKROOT = macosx; SKIP_INSTALL = YES; diff --git a/swift/extension/VPNExtension/VPNExtension.entitlements b/swift/extension/VPNExtension/VPNExtension.entitlements index 5b4eb027..dbbd0259 100644 --- a/swift/extension/VPNExtension/VPNExtension.entitlements +++ b/swift/extension/VPNExtension/VPNExtension.entitlements @@ -8,10 +8,6 @@ com.apple.security.app-sandbox - com.apple.security.application-groups - - group.net.defguard - com.apple.security.network.client com.apple.security.network.server From 24f3beae82b1aed8163c8ad1f41db3b5d3ef54d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adam=20Ciarcin=CC=81ski?= Date: Tue, 28 Oct 2025 14:09:43 +0100 Subject: [PATCH 11/28] Small fixes --- src-tauri/src/enterprise/provisioning/mod.rs | 17 +++++++++++++---- src-tauri/src/proto.rs | 8 +++++++- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/src-tauri/src/enterprise/provisioning/mod.rs b/src-tauri/src/enterprise/provisioning/mod.rs index a69e434b..2528e438 100644 --- a/src-tauri/src/enterprise/provisioning/mod.rs +++ b/src-tauri/src/enterprise/provisioning/mod.rs @@ -20,7 +20,10 @@ impl ProvisioningConfig { let file_content = match fs::read_to_string(path) { Ok(content) => content, Err(err) => { - warn!("Failed to open provisioning configuration file at {path:?}. Error details: {err}"); + warn!( + "Failed to open provisioning configuration file at {path:?}. Error details: \ + {err}" + ); return None; } }; @@ -31,7 +34,10 @@ impl ProvisioningConfig { match serde_json::from_str::(file_content) { Ok(config) => Some(config), Err(err) => { - warn!("Failed to parse provisioning configuration file at {path:?}. Error details: {err}"); + warn!( + "Failed to parse provisioning configuration file at {path:?}. Error details: \ + {err}" + ); None } } @@ -66,13 +72,16 @@ pub async fn handle_client_initialization(app_handle: &AppHandle) -> Option { - debug!("Provisioning config not found in {data_dir:?}. Proceeding with normal startup.") + debug!( + "Provisioning config not found in {data_dir:?}. Proceeding with normal \ + startup." + ); } } } } Err(err) => { - error!("Failed to verify if the client has already been initialized: {err}") + error!("Failed to verify if the client has already been initialized: {err}"); } } diff --git a/src-tauri/src/proto.rs b/src-tauri/src/proto.rs index 2174664f..ad041709 100644 --- a/src-tauri/src/proto.rs +++ b/src-tauri/src/proto.rs @@ -1,5 +1,5 @@ use crate::database::models::{ - location::{Location, LocationMfaMode as MfaMode}, + location::{Location, LocationMfaMode as MfaMode, ServiceLocationMode as SLocationMode}, Id, NoId, }; @@ -22,6 +22,11 @@ impl DeviceConfig { } }; + let service_location_mode = match self.service_location_mode { + Some(_service_location_mode) => self.service_location_mode().into(), + None => SLocationMode::Disabled, // Default to disabled if not set + }; + Location { id: NoId, instance_id, @@ -35,6 +40,7 @@ impl DeviceConfig { route_all_traffic: false, keepalive_interval: self.keepalive_interval.into(), location_mfa_mode, + service_location_mode, } } } From 7dd8d5b8cc11311c5811ae156896eaa926bc581f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adam=20Ciarcin=CC=81ski?= Date: Wed, 29 Oct 2025 13:17:49 +0100 Subject: [PATCH 12/28] Build with boringtun --- .github/workflows/build-macos.yaml | 72 +++++++++++++++++++ .github/workflows/release.yaml | 81 ++------------------- .gitmodules | 3 + biome.json | 2 +- boringtun | 1 + package.json | 4 +- pnpm-lock.yaml | 112 ++++++++++++++--------------- src-tauri/Cargo.lock | 78 ++++++++++---------- src-tauri/tauri.conf.json | 1 + src-tauri/tauri.linux.conf.json | 7 +- swift/.gitignore | 2 +- swift/boringtun | 1 + 12 files changed, 184 insertions(+), 180 deletions(-) create mode 100644 .github/workflows/build-macos.yaml create mode 160000 boringtun create mode 160000 swift/boringtun diff --git a/.github/workflows/build-macos.yaml b/.github/workflows/build-macos.yaml new file mode 100644 index 00000000..95c2acf4 --- /dev/null +++ b/.github/workflows/build-macos.yaml @@ -0,0 +1,72 @@ +name: Build macOS app +on: + workflow_call: + +jobs: + build-macos: + runs-on: + - self-hosted + - macOS + env: + APPLE_SIGNING_IDENTITY_APPLICATION: "Apple Distribution: defguard sp. z o.o. (82GZ7KN29J)" + APPLE_SIGNING_IDENTITY_INSTALLER: "3rd Party Mac Developer Installer: defguard sp. z o.o. (82GZ7KN29J)" + APPLE_ID: "kamil@defguard.net" + APPLE_TEAM_ID: "82GZ7KN29J" + steps: + - uses: actions/checkout@v5 + with: + submodules: recursive + - name: Write release version + run: | + VERSION=$(echo ${GITHUB_REF_NAME#v} | cut -d '-' -f1) + echo Version: $VERSION + echo "VERSION=$VERSION" >> ${GITHUB_ENV} + - uses: actions/setup-node@v6 + with: + node-version: "24" + - uses: pnpm/action-setup@v4 + with: + version: 10 + run_install: false + - name: Get pnpm store directory + shell: bash + run: echo "STORE_PATH=$(pnpm store path --silent)" >> ${GITHUB_ENV} + - uses: actions/cache@v4 + name: Setup pnpm cache + with: + path: ${{ env.STORE_PATH }} + key: ${{ runner.os }}-pnpm-build-store-${{ hashFiles('**/pnpm-lock.yaml') }} + restore-keys: | + ${{ runner.os }}-pnpm-build-store- + - name: Install deps + run: pnpm install --frozen-lockfile + - uses: dtolnay/rust-toolchain@stable + with: + targets: aarch64-apple-darwin,x86_64-apple-darwin + - name: Unlock keychain + run: security -v unlock-keychain -p "${{ secrets.KEYCHAIN_PASSWORD }}" login.keychain + - name: Build app + uses: tauri-apps/tauri-action@v0.5.23 # .24 seems broken, TODO: update when fixed + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + APPLE_SIGNING_IDENTITY: ${{ env.APPLE_SIGNING_IDENTITY_APPLICATION }} + APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }} + APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }} + APPLE_ID: ${{ env.APPLE_ID }} + APPLE_PASSWORD: ${{ secrets.NOTARYTOOL_APP_SPECIFIC_PASSWORD }} + APPLE_TEAM_ID: ${{ env.APPLE_TEAM_ID }} + - name: Build installation package + run: | + security -v unlock-keychain -p "${{ secrets.KEYCHAIN_PASSWORD }}" login.keychain + xcrun productbuild --sign "${APPLE_SIGNING_IDENTITY_INSTALLER}" --component "src-tauri/target/universal-apple-darwin/release/bundle/macos/defguard-client.app" /Applications defguard-client.pkg + xcrun notarytool submit --wait --apple-id ${{ env.APPLE_ID }} --password ${{ secrets.NOTARYTOOL_APP_SPECIFIC_PASSWORD }} --team-id ${{ env.APPLE_TEAM_ID }} defguard-client.pkg + xcrun stapler staple defguard-client.pkg + - name: Upload installation package + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ needs.create-release.outputs.upload_url }} + asset_path: defguard-client.pkg + asset_name: defguard-${{ matrix.target }}-${{ env.VERSION }}.pkg + asset_content_type: application/octet-stream diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 2d8ace2e..dc8eee97 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -120,7 +120,6 @@ jobs: - name: Upload DEB to APT repository #Add this to ubuntu 22.04 job (on merge dev -> main) with --codename=bookworm run: | COMPONENT=$([[ "${{ github.ref_name }}" == *"-"* ]] && echo "pre-release" || echo "release") # if tag contain "-" assume it's pre-release. - deb-s3 upload -l --bucket=apt.defguard.net --access-key-id=${{ secrets.AWS_ACCESS_KEY_APT }} --secret-access-key=${{ secrets.AWS_SECRET_KEY_APT }} --s3-region=eu-north-1 --no-fail-if-exists --codename=trixie --component="$COMPONENT" src-tauri/target/release/bundle/deb/defguard-client_${{ env.VERSION }}_${{ matrix.deb_arch }}.deb - name: Rename client binary run: mv src-tauri/target/release/defguard-client defguard-client-linux-${{ matrix.binary_arch }}-${{ github.ref_name }} @@ -226,15 +225,15 @@ jobs: for DIST in trixie bookworm; do aws s3 cp s3://apt.defguard.net/dists/${DIST}/Release . - + curl -X POST "${{ secrets.DEFGUARD_SIGNING_URL }}?signature_type=both" \ -H "Authorization: Bearer ${{ secrets.DEFGUARD_SIGNING_API_KEY }}" \ -F "file=@Release" \ -o response.json - + cat response.json | jq -r '.files["Release.gpg"].content' | base64 --decode > Release.gpg cat response.json | jq -r '.files.Release.content' | base64 --decode > InRelease - + aws s3 cp Release.gpg s3://apt.defguard.net/dists/${DIST}/ --acl public-read aws s3 cp InRelease s3://apt.defguard.net/dists/${DIST}/ --acl public-read @@ -313,79 +312,7 @@ jobs: build-macos: needs: - create-release - strategy: - fail-fast: false - matrix: - target: [aarch64-apple-darwin, x86_64-apple-darwin] - runs-on: - - self-hosted - - macOS - env: - APPLE_SIGNING_IDENTITY_APPLICATION: "Developer ID Application: defguard sp. z o.o. (82GZ7KN29J)" - APPLE_SIGNING_IDENTITY_INSTALLER: "Developer ID Installer: defguard sp. z o.o. (82GZ7KN29J)" - APPLE_ID: "kamil@defguard.net" - APPLE_TEAM_ID: "82GZ7KN29J" - steps: - - uses: actions/checkout@v5 - with: - submodules: "recursive" - - name: Write release version - run: | - VERSION=$(echo ${GITHUB_REF_NAME#v} | cut -d '-' -f1) - echo Version: $VERSION - echo "VERSION=$VERSION" >> ${GITHUB_ENV} - - uses: actions/setup-node@v4 - with: - node-version: "22" - - uses: pnpm/action-setup@v4 - with: - version: 10 - run_install: false - - name: Get pnpm store directory - shell: bash - run: echo "STORE_PATH=$(pnpm store path --silent)" >> ${GITHUB_ENV} - - uses: actions/cache@v4 - name: Setup pnpm cache - with: - path: ${{ env.STORE_PATH }} - key: ${{ runner.os }}-pnpm-build-store-${{ hashFiles('**/pnpm-lock.yaml') }} - restore-keys: | - ${{ runner.os }}-pnpm-build-store- - - name: Install deps - run: pnpm install --frozen-lockfile - - uses: dtolnay/rust-toolchain@stable - - name: Install protobuf compiler - run: brew install protobuf - - name: Install ARM target - run: rustup target add aarch64-apple-darwin - - name: Unlock keychain - run: security -v unlock-keychain -p "${{ secrets.KEYCHAIN_PASSWORD }}" /Users/admin/Library/Keychains/login.keychain - - name: Build app - uses: tauri-apps/tauri-action@v0.5.23 # .24 seems broken, TODO: update when fixed - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - APPLE_SIGNING_IDENTITY: ${{ env.APPLE_SIGNING_IDENTITY_APPLICATION }} - APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }} - APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }} - APPLE_ID: ${{ env.APPLE_ID }} - APPLE_PASSWORD: ${{ secrets.NOTARYTOOL_APP_SPECIFIC_PASSWORD }} - APPLE_TEAM_ID: ${{ env.APPLE_TEAM_ID }} - with: - args: --target ${{ matrix.target }} -v - - name: Build installation package - run: | - bash build-macos-package.sh src-tauri/target/${{ matrix.target }} src-tauri/resources-macos/scripts '${{ env.APPLE_SIGNING_IDENTITY_INSTALLER }}' /Users/admin/Library/Keychains/login.keychain - xcrun notarytool submit --wait --apple-id ${{ env.APPLE_ID }} --password ${{ secrets.NOTARYTOOL_APP_SPECIFIC_PASSWORD }} --team-id ${{ env.APPLE_TEAM_ID }} src-tauri/target/${{ matrix.target }}/product-signed/defguard.pkg - xcrun stapler staple src-tauri/target/${{ matrix.target }}/product-signed/defguard.pkg - - name: Upload installation package - uses: actions/upload-release-asset@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - upload_url: ${{ needs.create-release.outputs.upload_url }} - asset_path: src-tauri/target/${{ matrix.target }}/product-signed/defguard.pkg - asset_name: defguard-${{ matrix.target }}-${{ env.VERSION }}.pkg - asset_content_type: application/octet-stream + uses: ./.github/workflows/build-macos.yml # Builds Windows MSI and uploads it as artifact build-windows: diff --git a/.gitmodules b/.gitmodules index 5aee25bb..d4d2f74e 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,3 +4,6 @@ [submodule "src-tauri/proto"] path = src-tauri/proto url = ../proto.git +[submodule "swift/boringtun"] + path = swift/boringtun + url = ../boringtun.git diff --git a/biome.json b/biome.json index a0a83836..2441f3ed 100644 --- a/biome.json +++ b/biome.json @@ -1,5 +1,5 @@ { - "$schema": "https://biomejs.dev/schemas/2.2.4/schema.json", + "$schema": "https://biomejs.dev/schemas/2.3.2/schema.json", "vcs": { "enabled": false, "clientKind": "git", diff --git a/boringtun b/boringtun new file mode 160000 index 00000000..14c3845c --- /dev/null +++ b/boringtun @@ -0,0 +1 @@ +Subproject commit 14c3845c088b7ecec0d660a249bfc21a5d0ade0d diff --git a/package.json b/package.json index b61db577..682d4ee3 100644 --- a/package.json +++ b/package.json @@ -106,7 +106,7 @@ "zustand": "^5.0.8" }, "devDependencies": { - "@biomejs/biome": "^2.3.1", + "@biomejs/biome": "^2.3.2", "@hookform/devtools": "^4.4.0", "@svgr/cli": "^8.1.0", "@tanstack/react-query": "^5.90.5", @@ -114,7 +114,7 @@ "@tauri-apps/cli": "^2.9.1", "@types/file-saver": "^2.0.7", "@types/lodash-es": "^4.17.12", - "@types/node": "^24.9.1", + "@types/node": "^24.9.2", "@types/react": "^19.2.2", "@types/react-dom": "^19.2.2", "@vitejs/plugin-react": "^5.1.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a999d82c..2b88007d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -181,8 +181,8 @@ importers: version: 5.0.8(@types/react@19.2.2)(immer@10.2.0)(react@19.2.0)(use-sync-external-store@1.6.0(react@19.2.0)) devDependencies: '@biomejs/biome': - specifier: ^2.3.1 - version: 2.3.1 + specifier: ^2.3.2 + version: 2.3.2 '@hookform/devtools': specifier: ^4.4.0 version: 4.4.0(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) @@ -205,8 +205,8 @@ importers: specifier: ^4.17.12 version: 4.17.12 '@types/node': - specifier: ^24.9.1 - version: 24.9.1 + specifier: ^24.9.2 + version: 24.9.2 '@types/react': specifier: ^19.2.2 version: 19.2.2 @@ -215,10 +215,10 @@ importers: version: 19.2.2(@types/react@19.2.2) '@vitejs/plugin-react': specifier: ^5.1.0 - version: 5.1.0(vite@7.1.12(@types/node@24.9.1)(sass@1.92.1)(yaml@2.8.1)) + version: 5.1.0(vite@7.1.12(@types/node@24.9.2)(sass@1.92.1)(yaml@2.8.1)) '@vitejs/plugin-react-swc': specifier: ^4.2.0 - version: 4.2.0(vite@7.1.12(@types/node@24.9.1)(sass@1.92.1)(yaml@2.8.1)) + version: 4.2.0(vite@7.1.12(@types/node@24.9.2)(sass@1.92.1)(yaml@2.8.1)) autoprefixer: specifier: ^10.4.21 version: 10.4.21(postcss@8.5.6) @@ -245,7 +245,7 @@ importers: version: 5.9.3 vite: specifier: ^7.1.12 - version: 7.1.12(@types/node@24.9.1)(sass@1.92.1)(yaml@2.8.1) + version: 7.1.12(@types/node@24.9.2)(sass@1.92.1)(yaml@2.8.1) packages: @@ -336,55 +336,55 @@ packages: resolution: {integrity: sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==} engines: {node: '>=6.9.0'} - '@biomejs/biome@2.3.1': - resolution: {integrity: sha512-A29evf1R72V5bo4o2EPxYMm5mtyGvzp2g+biZvRFx29nWebGyyeOSsDWGx3tuNNMFRepGwxmA9ZQ15mzfabK2w==} + '@biomejs/biome@2.3.2': + resolution: {integrity: sha512-8e9tzamuDycx7fdrcJ/F/GDZ8SYukc5ud6tDicjjFqURKYFSWMl0H0iXNXZEGmcmNUmABgGuHThPykcM41INgg==} engines: {node: '>=14.21.3'} hasBin: true - '@biomejs/cli-darwin-arm64@2.3.1': - resolution: {integrity: sha512-ombSf3MnTUueiYGN1SeI9tBCsDUhpWzOwS63Dove42osNh0PfE1cUtHFx6eZ1+MYCCLwXzlFlYFdrJ+U7h6LcA==} + '@biomejs/cli-darwin-arm64@2.3.2': + resolution: {integrity: sha512-4LECm4kc3If0JISai4c3KWQzukoUdpxy4fRzlrPcrdMSRFksR9ZoXK7JBcPuLBmd2SoT4/d7CQS33VnZpgBjew==} engines: {node: '>=14.21.3'} cpu: [arm64] os: [darwin] - '@biomejs/cli-darwin-x64@2.3.1': - resolution: {integrity: sha512-pcOfwyoQkrkbGvXxRvZNe5qgD797IowpJPovPX5biPk2FwMEV+INZqfCaz4G5bVq9hYnjwhRMamg11U4QsRXrQ==} + '@biomejs/cli-darwin-x64@2.3.2': + resolution: {integrity: sha512-jNMnfwHT4N3wi+ypRfMTjLGnDmKYGzxVr1EYAPBcauRcDnICFXN81wD6wxJcSUrLynoyyYCdfW6vJHS/IAoTDA==} engines: {node: '>=14.21.3'} cpu: [x64] os: [darwin] - '@biomejs/cli-linux-arm64-musl@2.3.1': - resolution: {integrity: sha512-+DZYv8l7FlUtTrWs1Tdt1KcNCAmRO87PyOnxKGunbWm5HKg1oZBSbIIPkjrCtDZaeqSG1DiGx7qF+CPsquQRcg==} + '@biomejs/cli-linux-arm64-musl@2.3.2': + resolution: {integrity: sha512-2Zz4usDG1GTTPQnliIeNx6eVGGP2ry5vE/v39nT73a3cKN6t5H5XxjcEoZZh62uVZvED7hXXikclvI64vZkYqw==} engines: {node: '>=14.21.3'} cpu: [arm64] os: [linux] - '@biomejs/cli-linux-arm64@2.3.1': - resolution: {integrity: sha512-td5O8pFIgLs8H1sAZsD6v+5quODihyEw4nv2R8z7swUfIK1FKk+15e4eiYVLcAE4jUqngvh4j3JCNgg0Y4o4IQ==} + '@biomejs/cli-linux-arm64@2.3.2': + resolution: {integrity: sha512-amnqvk+gWybbQleRRq8TMe0rIv7GHss8mFJEaGuEZYWg1Tw14YKOkeo8h6pf1c+d3qR+JU4iT9KXnBKGON4klw==} engines: {node: '>=14.21.3'} cpu: [arm64] os: [linux] - '@biomejs/cli-linux-x64-musl@2.3.1': - resolution: {integrity: sha512-Y3Ob4nqgv38Mh+6EGHltuN+Cq8aj/gyMTJYzkFZV2AEj+9XzoXB9VNljz9pjfFNHUxvLEV4b55VWyxozQTBaUQ==} + '@biomejs/cli-linux-x64-musl@2.3.2': + resolution: {integrity: sha512-gzB19MpRdTuOuLtPpFBGrV3Lq424gHyq2lFj8wfX9tvLMLdmA/R9C7k/mqBp/spcbWuHeIEKgEs3RviOPcWGBA==} engines: {node: '>=14.21.3'} cpu: [x64] os: [linux] - '@biomejs/cli-linux-x64@2.3.1': - resolution: {integrity: sha512-PYWgEO7up7XYwSAArOpzsVCiqxBCXy53gsReAb1kKYIyXaoAlhBaBMvxR/k2Rm9aTuZ662locXUmPk/Aj+Xu+Q==} + '@biomejs/cli-linux-x64@2.3.2': + resolution: {integrity: sha512-8BG/vRAhFz1pmuyd24FQPhNeueLqPtwvZk6yblABY2gzL2H8fLQAF/Z2OPIc+BPIVPld+8cSiKY/KFh6k81xfA==} engines: {node: '>=14.21.3'} cpu: [x64] os: [linux] - '@biomejs/cli-win32-arm64@2.3.1': - resolution: {integrity: sha512-RHIG/zgo+69idUqVvV3n8+j58dKYABRpMyDmfWu2TITC+jwGPiEaT0Q3RKD+kQHiS80mpBrST0iUGeEXT0bU9A==} + '@biomejs/cli-win32-arm64@2.3.2': + resolution: {integrity: sha512-lCruqQlfWjhMlOdyf5pDHOxoNm4WoyY2vZ4YN33/nuZBRstVDuqPPjS0yBkbUlLEte11FbpW+wWSlfnZfSIZvg==} engines: {node: '>=14.21.3'} cpu: [arm64] os: [win32] - '@biomejs/cli-win32-x64@2.3.1': - resolution: {integrity: sha512-izl30JJ5Dp10mi90Eko47zhxE6pYyWPcnX1NQxKpL/yMhXxf95oLTzfpu4q+MDBh/gemNqyJEwjBpe0MT5iWPA==} + '@biomejs/cli-win32-x64@2.3.2': + resolution: {integrity: sha512-6Ee9P26DTb4D8sN9nXxgbi9Dw5vSOfH98M7UlmkjKB2vtUbrRqCbZiNfryGiwnPIpd6YUoTl7rLVD2/x1CyEHQ==} engines: {node: '>=14.21.3'} cpu: [x64] os: [win32] @@ -1283,8 +1283,8 @@ packages: '@types/ms@2.1.0': resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==} - '@types/node@24.9.1': - resolution: {integrity: sha512-QoiaXANRkSXK6p0Duvt56W208du4P9Uye9hWLWgGMDTEoKPhuenzNcC4vGUmrNkiOKTlIrBoyNQYNpSwfEZXSg==} + '@types/node@24.9.2': + resolution: {integrity: sha512-uWN8YqxXxqFMX2RqGOrumsKeti4LlmIMIyV0lgut4jx7KQBcBiW6vkDtIBvHnHIquwNfJhk8v2OtmO8zXWHfPA==} '@types/parse-json@4.0.2': resolution: {integrity: sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==} @@ -1673,8 +1673,8 @@ packages: resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} engines: {node: '>= 0.4'} - electron-to-chromium@1.5.240: - resolution: {integrity: sha512-OBwbZjWgrCOH+g6uJsA2/7Twpas2OlepS9uvByJjR2datRDuKGYeD+nP8lBBks2qnB7bGJNHDUx7c/YLaT3QMQ==} + electron-to-chromium@1.5.243: + resolution: {integrity: sha512-ZCphxFW3Q1TVhcgS9blfut1PX8lusVi2SvXQgmEEnK4TCmE1JhH2JkjJN+DNt0pJJwfBri5AROBnz2b/C+YU9g==} emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} @@ -3112,39 +3112,39 @@ snapshots: '@babel/helper-string-parser': 7.27.1 '@babel/helper-validator-identifier': 7.28.5 - '@biomejs/biome@2.3.1': + '@biomejs/biome@2.3.2': optionalDependencies: - '@biomejs/cli-darwin-arm64': 2.3.1 - '@biomejs/cli-darwin-x64': 2.3.1 - '@biomejs/cli-linux-arm64': 2.3.1 - '@biomejs/cli-linux-arm64-musl': 2.3.1 - '@biomejs/cli-linux-x64': 2.3.1 - '@biomejs/cli-linux-x64-musl': 2.3.1 - '@biomejs/cli-win32-arm64': 2.3.1 - '@biomejs/cli-win32-x64': 2.3.1 - - '@biomejs/cli-darwin-arm64@2.3.1': + '@biomejs/cli-darwin-arm64': 2.3.2 + '@biomejs/cli-darwin-x64': 2.3.2 + '@biomejs/cli-linux-arm64': 2.3.2 + '@biomejs/cli-linux-arm64-musl': 2.3.2 + '@biomejs/cli-linux-x64': 2.3.2 + '@biomejs/cli-linux-x64-musl': 2.3.2 + '@biomejs/cli-win32-arm64': 2.3.2 + '@biomejs/cli-win32-x64': 2.3.2 + + '@biomejs/cli-darwin-arm64@2.3.2': optional: true - '@biomejs/cli-darwin-x64@2.3.1': + '@biomejs/cli-darwin-x64@2.3.2': optional: true - '@biomejs/cli-linux-arm64-musl@2.3.1': + '@biomejs/cli-linux-arm64-musl@2.3.2': optional: true - '@biomejs/cli-linux-arm64@2.3.1': + '@biomejs/cli-linux-arm64@2.3.2': optional: true - '@biomejs/cli-linux-x64-musl@2.3.1': + '@biomejs/cli-linux-x64-musl@2.3.2': optional: true - '@biomejs/cli-linux-x64@2.3.1': + '@biomejs/cli-linux-x64@2.3.2': optional: true - '@biomejs/cli-win32-arm64@2.3.1': + '@biomejs/cli-win32-arm64@2.3.2': optional: true - '@biomejs/cli-win32-x64@2.3.1': + '@biomejs/cli-win32-x64@2.3.2': optional: true '@emotion/babel-plugin@11.13.5': @@ -3930,7 +3930,7 @@ snapshots: '@types/ms@2.1.0': {} - '@types/node@24.9.1': + '@types/node@24.9.2': dependencies: undici-types: 7.16.0 @@ -3959,15 +3959,15 @@ snapshots: '@use-gesture/core': 10.3.1 react: 19.2.0 - '@vitejs/plugin-react-swc@4.2.0(vite@7.1.12(@types/node@24.9.1)(sass@1.92.1)(yaml@2.8.1))': + '@vitejs/plugin-react-swc@4.2.0(vite@7.1.12(@types/node@24.9.2)(sass@1.92.1)(yaml@2.8.1))': dependencies: '@rolldown/pluginutils': 1.0.0-beta.43 '@swc/core': 1.13.5 - vite: 7.1.12(@types/node@24.9.1)(sass@1.92.1)(yaml@2.8.1) + vite: 7.1.12(@types/node@24.9.2)(sass@1.92.1)(yaml@2.8.1) transitivePeerDependencies: - '@swc/helpers' - '@vitejs/plugin-react@5.1.0(vite@7.1.12(@types/node@24.9.1)(sass@1.92.1)(yaml@2.8.1))': + '@vitejs/plugin-react@5.1.0(vite@7.1.12(@types/node@24.9.2)(sass@1.92.1)(yaml@2.8.1))': dependencies: '@babel/core': 7.28.5 '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.28.5) @@ -3975,7 +3975,7 @@ snapshots: '@rolldown/pluginutils': 1.0.0-beta.43 '@types/babel__core': 7.20.5 react-refresh: 0.18.0 - vite: 7.1.12(@types/node@24.9.1)(sass@1.92.1)(yaml@2.8.1) + vite: 7.1.12(@types/node@24.9.2)(sass@1.92.1)(yaml@2.8.1) transitivePeerDependencies: - supports-color @@ -4054,7 +4054,7 @@ snapshots: dependencies: baseline-browser-mapping: 2.8.20 caniuse-lite: 1.0.30001751 - electron-to-chromium: 1.5.240 + electron-to-chromium: 1.5.243 node-releases: 2.0.26 update-browserslist-db: 1.1.4(browserslist@4.27.0) @@ -4321,7 +4321,7 @@ snapshots: es-errors: 1.3.0 gopd: 1.2.0 - electron-to-chromium@1.5.240: {} + electron-to-chromium@1.5.243: {} emoji-regex@8.0.0: {} @@ -5849,7 +5849,7 @@ snapshots: d3-time: 3.1.0 d3-timer: 3.0.1 - vite@7.1.12(@types/node@24.9.1)(sass@1.92.1)(yaml@2.8.1): + vite@7.1.12(@types/node@24.9.2)(sass@1.92.1)(yaml@2.8.1): dependencies: esbuild: 0.25.11 fdir: 6.5.0(picomatch@4.0.3) @@ -5858,7 +5858,7 @@ snapshots: rollup: 4.52.5 tinyglobby: 0.2.15 optionalDependencies: - '@types/node': 24.9.1 + '@types/node': 24.9.2 fsevents: 2.3.3 sass: 1.92.1 yaml: 2.8.1 diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index 067a2219..46e7f0dd 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -31,9 +31,9 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "1.1.3" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" dependencies = [ "memchr", ] @@ -2805,9 +2805,9 @@ dependencies = [ [[package]] name = "icu_collections" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47" +checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43" dependencies = [ "displaydoc", "potential_utf", @@ -2818,9 +2818,9 @@ dependencies = [ [[package]] name = "icu_locale_core" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a" +checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6" dependencies = [ "displaydoc", "litemap", @@ -2831,11 +2831,10 @@ dependencies = [ [[package]] name = "icu_normalizer" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979" +checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599" dependencies = [ - "displaydoc", "icu_collections", "icu_normalizer_data", "icu_properties", @@ -2846,42 +2845,38 @@ dependencies = [ [[package]] name = "icu_normalizer_data" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3" +checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" [[package]] name = "icu_properties" -version = "2.0.1" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "016c619c1eeb94efb86809b015c58f479963de65bdb6253345c1a1276f22e32b" +checksum = "e93fcd3157766c0c8da2f8cff6ce651a31f0810eaa1c51ec363ef790bbb5fb99" dependencies = [ - "displaydoc", "icu_collections", "icu_locale_core", "icu_properties_data", "icu_provider", - "potential_utf", "zerotrie", "zerovec", ] [[package]] name = "icu_properties_data" -version = "2.0.1" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632" +checksum = "02845b3647bb045f1100ecd6480ff52f34c35f82d9880e029d329c21d1054899" [[package]] name = "icu_provider" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af" +checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614" dependencies = [ "displaydoc", "icu_locale_core", - "stable_deref_trait", - "tinystr", "writeable", "yoke", "zerofrom", @@ -3302,9 +3297,9 @@ checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" [[package]] name = "litemap" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" +checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" [[package]] name = "litrs" @@ -4528,9 +4523,9 @@ dependencies = [ [[package]] name = "potential_utf" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84df19adbe5b5a0782edcab45899906947ab039ccf4573713735ee7de1e6b08a" +checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77" dependencies = [ "zerovec", ] @@ -5302,9 +5297,9 @@ dependencies = [ [[package]] name = "rustls-webpki" -version = "0.103.7" +version = "0.103.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e10b3f4191e8a80e6b43eebabfac91e5dcecebb27a71f04e820c47ec41d314bf" +checksum = "2ffdfa2f5286e2247234e03f680868ac2815974dc39e00ea15adc445d0aafe52" dependencies = [ "ring", "rustls-pki-types", @@ -6894,9 +6889,9 @@ dependencies = [ [[package]] name = "tinystr" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b" +checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869" dependencies = [ "displaydoc", "zerovec", @@ -8751,9 +8746,9 @@ dependencies = [ [[package]] name = "writeable" -version = "0.6.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" +checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" [[package]] name = "wry" @@ -8861,11 +8856,10 @@ dependencies = [ [[package]] name = "yoke" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc" +checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954" dependencies = [ - "serde", "stable_deref_trait", "yoke-derive", "zerofrom", @@ -8873,9 +8867,9 @@ dependencies = [ [[package]] name = "yoke-derive" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" +checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" dependencies = [ "proc-macro2", "quote", @@ -9008,9 +9002,9 @@ dependencies = [ [[package]] name = "zerotrie" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595" +checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851" dependencies = [ "displaydoc", "yoke", @@ -9019,9 +9013,9 @@ dependencies = [ [[package]] name = "zerovec" -version = "0.11.4" +version = "0.11.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7aa2bd55086f1ab526693ecbe444205da57e25f4489879da80635a46d90e73b" +checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002" dependencies = [ "yoke", "zerofrom", @@ -9030,9 +9024,9 @@ dependencies = [ [[package]] name = "zerovec-derive" -version = "0.11.1" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" +checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" dependencies = [ "proc-macro2", "quote", diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index 442c2194..5199be65 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -41,6 +41,7 @@ } }, "macOS": { + "bundleVersion": "1", "entitlements": "./Client.entitlements", "files": { "embedded.provisionprofile": "Defguard_Client_Mac_App_Store.provisionprofile", diff --git a/src-tauri/tauri.linux.conf.json b/src-tauri/tauri.linux.conf.json index 1ceacbf7..c946ac5d 100644 --- a/src-tauri/tauri.linux.conf.json +++ b/src-tauri/tauri.linux.conf.json @@ -1,5 +1,10 @@ { + "build": { + "features": [ + "service" + ] + }, "bundle": { "longDescription": "IMPORTANT: Reboot or Re-login Required\nOn initial install the user is added to the defguard group.\nA reboot or logging out and back in is required for group membership changes to take effect.\nThis is not required on subsequent updates." } -} \ No newline at end of file +} diff --git a/swift/.gitignore b/swift/.gitignore index 9ca7835c..b996f867 100644 --- a/swift/.gitignore +++ b/swift/.gitignore @@ -1,7 +1,6 @@ .DS_Store */.build build -Boringtun /Packages xcuserdata/ DerivedData/ @@ -9,3 +8,4 @@ DerivedData/ .swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata .netrc Package.resolved +extension/BoringTun diff --git a/swift/boringtun b/swift/boringtun new file mode 160000 index 00000000..f47e80a9 --- /dev/null +++ b/swift/boringtun @@ -0,0 +1 @@ +Subproject commit f47e80a96923733bb9ed2bd5590f882dfb1d9b95 From f25005cd48613a5ff2d7bd2aca366297cd2cefe3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adam=20Ciarcin=CC=81ski?= Date: Wed, 29 Oct 2025 13:36:37 +0100 Subject: [PATCH 13/28] Update proto --- .gitmodules | 3 -- src-tauri/Info.plist | 8 +++++ src-tauri/proto | 2 +- src-tauri/tauri.macos.conf.json | 8 +++++ swift/boringtun | 1 - swift/build.sh | 53 +++++++++++++++++++++++++++++++++ 6 files changed, 70 insertions(+), 5 deletions(-) create mode 100644 src-tauri/Info.plist create mode 100644 src-tauri/tauri.macos.conf.json delete mode 160000 swift/boringtun create mode 100755 swift/build.sh diff --git a/.gitmodules b/.gitmodules index d4d2f74e..5aee25bb 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,6 +4,3 @@ [submodule "src-tauri/proto"] path = src-tauri/proto url = ../proto.git -[submodule "swift/boringtun"] - path = swift/boringtun - url = ../boringtun.git diff --git a/src-tauri/Info.plist b/src-tauri/Info.plist new file mode 100644 index 00000000..cceceddc --- /dev/null +++ b/src-tauri/Info.plist @@ -0,0 +1,8 @@ + + + + + ITSAppUsesNonExemptEncryption + + + diff --git a/src-tauri/proto b/src-tauri/proto index fee70601..764ba6e5 160000 --- a/src-tauri/proto +++ b/src-tauri/proto @@ -1 +1 @@ -Subproject commit fee706013b3bb5452c3c4dbf35bd973d0637ff25 +Subproject commit 764ba6e516781f5e13719d5ea6c5e7fcc7307c53 diff --git a/src-tauri/tauri.macos.conf.json b/src-tauri/tauri.macos.conf.json new file mode 100644 index 00000000..39e50dd0 --- /dev/null +++ b/src-tauri/tauri.macos.conf.json @@ -0,0 +1,8 @@ +{ + "build": { + "beforeBundleCommand": { + "cwd": "../swift", + "script": "./build.sh" + } + } +} diff --git a/swift/boringtun b/swift/boringtun deleted file mode 160000 index f47e80a9..00000000 --- a/swift/boringtun +++ /dev/null @@ -1 +0,0 @@ -Subproject commit f47e80a96923733bb9ed2bd5590f882dfb1d9b95 diff --git a/swift/build.sh b/swift/build.sh new file mode 100755 index 00000000..aee79de3 --- /dev/null +++ b/swift/build.sh @@ -0,0 +1,53 @@ +#!/bin/sh +set -e + +CARGO="${HOME}/.cargo/bin/cargo" +RUSTUP="${HOME}/.cargo/bin/rustup" +export MACOSX_DEPLOYMENT_TARGET=13.5 + +# Build BoringTun. + +pushd boringtun + +for TARGET in aarch64-apple-darwin x86_64-apple-darwin +do + ${RUSTUP} target add "${TARGET}" + ${CARGO} build --lib --locked --release --target ${TARGET} +done + +# Create universal library. + +mkdir -p target/universal/release +lipo -create \ + target/aarch64-apple-darwin/release/libboringtun.a \ + target/x86_64-apple-darwin/release/libboringtun.a \ + -output target/universal/release/libboringtun.a + +rm -f -r target/uniffi +${CARGO} run --release --bin uniffi-bindgen -- \ + --xcframework --headers --modulemap --swift-sources \ + target/aarch64-apple-darwin/release/libboringtun.a target/uniffi + +# Install BoringTun framework. + +DST="${PWD}/extension" + +mkdir -p ${DST}/BoringTun +cp -c target/uniffi/boringtun.swift ${DST}/BoringTun/ +rm -f -r ${DST}/BoringTun/boringtun.xcframework +xcodebuild -create-xcframework \ + -library target/universal/release/libboringtun.a \ + -headers target/uniffi \ + -output ${DST}/BoringTun/boringtun.xcframework +cp -c target/uniffi/boringtunFFI.h ${DST}/BoringTun/ + +popd + +# Build VPNExtension. + +if [ "${TAURI_ENV_DEBUG}" = 'false' ]; then + CONFIG=Release +else + CONFIG=Debug +fi +xcodebuild -project extension/VPNExtension.xcodeproj -target VPNExtension -configuration ${CONFIG} build From 8c6d72e498a751bc13742d48706b7c9a6d1542d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adam=20Ciarcin=CC=81ski?= Date: Wed, 29 Oct 2025 13:38:08 +0100 Subject: [PATCH 14/28] Fix boringtun submodule --- .gitmodules | 3 +++ boringtun | 1 - swift/boringtun | 1 + 3 files changed, 4 insertions(+), 1 deletion(-) delete mode 160000 boringtun create mode 160000 swift/boringtun diff --git a/.gitmodules b/.gitmodules index 5aee25bb..d4d2f74e 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,3 +4,6 @@ [submodule "src-tauri/proto"] path = src-tauri/proto url = ../proto.git +[submodule "swift/boringtun"] + path = swift/boringtun + url = ../boringtun.git diff --git a/boringtun b/boringtun deleted file mode 160000 index 14c3845c..00000000 --- a/boringtun +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 14c3845c088b7ecec0d660a249bfc21a5d0ade0d diff --git a/swift/boringtun b/swift/boringtun new file mode 160000 index 00000000..f47e80a9 --- /dev/null +++ b/swift/boringtun @@ -0,0 +1 @@ +Subproject commit f47e80a96923733bb9ed2bd5590f882dfb1d9b95 From 2531c30b39379b8e8591a4e8198ed6abfa858c71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adam=20Ciarcin=CC=81ski?= Date: Wed, 29 Oct 2025 13:40:49 +0100 Subject: [PATCH 15/28] Add provisionprofiles --- ...fguard_Client_Mac_App_Store.provisionprofile | Bin 0 -> 13173 bytes ..._VPNExtension_Mac_App_Store.provisionprofile | Bin 0 -> 13249 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 src-tauri/Defguard_Client_Mac_App_Store.provisionprofile create mode 100644 src-tauri/Defguard_VPNExtension_Mac_App_Store.provisionprofile diff --git a/src-tauri/Defguard_Client_Mac_App_Store.provisionprofile b/src-tauri/Defguard_Client_Mac_App_Store.provisionprofile new file mode 100644 index 0000000000000000000000000000000000000000..7eaff6cd7e3a35a410c8d4a87939131e6b3c810e GIT binary patch literal 13173 zcmdUW37p&1)o*69@2m++AP8HcVy2R!biXNd#~Sn`TZu6uCDGq z_ug~<=YP(USkTpls+^TdXZ9EtBRx8y#7TU%B%aw54mtX4J!dVQv1B3P z$3yV|sVf(-=z21WQa)X;S5UAH@qLC7aF))j(B9XB#6;B&*fr*tTp& zXTs|78SU<|t?5UqX+7grq1`BvR7Pdt;bEx}Ft09>J zg`|>}s>Lq|Fftl{F!tqLQ*sPeNT8FYq$t3EhbAJOEXaa>c%lfQE)=v`#$lpi&@csp zJW_XfDASjKT*;+0ML7&19LKyy5mhM+6)DCqBz%0;X5gAJk0ob{80>LLCQu(H<|~ z&C9)bDih5WElGmTNn*>Av&)=O;joAhP?55bN*9WmtUoR|tFa*N#A__W>!n=K;q^9Z zM5Js^Hhl&?nea!Q5wkZMRQl0+nwCmzO$oXp2p{)}70J=di@t2C8Vx7dT(eMdRC}Gi zwAI|J3WA>q6oVeSS>fX{5zo8*iXD^ja)MR!lu|;Pj;z^e4zs)i%k|Rvx&==POwkv` z%jG!dBYZ-ngwZjxoUAA@CDRn~{=6elunQ%7IP2#bQn57S-cYqtV#?tHYqJ|$R^D3k z=3`hrANJIeDGQeBkJpP$m)lSdn#w%l;tYX?A%mz~)mGJ)oH03)toHYMnw%w!qbiA_ zNk5L}L{$_igho|Omw8epF}=#*G>WP&O_x|Chhd`XkkBxmwxW&%VW}D!Pd?+ZxU-oY z;ZDnCE2VO1obsq~Si`Uj){;yRSeC{SCyvWblnFbq7K&%G4vBZMsy}P1$BmID@1kq* z7^bG2;ac2iSG*?PlyJFAbkmYg#3+?!M%$!Or_&wHAiN9h_crbIxC!*O*s(Eh(N|9e zJ7qLME4+!%b49L26JZz|DQI@*3Zf+3M*veW5-0#gs8F0+tjg7b_*AX0bC5&`uPvDTuYSdI@LSmJq-p z1@I`7Dgv4r?NDAA#;AHCiy1g$SpI@6E|Ak%$Z0ZkzJvL87K+KJF9TO?3@TT2|96t~7SOn(B-b}_= zi?@YFJM$mL(6o&t2-GvCZ31nfeEU6PCLJOZ7DN8H>Q6ASfl~XV z@~SGg6dPA+c#Bnwqv_5Y{e^Tg)x?7tF_X=PC?cm1D5xXgZyB2{v!A8;hQ%2qf~+N9 zVq*O^CS$D?#bQ3_tCYp8#b$6+OjO90C^#sRDcfysL2=s(NQPn@E=!^%Q3k(7OvY+# zGVZYnf@E?UX?wy}b=53ZPdu1SwDJ)fUhZY2NYH5yx&*5Sp(A)RVr*p+W`czx@n8}M+f}u%NB*F6iwXv)K178JYX^f(XV#|r6 z7EUDq=~@H-^cC93|2Gm=S#3*dPzZKk53CXC7B zC)}=Rj`xOglqHx$)6hpa5p^h`qC-hAYAE516ceUMh66<5OlXaANn)yLse|Q1U5i6- zVP!yvHp;Nt_*l+I=i;ibg*Is--}2>1V>E|~1jaL5(GIB6D6oKtyvtpVm%#dgK}B2z z75Z|74QwEs55u5Ua;SeESl3AZjImMHw=wSeuKSYTOU)uXB@ZLTyV1B3Q zc%#6!ilpMpF-W}SF2-A&nQk#=nviKnm@V+dh@3KE1uj1x;kXu>#c+&}ihjlHaGRN+ zLGP+7#i(8JI8-rg=$*QvB$6$jZ-jh zd^2T=09!d=Z9r$o*=g2Xp>dIRXmcO+N%3f*=8d*lLks4n1miJ)2L>71cpxMs~&u zIxyUJ5SX7gHyZI_85)m7XqC^Q3?_0AdFK29h617-u8ItUQV=DeXfWO%wAmS#CvQ#A zSxzEDE+4`a(k_RDSQ;jbi5eMep)7_gypgrW5VIMv${g#B=(4|9KUJ&*Jw?91w=UG`Mp@2RT4~?~^{h;Ym@{b2rR98_Z7_PfrBtD% zWTM)VDZ=1x8S=ISQgc?*l`I`WbC{BlB&Mk_J_D)u<-&BYLX~snkgsMonvxDHpLf|Z zA$Pq<#Y>C@Z}6$6!6^}bF^={MSvjjkG~OaGeLR(fF^GV#qSzt?tGSLeB=B(>109vU zg_USlR-K&)l^`(pu&xACMmzW=A4cJbs73hh9GdUgi%h%1!x8>C-=N{8$c$mYVYM2R%2`ovws4?=;qw+X> z7S04%7R20uX9d8bVaBi72J)YU_2DQuyktKcO__{ox83FUN&P{m zA?1q@iF{BlhLi46e=~^nn(L7`VQ*!VH95gHZ8dAFmPbh8hy>w0qu37#7I-qOUO!Tk#deJs;W!VT^8|U7;tV^ z*;UJBJ&qttQTddwF4>Z9myDpza`{Va88A%hWY3H~&~J*xPzo|=2iS?~D}jyY(Ht5f zJVk$_(i=@iYo!vnB?Ib9q&$|O!AUr?rj)3_>e!fq&Frq`l2%tPO}I$6sZz>GC40rh z;k1)%Q30~7*B4!M#awPW89QH6*s_npy{2Su9QUv`KHSgqO~fq6D}}n%iSrFl$R5ty z0xgf617D|dVCNoX#Mfa0S|QkC!e52V+&Eu{|G#W2u8hX5nFbw#_>7=|Uo(biyG(4* zIq->Xo2S)i4)fDNN%eGm8bRO=Kp8ejIWXWCiE=xJDHdvpCdBMRoSbs_$_b+dI28Ba z^T&=n#4vG}mYr+m5a1GE3!QuL2^_(QC}~fyDMEIIBZMts$|pp3#MYb3mI5iVH)LR& zrgSP1j5YKb@MM@QQK^c@;a7YC#cD`e9QI(m6~#@he1BPKm1BG%Akm1wp4Ku_VH>Qg z1J>}XGg3lc==W1n#7&A>RyOwL8d6?pF`%A#l^K&g(lSyIH)-7B0Q-&nyY}1CI5-4{ zEgo7!;@WRwaT=War5DMJ>i4%z8W##z$`BWr+q zTGpwS!0mM|tHo9A?6<~?bBUO*m571=8OIGm<*;n_$#jx(79*aTTV`{57w5`zVF(KS zoh*&5!wrC6VrEn&)Zw_C&m~YbbWq$7eH7q^1I?1C)l#v=l2|fPY~*VkV#@ayLJE;~ zG$4l|>ZO=dF?$1ivYK?pampp;jGUjski6ZVuDNp-tQPfSv63;MkNP3JH8kUKd%Qo8 z>*eV%`tuseEJCg3ki@7Pec(BI2~O1W+$!$pACH1NBrOCy1+$Z zqDO?BL8#Jf9hkR(9EHGv;t$WOmKo0zkU<~OFUVH8AWy-K&28XJxIr{D90@mQf-=z| z5_T5CW{AoAc8sv=_ylLDW$|A=`^4$?=>hht|h^$1n{_WW*YtW8F%G;j5*L z)k7A_z*VD-tXM&f)BfN%VU#v_Ioi@B5eMR zZh#H#DMA}sJDrALdva)_k{{kYTU-(pRjTG;hjI8;XedHS+b$jMZ~Bsv-85)uX!j8| zJp0O3snOK_uV;CoI%Ypl>u{(ZCzYT%r4O=kictNE%H<@N7nD8)sDM!Tin@GB?g()3 zezn)KpeQgfn3Rz%(=n1&g+j7<@K?2J;olQDBPnuOQVuHWNP1G6|AQ@pEO51IR%y1^ zWM~VwPpnF{^2jnCbn4qxwAEV7e{oNE%m7Dsc^98LcAQ@+n6{ZcEDx;g(4O+BItF@)GpH}#)x=s#dP{J+}H*WraM%&?A5ayr=i*98@+3Tf*Rg>5512nI2_ zxj(!Rqh>j5Y@_ovwuRv|c?SfvwhkuHurBH3@?u>}CoPs1k8MQTgAZkkLP+vv>!W$~ zELgWFRF@jf)+PGkhap@Fhbdx2)}a9)*{@jm#c7GtxB^4w0nVXG$i9CrvrLI~+6|jvP7#9%dXq1D2*B z=%^C6*l-eZf>t>5@Z&m#qvsC*Gj(W9$w-=28|EQLX!Rx@KD$$ol_W)nqsZ~|XB!cN z(a>+On{1Z;#QfPN?GfqxgY1QYK(O|gv(D&z8I`I9UIiuAjU0N=v4CFMnGad_W&LZX zV>CHubvrF1BbhaJBttdYV?_qLddAL1*W?Kk2fOCNxtgvS-Gg0S6Ml5=OA9{!*S%Xk zJxl)h{7L_szyJLo9lw-6G=1IM%kTTS`L{Qpwy^a4@mDXr^fcvxIfo=~Uc$LAa=-RS z?fIvEzkZtQ{M_BA-1cbt(??d%+jje;C4*a57IuC#2&Rff??x`)h>=(^{zH!sDpI&m3amE=ZTzR(c`t{rNE00?D=Or_D zZT@uc%IMtr8_w$e=E?W$@1EE-q3gzhw~>Lp$YC(C#~t3)_4%Y}$P~DAcTGSRXl08g z9fizWc|`Bltn=#n^v~YUe`oQspX_(i7f)M`5L2f0PU)IFd1_bJBpcF?n1`Q{u2o+j zI!YvQV13Dvvqah>V(M!bR6%{XB(hlRX2GPBkrRPq}Jg%$Hj2#ZZJC zr`4Y`Y2KtGj$ZS<@3_xSHlpwU_#De&tL@WX`&A8@qrIN1jbsv7$rR*}DKpwftvG&4 zch{tDFp2RN0y@z(A@PvqhV5_6*udT}VX#MiqN-o}QO_@rIPp(6&%jn(`TO72j@#pX z?8v`elwWqp@{i9ZmD%sKF8tONPwwE>V3$38)T`(nu?lWxrhX+`c`ht@zuX zn=by^-`8LA{MF}qQ})%qTMz%vh4^n?S$@lXM=g8rjk%|td-zrFo-b_rea5xp^Iu=P zZq~=f{tX*uUvr*q#+qxNKCE!pnwj5yVd-9}>*gnEa>dKvsH9VWJ6b@VSp7K}{J8Y- zw^aN=7x&SA=8o#}=FZ4d_uli3yKRZat%thUduChKT)pE@%5|9!s1;Y=^4_L9j$E~N z>z@#O)iZx9cQd~pxPR04p549sSKpq#>}}gsw?EM{agT@#kB|T?_W-cm*a4QV?y++; z`9FsunhqH)MuQnKwNb=^7!ly5?Z^KJl6@6qyne;crZ2eS<>Q@!J(Kq>Z+@e1PyY>3 zZ+P#Tqc7X>k*Dy%)Svet-ESVX^uxgPXD&uJegC6vkEPe2kUw&HCu*^`^^p0j=V z*Peg;%+06&;{CaECR{o5wuSQ+E6**N{c>vF&u^?;=?sP+_@y4bSt%TJ*Aql+?^aEXN0VuAGEpkGiBR*NTFy)2Loq>3oxhZv^eHq|^EUf|&xBD#Kd{(|H|42Sxax z#Ookr;IkdyCZ%;XSvYN6M`a1V)jETkBmHZxw_HtfN*2U}HkD2|wD}_igd-1;a<#lg8&Ch+j z={LW4!_to$pXVQ$y7xl+C2NAZXKWAM_Pgu+GxDGJeiHxb1 zdE;}^2|M>}yQ}=_T=K6cKlX01v2WMr`SUlua#4@vu@j%$KKJ?jvp1Zu=+OPw-*UM; zu;Srk&z`Qo^7ao2*E=h08;<|K{!e7eDaL@b;hn;BF)K@r%z@He7T)d)KkQy$Uw+AS~s$gn-o_v)$J&RMri7m4rt z$LasNoRx1xX03}jV(Q&zozU}ubJ8sjyplB~S3G_BA-C>%HTcFGTVKD5m_7UZTW9^+ zeAAy!zIV;@YZm7gyno%FclYji;hdW{zA*3`#|;Z^os4aIVfAC#{jYtr_p0@~?%7%U zBeQef%X7C3+;_prpFj4=)9KgWyp;cG>y7so99I3ol%KFK_oufso~i0w4-NdN{>1S+ zdxgiZ7`W>33p}rscdmP>^x^xv&+$w3cYeF&v2_1U_pLnZ@#TZhToJ!-Yw&l!x{4^A z`^wd}&DYNq_@}mAcjdX>pDofKbF7b$rZoahzkE6bXx%nsu-lBx z8Ue6wWIX>lDAgzr!wK*o9!Vj6!_P?fs)fTO1`JvrLt|8xuZk9kbE}A9qAJ;!yea*R7?GFF>XS3d#IPY5zZCSbXUG%Lv7caNIbu{|^N%!}hJ=4t% zyg%VzH&5SjDznnE=C6C_Rt7J9G_{?2{rI&@f1lrT*WuIuR_5-#?#9n<{l}eG*?)58 z<(B*Z{?=XIYo^@s)BRf?4W@s;_F_Z!!j;$RpM6_)?P&aK-@E0%IDR5Ze;wSW&vx}4 zcg`7W&bj>MIma*iG<51GD|&u+?|0QtpO`;*#?QA2`e!Xq?%H+Cz^?OA{n!6_*^`^k z*|WCi`j6*4{N@?D&1Zd5ADH;i^OGk%kojThCjE+a=Us0Y>|P7@^lkV>12S;g{}9}E zf6)z${ep@6MsNVim;xoYn|5Ebd*HfXeRR{zzpT9E^_9ENY+dm43%_;b zuKXV^Szli>b=rydawqPe{)=Nid1})Y)pd6q*$P~EJAKWpxA;4L`Nk3J8=w8=Te}h; z4KABC|HXBZ>CMlsJ^I08bGvu0-uW3;J9Lx(B4MZhvRi+|C7`tXA%{m|gFmV0(R$tM2t$K%=32TvMi(i08o)uC8I8)QtlCH-81E9C zU?+iqNx{aLl28I9K!5}Y!N3b(0@!qeaY6|sm>v>`nDWj@t1a04llQ*=m-n8(Z!O(B zckVs6oZtDKbFPqK38b)mD68B?e9&7ItR)Ralc zaBpO+S=ZL#UPsSxFS+9MdQQ>Rq*6Iu$e-4WE<<{CQeG&C>AZYeZzyQ*xAvaCa^{L9 zq?ZWBe3Y)Jq{|hZFNC`pLf6}`*JH(^BI)&Hkkt9yOdzO(KJDb#!T8LNR5hF_ZN;;XAO1_em zOxH*Ii>}lcA1xRIh^gTX6^g8% zRVl93r~82M{HjW~*Vjejo-7~X^J2u_;0e4b5GGkl<285AT4lMiO0@f+Db>jZNrJ!v zj7oAbr>np-u%aG}qi~$VNLi+QnD(425bzzxJOQ5+RXCwSAgG8iR8YmKMzC&)7c%-f zTc(oPMqiSNWXpX-A{EKx%yE*<6y&BkV=D`WihzeDpNbTvL{iD6(%zUvm!biJCaQi; z)E6=VyW3r_lHsB$-teG$iuXq7u*n?>R4iC6$rkedY9-(ZBVx=W4;JiwqU=d0N|6xn z&oq=ld#R81BnM1=sw874d%IG zNby^3hUS1cP<3accr6=pRpSXWp0LDfxrW1u76Znjh&Tk)S4UHbDwM1xeV&e%!|{@( z&(#pjAp%n=42ydSEF-J3%pfeLYG+xbR0`Lt9Km9k>d?-TAIadjtlA4$h)51#cAhks z44f;Qa+#g!REBgW%f$gk6|flNQe&`(AqVUw#gllNB@mh*$~4A>?06F+QfYfZbof0}7R*MeJfDL4g~f^i^QV2}zf3ws$*jU-l%dS#>xp#05GB$is(>N*^LgfQwae$n(lF?*nzX$70E4g^YlY&oe z4yur|XW+XwCv7~0kDy8-?{B&@m=Txd5-wAAoD&GlA1lQjenfDv+S$C6fxBr(^xzDcZ!iLK|HiL%RFNDg{qs+Z@Y3aYmt4K9FK z_y`$gNH^exhBbb~hj9))fINxG62{^zO{7Qn5zd;>8V8d@2YJSgJ;TQKp9Jh7)DVW5 zz{YS`P4Fkltg4oq6|0c1yK^P8z2VFnyh<{jXb^#voJyyI44KjUDwy5pZ5kR)lh@CR zbu%3x1AcQh&qXa(E;Ufi$+>L6Ggy?t$Jm#`WQo%?YSQ~FGIjZIXS1gd`o7u3HDE4uMaDcW29MXUbVZ%ftY-px< z6X#cv2x851Y|&tIVNy9O5^mX%u@G^k>O)+CL4OD|%8ME7QHrMAKFO_A2eYbS(5@$v zQPs{SICoe|1sqO?(?=L6=r|Km^d##Hru{5xN%%c@*+?o_F=(gUoH669G>v6yP+^lK zUmvhmQA@!ndaC*wlg10xJ`S_SD0|9O4NGBqFx8?Oag7Fa2+IiTASr)8r4c<2cM zOe+(JON#|~Np-xX5QqZ9cr`0QCRNa6s!j$mH!dr3Dl6kW$5NO~f#&X?wn~=0 zdYoa%YLh0g0YN1JA1Wqs}%GWc~0NIwIkS(<6W;TRzCFvY_eNC4LaWS+nh`6#P0GADBuXQm|K0g0k2$@;(m56cxu2_U{y z%aM#AXYxi+XUWcK7RmwVt8Uk17lAQ?wWx}~%4C`DgL90R!D3aKI71S6CSgFvkhf(y zTb4&-b(Q$|`O9k7OFA8qjOY$#7;_+PuJTb1EXU}6R1eq>#sMm2n=l5nA7#hxoLLba zBCy{|F_9Chi5##Z1E9QN++JlsNK6fA*32En8wq2|-2UW&ZHF5qE<*oi?F=Ap*q?;M zuLx-rERoHi$uG!iL;y<(eIo9tA5FlR31Y%?&;@g|(>JVJHj!s50=r^i$_~5 z-VBTs6>@4tJG*d}8WZKf3kjpYDbO|;N0YNHA4^g!W6;=yIo0+SG$zv7YX)=>bS!{s za~ajg1I`y!W}T4%}H zsZMOfTfotd2QooNG~NG#Ck5UR)%K)h)z#@c0Bp;h8S}F66ibA|tm;S!9yZ9SprItCat#%#uUMlP@qoxYuk9Q#F&Cmd?x1{TL?ya7ywHQ7L~X*^KHaSTgi1_r~O znWDRiV!~jsl5IE}vY!R0CBjxAk_qM=f*nurWHpk*14UrSm1HoJ30CWMsuIQ4iPLzkQTu~*%ebf8suUI$yl?|su!bpch%F^@TVMhQg6&j zg+{8Ft9ez~7s~r0!FoPmidXsunL6}Aqq%g7bfK6r6to&VT+@Q2b6$lt3}g~wAzCqT z$%dWH^~F+Yk<7a7Xw4mp%d7>LNwdY(aA}@qH3nGgtQ0U7xC8^Fg7pm4()u7RSHCDb zOAB?niSg~T!m?Dy%eOmg2_xV>Ldos`?qHi#jwQHGbU^H!X-@NcCbDoGymG)IXHj%y z{~Hkm%E*#TgUx7vY=c#_2m*YPOkGocSZ$TH7gQlLCJ*TEs5~K~0?a=Qx~pi|23XXI zbbxM<+`mIFc#Xl2*Ne_s0T0!IA)p%=Un<)9T9UWs5y5206q!W0jD|cpzpKIf3%O*; z$v6hmwy^9odYyxoy5ev*25MdlhgUEv=y%lP&Ow8mC$dVq8qMK3n=fe}%*aVWm6Mzb z+*0!@f^DxNq{6u131Z2%*TPaXiA7{QFi`ebQW4V2erO*T~xsf0zdRtOfvUr(7*h$H0f7#HNsTZUim7;)agQs|ktwE}8ja+#)57;bsU!m2ydOhhl8pEmjF*J?^d( z(WacMdP-%-%Ct0|KlJPof41rL&04)WnimW{QqF z8Z4qlcQ9Q~4@UImnA1oVeP|%4>e;~t*g6u|Y#p3|ktiZ#HxUI7&1WrTh)hkebr8w; zU#lya)bbNZstyrDm2EO$@4|7d&P!4au!(J*Z{l&5GSyuftkA(JCJZQJXJn1bi#esm zzvB^ep0NY>F#r$KY`HrYKEqF*aEj!6z0XzfTI1Le|G}iHD z#SD*yaMn>)rEz0vQKtk~FNNt;5u!f8>Bgea5UJ7XkVFGd!*_`MgtH99D`SQ_d{;EC z4iPB6CZzG42>hw#r{!50_F9V~RbvqqqE6P9FV)&}&9`%eGZ2ZBA-a`y1D^+O*5*GB z?Q8%CGQwZOG?5#4l|WNAsP%#z=R7(^zENM? z;K`D>=A$2g8w7>`H=sfU!;!UIsV)}m#ax08n43W>NAB|Lh(!kT4|?z@6ZmDZtG;ku#0&BL4=i3#ktY8zlWX-dlofLzyNb1RcQa z3I-8cEKcC&rj`{L%X|xB1kl1k$Q?)L*-R2!~jtV}t?KC@GeNG$5~&}<`Ss%88#6VCbh zv}~=CcwpijtaX17Cr51xL}*Elb!g|R#SPkJLW{w`xq{4(hBvLu4@3kR9GqzfE{95_ z%t9XGz~?~LwFu-0Mrlz*Kf_Wn?aY-GS297xEm5DlCh!C!*o!3zqHuOJ;^ZL=$xx<9 zKsEF!CXPvAF0qkJH|xHXQJ=AL6<4f`#f_D)81VZHN}m|xtj=asP+W);QfjS)*320b z{%OTlF45=Xh?FE`M-yS4q}fP}jDiGVMUirlC>%?cjU*$Xk5;#>jv%i&lHn9PiMC~V zsiGE2Sx8NGzDi?R$#&{;#){F*8%Q*gsf0{vf3Z}kH?;q2X;CVT%l&DRkF*mCc}Q|r z`XO>xkxKuhaWO7rrAmLLn$JthKWQuG%WVM;KCbq-ELAEnF<6w*^y)atN|F+99Q;wW zr2K0FrwWyFu~0dvsH34w81tZ;P?m&hDP3u__GBd8+b@?2)#B(j9(3tjO|;!wCXOVN z4?c^rjPSCP$G7;Wf@xXsjy$llBl+jf@f+RRas7`MX4#iywkNCtoGc*~Pv`sNf*_U4 z|H`z-4fkK0&e&nENby|%zci!q>!n4d$LIE`dNE!4@;thw9~tOJ3_--E<j+W@2Wbuh6y$4gf( zF4Hx2g=K|h<2%vNA(+ld!Gb$o8w<;)LE&Yov=UOuEA*Yh2vmha4B0tH9SP$JBVtOJ zk^TXbG1+f24%qr_W>dW1Y_bRg1Ev88>6*ScY`A?BWVEZ!FzC1uJDavb-@2}`a_jKi z>yY7|5HdXZw5^l7ySlsQFJH5E=DSaKU-ib@Fa2QG_M5)C`GfREWX|aQldf5CAtlke zpE5brGxhN9Pyjs~Idm!%W*$BhwnmY3OkP-qo`5XXDrX(Os9iaBeF1K8=&))fRnQb2 zU4YEj+D$%uPP?7IP^jpD)*QQVjsZaps0Fndt!4|qaE?(cBJF=XQbkDwZ@oEtdHc;s zp`?f^9A(|;oe7;E08P6xQr3Oh_}WbyP0rcfw0U$Uv&YY5q(y74$Z%Kh_|@o|GHLQ~ z*F3nR(>1euxT|Z@m1n)Uc>h1{-Qnt8@$hpe{A1z1kFGp+rFdxa^7mHX_fylaZ#-p5 z{<&i}F1g^8%C@p&tCMbhH2LWx>lf_2t!KsX-D{Os zKc89Jd(&sj3y%A?Y&ev??A+VVxme$QjOP>PzUK>fc<-zK_QgH7J^tvf9U!tM#|c=jmk@Tohlciiwg2p|uRCo2 z`w8#VH{ClI@5*g?r~G1l$($>SyX=vRzb1cUTUniXeIjw^EyZ>BRFAvx=EmRNxb~S( z&p*L1bNSLs&d^=8d8dBu5u09KG3(7cK7D&_WZuFpr}usH#C!I2Pwtx3b-?t-8Z>-Ju?4#^=maY29KAJsm`f7xn zI=ydd*OV#Ky1II-hy^iq%1GC`uZ~a0 zWUlsjo;H&n(2}XhAya3zu5Ah8)b6gHZcvGd8UkmcYZCvE`RZM7%-rI?deU&O`gloy z@yESCn}7W8Zk&mqeaQpAt}fc^-u{(8uF0-CWcB_tsLGu8o9BM(dr#~UHsBXNb;R$n z+oM~iPXDIk&y+`f9f#ht_`!k`~1qc3tcxp z!BS_x^o_w};*Up4$m8ojrvm%)`@f|U4?2X8_i?wERySS^KY8yx-}sf4uitX0!+*~l z^M;Lkepk6X^;hQXjW>OG{q0{_ckzzjA;h|;|5)tielc|a^*?y#t+#&u?HQ}yvtD}J zb@ z509UGcjzMatT`Wu=HtHN`buok?Hl*~ZS$5VeRpq*`s9nI|3bI#v71iO6^eJB-i3Vo zF5<~~SDf~jKIW@OJ@VNTcl>JZuGPmp_t3q+)TkD7iH0toZ|I6~xI(Fmm&?_hRMu&PuUKinlZ1C9 z?Juv>#sJQl0FzpVr=oU65*&scypR`l;6;e(wrwjUb=9(T%7lT61$b8*3|fwkubJLr zDK1pfARhEtX?sY^zMz^d_&U?_BX@uOu6Mq@Y4=~$O&`{tQW5XA#TT4^!O=fDjUM>$ zhE1!!d&)DnUVPXK_kC2}^zKvQyvG_|(+gLx{J8#k_K|6CpKCjRLqPYm^`TpTbGdhB z_Vd0^V%JTX@%4qP!iOGPdHSvm$1SI?dA6|h)xA6KD*k>R^~#CcKgiYJdGn5i3$Ne3 zrq{gv_-A*`doKIT)k}{%bl+7sT~r=A`?p7*F++dJZGR^n@1Jem@|C}yc7m*1Z_MnQ zGyLS9z1QeJ4rI;{?-z{fzEh{265jjbyd`sAyt{m)_l{kb^R|66wClPb{mOvvf8p7| zEo-jw-*xn_FU6N0cJjmX7Tw8iUM)Q0TD#D9fqK$Ev;R$1y4{bXje#dfwZiZ|37e`hhI65INE>b{Z9@c zwoR|y^um?sE?@uePu_Xvrd7Id?47@y`j3nJ}`m58I_HLtlZrZjxZH%A& z)J2EfviJ9aH{RIs`laNYIX~Pn`xmBbe|O@&8=l*+EVKBd%U^!0Z_o2*-njMopcmOmCs~{;%)e zp0r$h-`dk3TRr^r_hR?$2>j;fmy*g^yEj_zxN4RpKDqPqOU`oNaGd_AqdjC{dfm5y zyYanux%U=ktwVqN!>1#F)@?#QRvnK%JXI})l+5a~| z&eB;Mfc29P4(nr3DaAW33W8`mxVYye1nA^epp)wsclKcdnH<@LiFDFzopRQL7ev=Q z%HF*7kf-sQe*>h0I<+wo{1`M|~Jq3LtieqaC0 zdu7L-`ajM3WV}9bzH;)>6^Bhe7)xTZ%#2shuy}0+P{d0f&r{%gkPXDAfH2If9r?GWtH*&A8R@fr4Ry{IdyvbhbEJ!!SU;S@9yrNv=%JcSh;HzGOhi~lW7y{ zzdGLF!4QBJlcs&>kw3fgrU!<8$!u-Rxp|7T=&=6G!``3WFva)OF@OKlw)AxNmiyi> zNH=f1=jCV5NzZp*f81GXpWe3Y$E$8xv*Xe0W(kXLe00j6w|CvpT)OA5z1I&fesD_k zs5QGc?A-ptAxqcIA52Q0v*Y^j=yv{X`j20JVbbnbKaIck$YtNc-#zNc{7cif@18mL zm+w=?ne$(H-xz)6cvtsflLou9n?G5#Wd6;$&q8aSTyxzMOTCFpUa(|VOx?WT_@`Gs z;C%2M`47jQ#PKtSv2! Date: Wed, 29 Oct 2025 13:42:57 +0100 Subject: [PATCH 16/28] Test workflow --- .github/workflows/build-macos.yaml | 3 +++ .github/workflows/release.yaml | 2 -- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-macos.yaml b/.github/workflows/build-macos.yaml index 95c2acf4..0bcb8b1d 100644 --- a/.github/workflows/build-macos.yaml +++ b/.github/workflows/build-macos.yaml @@ -1,5 +1,8 @@ name: Build macOS app on: + push: + branches: + - swift_plugin workflow_call: jobs: diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index dc8eee97..8b0575ee 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -212,8 +212,6 @@ jobs: - self-hosted - Linux - X64 - strategy: - fail-fast: false steps: - name: Sign APT repository run: | From 76830ce599ea921c149f8ccfef769d0f41bd410e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adam=20Ciarcin=CC=81ski?= Date: Thu, 30 Oct 2025 12:55:59 +0100 Subject: [PATCH 17/28] Update dependencies --- src-tauri/Cargo.lock | 39 ++++++++++++++++++++++++++++++--------- src-tauri/Cargo.toml | 5 ++--- 2 files changed, 32 insertions(+), 12 deletions(-) diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index 46e7f0dd..265ffad5 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -647,6 +647,7 @@ dependencies = [ [[package]] name = "boringtun" version = "0.6.0" +source = "git+https://github.com/DefGuard/wireguard-rs?rev=0db4ea7bf4a6bd21c449f9ab8fa6676aebf4698f#0db4ea7bf4a6bd21c449f9ab8fa6676aebf4698f" dependencies = [ "aead", "base64 0.22.1", @@ -947,9 +948,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.50" +version = "4.5.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c2cfd7bf8a6017ddaa4e32ffe7403d547790db06bd171c1c53926faab501623" +checksum = "4c26d721170e0295f191a69bd9a1f93efcdb0aff38684b61ab5750468972e5f5" dependencies = [ "clap_builder", "clap_derive", @@ -957,9 +958,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.50" +version = "4.5.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a4c05b9e80c5ccd3a7ef080ad7b6ba7d6fc00a985b8b157197075677c82c7a0" +checksum = "75835f0c7bf681bfd05abe44e965760fea999a5286c6eb2d59883634fd02011a" dependencies = [ "anstream", "anstyle", @@ -1450,10 +1451,12 @@ dependencies = [ [[package]] name = "defguard_wireguard_rs" -version = "0.8.0" +version = "0.9.0" +source = "git+https://github.com/DefGuard/wireguard-rs?rev=0db4ea7bf4a6bd21c449f9ab8fa6676aebf4698f#0db4ea7bf4a6bd21c449f9ab8fa6676aebf4698f" dependencies = [ "base64 0.22.1", "boringtun", + "ipnet", "libc", "log", "netlink-packet-core", @@ -1465,6 +1468,8 @@ dependencies = [ "nix", "serde", "thiserror 2.0.17", + "windows 0.62.2", + "wireguard-nt", "x25519-dalek", ] @@ -6295,9 +6300,9 @@ checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" [[package]] name = "tauri" -version = "2.9.1" +version = "2.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9871670c6711f50fddd4e20350be6b9dd6e6c2b5d77d8ee8900eb0d58cd837a" +checksum = "8bceb52453e507c505b330afe3398510e87f428ea42b6e76ecb6bd63b15965b5" dependencies = [ "anyhow", "bytes", @@ -7421,9 +7426,9 @@ checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5" [[package]] name = "unicode-ident" -version = "1.0.20" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "462eeb75aeb73aea900253ce739c8e18a67423fadf006037cd3ff27e82748a06" +checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" [[package]] name = "unicode-normalization" @@ -8719,6 +8724,22 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "wireguard-nt" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22b4dbcc6c93786cf22e420ef96e8976bfb92a455070282302b74de5848191f4" +dependencies = [ + "bitflags 2.10.0", + "getrandom 0.2.16", + "ipnet", + "libloading 0.8.9", + "log", + "thiserror 1.0.69", + "widestring 0.4.3", + "windows-sys 0.59.0", +] + [[package]] name = "wit-bindgen" version = "0.46.0" diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 664f2331..a3125d6f 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -4,8 +4,7 @@ default-members = [".", "cli"] [workspace.dependencies] clap = { version = "4.5", features = ["cargo", "derive", "env"] } -defguard_wireguard_rs = { path = "../../wireguard-rs" } -# defguard_wireguard_rs = { git = "https://github.com/DefGuard/wireguard-rs", rev = "e50b6a6f2111381bfc010263210dda91694e1c6d" } +defguard_wireguard_rs = { git = "https://github.com/DefGuard/wireguard-rs", rev = "0db4ea7bf4a6bd21c449f9ab8fa6676aebf4698f" } dirs-next = "2.0" prost = "0.14" reqwest = { version = "0.12", features = ["cookies", "json"] } @@ -31,7 +30,7 @@ authors = ["Defguard"] edition = "2021" homepage = "https://github.com/DefGuard/client" license-file = "../LICENSE.md" -rust-version = "1.80" +rust-version = "1.85" version = "1.6.0" [package] From 61f74693a332f8c54e1d1d28eb7948c3eba48d6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adam=20Ciarcin=CC=81ski?= Date: Thu, 30 Oct 2025 17:02:15 +0100 Subject: [PATCH 18/28] Re-load VPN config when starting a tunnel --- package.json | 2 +- pnpm-lock.yaml | 202 +++++++++++++-------------- swift/plugin/Sources/Wireguard.swift | 131 ++++++++++------- 3 files changed, 182 insertions(+), 153 deletions(-) diff --git a/package.json b/package.json index 682d4ee3..56518635 100644 --- a/package.json +++ b/package.json @@ -111,7 +111,7 @@ "@svgr/cli": "^8.1.0", "@tanstack/react-query": "^5.90.5", "@tanstack/react-query-devtools": "^5.90.2", - "@tauri-apps/cli": "^2.9.1", + "@tauri-apps/cli": "^2.9.2", "@types/file-saver": "^2.0.7", "@types/lodash-es": "^4.17.12", "@types/node": "^24.9.2", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2b88007d..d3ad6026 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -196,8 +196,8 @@ importers: specifier: ^5.90.2 version: 5.90.2(@tanstack/react-query@5.90.5(react@19.2.0))(react@19.2.0) '@tauri-apps/cli': - specifier: ^2.9.1 - version: 2.9.1 + specifier: ^2.9.2 + version: 2.9.2 '@types/file-saver': specifier: ^2.0.7 version: 2.0.7 @@ -1005,68 +1005,68 @@ packages: peerDependencies: '@svgr/core': '*' - '@swc/core-darwin-arm64@1.13.5': - resolution: {integrity: sha512-lKNv7SujeXvKn16gvQqUQI5DdyY8v7xcoO3k06/FJbHJS90zEwZdQiMNRiqpYw/orU543tPaWgz7cIYWhbopiQ==} + '@swc/core-darwin-arm64@1.14.0': + resolution: {integrity: sha512-uHPC8rlCt04nvYNczWzKVdgnRhxCa3ndKTBBbBpResOZsRmiwRAvByIGh599j+Oo6Z5eyTPrgY+XfJzVmXnN7Q==} engines: {node: '>=10'} cpu: [arm64] os: [darwin] - '@swc/core-darwin-x64@1.13.5': - resolution: {integrity: sha512-ILd38Fg/w23vHb0yVjlWvQBoE37ZJTdlLHa8LRCFDdX4WKfnVBiblsCU9ar4QTMNdeTBEX9iUF4IrbNWhaF1Ng==} + '@swc/core-darwin-x64@1.14.0': + resolution: {integrity: sha512-2SHrlpl68vtePRknv9shvM9YKKg7B9T13tcTg9aFCwR318QTYo+FzsKGmQSv9ox/Ua0Q2/5y2BNjieffJoo4nA==} engines: {node: '>=10'} cpu: [x64] os: [darwin] - '@swc/core-linux-arm-gnueabihf@1.13.5': - resolution: {integrity: sha512-Q6eS3Pt8GLkXxqz9TAw+AUk9HpVJt8Uzm54MvPsqp2yuGmY0/sNaPPNVqctCX9fu/Nu8eaWUen0si6iEiCsazQ==} + '@swc/core-linux-arm-gnueabihf@1.14.0': + resolution: {integrity: sha512-SMH8zn01dxt809svetnxpeg/jWdpi6dqHKO3Eb11u4OzU2PK7I5uKS6gf2hx5LlTbcJMFKULZiVwjlQLe8eqtg==} engines: {node: '>=10'} cpu: [arm] os: [linux] - '@swc/core-linux-arm64-gnu@1.13.5': - resolution: {integrity: sha512-aNDfeN+9af+y+M2MYfxCzCy/VDq7Z5YIbMqRI739o8Ganz6ST+27kjQFd8Y/57JN/hcnUEa9xqdS3XY7WaVtSw==} + '@swc/core-linux-arm64-gnu@1.14.0': + resolution: {integrity: sha512-q2JRu2D8LVqGeHkmpVCljVNltG0tB4o4eYg+dElFwCS8l2Mnt9qurMCxIeo9mgoqz0ax+k7jWtIRHktnVCbjvQ==} engines: {node: '>=10'} cpu: [arm64] os: [linux] - '@swc/core-linux-arm64-musl@1.13.5': - resolution: {integrity: sha512-9+ZxFN5GJag4CnYnq6apKTnnezpfJhCumyz0504/JbHLo+Ue+ZtJnf3RhyA9W9TINtLE0bC4hKpWi8ZKoETyOQ==} + '@swc/core-linux-arm64-musl@1.14.0': + resolution: {integrity: sha512-uofpVoPCEUjYIv454ZEZ3sLgMD17nIwlz2z7bsn7rl301Kt/01umFA7MscUovFfAK2IRGck6XB+uulMu6aFhKQ==} engines: {node: '>=10'} cpu: [arm64] os: [linux] - '@swc/core-linux-x64-gnu@1.13.5': - resolution: {integrity: sha512-WD530qvHrki8Ywt/PloKUjaRKgstQqNGvmZl54g06kA+hqtSE2FTG9gngXr3UJxYu/cNAjJYiBifm7+w4nbHbA==} + '@swc/core-linux-x64-gnu@1.14.0': + resolution: {integrity: sha512-quTTx1Olm05fBfv66DEBuOsOgqdypnZ/1Bh3yGXWY7ANLFeeRpCDZpljD9BSjdsNdPOlwJmEUZXMHtGm3v1TZQ==} engines: {node: '>=10'} cpu: [x64] os: [linux] - '@swc/core-linux-x64-musl@1.13.5': - resolution: {integrity: sha512-Luj8y4OFYx4DHNQTWjdIuKTq2f5k6uSXICqx+FSabnXptaOBAbJHNbHT/06JZh6NRUouaf0mYXN0mcsqvkhd7Q==} + '@swc/core-linux-x64-musl@1.14.0': + resolution: {integrity: sha512-caaNAu+aIqT8seLtCf08i8C3/UC5ttQujUjejhMcuS1/LoCKtNiUs4VekJd2UGt+pyuuSrQ6dKl8CbCfWvWeXw==} engines: {node: '>=10'} cpu: [x64] os: [linux] - '@swc/core-win32-arm64-msvc@1.13.5': - resolution: {integrity: sha512-cZ6UpumhF9SDJvv4DA2fo9WIzlNFuKSkZpZmPG1c+4PFSEMy5DFOjBSllCvnqihCabzXzpn6ykCwBmHpy31vQw==} + '@swc/core-win32-arm64-msvc@1.14.0': + resolution: {integrity: sha512-EeW3jFlT3YNckJ6V/JnTfGcX7UHGyh6/AiCPopZ1HNaGiXVCKHPpVQZicmtyr/UpqxCXLrTgjHOvyMke7YN26A==} engines: {node: '>=10'} cpu: [arm64] os: [win32] - '@swc/core-win32-ia32-msvc@1.13.5': - resolution: {integrity: sha512-C5Yi/xIikrFUzZcyGj9L3RpKljFvKiDMtyDzPKzlsDrKIw2EYY+bF88gB6oGY5RGmv4DAX8dbnpRAqgFD0FMEw==} + '@swc/core-win32-ia32-msvc@1.14.0': + resolution: {integrity: sha512-dPai3KUIcihV5hfoO4QNQF5HAaw8+2bT7dvi8E5zLtecW2SfL3mUZipzampXq5FHll0RSCLzlrXnSx+dBRZIIQ==} engines: {node: '>=10'} cpu: [ia32] os: [win32] - '@swc/core-win32-x64-msvc@1.13.5': - resolution: {integrity: sha512-YrKdMVxbYmlfybCSbRtrilc6UA8GF5aPmGKBdPvjrarvsmf4i7ZHGCEnLtfOMd3Lwbs2WUZq3WdMbozYeLU93Q==} + '@swc/core-win32-x64-msvc@1.14.0': + resolution: {integrity: sha512-nm+JajGrTqUA6sEHdghDlHMNfH1WKSiuvljhdmBACW4ta4LC3gKurX2qZuiBARvPkephW9V/i5S8QPY1PzFEqg==} engines: {node: '>=10'} cpu: [x64] os: [win32] - '@swc/core@1.13.5': - resolution: {integrity: sha512-WezcBo8a0Dg2rnR82zhwoR6aRNxeTGfK5QCD6TQ+kg3xx/zNT02s/0o+81h/3zhvFSB24NtqEr8FTw88O5W/JQ==} + '@swc/core@1.14.0': + resolution: {integrity: sha512-oExhY90bes5pDTVrei0xlMVosTxwd/NMafIpqsC4dMbRYZ5KB981l/CX8tMnGsagTplj/RcG9BeRYmV6/J5m3w==} engines: {node: '>=10'} peerDependencies: '@swc/helpers': '>=0.5.17' @@ -1109,74 +1109,74 @@ packages: '@tauri-apps/api@2.9.0': resolution: {integrity: sha512-qD5tMjh7utwBk9/5PrTA/aGr3i5QaJ/Mlt7p8NilQ45WgbifUNPyKWsA63iQ8YfQq6R8ajMapU+/Q8nMcPRLNw==} - '@tauri-apps/cli-darwin-arm64@2.9.1': - resolution: {integrity: sha512-sdwhtsE/6njD0AjgfYEj1JyxZH4SBmCJSXpRm6Ph5fQeuZD6MyjzjdVOrrtFguyREVQ7xn0Ujkwvbo01ULthNg==} + '@tauri-apps/cli-darwin-arm64@2.9.2': + resolution: {integrity: sha512-g1OtCXydOZFYRUEAyGYdJ2lLaE3l5jk8o+Bro8y2WOLwBLtbWjBoJIVobOKFanfjG/Xr8H/UA+umEVILPhMc2A==} engines: {node: '>= 10'} cpu: [arm64] os: [darwin] - '@tauri-apps/cli-darwin-x64@2.9.1': - resolution: {integrity: sha512-c86g+67wTdI4TUCD7CaSd/13+oYuLQxVST4ZNJ5C+6i1kdnU3Us1L68N9MvbDLDQGJc9eo0pvuK6sCWkee+BzA==} + '@tauri-apps/cli-darwin-x64@2.9.2': + resolution: {integrity: sha512-nHHIY33noUmMOyFwAJz0xQyrYIXU+bae8MNos4TGsTo491YWAF2uzr6iW+Bq0N530xDcbe7EyRvDHgK43RmmVw==} engines: {node: '>= 10'} cpu: [x64] os: [darwin] - '@tauri-apps/cli-linux-arm-gnueabihf@2.9.1': - resolution: {integrity: sha512-IrB3gFQmueQKJjjisOcMktW/Gh6gxgqYO419doA3YZ7yIV5rbE8ZW52Q3I4AO+SlFEyVYer5kpi066p0JBlLGw==} + '@tauri-apps/cli-linux-arm-gnueabihf@2.9.2': + resolution: {integrity: sha512-Dq17LBdSuzf+fWOKMIyiSao+Fcq4FiQwYYlx3Nk8oafDINc8sVBjC5gv2xp18KzYhk9teSWfmDpD1sj+D3t7uw==} engines: {node: '>= 10'} cpu: [arm] os: [linux] - '@tauri-apps/cli-linux-arm64-gnu@2.9.1': - resolution: {integrity: sha512-Ke7TyXvu6HbWSkmVkFbbH19D3cLsd117YtXP/u9NIvSpYwKeFtnbpirrIUfPm44Q+PZFZ2Hvg8X9qoUiAK0zKw==} + '@tauri-apps/cli-linux-arm64-gnu@2.9.2': + resolution: {integrity: sha512-Pxj5k29Rxj9xEht4gdE744t5HLXTwBojkjYDXXyJ3mE+BEg9hFX5WkStg7OkyZwH60u8NSkDSMpo7MJTH9srmA==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - '@tauri-apps/cli-linux-arm64-musl@2.9.1': - resolution: {integrity: sha512-sGvy75sv55oeMulR5ArwPD28DsDQxqTzLhXCrpU9/nbFg/JImmI7k994YE9fr3V0qE3Cjk5gjLldRNv7I9sjwQ==} + '@tauri-apps/cli-linux-arm64-musl@2.9.2': + resolution: {integrity: sha512-mx82BuD4q3Yj5Zw+LXveZgPaDCnmH2At2LosX1siK77kaD5Ap5FF+FN0V4y+3cwq+Hcrk9AhEUPbHqoNOx1R2g==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - '@tauri-apps/cli-linux-riscv64-gnu@2.9.1': - resolution: {integrity: sha512-tEKbJydV3BdIxpAx8aGHW6VDg1xW4LlQuRD/QeFZdZNTreHJpMbJEcdvAcI+Hg6vgQpVpaoEldR9W4F6dYSLqQ==} + '@tauri-apps/cli-linux-riscv64-gnu@2.9.2': + resolution: {integrity: sha512-Ypm1nnr7k+ECC1+JfDcnxROHt6BX8t/4GplxBvdY68BDXtIcBbdhPWDos7MK+3bDmoaA0WSJbW+DUjpfSkyKgw==} engines: {node: '>= 10'} cpu: [riscv64] os: [linux] - '@tauri-apps/cli-linux-x64-gnu@2.9.1': - resolution: {integrity: sha512-mg5msXHagtHpyCVWgI01M26JeSrgE/otWyGdYcuTwyRYZYEJRTbcNt7hscOkdNlPBe7isScW7PVKbxmAjJJl4g==} + '@tauri-apps/cli-linux-x64-gnu@2.9.2': + resolution: {integrity: sha512-tg85cGIM9PWwsbQg8m3uah3SfoNapgUr4vhWtkqgeTDZOjQuQ2duTwCH4UiM7acBpbZHNzvRrxSFpv0U53TqQQ==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - '@tauri-apps/cli-linux-x64-musl@2.9.1': - resolution: {integrity: sha512-lFZEXkpDreUe3zKilvnMsrnKP9gwQudaEjDnOz/GMzbzNceIuPfFZz0cR/ky1Aoq4eSvZonPKHhROq4owz4fzg==} + '@tauri-apps/cli-linux-x64-musl@2.9.2': + resolution: {integrity: sha512-xW8qaz9bcwR35W2gIg7fKG9e1Z34idOsGpD2zIPgxlJyF314B/1qie50hbOqt5AbbXHR4iRpxKE4kA2grqMmkg==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - '@tauri-apps/cli-win32-arm64-msvc@2.9.1': - resolution: {integrity: sha512-ejc5RAp/Lm1Aj0EQHaT+Wdt5PHfdgQV5hIDV00MV6HNbIb5W4ZUFxMDaRkAg65gl9MvY2fH396riePW3RoKXDw==} + '@tauri-apps/cli-win32-arm64-msvc@2.9.2': + resolution: {integrity: sha512-A1PshB8oHdY7zYOPlLD7Om7/aD9sOUVREd765ElIzYDtptWcALwOP9jb22Wi01vDTqxf98E4ZGIcG2gxr4FhiA==} engines: {node: '>= 10'} cpu: [arm64] os: [win32] - '@tauri-apps/cli-win32-ia32-msvc@2.9.1': - resolution: {integrity: sha512-fSATtJDc0fNjVB6ystyi8NbwhNFk8i8E05h6KrsC8Fio5eaJIJvPCbC9pdrPl6kkxN1X7fj25ErBbgfqgcK8Fg==} + '@tauri-apps/cli-win32-ia32-msvc@2.9.2': + resolution: {integrity: sha512-AuCi0Vnc4qkXRLCC58das0u45SmXAjqcOjqF324CBKa1Z7jjNJESm0Sc2oc2G2q6f2eAbAfi34s2iJNaJU1hlQ==} engines: {node: '>= 10'} cpu: [ia32] os: [win32] - '@tauri-apps/cli-win32-x64-msvc@2.9.1': - resolution: {integrity: sha512-/JHlOzpUDhjBOO9w167bcYxfJbcMQv7ykS/Y07xjtcga8np0rzUzVGWYmLMH7orKcDMC7wjhheEW1x8cbGma/Q==} + '@tauri-apps/cli-win32-x64-msvc@2.9.2': + resolution: {integrity: sha512-kDoejyfvME/mLkR4VofQnmVPTt/smJvoXuE3xgTbUwcUQKqawM8EyQvxOHQosaJYfQphHi7G0ya8UZo3PlDZig==} engines: {node: '>= 10'} cpu: [x64] os: [win32] - '@tauri-apps/cli@2.9.1': - resolution: {integrity: sha512-kKi2/WWsNXKoMdatBl4xrT7e1Ce27JvsetBVfWuIb6D3ep/Y0WO5SIr70yarXOSWam8NyDur4ipzjZkg6m7VDg==} + '@tauri-apps/cli@2.9.2': + resolution: {integrity: sha512-aGzdVgxQW6WQ7e5nydPZ/30u8HvltHjO3Ytzf1wOxX1N5Yj2TsjKWRb/AWJlB95Huml3k3c/b6s0ijAvlSo9xw==} engines: {node: '>= 10'} hasBin: true @@ -1377,8 +1377,8 @@ packages: balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} - baseline-browser-mapping@2.8.20: - resolution: {integrity: sha512-JMWsdF+O8Orq3EMukbUN1QfbLK9mX2CkUmQBcW2T0s8OmdAUL5LLM/6wFwSrqXzlXB13yhyK9gTKS1rIizOduQ==} + baseline-browser-mapping@2.8.21: + resolution: {integrity: sha512-JU0h5APyQNsHOlAM7HnQnPToSDQoEBZqzu/YBlqDnEeymPnZDREeXJA3KBMQee+dKteAxZ2AtvQEvVYdZf241Q==} hasBin: true boolbase@1.0.0: @@ -2306,8 +2306,8 @@ packages: node-addon-api@7.1.1: resolution: {integrity: sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==} - node-releases@2.0.26: - resolution: {integrity: sha512-S2M9YimhSjBSvYnlr5/+umAnPHE++ODwt5e2Ij6FoX45HA/s4vHdkDx1eax2pAPeAOqu4s9b7ppahsyEFdVqQA==} + node-releases@2.0.27: + resolution: {integrity: sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==} normalize-package-data@2.5.0: resolution: {integrity: sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==} @@ -3689,51 +3689,51 @@ snapshots: transitivePeerDependencies: - typescript - '@swc/core-darwin-arm64@1.13.5': + '@swc/core-darwin-arm64@1.14.0': optional: true - '@swc/core-darwin-x64@1.13.5': + '@swc/core-darwin-x64@1.14.0': optional: true - '@swc/core-linux-arm-gnueabihf@1.13.5': + '@swc/core-linux-arm-gnueabihf@1.14.0': optional: true - '@swc/core-linux-arm64-gnu@1.13.5': + '@swc/core-linux-arm64-gnu@1.14.0': optional: true - '@swc/core-linux-arm64-musl@1.13.5': + '@swc/core-linux-arm64-musl@1.14.0': optional: true - '@swc/core-linux-x64-gnu@1.13.5': + '@swc/core-linux-x64-gnu@1.14.0': optional: true - '@swc/core-linux-x64-musl@1.13.5': + '@swc/core-linux-x64-musl@1.14.0': optional: true - '@swc/core-win32-arm64-msvc@1.13.5': + '@swc/core-win32-arm64-msvc@1.14.0': optional: true - '@swc/core-win32-ia32-msvc@1.13.5': + '@swc/core-win32-ia32-msvc@1.14.0': optional: true - '@swc/core-win32-x64-msvc@1.13.5': + '@swc/core-win32-x64-msvc@1.14.0': optional: true - '@swc/core@1.13.5': + '@swc/core@1.14.0': dependencies: '@swc/counter': 0.1.3 '@swc/types': 0.1.25 optionalDependencies: - '@swc/core-darwin-arm64': 1.13.5 - '@swc/core-darwin-x64': 1.13.5 - '@swc/core-linux-arm-gnueabihf': 1.13.5 - '@swc/core-linux-arm64-gnu': 1.13.5 - '@swc/core-linux-arm64-musl': 1.13.5 - '@swc/core-linux-x64-gnu': 1.13.5 - '@swc/core-linux-x64-musl': 1.13.5 - '@swc/core-win32-arm64-msvc': 1.13.5 - '@swc/core-win32-ia32-msvc': 1.13.5 - '@swc/core-win32-x64-msvc': 1.13.5 + '@swc/core-darwin-arm64': 1.14.0 + '@swc/core-darwin-x64': 1.14.0 + '@swc/core-linux-arm-gnueabihf': 1.14.0 + '@swc/core-linux-arm64-gnu': 1.14.0 + '@swc/core-linux-arm64-musl': 1.14.0 + '@swc/core-linux-x64-gnu': 1.14.0 + '@swc/core-linux-x64-musl': 1.14.0 + '@swc/core-win32-arm64-msvc': 1.14.0 + '@swc/core-win32-ia32-msvc': 1.14.0 + '@swc/core-win32-x64-msvc': 1.14.0 '@swc/counter@0.1.3': {} @@ -3766,52 +3766,52 @@ snapshots: '@tauri-apps/api@2.9.0': {} - '@tauri-apps/cli-darwin-arm64@2.9.1': + '@tauri-apps/cli-darwin-arm64@2.9.2': optional: true - '@tauri-apps/cli-darwin-x64@2.9.1': + '@tauri-apps/cli-darwin-x64@2.9.2': optional: true - '@tauri-apps/cli-linux-arm-gnueabihf@2.9.1': + '@tauri-apps/cli-linux-arm-gnueabihf@2.9.2': optional: true - '@tauri-apps/cli-linux-arm64-gnu@2.9.1': + '@tauri-apps/cli-linux-arm64-gnu@2.9.2': optional: true - '@tauri-apps/cli-linux-arm64-musl@2.9.1': + '@tauri-apps/cli-linux-arm64-musl@2.9.2': optional: true - '@tauri-apps/cli-linux-riscv64-gnu@2.9.1': + '@tauri-apps/cli-linux-riscv64-gnu@2.9.2': optional: true - '@tauri-apps/cli-linux-x64-gnu@2.9.1': + '@tauri-apps/cli-linux-x64-gnu@2.9.2': optional: true - '@tauri-apps/cli-linux-x64-musl@2.9.1': + '@tauri-apps/cli-linux-x64-musl@2.9.2': optional: true - '@tauri-apps/cli-win32-arm64-msvc@2.9.1': + '@tauri-apps/cli-win32-arm64-msvc@2.9.2': optional: true - '@tauri-apps/cli-win32-ia32-msvc@2.9.1': + '@tauri-apps/cli-win32-ia32-msvc@2.9.2': optional: true - '@tauri-apps/cli-win32-x64-msvc@2.9.1': + '@tauri-apps/cli-win32-x64-msvc@2.9.2': optional: true - '@tauri-apps/cli@2.9.1': + '@tauri-apps/cli@2.9.2': optionalDependencies: - '@tauri-apps/cli-darwin-arm64': 2.9.1 - '@tauri-apps/cli-darwin-x64': 2.9.1 - '@tauri-apps/cli-linux-arm-gnueabihf': 2.9.1 - '@tauri-apps/cli-linux-arm64-gnu': 2.9.1 - '@tauri-apps/cli-linux-arm64-musl': 2.9.1 - '@tauri-apps/cli-linux-riscv64-gnu': 2.9.1 - '@tauri-apps/cli-linux-x64-gnu': 2.9.1 - '@tauri-apps/cli-linux-x64-musl': 2.9.1 - '@tauri-apps/cli-win32-arm64-msvc': 2.9.1 - '@tauri-apps/cli-win32-ia32-msvc': 2.9.1 - '@tauri-apps/cli-win32-x64-msvc': 2.9.1 + '@tauri-apps/cli-darwin-arm64': 2.9.2 + '@tauri-apps/cli-darwin-x64': 2.9.2 + '@tauri-apps/cli-linux-arm-gnueabihf': 2.9.2 + '@tauri-apps/cli-linux-arm64-gnu': 2.9.2 + '@tauri-apps/cli-linux-arm64-musl': 2.9.2 + '@tauri-apps/cli-linux-riscv64-gnu': 2.9.2 + '@tauri-apps/cli-linux-x64-gnu': 2.9.2 + '@tauri-apps/cli-linux-x64-musl': 2.9.2 + '@tauri-apps/cli-win32-arm64-msvc': 2.9.2 + '@tauri-apps/cli-win32-ia32-msvc': 2.9.2 + '@tauri-apps/cli-win32-x64-msvc': 2.9.2 '@tauri-apps/plugin-clipboard-manager@2.3.2': dependencies: @@ -3962,7 +3962,7 @@ snapshots: '@vitejs/plugin-react-swc@4.2.0(vite@7.1.12(@types/node@24.9.2)(sass@1.92.1)(yaml@2.8.1))': dependencies: '@rolldown/pluginutils': 1.0.0-beta.43 - '@swc/core': 1.13.5 + '@swc/core': 1.14.0 vite: 7.1.12(@types/node@24.9.2)(sass@1.92.1)(yaml@2.8.1) transitivePeerDependencies: - '@swc/helpers' @@ -4032,7 +4032,7 @@ snapshots: balanced-match@1.0.2: {} - baseline-browser-mapping@2.8.20: {} + baseline-browser-mapping@2.8.21: {} boolbase@1.0.0: {} @@ -4052,10 +4052,10 @@ snapshots: browserslist@4.27.0: dependencies: - baseline-browser-mapping: 2.8.20 + baseline-browser-mapping: 2.8.21 caniuse-lite: 1.0.30001751 electron-to-chromium: 1.5.243 - node-releases: 2.0.26 + node-releases: 2.0.27 update-browserslist-db: 1.1.4(browserslist@4.27.0) byte-size@9.0.1: {} @@ -5145,7 +5145,7 @@ snapshots: node-addon-api@7.1.1: optional: true - node-releases@2.0.26: {} + node-releases@2.0.27: {} normalize-package-data@2.5.0: dependencies: diff --git a/swift/plugin/Sources/Wireguard.swift b/swift/plugin/Sources/Wireguard.swift index c21485e0..5788821a 100644 --- a/swift/plugin/Sources/Wireguard.swift +++ b/swift/plugin/Sources/Wireguard.swift @@ -9,6 +9,54 @@ let pluginAppId = "\(appId).VPNExtension" let plugin = WireguardPlugin() let logger = Logger(subsystem: appId, category: "WireguardPlugin") +/// From preferences load `NETunnelProviderManager` with a given `name. +func managerForName( + _ name: String, + completion: @escaping (NETunnelProviderManager?) -> Void +) { + var providerManager: NETunnelProviderManager? + NETunnelProviderManager.loadAllFromPreferences { managers, error in + guard let managers = managers else { + logger.info("No tunnel managers in user's settings") + return + } + guard error == nil else { + logger.warning( + "Error loading tunnel managers: \(error, privacy: .public)") + providerManager = nil + completion(nil) + return + } + logger.info("Loaded \(managers.count, privacy: .public) tunnel managers.") + + // Find the right protocol manager. + providerManager = nil + for manager in managers { + // Obtain named configuration. + if manager.localizedDescription != name { + continue + } + guard let tunnelProtocol = manager.protocolConfiguration as? NETunnelProviderProtocol + else { + continue + } + // Sometimes all managers from all apps come through, so filter by bundle ID. + if tunnelProtocol.providerBundleIdentifier == pluginAppId { + providerManager = manager + break + } + } + if providerManager == nil { + logger.log("No VPN manager found") + } else { + logger.log( + "Loaded provider manager: \(String(describing: providerManager!.localizedDescription), privacy: .public)" + ) + } + completion(providerManager) + } +} + @_cdecl("start_tunnel") public func startTunnel(json: SRString) -> Bool { let decoder = JSONDecoder() @@ -32,17 +80,28 @@ public func startTunnel(json: SRString) -> Bool { logger.info("Saving tunnel with config: \(String(describing: config))") saveConfig(config) + // MFA is not that fast to propagate pre-shared key, so wait a moment here. + Thread.sleep(forTimeInterval: 1) + // Note: this will re-load configuration from preferneces which is a desired effect. + startVPN(name: config.name) + return true } @_cdecl("stop_tunnel") public func stopTunnel(name: SRString) -> Bool { + // Blocking + let semaphore = DispatchSemaphore(value: 0) + managerForName(name.toString()) { manager in if let providerManager = manager { providerManager.connection.stopVPNTunnel() logger.info("VPN stopped") } + semaphore.signal() } + + semaphore.wait() return true } @@ -73,11 +132,14 @@ public func tunnelStats(name: SRString) -> Stats? { } semaphore.wait() - logger.info("Tunnel stats done") return result } +/// Save `TunnelConfiguration` to preferences. func saveConfig(_ config: TunnelConfiguration) { + // Blocking + let semaphore = DispatchSemaphore(value: 0) + managerForName(config.name) { manager in let providerManager = manager ?? NETunnelProviderManager() let tunnelProtocol = NETunnelProviderProtocol() @@ -95,6 +157,8 @@ func saveConfig(_ config: TunnelConfiguration) { logger.log( "Failed to convert config to dictionary: \(error.localizedDescription, privacy: .public)" ) + // TODO: signal failure + semaphore.signal() return } tunnelProtocol.providerConfiguration = configDict @@ -105,66 +169,31 @@ func saveConfig(_ config: TunnelConfiguration) { providerManager.saveToPreferences { error in if let error = error { logger.log("Failed to save provider manager: \(error, privacy: .public)") + // TODO: signal failure } else { logger.info("Config saved") } - } - // TEST - // MFA is not that fast to propagate pre-shared key, so wait a moment here. - Thread.sleep(forTimeInterval: 1) - do { - try providerManager.connection.startVPNTunnel() - logger.info("VPN started") - } catch { - logger.error("Failed to start VPN") + semaphore.signal() } } + + semaphore.wait() } -func managerForName( - _ name: String, - completion: @escaping (NETunnelProviderManager?) -> Void -) { - var providerManager: NETunnelProviderManager? - NETunnelProviderManager.loadAllFromPreferences { managers, error in - guard let managers = managers else { - logger.info("No tunnel managers in user's settings") - return - } - guard error == nil else { - logger.warning( - "Error loading tunnel managers: \(error, privacy: .public)") - providerManager = nil - completion(nil) - return - } - logger.info("Loaded \(managers.count, privacy: .public) tunnel managers.") - // Find the right protocol manager. - providerManager = nil - for manager in managers { - // Obtain named configuration. - if manager.localizedDescription != name { - continue - } - guard let tunnelProtocol = manager.protocolConfiguration as? NETunnelProviderProtocol - else { - continue - } - // Sometimes all managers from all apps come through, so filter by bundle ID. - if tunnelProtocol.providerBundleIdentifier == pluginAppId { - providerManager = manager - break - } +/// Start VPN tunnel for a given `name`. +func startVPN(name: String) { + managerForName(name) { manager in + guard let providerManager = manager else { + logger.warning("Couldn't load \(name) configuration from preferences") + return } - if providerManager == nil { - logger.log("No VPN manager found") - } else { - logger.log( - "Loaded provider manager: \(String(describing: providerManager!.localizedDescription), privacy: .public)" - ) + do { + try providerManager.connection.startVPNTunnel() + logger.info("VPN started") + } catch { + logger.error("Failed to start VPN: \(error, privacy: .public)") } - completion(providerManager) } } From bce3f8097252c418cd3293ae009c05cb49845352 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adam=20Ciarcin=CC=81ski?= Date: Fri, 31 Oct 2025 09:26:30 +0100 Subject: [PATCH 19/28] Closer to CI build --- .github/workflows/build-macos.yaml | 23 +++++-- src-tauri/tauri.conf.json | 2 +- swift/build.sh | 12 ++-- .../VPNExtension.xcodeproj/project.pbxproj | 66 ++++++++++++++++++- 4 files changed, 86 insertions(+), 17 deletions(-) diff --git a/.github/workflows/build-macos.yaml b/.github/workflows/build-macos.yaml index 0bcb8b1d..c77d1bcb 100644 --- a/.github/workflows/build-macos.yaml +++ b/.github/workflows/build-macos.yaml @@ -19,35 +19,42 @@ jobs: - uses: actions/checkout@v5 with: submodules: recursive + - name: Write release version run: | VERSION=$(echo ${GITHUB_REF_NAME#v} | cut -d '-' -f1) echo Version: $VERSION echo "VERSION=$VERSION" >> ${GITHUB_ENV} + - uses: actions/setup-node@v6 with: node-version: "24" + cache: "pnpm" + - uses: pnpm/action-setup@v4 with: version: 10 run_install: false + - name: Get pnpm store directory shell: bash run: echo "STORE_PATH=$(pnpm store path --silent)" >> ${GITHUB_ENV} - - uses: actions/cache@v4 - name: Setup pnpm cache - with: - path: ${{ env.STORE_PATH }} - key: ${{ runner.os }}-pnpm-build-store-${{ hashFiles('**/pnpm-lock.yaml') }} - restore-keys: | - ${{ runner.os }}-pnpm-build-store- + - name: Install deps run: pnpm install --frozen-lockfile + - uses: dtolnay/rust-toolchain@stable with: targets: aarch64-apple-darwin,x86_64-apple-darwin + - name: Unlock keychain run: security -v unlock-keychain -p "${{ secrets.KEYCHAIN_PASSWORD }}" login.keychain + + - name: Set build number + run: | + sed -i '' "s,@BUILD_NUMBER@,${{ github.run_number }}" src-tauri/tauri.conf.json + sed -i '' "s,@BUILD_NUMBER@,${{ github.run_number }}" swift/extension/VPNExtension.xcodeproj/project.pbxproj + - name: Build app uses: tauri-apps/tauri-action@v0.5.23 # .24 seems broken, TODO: update when fixed env: @@ -58,12 +65,14 @@ jobs: APPLE_ID: ${{ env.APPLE_ID }} APPLE_PASSWORD: ${{ secrets.NOTARYTOOL_APP_SPECIFIC_PASSWORD }} APPLE_TEAM_ID: ${{ env.APPLE_TEAM_ID }} + - name: Build installation package run: | security -v unlock-keychain -p "${{ secrets.KEYCHAIN_PASSWORD }}" login.keychain xcrun productbuild --sign "${APPLE_SIGNING_IDENTITY_INSTALLER}" --component "src-tauri/target/universal-apple-darwin/release/bundle/macos/defguard-client.app" /Applications defguard-client.pkg xcrun notarytool submit --wait --apple-id ${{ env.APPLE_ID }} --password ${{ secrets.NOTARYTOOL_APP_SPECIFIC_PASSWORD }} --team-id ${{ env.APPLE_TEAM_ID }} defguard-client.pkg xcrun stapler staple defguard-client.pkg + - name: Upload installation package uses: actions/upload-release-asset@v1 env: diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index 5199be65..d3b64670 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -41,7 +41,7 @@ } }, "macOS": { - "bundleVersion": "1", + "bundleVersion": "@BUILD_NUMBER@", "entitlements": "./Client.entitlements", "files": { "embedded.provisionprofile": "Defguard_Client_Mac_App_Store.provisionprofile", diff --git a/swift/build.sh b/swift/build.sh index aee79de3..28264f58 100755 --- a/swift/build.sh +++ b/swift/build.sh @@ -1,8 +1,10 @@ #!/bin/sh set -e +DST="${PWD}/extension/BoringTun" CARGO="${HOME}/.cargo/bin/cargo" RUSTUP="${HOME}/.cargo/bin/rustup" + export MACOSX_DEPLOYMENT_TARGET=13.5 # Build BoringTun. @@ -30,16 +32,14 @@ ${CARGO} run --release --bin uniffi-bindgen -- \ # Install BoringTun framework. -DST="${PWD}/extension" - -mkdir -p ${DST}/BoringTun -cp -c target/uniffi/boringtun.swift ${DST}/BoringTun/ -rm -f -r ${DST}/BoringTun/boringtun.xcframework +mkdir -p "${DST}" +cp -c target/uniffi/boringtun.swift "${DST}/" +rm -f -r "${DST}/boringtun.xcframework" xcodebuild -create-xcframework \ -library target/universal/release/libboringtun.a \ -headers target/uniffi \ -output ${DST}/BoringTun/boringtun.xcframework -cp -c target/uniffi/boringtunFFI.h ${DST}/BoringTun/ +cp -c target/uniffi/boringtunFFI.h "${DST}/" popd diff --git a/swift/extension/VPNExtension.xcodeproj/project.pbxproj b/swift/extension/VPNExtension.xcodeproj/project.pbxproj index 9f9e267a..2a253c04 100644 --- a/swift/extension/VPNExtension.xcodeproj/project.pbxproj +++ b/swift/extension/VPNExtension.xcodeproj/project.pbxproj @@ -121,7 +121,7 @@ attributes = { BuildIndependentTargetsInParallel = 1; LastSwiftUpdateCheck = 2600; - LastUpgradeCheck = 2600; + LastUpgradeCheck = 2610; TargetAttributes = { 66CABCD32EA76D060057D1AF = { CreatedOnToolsVersion = 26.0.1; @@ -171,7 +171,37 @@ 66CABCCE2EA76CD80057D1AF /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + DEAD_CODE_STRIPPING = YES; DEVELOPMENT_TEAM = 82GZ7KN29J; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + ONLY_ACTIVE_ARCH = YES; + STRING_CATALOG_GENERATE_SYMBOLS = YES; SWIFT_OBJC_BRIDGING_HEADER = "$(PROJECT_DIR)/BoringTun/boringtunFFI.h"; }; name = Debug; @@ -179,7 +209,35 @@ 66CABCCF2EA76CD80057D1AF /* Release */ = { isa = XCBuildConfiguration; buildSettings = { + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + DEAD_CODE_STRIPPING = YES; DEVELOPMENT_TEAM = 82GZ7KN29J; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + STRING_CATALOG_GENERATE_SYMBOLS = YES; SWIFT_OBJC_BRIDGING_HEADER = "$(PROJECT_DIR)/BoringTun/boringtunFFI.h"; }; name = Release; @@ -220,7 +278,8 @@ CODE_SIGN_ENTITLEMENTS = VPNExtension/VPNExtension.entitlements; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = "@BUILD_NUMBER@"; + DEAD_CODE_STRIPPING = YES; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = 82GZ7KN29J; ENABLE_APP_SANDBOX = YES; @@ -319,7 +378,8 @@ "CODE_SIGN_IDENTITY[sdk=macosx*]" = "3rd Party Mac Developer Application"; CODE_SIGN_STYLE = Manual; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = "@BUILD_NUMBER@"; + DEAD_CODE_STRIPPING = YES; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=macosx*]" = 82GZ7KN29J; From a98c90e7c0744034e3d49043c3d642ba98018471 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adam=20Ciarcin=CC=81ski?= Date: Fri, 31 Oct 2025 09:28:03 +0100 Subject: [PATCH 20/28] Fix sed --- .github/workflows/build-macos.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-macos.yaml b/.github/workflows/build-macos.yaml index c77d1bcb..a8830b2a 100644 --- a/.github/workflows/build-macos.yaml +++ b/.github/workflows/build-macos.yaml @@ -52,8 +52,8 @@ jobs: - name: Set build number run: | - sed -i '' "s,@BUILD_NUMBER@,${{ github.run_number }}" src-tauri/tauri.conf.json - sed -i '' "s,@BUILD_NUMBER@,${{ github.run_number }}" swift/extension/VPNExtension.xcodeproj/project.pbxproj + sed -i '' "s,@BUILD_NUMBER@,${{ github.run_number }}," src-tauri/tauri.conf.json + sed -i '' "s,@BUILD_NUMBER@,${{ github.run_number }}," swift/extension/VPNExtension.xcodeproj/project.pbxproj - name: Build app uses: tauri-apps/tauri-action@v0.5.23 # .24 seems broken, TODO: update when fixed From f8e736093651ef151fda8a1555410e2a75b93fdb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adam=20Ciarcin=CC=81ski?= Date: Fri, 31 Oct 2025 09:49:16 +0100 Subject: [PATCH 21/28] Abandon tauri-apps/tauri-action for the time being --- .github/workflows/build-macos.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build-macos.yaml b/.github/workflows/build-macos.yaml index a8830b2a..e3abb3f8 100644 --- a/.github/workflows/build-macos.yaml +++ b/.github/workflows/build-macos.yaml @@ -56,7 +56,8 @@ jobs: sed -i '' "s,@BUILD_NUMBER@,${{ github.run_number }}," swift/extension/VPNExtension.xcodeproj/project.pbxproj - name: Build app - uses: tauri-apps/tauri-action@v0.5.23 # .24 seems broken, TODO: update when fixed + # Switch back to tauri-action when this gets merged https://github.com/tauri-apps/tauri/pull/14379 + # uses: tauri-apps/tauri-action@v0.5.23 # .24 seems broken, TODO: update when fixed env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} APPLE_SIGNING_IDENTITY: ${{ env.APPLE_SIGNING_IDENTITY_APPLICATION }} @@ -65,6 +66,7 @@ jobs: APPLE_ID: ${{ env.APPLE_ID }} APPLE_PASSWORD: ${{ secrets.NOTARYTOOL_APP_SPECIFIC_PASSWORD }} APPLE_TEAM_ID: ${{ env.APPLE_TEAM_ID }} + run: cd src-tauri && cargo tauri build - name: Build installation package run: | From b08dc15ed671704adbc6d9df8540556a70b127de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adam=20Ciarcin=CC=81ski?= Date: Fri, 31 Oct 2025 09:54:56 +0100 Subject: [PATCH 22/28] Stick to Release build --- package.json | 2 +- pnpm-lock.yaml | 28 ++++++++++++++-------------- src-tauri/Cargo.lock | 10 +++++----- swift/build.sh | 8 ++++---- 4 files changed, 24 insertions(+), 24 deletions(-) diff --git a/package.json b/package.json index 56518635..319a7f2a 100644 --- a/package.json +++ b/package.json @@ -71,7 +71,7 @@ "classnames": "^2.5.1", "clsx": "^2.1.1", "compare-versions": "^6.1.1", - "dayjs": "^1.11.18", + "dayjs": "^1.11.19", "deepmerge-ts": "^7.1.5", "detect-browser": "^5.3.0", "fast-deep-equal": "^3.1.3", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d3ad6026..a5f9ff0e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -81,8 +81,8 @@ importers: specifier: ^6.1.1 version: 6.1.1 dayjs: - specifier: ^1.11.18 - version: 1.11.18 + specifier: ^1.11.19 + version: 1.11.19 deepmerge-ts: specifier: ^7.1.5 version: 7.1.5 @@ -1428,8 +1428,8 @@ packages: resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} engines: {node: '>=10'} - caniuse-lite@1.0.30001751: - resolution: {integrity: sha512-A0QJhug0Ly64Ii3eIqHu5X51ebln3k4yTUkY1j8drqpWHVreg/VLijN48cZ1bYPiqOQuqpkIKnzr/Ul8V+p6Cw==} + caniuse-lite@1.0.30001752: + resolution: {integrity: sha512-vKUk7beoukxE47P5gcVNKkDRzXdVofotshHwfR9vmpeFKxmI5PBpgOMC18LUJUA/DvJ70Y7RveasIBraqsyO/g==} ccount@2.0.1: resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} @@ -1604,8 +1604,8 @@ packages: resolution: {integrity: sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==} engines: {node: '>= 0.4'} - dayjs@1.11.18: - resolution: {integrity: sha512-zFBQ7WFRvVRhKcWoUh+ZA1g2HVgUbsZm9sbddh8EC5iv93sui8DVVz1Npvz+r6meo9VKfa8NyLWBsQK1VvIKPA==} + dayjs@1.11.19: + resolution: {integrity: sha512-t5EcLVS6QPBNqM2z8fakk/NKel+Xzshgt8FFKAn+qwlD1pzZWxh0nVCrvFK7ZDb6XucZeF9z8C7CBWTRIVApAw==} debug@4.4.3: resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} @@ -1673,8 +1673,8 @@ packages: resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} engines: {node: '>= 0.4'} - electron-to-chromium@1.5.243: - resolution: {integrity: sha512-ZCphxFW3Q1TVhcgS9blfut1PX8lusVi2SvXQgmEEnK4TCmE1JhH2JkjJN+DNt0pJJwfBri5AROBnz2b/C+YU9g==} + electron-to-chromium@1.5.244: + resolution: {integrity: sha512-OszpBN7xZX4vWMPJwB9illkN/znA8M36GQqQxi6MNy9axWxhOfJyZZJtSLQCpEFLHP2xK33BiWx9aIuIEXVCcw==} emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} @@ -4011,7 +4011,7 @@ snapshots: autoprefixer@10.4.21(postcss@8.5.6): dependencies: browserslist: 4.27.0 - caniuse-lite: 1.0.30001751 + caniuse-lite: 1.0.30001752 fraction.js: 4.3.7 normalize-range: 0.1.2 picocolors: 1.1.1 @@ -4053,8 +4053,8 @@ snapshots: browserslist@4.27.0: dependencies: baseline-browser-mapping: 2.8.21 - caniuse-lite: 1.0.30001751 - electron-to-chromium: 1.5.243 + caniuse-lite: 1.0.30001752 + electron-to-chromium: 1.5.244 node-releases: 2.0.27 update-browserslist-db: 1.1.4(browserslist@4.27.0) @@ -4081,7 +4081,7 @@ snapshots: camelcase@6.3.0: {} - caniuse-lite@1.0.30001751: {} + caniuse-lite@1.0.30001752: {} ccount@2.0.1: {} @@ -4253,7 +4253,7 @@ snapshots: es-errors: 1.3.0 is-data-view: 1.0.2 - dayjs@1.11.18: {} + dayjs@1.11.19: {} debug@4.4.3: dependencies: @@ -4321,7 +4321,7 @@ snapshots: es-errors: 1.3.0 gopd: 1.2.0 - electron-to-chromium@1.5.243: {} + electron-to-chromium@1.5.244: {} emoji-regex@8.0.0: {} diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index 265ffad5..7d08938d 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "adler2" @@ -7432,18 +7432,18 @@ checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" [[package]] name = "unicode-normalization" -version = "0.1.24" +version = "0.1.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956" +checksum = "5fd4f6878c9cb28d874b009da9e8d183b5abc80117c40bbd187a1fde336be6e8" dependencies = [ "tinyvec", ] [[package]] name = "unicode-properties" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e70f2a8b45122e719eb623c01822704c4e0907e7e426a05927e1a1cfff5b75d0" +checksum = "7df058c713841ad818f1dc5d3fd88063241cc61f49f5fbea4b951e8cf5a8d71d" [[package]] name = "unicode-segmentation" diff --git a/swift/build.sh b/swift/build.sh index 28264f58..d2c9098a 100755 --- a/swift/build.sh +++ b/swift/build.sh @@ -45,9 +45,9 @@ popd # Build VPNExtension. -if [ "${TAURI_ENV_DEBUG}" = 'false' ]; then +# if [ "${TAURI_ENV_DEBUG}" = 'false' ]; then CONFIG=Release -else - CONFIG=Debug -fi +# else +# CONFIG=Debug +# fi xcodebuild -project extension/VPNExtension.xcodeproj -target VPNExtension -configuration ${CONFIG} build From 468cebc347b1cd6274cf7cd28a81ef9fd9fe86e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adam=20Ciarcin=CC=81ski?= Date: Fri, 31 Oct 2025 10:09:06 +0100 Subject: [PATCH 23/28] Better packaging --- .github/workflows/build-macos.yaml | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/.github/workflows/build-macos.yaml b/.github/workflows/build-macos.yaml index e3abb3f8..4e03488e 100644 --- a/.github/workflows/build-macos.yaml +++ b/.github/workflows/build-macos.yaml @@ -60,18 +60,19 @@ jobs: # uses: tauri-apps/tauri-action@v0.5.23 # .24 seems broken, TODO: update when fixed env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - APPLE_SIGNING_IDENTITY: ${{ env.APPLE_SIGNING_IDENTITY_APPLICATION }} + # APPLE_SIGNING_IDENTITY: ${{ env.APPLE_SIGNING_IDENTITY_APPLICATION }} + APPLE_SIGNING_IDENTITY: "Apple Distribution: defguard sp. z o.o. (82GZ7KN29J)" + APPLE_INSTALLER_IDENTITY: "3rd Party Mac Developer Installer: defguard sp. z o.o. (82GZ7KN29J)" + APPLE_PROVIDER_SHORT_NAME: 82GZ7KN29J APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }} APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }} - APPLE_ID: ${{ env.APPLE_ID }} - APPLE_PASSWORD: ${{ secrets.NOTARYTOOL_APP_SPECIFIC_PASSWORD }} - APPLE_TEAM_ID: ${{ env.APPLE_TEAM_ID }} run: cd src-tauri && cargo tauri build - name: Build installation package run: | security -v unlock-keychain -p "${{ secrets.KEYCHAIN_PASSWORD }}" login.keychain xcrun productbuild --sign "${APPLE_SIGNING_IDENTITY_INSTALLER}" --component "src-tauri/target/universal-apple-darwin/release/bundle/macos/defguard-client.app" /Applications defguard-client.pkg + xcrun altool --upload-app --type macos --file defguard-client.pkg --apiKey ${{ secrets.APPLE_API_KEY }} --apiIssuer ${{ secrets.APPLE_API_ISSUER }} xcrun notarytool submit --wait --apple-id ${{ env.APPLE_ID }} --password ${{ secrets.NOTARYTOOL_APP_SPECIFIC_PASSWORD }} --team-id ${{ env.APPLE_TEAM_ID }} defguard-client.pkg xcrun stapler staple defguard-client.pkg @@ -82,5 +83,5 @@ jobs: with: upload_url: ${{ needs.create-release.outputs.upload_url }} asset_path: defguard-client.pkg - asset_name: defguard-${{ matrix.target }}-${{ env.VERSION }}.pkg + asset_name: defguard-client-${{ env.VERSION }}.pkg asset_content_type: application/octet-stream From bf16d8908135dc857c531439668f37970de7c3e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adam=20Ciarcin=CC=81ski?= Date: Fri, 31 Oct 2025 10:22:26 +0100 Subject: [PATCH 24/28] Another workflow run --- .github/workflows/build-macos.yaml | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/.github/workflows/build-macos.yaml b/.github/workflows/build-macos.yaml index 4e03488e..305e3fe3 100644 --- a/.github/workflows/build-macos.yaml +++ b/.github/workflows/build-macos.yaml @@ -11,8 +11,9 @@ jobs: - self-hosted - macOS env: - APPLE_SIGNING_IDENTITY_APPLICATION: "Apple Distribution: defguard sp. z o.o. (82GZ7KN29J)" + APPLE_SIGNING_IDENTITY: "Apple Distribution: defguard sp. z o.o. (82GZ7KN29J)" APPLE_SIGNING_IDENTITY_INSTALLER: "3rd Party Mac Developer Installer: defguard sp. z o.o. (82GZ7KN29J)" + APPLE_PROVIDER_SHORT_NAME: "82GZ7KN29J" APPLE_ID: "kamil@defguard.net" APPLE_TEAM_ID: "82GZ7KN29J" steps: @@ -60,18 +61,14 @@ jobs: # uses: tauri-apps/tauri-action@v0.5.23 # .24 seems broken, TODO: update when fixed env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - # APPLE_SIGNING_IDENTITY: ${{ env.APPLE_SIGNING_IDENTITY_APPLICATION }} - APPLE_SIGNING_IDENTITY: "Apple Distribution: defguard sp. z o.o. (82GZ7KN29J)" - APPLE_INSTALLER_IDENTITY: "3rd Party Mac Developer Installer: defguard sp. z o.o. (82GZ7KN29J)" - APPLE_PROVIDER_SHORT_NAME: 82GZ7KN29J - APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }} - APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }} + # APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }} + # APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }} run: cd src-tauri && cargo tauri build - name: Build installation package run: | security -v unlock-keychain -p "${{ secrets.KEYCHAIN_PASSWORD }}" login.keychain - xcrun productbuild --sign "${APPLE_SIGNING_IDENTITY_INSTALLER}" --component "src-tauri/target/universal-apple-darwin/release/bundle/macos/defguard-client.app" /Applications defguard-client.pkg + xcrun productbuild --sign "${{ env.APPLE_SIGNING_IDENTITY_INSTALLER }}" --component "src-tauri/target/universal-apple-darwin/release/bundle/macos/defguard-client.app" /Applications defguard-client.pkg xcrun altool --upload-app --type macos --file defguard-client.pkg --apiKey ${{ secrets.APPLE_API_KEY }} --apiIssuer ${{ secrets.APPLE_API_ISSUER }} xcrun notarytool submit --wait --apple-id ${{ env.APPLE_ID }} --password ${{ secrets.NOTARYTOOL_APP_SPECIFIC_PASSWORD }} --team-id ${{ env.APPLE_TEAM_ID }} defguard-client.pkg xcrun stapler staple defguard-client.pkg From bf23f6727fc904e95d2a740178bcc7da95453715 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adam=20Ciarcin=CC=81ski?= Date: Fri, 31 Oct 2025 10:28:08 +0100 Subject: [PATCH 25/28] Bundle again --- .github/workflows/build-macos.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-macos.yaml b/.github/workflows/build-macos.yaml index 305e3fe3..19fa28ae 100644 --- a/.github/workflows/build-macos.yaml +++ b/.github/workflows/build-macos.yaml @@ -63,7 +63,7 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }} # APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }} - run: cd src-tauri && cargo tauri build + run: cd src-tauri && cargo tauri build --bundles app --target universal-apple-darwin - name: Build installation package run: | @@ -80,5 +80,5 @@ jobs: with: upload_url: ${{ needs.create-release.outputs.upload_url }} asset_path: defguard-client.pkg - asset_name: defguard-client-${{ env.VERSION }}.pkg + asset_name: defguard-client-universal-${{ env.VERSION }}.pkg asset_content_type: application/octet-stream From 363a71f89ed17c0a4377db86bf163e4498a2985e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adam=20Ciarcin=CC=81ski?= Date: Fri, 31 Oct 2025 10:42:44 +0100 Subject: [PATCH 26/28] Ready to be merged --- .github/workflows/build-macos.yaml | 25 ++++++++---------- build-macos-package.sh | 41 ------------------------------ 2 files changed, 11 insertions(+), 55 deletions(-) delete mode 100755 build-macos-package.sh diff --git a/.github/workflows/build-macos.yaml b/.github/workflows/build-macos.yaml index 19fa28ae..d3054ee3 100644 --- a/.github/workflows/build-macos.yaml +++ b/.github/workflows/build-macos.yaml @@ -1,8 +1,5 @@ name: Build macOS app on: - push: - branches: - - swift_plugin workflow_call: jobs: @@ -70,15 +67,15 @@ jobs: security -v unlock-keychain -p "${{ secrets.KEYCHAIN_PASSWORD }}" login.keychain xcrun productbuild --sign "${{ env.APPLE_SIGNING_IDENTITY_INSTALLER }}" --component "src-tauri/target/universal-apple-darwin/release/bundle/macos/defguard-client.app" /Applications defguard-client.pkg xcrun altool --upload-app --type macos --file defguard-client.pkg --apiKey ${{ secrets.APPLE_API_KEY }} --apiIssuer ${{ secrets.APPLE_API_ISSUER }} - xcrun notarytool submit --wait --apple-id ${{ env.APPLE_ID }} --password ${{ secrets.NOTARYTOOL_APP_SPECIFIC_PASSWORD }} --team-id ${{ env.APPLE_TEAM_ID }} defguard-client.pkg - xcrun stapler staple defguard-client.pkg + # xcrun notarytool submit --wait --apple-id ${{ env.APPLE_ID }} --password ${{ secrets.NOTARYTOOL_APP_SPECIFIC_PASSWORD }} --team-id ${{ env.APPLE_TEAM_ID }} defguard-client.pkg + # xcrun stapler staple defguard-client.pkg - - name: Upload installation package - uses: actions/upload-release-asset@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - upload_url: ${{ needs.create-release.outputs.upload_url }} - asset_path: defguard-client.pkg - asset_name: defguard-client-universal-${{ env.VERSION }}.pkg - asset_content_type: application/octet-stream + # - name: Upload installation package + # uses: actions/upload-release-asset@v1 + # env: + # GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + # with: + # upload_url: ${{ needs.create-release.outputs.upload_url }} + # asset_path: defguard-client.pkg + # asset_name: defguard-client-universal-${{ env.VERSION }}.pkg + # asset_content_type: application/octet-stream diff --git a/build-macos-package.sh b/build-macos-package.sh deleted file mode 100755 index 85c6002f..00000000 --- a/build-macos-package.sh +++ /dev/null @@ -1,41 +0,0 @@ -#!/bin/bash - -set -e - -TARGET_DIRECTORY=$1 -SCRIPTS_DIRECTORY=$2 -APPLE_PACKAGE_SIGNING_IDENTITY=$3 -KEYCHAIN=$4 - -mkdir -p "${TARGET_DIRECTORY}/package" -mkdir -p "${TARGET_DIRECTORY}/product" -mkdir -p "${TARGET_DIRECTORY}/product-signed" - -APP_ROOT="${TARGET_DIRECTORY}/release/bundle/macos/defguard-client.app" - -chmod -R 755 ${APP_ROOT} - -pkgbuild \ - --analyze \ - --root ${APP_ROOT} \ - "${TARGET_DIRECTORY}/defguard-client.plist" - -PACKAGE_PATH="${TARGET_DIRECTORY}/package/defguard.pkg" - -pkgbuild \ - --identifier "net.defguard" \ - --root ${APP_ROOT} \ - --component-plist ${TARGET_DIRECTORY}/defguard-client.plist \ - --install-location "/Applications/defguard-client.app" \ - --scripts ${SCRIPTS_DIRECTORY} \ - "${PACKAGE_PATH}" - -productbuild \ - --package "${PACKAGE_PATH}" \ - "${TARGET_DIRECTORY}/product/defguard.pkg" - -productsign \ - --sign "${APPLE_PACKAGE_SIGNING_IDENTITY}" \ - --keychain "${KEYCHAIN}" \ - "${TARGET_DIRECTORY}/product/defguard.pkg" \ - "${TARGET_DIRECTORY}/product-signed/defguard.pkg" From 9d7698695483857e4ecb5a9dc3b957afb5a272e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adam=20Ciarcin=CC=81ski?= Date: Fri, 31 Oct 2025 11:02:34 +0100 Subject: [PATCH 27/28] Make clippy happy --- src-tauri/src/database/models/location.rs | 5 ++++- src-tauri/src/utils.rs | 8 ++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src-tauri/src/database/models/location.rs b/src-tauri/src/database/models/location.rs index c98dcc0b..3b092b50 100644 --- a/src-tauri/src/database/models/location.rs +++ b/src-tauri/src/database/models/location.rs @@ -1,4 +1,6 @@ -use std::{fmt, net::IpAddr, str::FromStr}; +#[cfg(target_os = "macos")] +use std::net::IpAddr; +use std::{fmt, str::FromStr}; use defguard_wireguard_rs::{host::Peer, key::Key, net::IpAddrMask, InterfaceConfiguration}; use serde::{Deserialize, Serialize}; @@ -235,6 +237,7 @@ impl Location { } /// Split DNS settings into resolver IP addresses and search domains. + #[cfg(target_os = "macos")] pub(crate) fn dns(&self) -> (Vec, Vec) { let mut dns = Vec::new(); let mut dns_search = Vec::new(); diff --git a/src-tauri/src/utils.rs b/src-tauri/src/utils.rs index ee5b4ce7..a864cc22 100644 --- a/src-tauri/src/utils.rs +++ b/src-tauri/src/utils.rs @@ -1,4 +1,6 @@ -use std::{env, path::Path, process::Command, str::FromStr, time::Duration}; +#[cfg(target_os = "macos")] +use std::time::Duration; +use std::{env, path::Path, process::Command, str::FromStr}; use common::{find_free_tcp_port, get_interface_name}; use defguard_wireguard_rs::{host::Peer, key::Key, net::IpAddrMask, InterfaceConfiguration}; @@ -71,10 +73,8 @@ pub(crate) async fn setup_interface( }; debug!("Found free port: {port} for interface {interface_name}."); - let (dns, dns_search) = location.dns(); - let interface_config = location - .interface_configurarion(&*DB_POOL, interface_name.clone(), preshared_key) + .interface_configurarion(pool, interface_name.clone(), preshared_key) .await?; debug!("Creating interface for location {location} with configuration {interface_config:?}"); let request = CreateInterfaceRequest { From 4085b355d4b0d30e9b459f1b47ccf5e675aa4b73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adam=20Ciarcin=CC=81ski?= Date: Fri, 31 Oct 2025 11:49:19 +0100 Subject: [PATCH 28/28] Fix path in build.sh --- swift/build.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/swift/build.sh b/swift/build.sh index d2c9098a..04112714 100755 --- a/swift/build.sh +++ b/swift/build.sh @@ -38,7 +38,7 @@ rm -f -r "${DST}/boringtun.xcframework" xcodebuild -create-xcframework \ -library target/universal/release/libboringtun.a \ -headers target/uniffi \ - -output ${DST}/BoringTun/boringtun.xcframework + -output ${DST}/boringtun.xcframework cp -c target/uniffi/boringtunFFI.h "${DST}/" popd