From 16fa634351252821a4549bd3f1d61a8db09ba642 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20W=C3=B3jcik?= Date: Mon, 11 Aug 2025 11:37:50 +0200 Subject: [PATCH 1/8] update dependencies --- Cargo.lock | 65 ++++++++++++++++++------------- flake.lock | 12 +++--- web/package.json | 8 ++-- web/pnpm-lock.yaml | 96 +++++++++++++++++++++++----------------------- 4 files changed, 96 insertions(+), 85 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 705a4a2a38..d7ad6e4335 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -613,9 +613,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.31" +version = "1.2.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3a42d84bb6b69d3a8b3eaacf0d88f179e1929695e1ad012b6cf64d9caaa5fd2" +checksum = "2352e5597e9c544d5e6d9c95190d5d27738ade584fa8db0a16e130e5c2b5296e" dependencies = [ "jobserver", "libc", @@ -708,9 +708,9 @@ checksum = "bba18ee93d577a8428902687bcc2b6b45a56b1981a1f6d779731c86cc4c5db18" [[package]] name = "clap" -version = "4.5.42" +version = "4.5.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed87a9d530bb41a67537289bafcac159cb3ee28460e0a4571123d2a778a6a882" +checksum = "50fd97c9dc2399518aa331917ac6f274280ec5eb34e555dd291899745c48ec6f" dependencies = [ "clap_builder", "clap_derive", @@ -718,9 +718,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.42" +version = "4.5.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64f4f3f3c77c94aff3c7e9aac9a2ca1974a5adf392a8bb751e827d6d127ab966" +checksum = "c35b5830294e1fa0462034af85cc95225a4cb07092c088c55bda3147cfcd8f65" dependencies = [ "anstream", "anstyle", @@ -1843,9 +1843,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.4.11" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17da50a276f1e01e0ba6c029e47b7100754904ee8a278f886546e98575380785" +checksum = "f3c0b69cfcb4e1b9f1bf2f53f95f766e4661169728ec61cd3fe5a0166f2d1386" dependencies = [ "atomic-waker", "bytes", @@ -1884,9 +1884,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.15.4" +version = "0.15.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" dependencies = [ "allocator-api2", "equivalent", @@ -1899,7 +1899,7 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7382cf6263419f2d8df38c55d7da83da5c18aef87fc7a7fc1fb1e344edfe14c1" dependencies = [ - "hashbrown 0.15.4", + "hashbrown 0.15.5", ] [[package]] @@ -2316,7 +2316,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fe4cd85333e22411419a0bcae1297d25e58c9443848b11dc6a86fefe8c78a661" dependencies = [ "equivalent", - "hashbrown 0.15.4", + "hashbrown 0.15.5", "serde", ] @@ -2549,9 +2549,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.174" +version = "0.2.175" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776" +checksum = "6a82ae493e598baaea5209805c49bbf2ea7de956d50d7da0da1164f9c6d28543" [[package]] name = "libgit2-sys" @@ -2571,6 +2571,17 @@ version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" +[[package]] +name = "libredox" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "391290121bad3d37fbddad76d8f5d1c1c314cfc646d143d7e07a3086ddff0ce3" +dependencies = [ + "bitflags 2.9.1", + "libc", + "redox_syscall", +] + [[package]] name = "libsqlite3-sys" version = "0.30.1" @@ -3525,9 +3536,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.95" +version = "1.0.96" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" +checksum = "beef09f85ae72cea1ef96ba6870c51e6382ebfa4f0e85b643459331f3daa5be0" dependencies = [ "unicode-ident", ] @@ -4053,7 +4064,7 @@ dependencies = [ "openssl-probe", "rustls-pki-types", "schannel", - "security-framework 3.2.0", + "security-framework 3.3.0", ] [[package]] @@ -4088,9 +4099,9 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.21" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a0d197bd2c9dc6e53b84da9556a69ba4cdfab8619eb41a8bd1cc2027a0f6b1d" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" [[package]] name = "ryu" @@ -4185,9 +4196,9 @@ dependencies = [ [[package]] name = "security-framework" -version = "3.2.0" +version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "271720403f46ca04f7ba6f55d438f8bd878d6b8ca0a1046e8228c4145bcbb316" +checksum = "80fb1d92c5028aa318b4b8bd7302a5bfcf48be96a37fc6fc790f806b0004ee0c" dependencies = [ "bitflags 2.9.1", "core-foundation 0.10.1", @@ -4491,9 +4502,9 @@ checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" [[package]] name = "slab" -version = "0.4.10" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04dc19736151f35336d325007ac991178d504a119863a2fcb3758cdb5e52c50d" +checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589" [[package]] name = "slug" @@ -4583,7 +4594,7 @@ dependencies = [ "futures-intrusive", "futures-io", "futures-util", - "hashbrown 0.15.4", + "hashbrown 0.15.5", "hashlink", "indexmap 2.10.0", "ipnetwork", @@ -5956,11 +5967,11 @@ dependencies = [ [[package]] name = "whoami" -version = "1.6.0" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6994d13118ab492c3c80c1f81928718159254c53c472bf9ce36f8dae4add02a7" +checksum = "5d4a4db5077702ca3015d3d02d74974948aba2ad9e12ab7df718ee64ccd7e97d" dependencies = [ - "redox_syscall", + "libredox", "wasite", ] diff --git a/flake.lock b/flake.lock index a874e42a18..4c226f533e 100644 --- a/flake.lock +++ b/flake.lock @@ -20,11 +20,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1751984180, - "narHash": "sha256-LwWRsENAZJKUdD3SpLluwDmdXY9F45ZEgCb0X+xgOL0=", + "lastModified": 1754725699, + "narHash": "sha256-iAcj9T/Y+3DBy2J0N+yF9XQQQ8IEb5swLFzs23CdP88=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "9807714d6944a957c2e036f84b0ff8caf9930bc0", + "rev": "85dbfc7aaf52ecb755f87e577ddbe6dbbdbc1054", "type": "github" }, "original": { @@ -48,11 +48,11 @@ ] }, "locked": { - "lastModified": 1752461263, - "narHash": "sha256-f4XVgqkWF1vSzPbOG5xvi4aAd/n1GwSNsji3mLMFwYQ=", + "lastModified": 1754880555, + "narHash": "sha256-tG6l0wiX8V8IvG4HFYY8IYN5vpNAxQ+UWunjjpE6SqU=", "owner": "oxalica", "repo": "rust-overlay", - "rev": "9cc51d100d24fb7ea13a0bee1480ee84fa12a0ad", + "rev": "17c591a44e4eb77f05f27cd37e1cfc3f219c7fc4", "type": "github" }, "original": { diff --git a/web/package.json b/web/package.json index e59dbb3897..8b832fb03f 100644 --- a/web/package.json +++ b/web/package.json @@ -50,7 +50,7 @@ "@stablelib/base64": "^2.0.1", "@stablelib/x25519": "^2.0.1", "@tanstack/query-core": "^5.83.1", - "@tanstack/react-query": "^5.84.1", + "@tanstack/react-query": "^5.84.2", "@tanstack/react-virtual": "3.13.12", "@tanstack/virtual-core": "3.13.12", "@use-gesture/react": "^10.3.1", @@ -74,7 +74,7 @@ "humanize-duration": "^3.33.0", "ipaddr.js": "^2.2.0", "itertools": "^2.4.1", - "js-base64": "^3.7.7", + "js-base64": "^3.7.8", "lodash-es": "^4.17.21", "merge-refs": "^2.0.0", "millify": "^6.1.0", @@ -117,12 +117,12 @@ "@csstools/css-parser-algorithms": "^3.0.5", "@csstools/css-tokenizer": "^3.0.4", "@hookform/devtools": "^4.4.0", - "@tanstack/react-query-devtools": "^5.84.1", + "@tanstack/react-query-devtools": "^5.84.2", "@types/byte-size": "^8.1.2", "@types/file-saver": "^2.0.7", "@types/humanize-duration": "^3.27.4", "@types/lodash-es": "^4.17.12", - "@types/node": "^24.2.0", + "@types/node": "^24.2.1", "@types/qs": "^6.14.0", "@types/react": "^18.3.23", "@types/react-dom": "^18.3.7", diff --git a/web/pnpm-lock.yaml b/web/pnpm-lock.yaml index 32f1544d00..fd8547b115 100644 --- a/web/pnpm-lock.yaml +++ b/web/pnpm-lock.yaml @@ -33,8 +33,8 @@ importers: specifier: ^5.83.1 version: 5.83.1 '@tanstack/react-query': - specifier: ^5.84.1 - version: 5.84.1(react@18.3.1) + specifier: ^5.84.2 + version: 5.84.2(react@18.3.1) '@tanstack/react-virtual': specifier: 3.13.12 version: 3.13.12(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -105,8 +105,8 @@ importers: specifier: ^2.4.1 version: 2.4.1 js-base64: - specifier: ^3.7.7 - version: 3.7.7 + specifier: ^3.7.8 + version: 3.7.8 lodash-es: specifier: ^4.17.21 version: 4.17.21 @@ -229,8 +229,8 @@ importers: specifier: ^4.4.0 version: 4.4.0(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@tanstack/react-query-devtools': - specifier: ^5.84.1 - version: 5.84.1(@tanstack/react-query@5.84.1(react@18.3.1))(react@18.3.1) + specifier: ^5.84.2 + version: 5.84.2(@tanstack/react-query@5.84.2(react@18.3.1))(react@18.3.1) '@types/byte-size': specifier: ^8.1.2 version: 8.1.2 @@ -244,8 +244,8 @@ importers: specifier: ^4.17.12 version: 4.17.12 '@types/node': - specifier: ^24.2.0 - version: 24.2.0 + specifier: ^24.2.1 + version: 24.2.1 '@types/qs': specifier: ^6.14.0 version: 6.14.0 @@ -263,7 +263,7 @@ importers: version: 1.8.8 '@vitejs/plugin-react-swc': specifier: ^3.11.0 - version: 3.11.0(vite@7.1.1(@types/node@24.2.0)(jiti@2.4.2)(sass@1.70.0)(terser@5.37.0)(yaml@2.6.1)) + version: 3.11.0(vite@7.1.1(@types/node@24.2.1)(jiti@2.4.2)(sass@1.70.0)(terser@5.37.0)(yaml@2.6.1)) autoprefixer: specifier: ^10.4.21 version: 10.4.21(postcss@8.5.6) @@ -299,10 +299,10 @@ importers: version: 5.9.2 vite: specifier: ^7.1.1 - version: 7.1.1(@types/node@24.2.0)(jiti@2.4.2)(sass@1.70.0)(terser@5.37.0)(yaml@2.6.1) + version: 7.1.1(@types/node@24.2.1)(jiti@2.4.2)(sass@1.70.0)(terser@5.37.0)(yaml@2.6.1) vite-plugin-package-version: specifier: ^1.1.0 - version: 1.1.0(vite@7.1.1(@types/node@24.2.0)(jiti@2.4.2)(sass@1.70.0)(terser@5.37.0)(yaml@2.6.1)) + version: 1.1.0(vite@7.1.1(@types/node@24.2.1)(jiti@2.4.2)(sass@1.70.0)(terser@5.37.0)(yaml@2.6.1)) packages: @@ -965,14 +965,14 @@ packages: '@tanstack/query-devtools@5.84.0': resolution: {integrity: sha512-fbF3n+z1rqhvd9EoGp5knHkv3p5B2Zml1yNRjh7sNXklngYI5RVIWUrUjZ1RIcEoscarUb0+bOvIs5x9dwzOXQ==} - '@tanstack/react-query-devtools@5.84.1': - resolution: {integrity: sha512-nle+OQ9B3Z3EG2R3ixvaNcJ6OeqGwmAc5iMDW6Vj+emLZkWRrN3BDsrzZQu414n34lpxplnC7z1jmKuU/scHCQ==} + '@tanstack/react-query-devtools@5.84.2': + resolution: {integrity: sha512-ojJ66QoW9noqK35Lsmfqpfucj6wuOxLL2TYwEwpvU+iUQ5R/7TKpapWvpy9kZyNSl0mxv5mpS+ImfR8aL8/x3g==} peerDependencies: - '@tanstack/react-query': ^5.84.1 + '@tanstack/react-query': ^5.84.2 react: ^18 || ^19 - '@tanstack/react-query@5.84.1': - resolution: {integrity: sha512-zo7EUygcWJMQfFNWDSG7CBhy8irje/XY0RDVKKV4IQJAysb+ZJkkJPcnQi+KboyGUgT+SQebRFoTqLuTtfoDLw==} + '@tanstack/react-query@5.84.2': + resolution: {integrity: sha512-cZadySzROlD2+o8zIfbD978p0IphuQzRWiiH3I2ugnTmz4jbjc0+TdibpwqxlzynEen8OulgAg+rzdNF37s7XQ==} peerDependencies: react: ^18 || ^19 @@ -1051,8 +1051,8 @@ packages: '@types/ms@2.1.0': resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==} - '@types/node@24.2.0': - resolution: {integrity: sha512-3xyG3pMCq3oYCNg7/ZP+E1ooTaGB4cG8JWRsqqOYQdbWNY4zbaV0Ennrd7stjiJEFZCaybcIgpTjJWHRfBSIDw==} + '@types/node@24.2.1': + resolution: {integrity: sha512-DRh5K+ka5eJic8CjH7td8QpYEV6Zo10gfRkjHCO3weqZHWDtAaSTFtl4+VMqOJ4N5jcuhZ9/l+yy8rVgw7BQeQ==} '@types/normalize-package-data@2.4.4': resolution: {integrity: sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==} @@ -1180,8 +1180,8 @@ packages: resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} engines: {node: '>=8'} - browserslist@4.25.1: - resolution: {integrity: sha512-KGj0KoOMXLpSNkkEI6Z6mShmQy0bc1I+T7K9N81k4WWMrfz+6fQ6es80B/YLAeRoKvjYE1YSHHOW1qe9xIVzHw==} + browserslist@4.25.2: + resolution: {integrity: sha512-0si2SJK3ooGzIawRu61ZdPCO1IncZwS8IzuX73sPZsXW6EQ/w/DAfPyKI8l1ETTCr2MnvqWitmlCUxgdul45jA==} engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true @@ -1217,8 +1217,8 @@ packages: resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==} engines: {node: '>=6'} - caniuse-lite@1.0.30001731: - resolution: {integrity: sha512-lDdp2/wrOmTRWuoB5DpfNkC0rJDU8DqRa6nYL6HK6sytw70QMopt/NIc/9SM7ylItlBWfACXk0tEn37UWM/+mg==} + caniuse-lite@1.0.30001734: + resolution: {integrity: sha512-uhE1Ye5vgqju6OI71HTQqcBCZrvHugk0MjLak7Q+HfoBgoq5Bi+5YnwjP4fjDgrtYr/l8MVRBvzz9dPD4KyK0A==} ccount@2.0.1: resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} @@ -1563,8 +1563,8 @@ packages: resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} engines: {node: '>= 0.4'} - es-toolkit@1.39.8: - resolution: {integrity: sha512-A8QO9TfF+rltS8BXpdu8OS+rpGgEdnRhqIVxO/ZmNvnXBYgOdSsxukT55ELyP94gZIntWJ+Li9QRrT2u1Kitpg==} + es-toolkit@1.39.9: + resolution: {integrity: sha512-9OtbkZmTA2Qc9groyA1PUNeb6knVTkvB2RSdr/LcJXDL8IdEakaxwXLHXa7VX/Wj0GmdMJPR3WhnPGhiP3E+qg==} esbuild@0.25.8: resolution: {integrity: sha512-vVC0USHGtMi8+R4Kz8rt6JhEWLxsv9Rnu/lGYbPR8u47B+DCBksq9JarW0zOO7bs37hyOK1l2/oqtbciutL5+Q==} @@ -1929,8 +1929,8 @@ packages: resolution: {integrity: sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A==} hasBin: true - js-base64@3.7.7: - resolution: {integrity: sha512-7rCnleh0z2CkXhH67J8K1Ytz0b2Y+yxTPL+/KOJoa20hfnVQ/3/T6W/KflYI4bRHRagNeXeU2bkNGI3v1oS/lw==} + js-base64@3.7.8: + resolution: {integrity: sha512-hNngCeKxIUQiEUN3GPJOkz4wF/YvdUdbNL9hsBcMQTkKzboD7T/q3OYOuuPZLUE6dBxSGpwhk5mwuDud7JVAow==} js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} @@ -3121,7 +3121,7 @@ snapshots: dependencies: '@babel/compat-data': 7.28.0 '@babel/helper-validator-option': 7.27.1 - browserslist: 4.25.1 + browserslist: 4.25.2 lru-cache: 5.1.1 semver: 6.3.1 @@ -3643,13 +3643,13 @@ snapshots: '@tanstack/query-devtools@5.84.0': {} - '@tanstack/react-query-devtools@5.84.1(@tanstack/react-query@5.84.1(react@18.3.1))(react@18.3.1)': + '@tanstack/react-query-devtools@5.84.2(@tanstack/react-query@5.84.2(react@18.3.1))(react@18.3.1)': dependencies: '@tanstack/query-devtools': 5.84.0 - '@tanstack/react-query': 5.84.1(react@18.3.1) + '@tanstack/react-query': 5.84.2(react@18.3.1) react: 18.3.1 - '@tanstack/react-query@5.84.1(react@18.3.1)': + '@tanstack/react-query@5.84.2(react@18.3.1)': dependencies: '@tanstack/query-core': 5.83.1 react: 18.3.1 @@ -3722,7 +3722,7 @@ snapshots: '@types/ms@2.1.0': {} - '@types/node@24.2.0': + '@types/node@24.2.1': dependencies: undici-types: 7.10.0 @@ -3773,11 +3773,11 @@ snapshots: '@use-gesture/core': 10.3.1 react: 18.3.1 - '@vitejs/plugin-react-swc@3.11.0(vite@7.1.1(@types/node@24.2.0)(jiti@2.4.2)(sass@1.70.0)(terser@5.37.0)(yaml@2.6.1))': + '@vitejs/plugin-react-swc@3.11.0(vite@7.1.1(@types/node@24.2.1)(jiti@2.4.2)(sass@1.70.0)(terser@5.37.0)(yaml@2.6.1))': dependencies: '@rolldown/pluginutils': 1.0.0-beta.27 '@swc/core': 1.13.3 - vite: 7.1.1(@types/node@24.2.0)(jiti@2.4.2)(sass@1.70.0)(terser@5.37.0)(yaml@2.6.1) + vite: 7.1.1(@types/node@24.2.1)(jiti@2.4.2)(sass@1.70.0)(terser@5.37.0)(yaml@2.6.1) transitivePeerDependencies: - '@swc/helpers' @@ -3814,8 +3814,8 @@ snapshots: autoprefixer@10.4.21(postcss@8.5.6): dependencies: - browserslist: 4.25.1 - caniuse-lite: 1.0.30001731 + browserslist: 4.25.2 + caniuse-lite: 1.0.30001734 fraction.js: 4.3.7 normalize-range: 0.1.2 picocolors: 1.1.1 @@ -3853,12 +3853,12 @@ snapshots: dependencies: fill-range: 7.1.1 - browserslist@4.25.1: + browserslist@4.25.2: dependencies: - caniuse-lite: 1.0.30001731 + caniuse-lite: 1.0.30001734 electron-to-chromium: 1.5.199 node-releases: 2.0.19 - update-browserslist-db: 1.1.3(browserslist@4.25.1) + update-browserslist-db: 1.1.3(browserslist@4.25.2) buffer-from@1.1.2: {} @@ -3884,7 +3884,7 @@ snapshots: camelcase@5.3.1: {} - caniuse-lite@1.0.30001731: {} + caniuse-lite@1.0.30001734: {} ccount@2.0.1: {} @@ -4261,7 +4261,7 @@ snapshots: has-tostringtag: 1.0.2 hasown: 2.0.2 - es-toolkit@1.39.8: {} + es-toolkit@1.39.9: {} esbuild@0.25.8: optionalDependencies: @@ -4653,7 +4653,7 @@ snapshots: jiti@2.4.2: optional: true - js-base64@3.7.7: {} + js-base64@3.7.8: {} js-tokens@4.0.0: {} @@ -5338,7 +5338,7 @@ snapshots: '@reduxjs/toolkit': 2.8.2(react-redux@9.2.0(@types/react@18.3.23)(react@18.3.1)(redux@5.0.1))(react@18.3.1) clsx: 2.1.1 decimal.js-light: 2.5.1 - es-toolkit: 1.39.8 + es-toolkit: 1.39.9 eventemitter3: 5.0.1 immer: 10.1.1 react: 18.3.1 @@ -5793,9 +5793,9 @@ snapshots: unist-util-is: 6.0.0 unist-util-visit-parents: 6.0.1 - update-browserslist-db@1.1.3(browserslist@4.25.1): + update-browserslist-db@1.1.3(browserslist@4.25.2): dependencies: - browserslist: 4.25.1 + browserslist: 4.25.2 escalade: 3.2.0 picocolors: 1.1.1 @@ -5860,11 +5860,11 @@ snapshots: d3-time: 3.1.0 d3-timer: 3.0.1 - vite-plugin-package-version@1.1.0(vite@7.1.1(@types/node@24.2.0)(jiti@2.4.2)(sass@1.70.0)(terser@5.37.0)(yaml@2.6.1)): + vite-plugin-package-version@1.1.0(vite@7.1.1(@types/node@24.2.1)(jiti@2.4.2)(sass@1.70.0)(terser@5.37.0)(yaml@2.6.1)): dependencies: - vite: 7.1.1(@types/node@24.2.0)(jiti@2.4.2)(sass@1.70.0)(terser@5.37.0)(yaml@2.6.1) + vite: 7.1.1(@types/node@24.2.1)(jiti@2.4.2)(sass@1.70.0)(terser@5.37.0)(yaml@2.6.1) - vite@7.1.1(@types/node@24.2.0)(jiti@2.4.2)(sass@1.70.0)(terser@5.37.0)(yaml@2.6.1): + vite@7.1.1(@types/node@24.2.1)(jiti@2.4.2)(sass@1.70.0)(terser@5.37.0)(yaml@2.6.1): dependencies: esbuild: 0.25.8 fdir: 6.4.6(picomatch@4.0.3) @@ -5873,7 +5873,7 @@ snapshots: rollup: 4.46.2 tinyglobby: 0.2.14 optionalDependencies: - '@types/node': 24.2.0 + '@types/node': 24.2.1 fsevents: 2.3.3 jiti: 2.4.2 sass: 1.70.0 From b93a906699ece81bf157cd0c848427012225190a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20W=C3=B3jcik?= Date: Mon, 11 Aug 2025 13:36:34 +0200 Subject: [PATCH 2/8] disable external MFA option if enterprise features are disabled --- .../FormLocationMfaModeSelect.tsx | 12 +++++++++--- .../Form/FormLocationMfaModeSelect/style.scss | 19 ++++++++++++++++--- 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/web/src/shared/components/Form/FormLocationMfaModeSelect/FormLocationMfaModeSelect.tsx b/web/src/shared/components/Form/FormLocationMfaModeSelect/FormLocationMfaModeSelect.tsx index 3fb096fd04..3c1fe8cad7 100644 --- a/web/src/shared/components/Form/FormLocationMfaModeSelect/FormLocationMfaModeSelect.tsx +++ b/web/src/shared/components/Form/FormLocationMfaModeSelect/FormLocationMfaModeSelect.tsx @@ -10,6 +10,7 @@ import { useI18nContext } from '../../../../i18n/i18n-react'; import { RadioButton } from '../../../defguard-ui/components/Layout/RadioButton/Radiobutton'; import type { SelectOption } from '../../../defguard-ui/components/Layout/Select/types'; import { LocationMfaMode } from '../../../types'; +import { useAppStore } from '../../../hooks/store/useAppStore'; type Props = { controller: UseControllerProps; @@ -22,6 +23,7 @@ export const FormLocationMfaModeSelect = ({ const { field: { onChange, value: fieldValue }, } = useController(controller); + const enterpriseEnabled = useAppStore((s) => s.appInfo?.license_info.enterprise); const options = useMemo( (): SelectOption[] => [ @@ -39,6 +41,7 @@ export const FormLocationMfaModeSelect = ({ key: LocationMfaMode.EXTERNAL, value: LocationMfaMode.EXTERNAL, label: LL.components.locationMfaModeSelect.options.external(), + disabled: !enterpriseEnabled }, ], [ @@ -51,16 +54,19 @@ export const FormLocationMfaModeSelect = ({ return (
- {options.map(({ key, value, label }) => { + {options.map(({ key, value, label, disabled = false }) => { const active = fieldValue === value; return (
{ - onChange(value); + if (!disabled) { + onChange(value); + } }} >

{label}

diff --git a/web/src/shared/components/Form/FormLocationMfaModeSelect/style.scss b/web/src/shared/components/Form/FormLocationMfaModeSelect/style.scss index c543593e2e..b1ace8d581 100644 --- a/web/src/shared/components/Form/FormLocationMfaModeSelect/style.scss +++ b/web/src/shared/components/Form/FormLocationMfaModeSelect/style.scss @@ -15,8 +15,7 @@ border-radius: 10px; cursor: pointer; user-select: none; - transition-property: border-color; - + transition-property: border-color, opacity; @include animate-standard; &:not(.active) { @@ -36,6 +35,20 @@ } } + &.disabled { + opacity: 0.6; + cursor: not-allowed; + background-color: var(--surface-secondary); + + .label { + color: var(--text-body-disabled); + } + + &:hover { + border-color: var(--border-primary); + } + } + .label { color: var(--text-body-secondary); transition-property: color; @@ -43,4 +56,4 @@ @include animate-standard; } } -} +} \ No newline at end of file From 3b710cd872953994964e2030f9cf260ed5bf088c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20W=C3=B3jcik?= Date: Mon, 11 Aug 2025 14:09:22 +0200 Subject: [PATCH 3/8] disable external MFA if external openid provider is not configured --- crates/defguard_core/src/handlers/app_info.rs | 7 +++++++ .../FormLocationMfaModeSelect.tsx | 4 +++- web/src/shared/types.ts | 1 + 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/crates/defguard_core/src/handlers/app_info.rs b/crates/defguard_core/src/handlers/app_info.rs index 7ba365a774..e8126ecdbe 100644 --- a/crates/defguard_core/src/handlers/app_info.rs +++ b/crates/defguard_core/src/handlers/app_info.rs @@ -7,6 +7,7 @@ use crate::{ auth::SessionInfo, db::{Settings, WireguardNetwork}, enterprise::{ + db::models::openid_provider::OpenIdProvider, is_enterprise_enabled, is_enterprise_free, license::get_cached_license, limits::{LimitsExceeded, get_counts}, @@ -41,19 +42,24 @@ pub struct AppInfo { smtp_enabled: bool, license_info: LicenseInfo, ldap_info: LdapInfo, + external_openid_enabled: bool, } pub(crate) async fn get_app_info( State(appstate): State, _session: SessionInfo, ) -> ApiResult { + // both `await`s are executed upfront to avoid holding license `RwLock` across an await point let networks = WireguardNetwork::all(&appstate.pool).await?; + let external_openid_enabled = OpenIdProvider::get_current(&appstate.pool).await?.is_some(); + let settings = Settings::get_current_settings(); let enterprise = is_enterprise_enabled(); let license = get_cached_license(); let counts = get_counts(); let limits_exceeded = counts.get_exceeded_limits(license.as_ref()); let any_limit_exceeded = limits_exceeded.any(); + let res = AppInfo { network_present: !networks.is_empty(), smtp_enabled: settings.smtp_configured(), @@ -68,6 +74,7 @@ pub(crate) async fn get_app_info( enabled: settings.ldap_enabled, ad: settings.ldap_uses_ad, }, + external_openid_enabled, }; Ok(ApiResponse::new(json!(res), StatusCode::OK)) diff --git a/web/src/shared/components/Form/FormLocationMfaModeSelect/FormLocationMfaModeSelect.tsx b/web/src/shared/components/Form/FormLocationMfaModeSelect/FormLocationMfaModeSelect.tsx index 3c1fe8cad7..872dca98a8 100644 --- a/web/src/shared/components/Form/FormLocationMfaModeSelect/FormLocationMfaModeSelect.tsx +++ b/web/src/shared/components/Form/FormLocationMfaModeSelect/FormLocationMfaModeSelect.tsx @@ -24,6 +24,8 @@ export const FormLocationMfaModeSelect = ({ field: { onChange, value: fieldValue }, } = useController(controller); const enterpriseEnabled = useAppStore((s) => s.appInfo?.license_info.enterprise); + const externalOpenIdConfigured = useAppStore((s) => s.appInfo?.external_openid_enabled); + const externalMfaDisabled = !(enterpriseEnabled && externalOpenIdConfigured); const options = useMemo( (): SelectOption[] => [ @@ -41,7 +43,7 @@ export const FormLocationMfaModeSelect = ({ key: LocationMfaMode.EXTERNAL, value: LocationMfaMode.EXTERNAL, label: LL.components.locationMfaModeSelect.options.external(), - disabled: !enterpriseEnabled + disabled: externalMfaDisabled }, ], [ diff --git a/web/src/shared/types.ts b/web/src/shared/types.ts index 59d2410939..1896bc5619 100644 --- a/web/src/shared/types.ts +++ b/web/src/shared/types.ts @@ -360,6 +360,7 @@ export interface AppInfo { smtp_enabled: boolean; license_info: LicenseInfo; ldap_info: LdapInfo; + external_openid_enabled: boolean; } export type GetDeviceConfigRequest = { From ac9bc3436206fee04f713d8acc92cbcbf794e955 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20W=C3=B3jcik?= Date: Mon, 11 Aug 2025 14:12:46 +0200 Subject: [PATCH 4/8] formatting --- .../FormLocationMfaModeSelect.tsx | 7 ++++--- .../components/Form/FormLocationMfaModeSelect/style.scss | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/web/src/shared/components/Form/FormLocationMfaModeSelect/FormLocationMfaModeSelect.tsx b/web/src/shared/components/Form/FormLocationMfaModeSelect/FormLocationMfaModeSelect.tsx index 872dca98a8..0c87aae1c7 100644 --- a/web/src/shared/components/Form/FormLocationMfaModeSelect/FormLocationMfaModeSelect.tsx +++ b/web/src/shared/components/Form/FormLocationMfaModeSelect/FormLocationMfaModeSelect.tsx @@ -9,8 +9,8 @@ import { import { useI18nContext } from '../../../../i18n/i18n-react'; import { RadioButton } from '../../../defguard-ui/components/Layout/RadioButton/Radiobutton'; import type { SelectOption } from '../../../defguard-ui/components/Layout/Select/types'; -import { LocationMfaMode } from '../../../types'; import { useAppStore } from '../../../hooks/store/useAppStore'; +import { LocationMfaMode } from '../../../types'; type Props = { controller: UseControllerProps; @@ -43,13 +43,14 @@ export const FormLocationMfaModeSelect = ({ key: LocationMfaMode.EXTERNAL, value: LocationMfaMode.EXTERNAL, label: LL.components.locationMfaModeSelect.options.external(), - disabled: externalMfaDisabled + disabled: externalMfaDisabled, }, ], [ LL.components.locationMfaModeSelect.options.disabled, LL.components.locationMfaModeSelect.options.external, LL.components.locationMfaModeSelect.options.internal, + externalMfaDisabled, ], ); @@ -62,7 +63,7 @@ export const FormLocationMfaModeSelect = ({
{ diff --git a/web/src/shared/components/Form/FormLocationMfaModeSelect/style.scss b/web/src/shared/components/Form/FormLocationMfaModeSelect/style.scss index b1ace8d581..f61984de9c 100644 --- a/web/src/shared/components/Form/FormLocationMfaModeSelect/style.scss +++ b/web/src/shared/components/Form/FormLocationMfaModeSelect/style.scss @@ -56,4 +56,4 @@ @include animate-standard; } } -} \ No newline at end of file +} From f7bc75968b1f9b27a128cd3c35e808ec72d49bb6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20W=C3=B3jcik?= Date: Mon, 11 Aug 2025 16:41:41 +0200 Subject: [PATCH 5/8] remove unnecessary result --- crates/defguard_core/src/db/models/wireguard.rs | 8 +++----- .../defguard_core/src/enterprise/db/models/acl/tests.rs | 2 -- crates/defguard_core/src/enterprise/directory_sync/mod.rs | 1 - crates/defguard_core/src/handlers/wireguard.rs | 3 +-- crates/defguard_core/src/lib.rs | 7 +++---- crates/defguard_core/src/wg_config.rs | 2 +- crates/defguard_core/tests/integration/acl.rs | 2 -- .../tests/integration/wireguard_network_import.rs | 1 - 8 files changed, 8 insertions(+), 18 deletions(-) diff --git a/crates/defguard_core/src/db/models/wireguard.rs b/crates/defguard_core/src/db/models/wireguard.rs index 580fd82e4c..198887d0ef 100644 --- a/crates/defguard_core/src/db/models/wireguard.rs +++ b/crates/defguard_core/src/db/models/wireguard.rs @@ -246,10 +246,10 @@ impl WireguardNetwork { acl_enabled: bool, acl_default_allow: bool, location_mfa_mode: LocationMfaMode, - ) -> Result { + ) -> Self { let prvkey = StaticSecret::random_from_rng(OsRng); let pubkey = PublicKey::from(&prvkey); - Ok(Self { + Self { id: NoId, name, address, @@ -266,7 +266,7 @@ impl WireguardNetwork { acl_enabled, acl_default_allow, location_mfa_mode, - }) + } } /// Try to set `address` from `&str`. @@ -2036,7 +2036,6 @@ mod test { false, LocationMfaMode::Disabled, ) - .unwrap() .save(&pool) .await .unwrap(); @@ -2168,7 +2167,6 @@ mod test { false, LocationMfaMode::Disabled, ) - .unwrap() .save(&pool) .await .unwrap(); diff --git a/crates/defguard_core/src/enterprise/db/models/acl/tests.rs b/crates/defguard_core/src/enterprise/db/models/acl/tests.rs index 211c8cc769..ca828a4238 100644 --- a/crates/defguard_core/src/enterprise/db/models/acl/tests.rs +++ b/crates/defguard_core/src/enterprise/db/models/acl/tests.rs @@ -183,7 +183,6 @@ async fn test_rule_relations(_: PgPoolOptions, options: PgConnectOptions) { false, LocationMfaMode::Disabled, ) - .unwrap() .save(&pool) .await .unwrap(); @@ -200,7 +199,6 @@ async fn test_rule_relations(_: PgPoolOptions, options: PgConnectOptions) { false, LocationMfaMode::Disabled, ) - .unwrap() .save(&pool) .await .unwrap(); diff --git a/crates/defguard_core/src/enterprise/directory_sync/mod.rs b/crates/defguard_core/src/enterprise/directory_sync/mod.rs index fef3db04c3..73faaf8f19 100644 --- a/crates/defguard_core/src/enterprise/directory_sync/mod.rs +++ b/crates/defguard_core/src/enterprise/directory_sync/mod.rs @@ -957,7 +957,6 @@ mod test { false, LocationMfaMode::Disabled, ) - .unwrap() .save(pool) .await .unwrap(); diff --git a/crates/defguard_core/src/handlers/wireguard.rs b/crates/defguard_core/src/handlers/wireguard.rs index b603f81294..603a0c8a4f 100644 --- a/crates/defguard_core/src/handlers/wireguard.rs +++ b/crates/defguard_core/src/handlers/wireguard.rs @@ -150,8 +150,7 @@ pub(crate) async fn create_network( data.acl_enabled, data.acl_default_allow, data.location_mfa_mode, - ) - .map_err(|_| WebError::Serialization("Invalid network address".into()))?; + ); let mut transaction = appstate.pool.begin().await?; let network = network.save(&mut *transaction).await?; diff --git a/crates/defguard_core/src/lib.rs b/crates/defguard_core/src/lib.rs index fec31d6c10..436c923d66 100644 --- a/crates/defguard_core/src/lib.rs +++ b/crates/defguard_core/src/lib.rs @@ -739,8 +739,7 @@ pub async fn init_dev_env(config: &DefGuardConfig) { false, false, LocationMfaMode::Disabled, - ) - .expect("Could not create network"); + ); network.pubkey = "zGMeVGm9HV9I4wSKF9AXmYnnAIhDySyqLMuKpcfIaQo=".to_string(); network.prvkey = "MAk3d5KuB167G88HM7nGYR6ksnPMAOguAg2s5EcPp1M=".to_string(); network @@ -838,7 +837,7 @@ pub async fn init_vpn_location( false, false, LocationMfaMode::Disabled, - )? + ) .save(&mut *transaction) .await?; if network.id != location_id { @@ -877,7 +876,7 @@ pub async fn init_vpn_location( false, false, LocationMfaMode::Disabled, - )? + ) .save(pool) .await? }; diff --git a/crates/defguard_core/src/wg_config.rs b/crates/defguard_core/src/wg_config.rs index f634073b9b..4dcdc47ff4 100644 --- a/crates/defguard_core/src/wg_config.rs +++ b/crates/defguard_core/src/wg_config.rs @@ -112,7 +112,7 @@ pub(crate) fn parse_wireguard_config( false, false, LocationMfaMode::Disabled, - )?; + ); network.pubkey = pubkey; network.prvkey = prvkey.to_string(); diff --git a/crates/defguard_core/tests/integration/acl.rs b/crates/defguard_core/tests/integration/acl.rs index b1a1b223a4..103c69c845 100644 --- a/crates/defguard_core/tests/integration/acl.rs +++ b/crates/defguard_core/tests/integration/acl.rs @@ -426,7 +426,6 @@ async fn test_related_objects(_: PgPoolOptions, options: PgConnectOptions) { false, LocationMfaMode::Disabled, ) - .unwrap() .save(&pool) .await .unwrap(); @@ -767,7 +766,6 @@ async fn test_rule_delete_state_applied(_: PgPoolOptions, options: PgConnectOpti false, LocationMfaMode::Disabled, ) - .unwrap() .save(&pool) .await .unwrap(); diff --git a/crates/defguard_core/tests/integration/wireguard_network_import.rs b/crates/defguard_core/tests/integration/wireguard_network_import.rs index bef4ba9727..364543e3b9 100644 --- a/crates/defguard_core/tests/integration/wireguard_network_import.rs +++ b/crates/defguard_core/tests/integration/wireguard_network_import.rs @@ -63,7 +63,6 @@ async fn test_config_import(_: PgPoolOptions, options: PgConnectOptions) { false, LocationMfaMode::Disabled, ) - .unwrap(); initial_network.save(&pool).await.unwrap(); // add existing devices From 92cb1478e6c9dbbd74b408372b0b7372e34d8db7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20W=C3=B3jcik?= Date: Tue, 12 Aug 2025 08:19:49 +0200 Subject: [PATCH 6/8] validate selected mfa mode --- .../defguard_core/src/handlers/wireguard.rs | 40 ++++++++++++++++++- .../integration/wireguard_network_import.rs | 2 +- 2 files changed, 40 insertions(+), 2 deletions(-) diff --git a/crates/defguard_core/src/handlers/wireguard.rs b/crates/defguard_core/src/handlers/wireguard.rs index 603a0c8a4f..44e2776204 100644 --- a/crates/defguard_core/src/handlers/wireguard.rs +++ b/crates/defguard_core/src/handlers/wireguard.rs @@ -35,7 +35,10 @@ use crate::{ }, }, }, - enterprise::{handlers::CanManageDevices, limits::update_counts}, + enterprise::{ + db::models::openid_provider::OpenIdProvider, handlers::CanManageDevices, + is_enterprise_enabled, limits::update_counts, + }, events::{ApiEvent, ApiEventType, ApiRequestContext}, grpc::GatewayMap, handlers::mail::send_new_device_added_email, @@ -88,6 +91,36 @@ impl WireguardNetworkData { .as_ref() .map_or(Vec::new(), |ips| parse_network_address_list(ips)) } + + pub(crate) async fn validate_location_mfa_mode<'e, E: sqlx::PgExecutor<'e>>( + &self, + executor: E, + ) -> Result<(), WebError> { + // if external MFA was chosen verify if enterprise features are enabled + // and external OpenID provider is configured + if self.location_mfa_mode == LocationMfaMode::External { + if !is_enterprise_enabled() { + error!( + "Unable to create location with external MFA. External OpenID provider is not configured" + ); + + return Err(WebError::Forbidden( + "Cannot enable external MFA. Enterprise features are disabled".into(), + )); + } + + if OpenIdProvider::get_current(executor).await?.is_none() { + error!( + "Unable to create location with external MFA. External OpenID provider is not configured" + ); + return Err(WebError::BadRequest( + "Cannot enable external MFA. External OpenID provider is not configured".into(), + )); + } + } + + Ok(()) + } } // Used in process of importing network from WireGuard config @@ -137,6 +170,9 @@ pub(crate) async fn create_network( "User {} creating WireGuard network {network_name}", session.user.username ); + + data.validate_location_mfa_mode(&appstate.pool).await?; + let allowed_ips = data.parse_allowed_ips(); let network = WireguardNetwork::new( data.name, @@ -219,6 +255,8 @@ pub(crate) async fn modify_network( "User {} updating WireGuard network {network_id}", session.user.username ); + data.validate_location_mfa_mode(&appstate.pool).await?; + let mut network = find_network(network_id, &appstate.pool).await?; // store network before mods let before = network.clone(); diff --git a/crates/defguard_core/tests/integration/wireguard_network_import.rs b/crates/defguard_core/tests/integration/wireguard_network_import.rs index 364543e3b9..59217fb90f 100644 --- a/crates/defguard_core/tests/integration/wireguard_network_import.rs +++ b/crates/defguard_core/tests/integration/wireguard_network_import.rs @@ -62,7 +62,7 @@ async fn test_config_import(_: PgPoolOptions, options: PgConnectOptions) { false, false, LocationMfaMode::Disabled, - ) + ); initial_network.save(&pool).await.unwrap(); // add existing devices From 2d3d61ec05d670713dd8b28fed33493b9ecaa0c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20W=C3=B3jcik?= Date: Tue, 12 Aug 2025 10:29:19 +0200 Subject: [PATCH 7/8] test validation --- .../tests/integration/wireguard.rs | 187 +++++++++++++++++- 1 file changed, 186 insertions(+), 1 deletion(-) diff --git a/crates/defguard_core/tests/integration/wireguard.rs b/crates/defguard_core/tests/integration/wireguard.rs index 2f71537a20..f3d1385e64 100644 --- a/crates/defguard_core/tests/integration/wireguard.rs +++ b/crates/defguard_core/tests/integration/wireguard.rs @@ -5,11 +5,17 @@ use defguard_core::{ Device, GatewayEvent, Id, WireguardNetwork, models::{ device::WireguardNetworkDevice, + settings::OpenidUsernameHandling, wireguard::{ DEFAULT_DISCONNECT_THRESHOLD, DEFAULT_KEEPALIVE_INTERVAL, LocationMfaMode, }, }, }, + enterprise::{ + db::models::openid_provider::{DirectorySyncTarget, DirectorySyncUserBehavior}, + handlers::openid_providers::AddProviderData, + license::{get_cached_license, set_cached_license}, + }, handlers::{Auth, GroupInfo, wireguard::WireguardNetworkData}, }; use ipnetwork::IpNetwork; @@ -18,7 +24,9 @@ use reqwest::StatusCode; use serde_json::json; use sqlx::postgres::{PgConnectOptions, PgPoolOptions}; -use crate::common::{make_network, make_test_client, setup_pool}; +use crate::common::{ + authenticate_admin, exceed_enterprise_limits, make_network, make_test_client, setup_pool, +}; #[sqlx::test] async fn test_network(_: PgPoolOptions, options: PgConnectOptions) { @@ -116,6 +124,183 @@ async fn test_network(_: PgPoolOptions, options: PgConnectOptions) { assert_matches!(event, GatewayEvent::NetworkDeleted(..)); } +#[sqlx::test] +async fn test_location_mfa_mode_validation_create(_: PgPoolOptions, options: PgConnectOptions) { + let pool = setup_pool(options).await; + + let (client, _client_state) = make_test_client(pool).await; + authenticate_admin(&client).await; + + exceed_enterprise_limits(&client).await; + + // unset the license + let license = get_cached_license().clone(); + set_cached_license(None); + + let location_data = WireguardNetworkData { + name: "test_location".into(), + address: "10.1.1.0/24".into(), + endpoint: "10.1.1.1".parse().unwrap(), + port: 55555, + allowed_ips: Some("10.1.1.0/24, 10.2.0.1/16, 10.10.10.54/32".into()), + dns: None, + allowed_groups: vec!["admin".into()], + keepalive_interval: DEFAULT_KEEPALIVE_INTERVAL, + peer_disconnect_threshold: DEFAULT_DISCONNECT_THRESHOLD, + acl_enabled: false, + acl_default_allow: false, + location_mfa_mode: LocationMfaMode::External, + }; + + // create network + let response = client + .post("/api/v1/network") + .json(&location_data) + .send() + .await; + assert_eq!(response.status(), StatusCode::FORBIDDEN); + + // restore valid license and try again + set_cached_license(license); + let response = client + .post("/api/v1/network") + .json(&location_data) + .send() + .await; + assert_eq!(response.status(), StatusCode::BAD_REQUEST); + + // add external OpenID provider + let provider_data = AddProviderData { + name: "test".to_string(), + base_url: "https://accounts.google.com".to_string(), + client_id: "client_id".to_string(), + client_secret: "client_secret".to_string(), + display_name: Some("display_name".to_string()), + admin_email: None, + google_service_account_email: None, + google_service_account_key: None, + directory_sync_enabled: false, + directory_sync_interval: 100, + directory_sync_user_behavior: DirectorySyncUserBehavior::Keep.to_string(), + directory_sync_admin_behavior: DirectorySyncUserBehavior::Keep.to_string(), + directory_sync_target: DirectorySyncTarget::All.to_string(), + create_account: false, + okta_dirsync_client_id: None, + okta_private_jwk: None, + directory_sync_group_match: None, + username_handling: OpenidUsernameHandling::PruneEmailDomain, + }; + + let response = client + .post("/api/v1/openid/provider") + .json(&provider_data) + .send() + .await; + + assert_eq!(response.status(), StatusCode::CREATED); + + // try again + let response = client + .post("/api/v1/network") + .json(&location_data) + .send() + .await; + assert_eq!(response.status(), StatusCode::CREATED); +} + +#[sqlx::test] +async fn test_location_mfa_mode_validation_modify(_: PgPoolOptions, options: PgConnectOptions) { + let pool = setup_pool(options).await; + + let (client, _client_state) = make_test_client(pool).await; + authenticate_admin(&client).await; + + let mut location_data = WireguardNetworkData { + name: "test_location".into(), + address: "10.1.1.0/24".into(), + endpoint: "10.1.1.1".parse().unwrap(), + port: 55555, + allowed_ips: Some("10.1.1.0/24, 10.2.0.1/16, 10.10.10.54/32".into()), + dns: None, + allowed_groups: vec!["admin".into()], + keepalive_interval: DEFAULT_KEEPALIVE_INTERVAL, + peer_disconnect_threshold: DEFAULT_DISCONNECT_THRESHOLD, + acl_enabled: false, + acl_default_allow: false, + location_mfa_mode: LocationMfaMode::Disabled, + }; + + // create network + let response = client + .post("/api/v1/network") + .json(&location_data) + .send() + .await; + assert_eq!(response.status(), StatusCode::CREATED); + + exceed_enterprise_limits(&client).await; + + // unset the license + let license = get_cached_license().clone(); + set_cached_license(None); + + // attempt to modify location + location_data.location_mfa_mode = LocationMfaMode::External; + let response = client + .put("/api/v1/network/1") + .json(&location_data) + .send() + .await; + assert_eq!(response.status(), StatusCode::FORBIDDEN); + + // restore valid license and try again + set_cached_license(license); + let response = client + .put("/api/v1/network/1") + .json(&location_data) + .send() + .await; + assert_eq!(response.status(), StatusCode::BAD_REQUEST); + + // add external OpenID provider + let provider_data = AddProviderData { + name: "test".to_string(), + base_url: "https://accounts.google.com".to_string(), + client_id: "client_id".to_string(), + client_secret: "client_secret".to_string(), + display_name: Some("display_name".to_string()), + admin_email: None, + google_service_account_email: None, + google_service_account_key: None, + directory_sync_enabled: false, + directory_sync_interval: 100, + directory_sync_user_behavior: DirectorySyncUserBehavior::Keep.to_string(), + directory_sync_admin_behavior: DirectorySyncUserBehavior::Keep.to_string(), + directory_sync_target: DirectorySyncTarget::All.to_string(), + create_account: false, + okta_dirsync_client_id: None, + okta_private_jwk: None, + directory_sync_group_match: None, + username_handling: OpenidUsernameHandling::PruneEmailDomain, + }; + + let response = client + .post("/api/v1/openid/provider") + .json(&provider_data) + .send() + .await; + + assert_eq!(response.status(), StatusCode::CREATED); + + // try again + let response = client + .put("/api/v1/network/1") + .json(&location_data) + .send() + .await; + assert_eq!(response.status(), StatusCode::OK); +} + #[sqlx::test] async fn test_device(_: PgPoolOptions, options: PgConnectOptions) { let pool = setup_pool(options).await; From b340d58f607a30c4531b198f632329e42958ee76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20W=C3=B3jcik?= Date: Tue, 12 Aug 2025 10:48:18 +0200 Subject: [PATCH 8/8] add serde rename --- crates/defguard_core/src/db/models/device.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/crates/defguard_core/src/db/models/device.rs b/crates/defguard_core/src/db/models/device.rs index c45c371dae..8977f70288 100644 --- a/crates/defguard_core/src/db/models/device.rs +++ b/crates/defguard_core/src/db/models/device.rs @@ -49,6 +49,7 @@ pub struct DeviceConfig { // Network: A stand-alone device added by a user permanently bound to one network, e.g. a printer #[derive(Clone, Debug, Deserialize, PartialEq, Serialize, ToSchema, Type)] #[sqlx(type_name = "device_type", rename_all = "snake_case")] +#[serde(rename_all = "snake_case")] pub enum DeviceType { User, Network,