From c98656e3fed9dc4a584522b6a3ec450c651f085f Mon Sep 17 00:00:00 2001
From: Jacek Chmielewski
Date: Wed, 24 Sep 2025 11:13:15 +0200
Subject: [PATCH 1/2] Release/1.5.1 (#1611)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* fix password reset grpc sending unparsed user agent (#1546)
Co-authored-by: Filip Ślęzak
* Fixes pentest issue DG25-10 from 2025-09-02 (#1579)
* validate phone number during enrollment
* also check phone numbers in core API endpoints
* Do not display sensitive data from protos (#1580)
* Don't send empty strings when phone number is not provided (#1583)
* don't send empty strings when phone number is not providecleand
* use zod trim() instead of trimObjectStrings helper
* Fixes pentest issue DG25-17 from 2025-09-02 (#1581)
* fix open redirect pentest issue
* add tests and handling of get requests, allow redirects if url is allowed for the client
* compare the whole url, not just domain
* cargo clippy fixes
* wip fix openid flow tests
* fix panic in the contains_redirect_url method
* cleanup eprintln statements
* bring back the other openid flow test
* state-based fallback url in openid test
* ensure openid client names don't contain HTML (#1587)
* ensure login responses don't allow login enumeration (#1588)
* Fixes pentest issue DG25-24 from 2025-09-02 (#1585)
* put mail handler into a separate crate (#1590)
* put random & secret modules into a common crate
* move DB setup code to common crate
* move version to common crate
* move id types to common crate
* move AuthCode model into common crate
* move auth key model
* move biometric auth model
* move device login model
* remove unnecessary feature flags
* move global value macro
* move model error
* move server config
* move hex module
* move protos to a separate crate
* put mailer into a separate crate
* update query data
* remove commented out code
* add new crates
* update flake inputs
* move AsCsv trait
* fix failing test
* move claims struct
* Cleanup and revive OpenID login test (#1591)
* use default subject as fallback (#1593)
* Fixes pentest issue DG25-25 and DG25-20 from 2025-09-02 (#1574)
* Fixes pentest issue DG25-32 from 2025-09-02 (#1597)
* custom Debug implementation for Settings struct to avoid exposing license key in logs
* cargo update
* fix document links (#1599)
* fix links in readme
* fix frontend links
* bump version to 1.5.1
* sanitize branch name for docker cache
* don't log settings during partial update
* cargo fmt
---------
Co-authored-by: Aleksander <170264518+t-aleksander@users.noreply.github.com>
Co-authored-by: Maciej Wójcik
Co-authored-by: Maciek <19913370+wojcik91@users.noreply.github.com>
Co-authored-by: Filip Ślęzak
Co-authored-by: Adam
---
.github/workflows/build-docker.yml | 7 +-
...b7d7faff6d6327e279362212cda4960caca0.json} | 4 +-
...35ad0e24e4855aa42cdceab2712f8c8dbef4.json} | 4 +-
...6a96461ecb5edf023ab88d71f9887fc0f2f2.json} | 6 +-
...dde95cf576aee8744697f1acf957e3fdd1552.json | 59 ++
Cargo.lock | 574 ++++++++++++----
Cargo.toml | 13 +-
README.md | 54 +-
crates/defguard/Cargo.toml | 2 +
crates/defguard/src/main.rs | 22 +-
crates/defguard_common/Cargo.toml | 39 ++
crates/defguard_common/build.rs | 10 +
crates/defguard_common/src/auth/claims.rs | 98 +++
crates/defguard_common/src/auth/mod.rs | 1 +
.../src/config.rs | 13 +-
crates/defguard_common/src/csv.rs | 17 +
crates/defguard_common/src/db/mod.rs | 47 ++
.../src/db/models/auth_code.rs | 43 +-
.../src/db/models/authentication_key.rs | 9 +-
.../src/db/models/biometric_auth.rs | 15 +-
.../src/db/models/device_login.rs | 6 +-
.../src/db/models/error.rs | 0
crates/defguard_common/src/db/models/mod.rs | 15 +
.../src/db/models/settings.rs | 126 +++-
crates/defguard_common/src/db/models/user.rs | 30 +
.../src/globals.rs | 0
.../src/hex.rs | 0
crates/defguard_common/src/lib.rs | 11 +
.../src/random.rs | 4 +-
.../src/secret.rs | 0
crates/defguard_core/Cargo.toml | 31 +-
crates/defguard_core/build.rs | 27 +-
crates/defguard_core/src/appstate.rs | 4 +-
crates/defguard_core/src/auth/mod.rs | 178 +----
crates/defguard_core/src/db/mod.rs | 42 +-
.../src/db/models/activity_log/metadata.rs | 30 +-
.../src/db/models/activity_log/mod.rs | 2 +-
crates/defguard_core/src/db/models/device.rs | 17 +-
.../defguard_core/src/db/models/enrollment.rs | 52 +-
crates/defguard_core/src/db/models/group.rs | 6 +-
crates/defguard_core/src/db/models/mod.rs | 27 +-
.../src/db/models/oauth2authorizedapp.rs | 2 +-
.../src/db/models/oauth2client.rs | 64 +-
.../src/db/models/oauth2token.rs | 3 +-
.../src/db/models/polling_token.rs | 6 +-
crates/defguard_core/src/db/models/session.rs | 12 +-
crates/defguard_core/src/db/models/user.rs | 97 +--
.../defguard_core/src/db/models/webauthn.rs | 3 +-
crates/defguard_core/src/db/models/webhook.rs | 2 +-
.../defguard_core/src/db/models/wireguard.rs | 23 +-
.../src/db/models/wireguard_peer_stats.rs | 2 +-
crates/defguard_core/src/db/models/yubikey.rs | 2 +-
.../activity_log_stream/http_stream.rs | 8 +-
.../src/enterprise/db/models/acl.rs | 6 +-
.../src/enterprise/db/models/acl/tests.rs | 3 +-
.../db/models/activity_log_stream.rs | 4 +-
.../src/enterprise/db/models/api_tokens.rs | 2 +-
.../enterprise/db/models/openid_provider.rs | 2 +-
.../src/enterprise/db/models/snat.rs | 6 +-
.../src/enterprise/directory_sync/mod.rs | 3 +-
.../src/enterprise/directory_sync/tests.rs | 17 +-
.../src/enterprise/firewall/mod.rs | 13 +-
.../src/enterprise/firewall/tests.rs | 12 +-
.../src/enterprise/grpc/desktop_client_mfa.rs | 8 +-
.../src/enterprise/grpc/polling.rs | 9 +-
.../src/enterprise/handlers/acl.rs | 2 +-
.../handlers/activity_log_stream.rs | 2 +-
.../src/enterprise/handlers/api_tokens.rs | 2 +-
.../src/enterprise/handlers/openid_login.rs | 171 ++---
.../enterprise/handlers/openid_providers.rs | 57 +-
.../src/enterprise/ldap/client.rs | 6 +-
.../defguard_core/src/enterprise/ldap/hash.rs | 3 +-
.../defguard_core/src/enterprise/ldap/mod.rs | 29 +-
.../src/enterprise/ldap/model.rs | 7 +-
.../defguard_core/src/enterprise/ldap/sync.rs | 30 +-
.../src/enterprise/ldap/tests.rs | 7 +-
.../src/enterprise/ldap/utils.rs | 3 +-
.../defguard_core/src/enterprise/license.rs | 10 +-
crates/defguard_core/src/enterprise/limits.rs | 3 +-
.../src/enterprise/snat/handlers.rs | 3 +-
crates/defguard_core/src/error.rs | 10 +-
crates/defguard_core/src/events.rs | 28 +-
crates/defguard_core/src/grpc/auth.rs | 9 +-
crates/defguard_core/src/grpc/client_mfa.rs | 41 +-
crates/defguard_core/src/grpc/enrollment.rs | 239 +++++--
.../src/grpc/gateway/client_state.rs | 3 +-
crates/defguard_core/src/grpc/gateway/map.rs | 3 +-
crates/defguard_core/src/grpc/gateway/mod.rs | 17 +-
.../defguard_core/src/grpc/gateway/state.rs | 4 +-
crates/defguard_core/src/grpc/interceptor.rs | 10 +-
crates/defguard_core/src/grpc/mod.rs | 91 +--
.../defguard_core/src/grpc/password_reset.rs | 32 +-
crates/defguard_core/src/grpc/utils.rs | 20 +-
crates/defguard_core/src/grpc/worker.rs | 12 +-
.../src/handlers/activity_log.rs | 7 +-
crates/defguard_core/src/handlers/app_info.rs | 4 +-
crates/defguard_core/src/handlers/auth.rs | 32 +-
crates/defguard_core/src/handlers/group.rs | 3 +-
crates/defguard_core/src/handlers/mail.rs | 33 +-
crates/defguard_core/src/handlers/mod.rs | 10 +-
.../src/handlers/network_devices.rs | 6 +-
.../src/handlers/openid_clients.rs | 20 +
.../defguard_core/src/handlers/openid_flow.rs | 231 +++++--
crates/defguard_core/src/handlers/settings.rs | 24 +-
.../src/handlers/ssh_authorized_keys.rs | 9 +-
crates/defguard_core/src/handlers/user.rs | 44 +-
.../defguard_core/src/handlers/wireguard.rs | 6 +-
crates/defguard_core/src/handlers/worker.rs | 3 +-
crates/defguard_core/src/headers.rs | 17 +-
crates/defguard_core/src/lib.rs | 96 +--
crates/defguard_core/src/support.rs | 7 +-
crates/defguard_core/src/updates.rs | 8 +-
crates/defguard_core/src/utility_thread.rs | 3 +-
crates/defguard_core/src/version.rs | 4 +-
crates/defguard_core/src/wg_config.rs | 2 +-
.../src/wireguard_peer_disconnect.rs | 4 +-
.../tests/integration/api/acl.rs | 11 +-
.../tests/integration/api/api_tokens.rs | 4 +-
.../tests/integration/api/auth.rs | 72 +-
.../tests/integration/api/common/client.rs | 2 -
.../tests/integration/api/common/mod.rs | 32 +-
.../tests/integration/api/forward_auth.rs | 3 +-
.../tests/integration/api/mod.rs | 2 +
.../tests/integration/api/oauth.rs | 3 +-
.../tests/integration/api/openid.rs | 645 ++++++++++++++++--
.../tests/integration/api/openid_login.rs | 324 ++++-----
.../tests/integration/api/settings.rs | 10 +-
.../tests/integration/api/snat.rs | 2 +-
.../tests/integration/api/user.rs | 10 +-
.../tests/integration/api/webhook.rs | 6 +-
.../tests/integration/api/wireguard.rs | 4 +-
.../api/wireguard_network_allowed_groups.rs | 4 +-
.../api/wireguard_network_devices.rs | 3 +-
.../api/wireguard_network_stats.rs | 16 +-
.../tests/integration/api/worker.rs | 6 +-
.../defguard_core/tests/integration/common.rs | 7 +-
.../integration/grpc/common/mock_gateway.rs | 10 +-
.../tests/integration/grpc/common/mod.rs | 5 +-
.../tests/integration/grpc/gateway.rs | 17 +-
crates/defguard_event_logger/Cargo.toml | 17 +-
crates/defguard_event_logger/src/lib.rs | 38 +-
crates/defguard_event_logger/src/message.rs | 8 +-
crates/defguard_event_router/Cargo.toml | 1 +
crates/defguard_event_router/src/lib.rs | 2 +-
crates/defguard_mail/Cargo.toml | 26 +
.../src/mail.rs => defguard_mail/src/lib.rs} | 4 +-
.../src/templates.rs | 63 +-
.../templates/base.tera | 2 +-
.../templates/macros.tera | 0
.../templates/mail_desktop_start.tera | 0
.../templates/mail_email_mfa_activation.tera | 0
.../templates/mail_email_mfa_code.tera | 0
.../mail_enrollment_admin_notification.tera | 0
.../templates/mail_enrollment_start.tera | 0
.../templates/mail_enrollment_welcome.tera | 0
.../templates/mail_gateway_disconnected.tera | 0
.../templates/mail_gateway_reconnected.tera | 0
.../templates/mail_mfa_configured.tera | 0
.../templates/mail_new_device_added.tera | 0
.../templates/mail_new_device_login.tera | 0
.../templates/mail_new_device_ocid_login.tera | 0
.../templates/mail_password_reset_start.tera | 0
.../mail_password_reset_success.tera | 0
.../templates/mail_support_data.tera | 0
.../templates/mail_test.tera | 0
crates/defguard_proto/Cargo.toml | 17 +
crates/defguard_proto/build.rs | 37 +
crates/defguard_proto/src/lib.rs | 66 ++
deny.toml | 9 +
flake.lock | 12 +-
web/src/i18n/en/index.ts | 12 +-
web/src/i18n/i18n-types.ts | 24 +-
web/src/i18n/ko/index.ts | 6 +-
web/src/i18n/pl/index.ts | 10 +-
.../ProfileDetailsForm/ProfileDetailsForm.tsx | 7 +-
.../components/AddUserForm/AddUserForm.tsx | 23 +-
176 files changed, 3297 insertions(+), 1666 deletions(-)
rename .sqlx/{query-796641fb2d79872ae5de64c8b9181e5890a3a122ea5e37ad2fa216c9db47f0a3.json => query-04163625da5365779cb5e2a47242b7d7faff6d6327e279362212cda4960caca0.json} (96%)
rename .sqlx/{query-321ce9355db39c3d93d8b915ba7888357f5403c2e9e97fa17e502223bbcc918a.json => query-27f3c5ea4443993df10ea337195635ad0e24e4855aa42cdceab2712f8c8dbef4.json} (82%)
rename .sqlx/{query-7ddef79c85c3e85b979d5a8a5e50660bcae531c2b8342ae2feffea7454450f10.json => query-4a1fba6c990265bc278d4e1534f06a96461ecb5edf023ab88d71f9887fc0f2f2.json} (94%)
create mode 100644 .sqlx/query-ef66255ab254e8d0981226b2e9fdde95cf576aee8744697f1acf957e3fdd1552.json
create mode 100644 crates/defguard_common/Cargo.toml
create mode 100644 crates/defguard_common/build.rs
create mode 100644 crates/defguard_common/src/auth/claims.rs
create mode 100644 crates/defguard_common/src/auth/mod.rs
rename crates/{defguard_core => defguard_common}/src/config.rs (97%)
create mode 100644 crates/defguard_common/src/csv.rs
create mode 100644 crates/defguard_common/src/db/mod.rs
rename crates/{defguard_core => defguard_common}/src/db/models/auth_code.rs (50%)
rename crates/{defguard_core => defguard_common}/src/db/models/authentication_key.rs (94%)
rename crates/{defguard_core => defguard_common}/src/db/models/biometric_auth.rs (95%)
rename crates/{defguard_core => defguard_common}/src/db/models/device_login.rs (93%)
rename crates/{defguard_core => defguard_common}/src/db/models/error.rs (100%)
create mode 100644 crates/defguard_common/src/db/models/mod.rs
rename crates/{defguard_core => defguard_common}/src/db/models/settings.rs (75%)
create mode 100644 crates/defguard_common/src/db/models/user.rs
rename crates/{defguard_core => defguard_common}/src/globals.rs (100%)
rename crates/{defguard_core => defguard_common}/src/hex.rs (100%)
create mode 100644 crates/defguard_common/src/lib.rs
rename crates/{defguard_core => defguard_common}/src/random.rs (77%)
rename crates/{defguard_core => defguard_common}/src/secret.rs (100%)
create mode 100644 crates/defguard_mail/Cargo.toml
rename crates/{defguard_core/src/mail.rs => defguard_mail/src/lib.rs} (98%)
rename crates/{defguard_core => defguard_mail}/src/templates.rs (93%)
rename crates/{defguard_core => defguard_mail}/templates/base.tera (99%)
rename crates/{defguard_core => defguard_mail}/templates/macros.tera (100%)
rename crates/{defguard_core => defguard_mail}/templates/mail_desktop_start.tera (100%)
rename crates/{defguard_core => defguard_mail}/templates/mail_email_mfa_activation.tera (100%)
rename crates/{defguard_core => defguard_mail}/templates/mail_email_mfa_code.tera (100%)
rename crates/{defguard_core => defguard_mail}/templates/mail_enrollment_admin_notification.tera (100%)
rename crates/{defguard_core => defguard_mail}/templates/mail_enrollment_start.tera (100%)
rename crates/{defguard_core => defguard_mail}/templates/mail_enrollment_welcome.tera (100%)
rename crates/{defguard_core => defguard_mail}/templates/mail_gateway_disconnected.tera (100%)
rename crates/{defguard_core => defguard_mail}/templates/mail_gateway_reconnected.tera (100%)
rename crates/{defguard_core => defguard_mail}/templates/mail_mfa_configured.tera (100%)
rename crates/{defguard_core => defguard_mail}/templates/mail_new_device_added.tera (100%)
rename crates/{defguard_core => defguard_mail}/templates/mail_new_device_login.tera (100%)
rename crates/{defguard_core => defguard_mail}/templates/mail_new_device_ocid_login.tera (100%)
rename crates/{defguard_core => defguard_mail}/templates/mail_password_reset_start.tera (100%)
rename crates/{defguard_core => defguard_mail}/templates/mail_password_reset_success.tera (100%)
rename crates/{defguard_core => defguard_mail}/templates/mail_support_data.tera (100%)
rename crates/{defguard_core => defguard_mail}/templates/mail_test.tera (100%)
create mode 100644 crates/defguard_proto/Cargo.toml
create mode 100644 crates/defguard_proto/build.rs
create mode 100644 crates/defguard_proto/src/lib.rs
diff --git a/.github/workflows/build-docker.yml b/.github/workflows/build-docker.yml
index c17f985182..f25226c1b7 100644
--- a/.github/workflows/build-docker.yml
+++ b/.github/workflows/build-docker.yml
@@ -55,6 +55,9 @@ jobs:
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
+ - name: Sanitize branch name
+ run: echo "SAFE_REF=${GITHUB_REF_NAME//\//-}" >> $GITHUB_ENV
+
- name: Build container
uses: docker/build-push-action@v6
with:
@@ -65,8 +68,8 @@ jobs:
tags: "${{ env.GHCR_REPO }}:${{ github.sha }}-${{ matrix.tag }}"
cache-from: |
type=registry,ref=${{ env.GHCR_REPO }}:cache-${{ matrix.tag }}
- type=registry,ref=${{ env.GHCR_REPO }}:cache-${{ matrix.tag }}-${{ github.ref_name }}
- cache-to: type=registry,mode=max,ref=${{ env.GHCR_REPO }}:cache-${{ matrix.tag }}-${{ github.ref_name }}
+ type=registry,ref=${{ env.GHCR_REPO }}:cache-${{ matrix.tag }}-${{ env.SAFE_REF }}
+ cache-to: type=registry,mode=max,ref=${{ env.GHCR_REPO }}:cache-${{ matrix.tag }}-${{ env.SAFE_REF }}
- name: Scan image with Trivy
uses: aquasecurity/trivy-action@0.32.0
diff --git a/.sqlx/query-796641fb2d79872ae5de64c8b9181e5890a3a122ea5e37ad2fa216c9db47f0a3.json b/.sqlx/query-04163625da5365779cb5e2a47242b7d7faff6d6327e279362212cda4960caca0.json
similarity index 96%
rename from .sqlx/query-796641fb2d79872ae5de64c8b9181e5890a3a122ea5e37ad2fa216c9db47f0a3.json
rename to .sqlx/query-04163625da5365779cb5e2a47242b7d7faff6d6327e279362212cda4960caca0.json
index 65b55605ac..7396561c7f 100644
--- a/.sqlx/query-796641fb2d79872ae5de64c8b9181e5890a3a122ea5e37ad2fa216c9db47f0a3.json
+++ b/.sqlx/query-04163625da5365779cb5e2a47242b7d7faff6d6327e279362212cda4960caca0.json
@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
- "query": "SELECT id, username, password_hash, last_name, first_name, email, phone, mfa_enabled, totp_enabled, email_mfa_enabled, totp_secret, email_mfa_secret, mfa_method \"mfa_method: _\", recovery_codes, is_active, openid_sub, from_ldap, ldap_pass_randomized, ldap_rdn, ldap_user_path FROM \"user\" WHERE openid_sub = $1 LIMIT 1",
+ "query": "SELECT id, username, password_hash, last_name, first_name, email, phone, mfa_enabled, totp_enabled, email_mfa_enabled, totp_secret, email_mfa_secret, mfa_method \"mfa_method: _\", recovery_codes, is_active, openid_sub, from_ldap, ldap_pass_randomized, ldap_rdn, ldap_user_path FROM \"user\" WHERE openid_sub = $1",
"describe": {
"columns": [
{
@@ -144,5 +144,5 @@
true
]
},
- "hash": "796641fb2d79872ae5de64c8b9181e5890a3a122ea5e37ad2fa216c9db47f0a3"
+ "hash": "04163625da5365779cb5e2a47242b7d7faff6d6327e279362212cda4960caca0"
}
diff --git a/.sqlx/query-321ce9355db39c3d93d8b915ba7888357f5403c2e9e97fa17e502223bbcc918a.json b/.sqlx/query-27f3c5ea4443993df10ea337195635ad0e24e4855aa42cdceab2712f8c8dbef4.json
similarity index 82%
rename from .sqlx/query-321ce9355db39c3d93d8b915ba7888357f5403c2e9e97fa17e502223bbcc918a.json
rename to .sqlx/query-27f3c5ea4443993df10ea337195635ad0e24e4855aa42cdceab2712f8c8dbef4.json
index c4bb584637..00ccd67e94 100644
--- a/.sqlx/query-321ce9355db39c3d93d8b915ba7888357f5403c2e9e97fa17e502223bbcc918a.json
+++ b/.sqlx/query-27f3c5ea4443993df10ea337195635ad0e24e4855aa42cdceab2712f8c8dbef4.json
@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
- "query": "SELECT id, user_id, client_id, code, redirect_uri, scope, auth_time, nonce, code_challenge FROM authorization_code WHERE code = $1",
+ "query": "DELETE FROM authorization_code WHERE code = $1 RETURNING id, user_id, client_id, code, redirect_uri, scope, auth_time, nonce, code_challenge",
"describe": {
"columns": [
{
@@ -66,5 +66,5 @@
true
]
},
- "hash": "321ce9355db39c3d93d8b915ba7888357f5403c2e9e97fa17e502223bbcc918a"
+ "hash": "27f3c5ea4443993df10ea337195635ad0e24e4855aa42cdceab2712f8c8dbef4"
}
diff --git a/.sqlx/query-7ddef79c85c3e85b979d5a8a5e50660bcae531c2b8342ae2feffea7454450f10.json b/.sqlx/query-4a1fba6c990265bc278d4e1534f06a96461ecb5edf023ab88d71f9887fc0f2f2.json
similarity index 94%
rename from .sqlx/query-7ddef79c85c3e85b979d5a8a5e50660bcae531c2b8342ae2feffea7454450f10.json
rename to .sqlx/query-4a1fba6c990265bc278d4e1534f06a96461ecb5edf023ab88d71f9887fc0f2f2.json
index 9f60163eac..fa1068e52b 100644
--- a/.sqlx/query-7ddef79c85c3e85b979d5a8a5e50660bcae531c2b8342ae2feffea7454450f10.json
+++ b/.sqlx/query-4a1fba6c990265bc278d4e1534f06a96461ecb5edf023ab88d71f9887fc0f2f2.json
@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
- "query": "SELECT openid_enabled, wireguard_enabled, webhooks_enabled, worker_enabled, challenge_template, instance_name, main_logo_url, nav_logo_url, smtp_server, smtp_port, smtp_encryption \"smtp_encryption: _\", smtp_user, smtp_password \"smtp_password?: SecretStringWrapper\", smtp_sender, enrollment_vpn_step_optional, enrollment_welcome_message, enrollment_welcome_email, enrollment_welcome_email_subject, enrollment_use_welcome_message_as_email, uuid, ldap_url, ldap_bind_username, ldap_bind_password \"ldap_bind_password?: SecretStringWrapper\", ldap_group_search_base, ldap_user_search_base, ldap_user_obj_class, ldap_group_obj_class, ldap_username_attr, ldap_groupname_attr, ldap_group_member_attr, ldap_member_attr, openid_create_account, license, gateway_disconnect_notifications_enabled, ldap_use_starttls, ldap_tls_verify_cert, gateway_disconnect_notifications_inactivity_threshold, gateway_disconnect_notifications_reconnect_notification_enabled, ldap_sync_status \"ldap_sync_status: SyncStatus\", ldap_enabled, ldap_sync_enabled, ldap_is_authoritative, ldap_sync_interval, ldap_user_auxiliary_obj_classes, ldap_uses_ad, ldap_user_rdn_attr, ldap_sync_groups, openid_username_handling \"openid_username_handling: OpenidUsernameHandling\" FROM \"settings\" WHERE id = 1",
+ "query": "SELECT openid_enabled, wireguard_enabled, webhooks_enabled, worker_enabled, challenge_template, instance_name, main_logo_url, nav_logo_url, smtp_server, smtp_port, smtp_encryption \"smtp_encryption: _\", smtp_user, smtp_password \"smtp_password?: SecretStringWrapper\", smtp_sender, enrollment_vpn_step_optional, enrollment_welcome_message, enrollment_welcome_email, enrollment_welcome_email_subject, enrollment_use_welcome_message_as_email, uuid, ldap_url, ldap_bind_username, ldap_bind_password \"ldap_bind_password?: SecretStringWrapper\", ldap_group_search_base, ldap_user_search_base, ldap_user_obj_class, ldap_group_obj_class, ldap_username_attr, ldap_groupname_attr, ldap_group_member_attr, ldap_member_attr, openid_create_account, license, gateway_disconnect_notifications_enabled, ldap_use_starttls, ldap_tls_verify_cert, gateway_disconnect_notifications_inactivity_threshold, gateway_disconnect_notifications_reconnect_notification_enabled, ldap_sync_status \"ldap_sync_status: LdapSyncStatus\", ldap_enabled, ldap_sync_enabled, ldap_is_authoritative, ldap_sync_interval, ldap_user_auxiliary_obj_classes, ldap_uses_ad, ldap_user_rdn_attr, ldap_sync_groups, openid_username_handling \"openid_username_handling: OpenidUsernameHandling\" FROM \"settings\" WHERE id = 1",
"describe": {
"columns": [
{
@@ -206,7 +206,7 @@
},
{
"ordinal": 38,
- "name": "ldap_sync_status: SyncStatus",
+ "name": "ldap_sync_status: LdapSyncStatus",
"type_info": {
"Custom": {
"name": "ldap_sync_status",
@@ -330,5 +330,5 @@
false
]
},
- "hash": "7ddef79c85c3e85b979d5a8a5e50660bcae531c2b8342ae2feffea7454450f10"
+ "hash": "4a1fba6c990265bc278d4e1534f06a96461ecb5edf023ab88d71f9887fc0f2f2"
}
diff --git a/.sqlx/query-ef66255ab254e8d0981226b2e9fdde95cf576aee8744697f1acf957e3fdd1552.json b/.sqlx/query-ef66255ab254e8d0981226b2e9fdde95cf576aee8744697f1acf957e3fdd1552.json
new file mode 100644
index 0000000000..8b4597bc46
--- /dev/null
+++ b/.sqlx/query-ef66255ab254e8d0981226b2e9fdde95cf576aee8744697f1acf957e3fdd1552.json
@@ -0,0 +1,59 @@
+{
+ "db_name": "PostgreSQL",
+ "query": "SELECT c.id, c.client_id, c.client_secret, c.redirect_uri, c.scope, c.name, c.enabled FROM oauth2client c JOIN oauth2authorizedapp a ON a.oauth2client_id = c.id JOIN oauth2token t ON t.oauth2authorizedapp_id = a.id WHERE t.access_token = $1 OR t.refresh_token = $2",
+ "describe": {
+ "columns": [
+ {
+ "ordinal": 0,
+ "name": "id",
+ "type_info": "Int8"
+ },
+ {
+ "ordinal": 1,
+ "name": "client_id",
+ "type_info": "Text"
+ },
+ {
+ "ordinal": 2,
+ "name": "client_secret",
+ "type_info": "Text"
+ },
+ {
+ "ordinal": 3,
+ "name": "redirect_uri",
+ "type_info": "TextArray"
+ },
+ {
+ "ordinal": 4,
+ "name": "scope",
+ "type_info": "TextArray"
+ },
+ {
+ "ordinal": 5,
+ "name": "name",
+ "type_info": "Text"
+ },
+ {
+ "ordinal": 6,
+ "name": "enabled",
+ "type_info": "Bool"
+ }
+ ],
+ "parameters": {
+ "Left": [
+ "Text",
+ "Text"
+ ]
+ },
+ "nullable": [
+ false,
+ false,
+ false,
+ false,
+ false,
+ false,
+ false
+ ]
+ },
+ "hash": "ef66255ab254e8d0981226b2e9fdde95cf576aee8744697f1acf957e3fdd1552"
+}
diff --git a/Cargo.lock b/Cargo.lock
index 57464586f5..0bd268902d 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -89,6 +89,19 @@ version = "0.2.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
+[[package]]
+name = "ammonia"
+version = "4.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "17e913097e1a2124b46746c980134e8c954bc17a6a59bb3fde96f088d126dde6"
+dependencies = [
+ "cssparser",
+ "html5ever",
+ "maplit",
+ "tendril",
+ "url",
+]
+
[[package]]
name = "android_system_properties"
version = "0.1.5"
@@ -150,9 +163,9 @@ dependencies = [
[[package]]
name = "anyhow"
-version = "1.0.99"
+version = "1.0.100"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b0674a1ddeecb70197781e945de4b3b8ffb61fa939a5597bcf48503737663100"
+checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61"
[[package]]
name = "arbitrary"
@@ -569,9 +582,9 @@ dependencies = [
[[package]]
name = "cc"
-version = "1.2.36"
+version = "1.2.38"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5252b3d2648e5eedbc1a6f501e3c795e07025c1e93bbf8bbdd6eef7f447a6d54"
+checksum = "80f41ae168f955c12fb8960b057d70d0ca153fb83182b57d86380443527be7e9"
dependencies = [
"find-msvc-tools",
"jobserver",
@@ -664,9 +677,9 @@ checksum = "bba18ee93d577a8428902687bcc2b6b45a56b1981a1f6d779731c86cc4c5db18"
[[package]]
name = "clap"
-version = "4.5.47"
+version = "4.5.48"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7eac00902d9d136acd712710d71823fb8ac8004ca445a89e73a41d45aa712931"
+checksum = "e2134bb3ea021b78629caa971416385309e0131b351b25e01dc16fb54e1b5fae"
dependencies = [
"clap_builder",
"clap_derive",
@@ -674,9 +687,9 @@ dependencies = [
[[package]]
name = "clap_builder"
-version = "4.5.47"
+version = "4.5.48"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2ad9bbf750e73b5884fb8a211a9424a1906c1e156724260fdae972f31d70e1d6"
+checksum = "c2ba64afa3c0a6df7fa517765e31314e983f51dda798ffba27b988194fb65dc9"
dependencies = [
"anstream",
"anstyle",
@@ -921,6 +934,29 @@ dependencies = [
"typenum",
]
+[[package]]
+name = "cssparser"
+version = "0.35.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4e901edd733a1472f944a45116df3f846f54d37e67e68640ac8bb69689aca2aa"
+dependencies = [
+ "cssparser-macros",
+ "dtoa-short",
+ "itoa",
+ "phf",
+ "smallvec",
+]
+
+[[package]]
+name = "cssparser-macros"
+version = "0.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331"
+dependencies = [
+ "quote",
+ "syn",
+]
+
[[package]]
name = "ctr"
version = "0.9.2"
@@ -980,8 +1016,18 @@ version = "0.20.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee"
dependencies = [
- "darling_core",
- "darling_macro",
+ "darling_core 0.20.11",
+ "darling_macro 0.20.11",
+]
+
+[[package]]
+name = "darling"
+version = "0.21.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9cdf337090841a411e2a7f3deb9187445851f91b309c0c0a29e05f74a00a48c0"
+dependencies = [
+ "darling_core 0.21.3",
+ "darling_macro 0.21.3",
]
[[package]]
@@ -998,13 +1044,38 @@ dependencies = [
"syn",
]
+[[package]]
+name = "darling_core"
+version = "0.21.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1247195ecd7e3c85f83c8d2a366e4210d588e802133e1e355180a9870b517ea4"
+dependencies = [
+ "fnv",
+ "ident_case",
+ "proc-macro2",
+ "quote",
+ "strsim",
+ "syn",
+]
+
[[package]]
name = "darling_macro"
version = "0.20.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead"
dependencies = [
- "darling_core",
+ "darling_core 0.20.11",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "darling_macro"
+version = "0.21.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d38308df82d1080de0afee5d069fa14b0326a88c14f15c5ccda35b4a6c414c81"
+dependencies = [
+ "darling_core 0.21.3",
"quote",
"syn",
]
@@ -1030,9 +1101,11 @@ version = "0.0.0"
dependencies = [
"anyhow",
"bytes",
+ "defguard_common",
"defguard_core",
"defguard_event_logger",
"defguard_event_router",
+ "defguard_mail",
"defguard_version",
"dotenvy",
"secrecy",
@@ -1040,10 +1113,41 @@ dependencies = [
"tracing",
]
+[[package]]
+name = "defguard_common"
+version = "1.5.1"
+dependencies = [
+ "anyhow",
+ "base64 0.22.1",
+ "chrono",
+ "clap",
+ "ed25519-dalek",
+ "humantime",
+ "ipnetwork",
+ "jsonwebtoken",
+ "matches",
+ "model_derive",
+ "openidconnect",
+ "rand 0.8.5",
+ "reqwest",
+ "rsa",
+ "secrecy",
+ "serde",
+ "sqlx",
+ "struct-patch",
+ "thiserror 2.0.16",
+ "tonic",
+ "tracing",
+ "utoipa",
+ "uuid",
+ "vergen-git2",
+]
+
[[package]]
name = "defguard_core"
-version = "1.5.0"
+version = "0.0.0"
dependencies = [
+ "ammonia",
"anyhow",
"argon2",
"axum",
@@ -1054,10 +1158,11 @@ dependencies = [
"bytes",
"chrono",
"claims",
- "clap",
+ "defguard_common",
+ "defguard_mail",
+ "defguard_proto",
"defguard_version",
"defguard_web_ui",
- "ed25519-dalek",
"humantime",
"hyper-util",
"ipnetwork",
@@ -1073,7 +1178,6 @@ dependencies = [
"paste",
"pgp",
"prost",
- "pulldown-cmark",
"rand 0.8.5",
"regex",
"reqwest",
@@ -1112,7 +1216,6 @@ dependencies = [
"utoipa",
"utoipa-swagger-ui",
"uuid",
- "vergen-git2",
"webauthn-authenticator-rs",
"webauthn-rs",
"webauthn-rs-proto",
@@ -1125,6 +1228,7 @@ version = "0.0.0"
dependencies = [
"bytes",
"chrono",
+ "defguard_common",
"defguard_core",
"serde_json",
"sqlx",
@@ -1139,11 +1243,42 @@ version = "0.0.0"
dependencies = [
"defguard_core",
"defguard_event_logger",
+ "defguard_mail",
+ "thiserror 2.0.16",
+ "tokio",
+ "tracing",
+]
+
+[[package]]
+name = "defguard_mail"
+version = "0.0.0"
+dependencies = [
+ "chrono",
+ "claims",
+ "defguard_common",
+ "lettre",
+ "pulldown-cmark",
+ "reqwest",
+ "serde",
+ "serde_json",
+ "sqlx",
+ "tera",
"thiserror 2.0.16",
"tokio",
"tracing",
]
+[[package]]
+name = "defguard_proto"
+version = "0.0.0"
+dependencies = [
+ "prost",
+ "serde",
+ "tonic",
+ "tonic-prost",
+ "tonic-prost-build",
+]
+
[[package]]
name = "defguard_version"
version = "0.0.0"
@@ -1230,7 +1365,7 @@ version = "0.20.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2d5bcf7b024d6835cfb3d473887cd966994907effbe9227e8c8219824d06c4e8"
dependencies = [
- "darling",
+ "darling 0.20.11",
"proc-macro2",
"quote",
"syn",
@@ -1358,6 +1493,21 @@ dependencies = [
"zeroize",
]
+[[package]]
+name = "dtoa"
+version = "1.0.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d6add3b8cff394282be81f3fc1a0605db594ed69890078ca6e2cab1c408bcf04"
+
+[[package]]
+name = "dtoa-short"
+version = "0.3.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cd1511a7b6a56299bd043a9c167a6d2bfb37bf84a6dfceaba651168adfb43c87"
+dependencies = [
+ "dtoa",
+]
+
[[package]]
name = "dyn-clone"
version = "1.0.20"
@@ -1538,9 +1688,9 @@ checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d"
[[package]]
name = "find-msvc-tools"
-version = "0.1.1"
+version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7fd99930f64d146689264c637b5af2f0233a933bef0d8570e2526bf9e083192d"
+checksum = "1ced73b1dacfc750a6db6c0a0c3a3853c8b41997e2e2c563dc90804ae6867959"
[[package]]
name = "fixedbitset"
@@ -1622,6 +1772,16 @@ version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c"
+[[package]]
+name = "futf"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "df420e2e84819663797d1ec6544b13c5be84629e7bb00dc960d6917db2987843"
+dependencies = [
+ "mac",
+ "new_debug_unreachable",
+]
+
[[package]]
name = "futures"
version = "0.3.31"
@@ -1765,7 +1925,7 @@ dependencies = [
"js-sys",
"libc",
"r-efi",
- "wasi 0.14.5+wasi-0.2.4",
+ "wasi 0.14.7+wasi-0.2.4",
"wasm-bindgen",
]
@@ -1845,7 +2005,7 @@ dependencies = [
"futures-core",
"futures-sink",
"http",
- "indexmap 2.11.1",
+ "indexmap 2.11.4",
"slab",
"tokio",
"tokio-util",
@@ -1885,6 +2045,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"
@@ -1968,6 +2134,17 @@ dependencies = [
"windows-link 0.1.3",
]
+[[package]]
+name = "html5ever"
+version = "0.35.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "55d958c2f74b664487a2035fe1dadb032c48718a03b63f3ab0b8537db8549ed4"
+dependencies = [
+ "log",
+ "markup5ever",
+ "match_token",
+]
+
[[package]]
name = "http"
version = "1.3.1"
@@ -2031,9 +2208,9 @@ dependencies = [
[[package]]
name = "humantime"
-version = "2.2.0"
+version = "2.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9b112acc8b3adf4b107a8ec20977da0273a8c386765a3ec0229bd500a1443f9f"
+checksum = "135b12329e5e3ce057a9f972339ea52bc954fe1e9358ef27f95e89716fbc5424"
[[package]]
name = "hyper"
@@ -2106,9 +2283,9 @@ dependencies = [
[[package]]
name = "hyper-util"
-version = "0.1.16"
+version = "0.1.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8d9b05277c7e8da2c93a568989bb6207bef0112e8d17df7a6eda4a3cf143bc5e"
+checksum = "3c6995591a8f1380fcb4ba966a252a4b29188d51d2b89e3a252f5305be65aea8"
dependencies = [
"base64 0.22.1",
"bytes",
@@ -2132,9 +2309,9 @@ dependencies = [
[[package]]
name = "iana-time-zone"
-version = "0.1.63"
+version = "0.1.64"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b0c919e5debc312ad217002b8048a17b7d83f80703865bbfcfebb0458b0b27d8"
+checksum = "33e57f83510bb73707521ebaffa789ec8caf86f9657cad665b092b581d40e9fb"
dependencies = [
"android_system_properties",
"core-foundation-sys",
@@ -2305,13 +2482,14 @@ dependencies = [
[[package]]
name = "indexmap"
-version = "2.11.1"
+version = "2.11.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "206a8042aec68fa4a62e8d3f7aa4ceb508177d9324faf261e1959e495b7a1921"
+checksum = "4b0f83760fb341a774ed326568e19f5a863af4a952def8c39f9ab92fd95b88e5"
dependencies = [
"equivalent",
- "hashbrown 0.15.5",
+ "hashbrown 0.16.0",
"serde",
+ "serde_core",
]
[[package]]
@@ -2401,9 +2579,9 @@ dependencies = [
[[package]]
name = "js-sys"
-version = "0.3.78"
+version = "0.3.80"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0c0b063578492ceec17683ef2f8c5e89121fbd0b172cbc280635ab7567db2738"
+checksum = "852f13bec5eba4ba9afbeb93fd7c13fe56147f055939ae21c43a29a0ecb2702e"
dependencies = [
"once_cell",
"wasm-bindgen",
@@ -2561,9 +2739,9 @@ checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de"
[[package]]
name = "libredox"
-version = "0.1.9"
+version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "391290121bad3d37fbddad76d8f5d1c1c314cfc646d143d7e07a3086ddff0ce3"
+checksum = "416f7e718bdb06000964960ffa43b4335ad4012ae8b99060261aa4a8088d5ccb"
dependencies = [
"bitflags 2.9.4",
"libc",
@@ -2641,6 +2819,40 @@ version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154"
+[[package]]
+name = "mac"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4"
+
+[[package]]
+name = "maplit"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d"
+
+[[package]]
+name = "markup5ever"
+version = "0.35.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "311fe69c934650f8f19652b3946075f0fc41ad8757dbb68f1ca14e7900ecc1c3"
+dependencies = [
+ "log",
+ "tendril",
+ "web_atoms",
+]
+
+[[package]]
+name = "match_token"
+version = "0.35.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac84fd3f360fcc43dc5f5d186f02a94192761a080e8bc58621ad4d12296a58cf"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
[[package]]
name = "matchers"
version = "0.2.0"
@@ -2760,6 +2972,12 @@ dependencies = [
"tempfile",
]
+[[package]]
+name = "new_debug_unreachable"
+version = "1.0.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086"
+
[[package]]
name = "nom"
version = "7.1.3"
@@ -3211,9 +3429,9 @@ checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220"
[[package]]
name = "pest"
-version = "2.8.1"
+version = "2.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1db05f56d34358a8b1066f67cbb203ee3e7ed2ba674a6263a1d5ec6db2204323"
+checksum = "21e0a3a33733faeaf8651dfee72dd0f388f0c8e5ad496a3478fa5a922f49cfa8"
dependencies = [
"memchr",
"thiserror 2.0.16",
@@ -3222,9 +3440,9 @@ dependencies = [
[[package]]
name = "pest_derive"
-version = "2.8.1"
+version = "2.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bb056d9e8ea77922845ec74a1c4e8fb17e7c218cc4fc11a15c5d25e189aa40bc"
+checksum = "bc58706f770acb1dbd0973e6530a3cff4746fb721207feb3a8a6064cd0b6c663"
dependencies = [
"pest",
"pest_generator",
@@ -3232,9 +3450,9 @@ dependencies = [
[[package]]
name = "pest_generator"
-version = "2.8.1"
+version = "2.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "87e404e638f781eb3202dc82db6760c8ae8a1eeef7fb3fa8264b2ef280504966"
+checksum = "6d4f36811dfe07f7b8573462465d5cb8965fffc2e71ae377a33aecf14c2c9a2f"
dependencies = [
"pest",
"pest_meta",
@@ -3245,9 +3463,9 @@ dependencies = [
[[package]]
name = "pest_meta"
-version = "2.8.1"
+version = "2.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "edd1101f170f5903fde0914f899bb503d9ff5271d7ba76bbb70bea63690cc0d5"
+checksum = "42919b05089acbd0a5dcd5405fb304d17d1053847b81163d09c4ad18ce8e8420"
dependencies = [
"pest",
"sha2",
@@ -3260,7 +3478,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3672b37090dbd86368a4145bc067582552b29c27377cad4e0a306c97f9bd7772"
dependencies = [
"fixedbitset",
- "indexmap 2.11.1",
+ "indexmap 2.11.4",
]
[[package]]
@@ -3337,6 +3555,7 @@ version = "0.11.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078"
dependencies = [
+ "phf_macros",
"phf_shared",
]
@@ -3360,6 +3579,19 @@ dependencies = [
"rand 0.8.5",
]
+[[package]]
+name = "phf_macros"
+version = "0.11.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f84ac04429c13a7ff43785d75ad27569f2951ce0ffd30a3321230db2fc727216"
+dependencies = [
+ "phf_generator",
+ "phf_shared",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
[[package]]
name = "phf_shared"
version = "0.11.3"
@@ -3430,12 +3662,12 @@ checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c"
[[package]]
name = "plist"
-version = "1.7.4"
+version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3af6b589e163c5a788fab00ce0c0366f6efbb9959c2f9874b224936af7fce7e1"
+checksum = "740ebea15c5d1428f910cd1a5f52cebf8d25006245ed8ade92702f4943d91e07"
dependencies = [
"base64 0.22.1",
- "indexmap 2.11.1",
+ "indexmap 2.11.4",
"quick-xml",
"serde",
"time",
@@ -3477,6 +3709,12 @@ dependencies = [
"zerocopy",
]
+[[package]]
+name = "precomputed-hash"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c"
+
[[package]]
name = "prettyplease"
version = "0.2.37"
@@ -3498,9 +3736,9 @@ dependencies = [
[[package]]
name = "proc-macro-crate"
-version = "3.3.0"
+version = "3.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "edce586971a4dfaa28950c6f18ed55e0406c1ab88bbce2c6f6293a7aaba73d35"
+checksum = "219cb19e96be00ab2e37d6e299658a0cfa83e52429179969b0f0121b4ac46983"
dependencies = [
"toml_edit",
]
@@ -4024,9 +4262,9 @@ dependencies = [
[[package]]
name = "rustls"
-version = "0.23.31"
+version = "0.23.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c0ebcbd2f03de0fc1122ad9bb24b127a5a6cd51d72604a3f3c50ac459762b6cc"
+checksum = "cd3c25631629d034ce7cd9940adc9d45762d46de2b0f57193c4443b92c6d4d40"
dependencies = [
"log",
"once_cell",
@@ -4046,7 +4284,7 @@ dependencies = [
"openssl-probe",
"rustls-pki-types",
"schannel",
- "security-framework 3.4.0",
+ "security-framework 3.5.0",
]
[[package]]
@@ -4061,9 +4299,9 @@ dependencies = [
[[package]]
name = "rustls-webpki"
-version = "0.103.4"
+version = "0.103.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0a17884ae0c1b773f1ccd2bd4a8c72f16da897310a98b0e84bf349ad5ead92fc"
+checksum = "8572f3c2cb9934231157b45499fc41e1f58c589fdfb81a844ba873265e80f8eb"
dependencies = [
"ring",
"rustls-pki-types",
@@ -4170,9 +4408,9 @@ dependencies = [
[[package]]
name = "security-framework"
-version = "3.4.0"
+version = "3.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "60b369d18893388b345804dc0007963c99b7d665ae71d275812d828c6f089640"
+checksum = "cc198e42d9b7510827939c9a15f5062a0c913f3371d765977e586d2fe6c16f4a"
dependencies = [
"bitflags 2.9.4",
"core-foundation 0.10.1",
@@ -4193,19 +4431,21 @@ dependencies = [
[[package]]
name = "semver"
-version = "1.0.26"
+version = "1.0.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0"
+checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2"
dependencies = [
"serde",
+ "serde_core",
]
[[package]]
name = "serde"
-version = "1.0.219"
+version = "1.0.226"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6"
+checksum = "0dca6411025b24b60bfa7ec1fe1f8e710ac09782dca409ee8237ba74b51295fd"
dependencies = [
+ "serde_core",
"serde_derive",
]
@@ -4221,11 +4461,12 @@ dependencies = [
[[package]]
name = "serde_bytes"
-version = "0.11.17"
+version = "0.11.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8437fd221bde2d4ca316d61b90e337e9e702b3820b87d63caa9ba6c02bd06d96"
+checksum = "a5d440709e79d88e51ac01c4b72fc6cb7314017bb7da9eeff678aa94c10e3ea8"
dependencies = [
"serde",
+ "serde_core",
]
[[package]]
@@ -4238,11 +4479,20 @@ dependencies = [
"serde",
]
+[[package]]
+name = "serde_core"
+version = "1.0.226"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ba2ba63999edb9dac981fb34b3e5c0d111a69b0924e253ed29d83f7c99e966a4"
+dependencies = [
+ "serde_derive",
+]
+
[[package]]
name = "serde_derive"
-version = "1.0.219"
+version = "1.0.226"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00"
+checksum = "8db53ae22f34573731bafa1db20f04027b2d25e02d8205921b569171699cdb33"
dependencies = [
"proc-macro2",
"quote",
@@ -4251,37 +4501,39 @@ dependencies = [
[[package]]
name = "serde_html_form"
-version = "0.2.7"
+version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9d2de91cf02bbc07cde38891769ccd5d4f073d22a40683aa4bc7a95781aaa2c4"
+checksum = "b2f2d7ff8a2140333718bb329f5c40fc5f0865b84c426183ce14c97d2ab8154f"
dependencies = [
"form_urlencoded",
- "indexmap 2.11.1",
+ "indexmap 2.11.4",
"itoa",
"ryu",
- "serde",
+ "serde_core",
]
[[package]]
name = "serde_json"
-version = "1.0.143"
+version = "1.0.145"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d401abef1d108fbd9cbaebc3e46611f4b1021f714a0597a71f41ee463f5f4a5a"
+checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c"
dependencies = [
"itoa",
"memchr",
"ryu",
"serde",
+ "serde_core",
]
[[package]]
name = "serde_path_to_error"
-version = "0.1.17"
+version = "0.1.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "59fab13f937fa393d08645bf3a84bdfe86e296747b506ada67bb15f10f218b2a"
+checksum = "10a9ff822e371bb5403e391ecd83e182e0e77ba7f6fe0160b795797109d1b457"
dependencies = [
"itoa",
"serde",
+ "serde_core",
]
[[package]]
@@ -4318,15 +4570,15 @@ dependencies = [
[[package]]
name = "serde_with"
-version = "3.14.0"
+version = "3.14.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f2c45cd61fefa9db6f254525d46e392b852e0e61d9a1fd36e5bd183450a556d5"
+checksum = "c522100790450cf78eeac1507263d0a350d4d5b30df0c8e1fe051a10c22b376e"
dependencies = [
"base64 0.22.1",
"chrono",
"hex",
"indexmap 1.9.3",
- "indexmap 2.11.1",
+ "indexmap 2.11.4",
"schemars 0.9.0",
"schemars 1.0.4",
"serde",
@@ -4338,11 +4590,11 @@ dependencies = [
[[package]]
name = "serde_with_macros"
-version = "3.14.0"
+version = "3.14.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "de90945e6565ce0d9a25098082ed4ee4002e047cb59892c318d66821e14bb30f"
+checksum = "327ada00f7d64abaac1e55a6911e90cf665aa051b9a561c7006c157f4633135e"
dependencies = [
- "darling",
+ "darling 0.21.3",
"proc-macro2",
"quote",
"syn",
@@ -4354,7 +4606,7 @@ version = "0.9.34+deprecated"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47"
dependencies = [
- "indexmap 2.11.1",
+ "indexmap 2.11.4",
"itoa",
"ryu",
"serde",
@@ -4604,7 +4856,7 @@ dependencies = [
"futures-util",
"hashbrown 0.15.5",
"hashlink",
- "indexmap 2.11.1",
+ "indexmap 2.11.4",
"ipnetwork",
"log",
"memchr",
@@ -4831,6 +5083,31 @@ dependencies = [
"windows-sys 0.59.0",
]
+[[package]]
+name = "string_cache"
+version = "0.8.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bf776ba3fa74f83bf4b63c3dcbbf82173db2632ed8452cb2d891d33f459de70f"
+dependencies = [
+ "new_debug_unreachable",
+ "parking_lot",
+ "phf_shared",
+ "precomputed-hash",
+ "serde",
+]
+
+[[package]]
+name = "string_cache_codegen"
+version = "0.5.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c711928715f1fe0fe509c53b43e993a9a557babc2d0a3567d0a3006f1ac931a0"
+dependencies = [
+ "phf_generator",
+ "phf_shared",
+ "proc-macro2",
+ "quote",
+]
+
[[package]]
name = "stringprep"
version = "0.1.5"
@@ -4966,6 +5243,17 @@ dependencies = [
"windows-sys 0.61.0",
]
+[[package]]
+name = "tendril"
+version = "0.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d24a120c5fc464a3458240ee02c299ebcb9d67b5249c8848b09d639dca8d7bb0"
+dependencies = [
+ "futf",
+ "mac",
+ "utf-8",
+]
+
[[package]]
name = "tera"
version = "1.20.0"
@@ -5039,11 +5327,12 @@ dependencies = [
[[package]]
name = "time"
-version = "0.3.43"
+version = "0.3.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "83bde6f1ec10e72d583d91623c939f623002284ef622b87de38cfd546cbf2031"
+checksum = "91e7d9e3bb61134e77bde20dd4825b97c010155709965fedf0f49bb138e52a9d"
dependencies = [
"deranged",
+ "itoa",
"libc",
"num-conv",
"num_threads",
@@ -5145,9 +5434,9 @@ dependencies = [
[[package]]
name = "tokio-rustls"
-version = "0.26.2"
+version = "0.26.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8e727b36a1a0e8b74c376ac2211e40c2c8af09fb4013c60d910495810f008e9b"
+checksum = "05f63835928ca123f1bef57abbcd23bb2ba0ac9ae1235f1e65bda0d06e7786bd"
dependencies = [
"rustls",
"tokio",
@@ -5180,18 +5469,31 @@ dependencies = [
[[package]]
name = "toml_datetime"
-version = "0.6.11"
+version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c"
+checksum = "32f1085dec27c2b6632b04c80b3bb1b4300d6495d1e129693bdda7d91e72eec1"
+dependencies = [
+ "serde_core",
+]
[[package]]
name = "toml_edit"
-version = "0.22.27"
+version = "0.23.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a"
+checksum = "f3effe7c0e86fdff4f69cdd2ccc1b96f933e24811c5441d44904e8683e27184b"
dependencies = [
- "indexmap 2.11.1",
+ "indexmap 2.11.4",
"toml_datetime",
+ "toml_parser",
+ "winnow",
+]
+
+[[package]]
+name = "toml_parser"
+version = "1.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4cf893c33be71572e0e9aa6dd15e6677937abd686b066eac3f8cd3531688a627"
+dependencies = [
"winnow",
]
@@ -5299,7 +5601,7 @@ checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9"
dependencies = [
"futures-core",
"futures-util",
- "indexmap 2.11.1",
+ "indexmap 2.11.4",
"pin-project-lite",
"slab",
"sync_wrapper",
@@ -5599,6 +5901,12 @@ dependencies = [
"serde",
]
+[[package]]
+name = "utf-8"
+version = "0.7.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9"
+
[[package]]
name = "utf8_iter"
version = "1.0.4"
@@ -5617,7 +5925,7 @@ version = "5.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2fcc29c80c21c31608227e0912b2d7fddba57ad76b606890627ba8ee7964e993"
dependencies = [
- "indexmap 2.11.1",
+ "indexmap 2.11.4",
"serde",
"serde_json",
"utoipa-gen",
@@ -5757,18 +6065,18 @@ checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
[[package]]
name = "wasi"
-version = "0.14.5+wasi-0.2.4"
+version = "0.14.7+wasi-0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a4494f6290a82f5fe584817a676a34b9d6763e8d9d18204009fb31dceca98fd4"
+checksum = "883478de20367e224c0090af9cf5f9fa85bed63a95c1abf3afc5c083ebc06e8c"
dependencies = [
"wasip2",
]
[[package]]
name = "wasip2"
-version = "1.0.0+wasi-0.2.4"
+version = "1.0.1+wasi-0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "03fa2761397e5bd52002cd7e73110c71af2109aca4e521a9f40473fe685b0a24"
+checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7"
dependencies = [
"wit-bindgen",
]
@@ -5781,9 +6089,9 @@ checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b"
[[package]]
name = "wasm-bindgen"
-version = "0.2.101"
+version = "0.2.103"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7e14915cadd45b529bb8d1f343c4ed0ac1de926144b746e2710f9cd05df6603b"
+checksum = "ab10a69fbd0a177f5f649ad4d8d3305499c42bab9aef2f7ff592d0ec8f833819"
dependencies = [
"cfg-if",
"once_cell",
@@ -5794,9 +6102,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-backend"
-version = "0.2.101"
+version = "0.2.103"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e28d1ba982ca7923fd01448d5c30c6864d0a14109560296a162f80f305fb93bb"
+checksum = "0bb702423545a6007bbc368fde243ba47ca275e549c8a28617f56f6ba53b1d1c"
dependencies = [
"bumpalo",
"log",
@@ -5808,9 +6116,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-futures"
-version = "0.4.51"
+version = "0.4.53"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0ca85039a9b469b38336411d6d6ced91f3fc87109a2a27b0c197663f5144dffe"
+checksum = "a0b221ff421256839509adbb55998214a70d829d3a28c69b4a6672e9d2a42f67"
dependencies = [
"cfg-if",
"js-sys",
@@ -5821,9 +6129,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro"
-version = "0.2.101"
+version = "0.2.103"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7c3d463ae3eff775b0c45df9da45d68837702ac35af998361e2c84e7c5ec1b0d"
+checksum = "fc65f4f411d91494355917b605e1480033152658d71f722a90647f56a70c88a0"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
@@ -5831,9 +6139,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro-support"
-version = "0.2.101"
+version = "0.2.103"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7bb4ce89b08211f923caf51d527662b75bdc9c9c7aab40f86dcb9fb85ac552aa"
+checksum = "ffc003a991398a8ee604a401e194b6b3a39677b3173d6e74495eb51b82e99a32"
dependencies = [
"proc-macro2",
"quote",
@@ -5844,9 +6152,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-shared"
-version = "0.2.101"
+version = "0.2.103"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f143854a3b13752c6950862c906306adb27c7e839f7414cec8fea35beab624c1"
+checksum = "293c37f4efa430ca14db3721dfbe48d8c33308096bd44d80ebaa775ab71ba1cf"
dependencies = [
"unicode-ident",
]
@@ -5866,9 +6174,9 @@ dependencies = [
[[package]]
name = "web-sys"
-version = "0.3.78"
+version = "0.3.80"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "77e4b637749ff0d92b8fad63aa1f7cff3cbe125fd49c175cd6345e7272638b12"
+checksum = "fbe734895e869dc429d78c4b433f8d17d95f8d05317440b4fad5ab2d33e596dc"
dependencies = [
"js-sys",
"wasm-bindgen",
@@ -5884,6 +6192,18 @@ dependencies = [
"wasm-bindgen",
]
+[[package]]
+name = "web_atoms"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "57ffde1dc01240bdf9992e3205668b235e59421fd085e8a317ed98da0178d414"
+dependencies = [
+ "phf",
+ "phf_codegen",
+ "string_cache",
+ "string_cache_codegen",
+]
+
[[package]]
name = "webauthn-attestation-ca"
version = "0.5.2"
@@ -6015,15 +6335,15 @@ dependencies = [
[[package]]
name = "windows-core"
-version = "0.61.2"
+version = "0.62.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3"
+checksum = "57fe7168f7de578d2d8a05b07fd61870d2e73b4020e9f49aa00da8471723497c"
dependencies = [
"windows-implement",
"windows-interface",
- "windows-link 0.1.3",
- "windows-result",
- "windows-strings",
+ "windows-link 0.2.0",
+ "windows-result 0.4.0",
+ "windows-strings 0.5.0",
]
[[package]]
@@ -6067,8 +6387,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b8a9ed28765efc97bbc954883f4e6796c33a06546ebafacbabee9696967499e"
dependencies = [
"windows-link 0.1.3",
- "windows-result",
- "windows-strings",
+ "windows-result 0.3.4",
+ "windows-strings 0.4.2",
]
[[package]]
@@ -6080,6 +6400,15 @@ dependencies = [
"windows-link 0.1.3",
]
+[[package]]
+name = "windows-result"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7084dcc306f89883455a206237404d3eaf961e5bd7e0f312f7c91f57eb44167f"
+dependencies = [
+ "windows-link 0.2.0",
+]
+
[[package]]
name = "windows-strings"
version = "0.4.2"
@@ -6089,6 +6418,15 @@ dependencies = [
"windows-link 0.1.3",
]
+[[package]]
+name = "windows-strings"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7218c655a553b0bed4426cf54b20d7ba363ef543b52d515b3e48d7fd55318dda"
+dependencies = [
+ "windows-link 0.2.0",
+]
+
[[package]]
name = "windows-sys"
version = "0.48.0"
@@ -6331,9 +6669,9 @@ dependencies = [
[[package]]
name = "wit-bindgen"
-version = "0.45.1"
+version = "0.46.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5c573471f125075647d03df72e026074b7203790d41351cd6edc96f46bcccd36"
+checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59"
[[package]]
name = "writeable"
@@ -6515,7 +6853,7 @@ dependencies = [
"arbitrary",
"crc32fast",
"flate2",
- "indexmap 2.11.1",
+ "indexmap 2.11.4",
"memchr",
"zopfli",
]
diff --git a/Cargo.toml b/Cargo.toml
index d6405991da..513ecf7cf7 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -11,9 +11,12 @@ resolver = "2"
[workspace.dependencies]
# internal crates
-defguard_core = { path = "./crates/defguard_core", version = "1.5.0" }
+defguard_common = { path = "./crates/defguard_common", version = "1.5.0" }
+defguard_core = { path = "./crates/defguard_core", version = "0.0.0" }
defguard_event_logger = { path = "./crates/defguard_event_logger", version = "0.0.0" }
defguard_event_router = { path = "./crates/defguard_event_router", version = "0.0.0" }
+defguard_mail = { path = "./crates/defguard_mail", version = "0.0.0" }
+defguard_proto = { path = "./crates/defguard_proto", version = "0.0.0" }
defguard_version = { path = "./crates/defguard_version", version = "0.0.0" }
defguard_web_ui = { path = "./crates/defguard_web_ui", version = "0.0.0" }
model_derive = { path = "./crates/model_derive", version = "0.0.0" }
@@ -35,6 +38,7 @@ chrono = { version = "0.4", default-features = false, features = [
"clock",
"serde",
] }
+claims = "0.8"
clap = { version = "4.5", features = ["derive", "env"] }
humantime = "2.1"
# match version used by sqlx
@@ -43,10 +47,15 @@ jsonwebkey = { version = "0.3", features = ["pkcs-convert"] }
jsonwebtoken = "9.3"
ldap3 = { version = "0.11", default-features = false, features = ["tls"] }
lettre = { version = "0.11", features = ["tokio1-native-tls"] }
+matches = "0.1"
md4 = "0.10"
+openidconnect = { version = "4.0", default-features = false, features = [
+ "reqwest",
+] }
parse_link_header = "0.4"
paste = "1.0"
pgp = { version = "0.16", default-features = false }
+prost = "0.14"
pulldown-cmark = "0.13"
# match version used by sqlx
rand = "0.8"
@@ -93,6 +102,8 @@ tonic = { version = "0.14", features = [
"tls-ring",
] }
tonic-health = "0.14"
+tonic-prost = "0.14"
+tonic-prost-build = "0.14"
totp-lite = { version = "2.0" }
tower-http = { version = "0.6", features = ["fs", "trace", "set-header"] }
tracing = "0.1"
diff --git a/README.md b/README.md
index 99e5e6a309..a4e0ce6a48 100644
--- a/README.md
+++ b/README.md
@@ -10,17 +10,17 @@
### Defguard provides Comprehensive Access Control (a complete security platform):
-- **[WireGuard® VPN with 2FA/MFA](https://docs.defguard.net/admin-and-features/wireguard/multi-factor-authentication-mfa-2fa/architecture)** - not 2FA to "access application" like most solutions
- - The only solution with [automatic and real-time synchronization](https://docs.defguard.net/enterprise/automatic-real-time-desktop-client-configuration) for users' desktop client settings (including all VPNs/locations).
- - Control users [ability to manage devices and VPN options](https://docs.defguard.net/enterprise/behavior-customization)
-- [ACLs/Firewall Management](https://docs.defguard.net/enterprise/all-enteprise-features/access-control-list) for Linux and FreeBSD/OPNSense
-- [Integrated SSO based on OpenID Connect](https://docs.defguard.net/admin-and-features/openid-connect):
+- **[WireGuard® VPN with 2FA/MFA](https://docs.defguard.net/in-depth/architecture/architecture)** - not 2FA to "access application" like most solutions
+ - The only solution with [automatic and real-time synchronization](https://docs.defguard.net/features/remote-user-enrollment/automatic-real-time-desktop-client-configuration) for users' desktop client settings (including all VPNs/locations).
+ - Control users [ability to manage devices and VPN options](https://docs.defguard.net/features/wireguard/behavior-customization)
+- [ACLs/Firewall Management](https://docs.defguard.net/features/access-control-list) for Linux and FreeBSD/OPNSense
+- [Integrated SSO based on OpenID Connect](https://docs.defguard.net/features/openid-connect):
- significant cost saving, simplifying deployment and maintenance
- enabling features unavailable to VPN platforms relying upon 3rd party SSO integration
-- Already using Google/Microsoft or other OpenID Provider? - [external OpenID provider support](https://docs.defguard.net/enterprise/external-openid-providers)
-- [Two way Active Directory/LDAP synchronization](https://docs.defguard.net/enterprise/all-enteprise-features/ldap-and-active-directory-integration/two-way-ldap-and-active-directory-synchronization)
-- Only solution with [secure remote user Enrollment & Onboarding](https://docs.defguard.net/help/enrollment)
-- Yubico YubiKey Hardware [security key management and provisioning](https://docs.defguard.net/admin-and-features/yubikey-provisioning)
+- Already using Google/Microsoft or other OpenID Provider? - [external OpenID provider support](https://docs.defguard.net/features/external-openid-providers)
+- [Two way Active Directory/LDAP synchronization](https://docs.defguard.net/features/ldap-and-active-directory-integration/two-way-ldap-and-active-directory-synchronization)
+- Only solution with [secure remote user Enrollment & Onboarding](https://docs.defguard.net/using-defguard-for-end-users/enrollment)
+- Yubico YubiKey Hardware [security key management and provisioning](https://docs.defguard.net/features/yubikey-provisioning)
- Secure and robust architecture, featuring components and micro-services seamlessly deployable in diverse network setups (eg. utilizing network segments like Demilitarized Zones, Intranet with no external access, etc), ensuring a secure environment.
- Enterprise ready (multiple Locations/Gateways/Kubernetes deployment, etc..)
- Built on WireGuard® protocol which is faster than IPSec, and significantly faster than OpenVPN
@@ -67,8 +67,8 @@ Better quality video can [be viewed here](https://github.com/DefGuard/docs/raw/d
[Desktop client](https://github.com/DefGuard/client):
- **2FA / Multi-Factor Authentication** with TOTP or email based tokens & WireGuard PSK
-- [automatic and real-time synchronization](https://docs.defguard.net/enterprise/automatic-real-time-desktop-client-configuration) for users' desktop client settings (including all VPNs/locations).
-- Control users [ability to manage devices and VPN options](https://docs.defguard.net/enterprise/behavior-customization)
+- [automatic and real-time synchronization](https://docs.defguard.net/features/remote-user-enrollment/automatic-real-time-desktop-client-configuration) for users' desktop client settings (including all VPNs/locations).
+- Control users [ability to manage devices and VPN options](https://docs.defguard.net/features/wireguard/behavior-customization)
- Defguard instances as well as **any WireGuard tunnel** - just import your tunnels - one client for all WireGuard connections
- Secure and remote user enrollment - setting up password, automatically configuring the client for all VPN Locations/Networks
- Onboarding - displaying custom onboarding messages, with templates, links ...
@@ -79,7 +79,7 @@ Better quality video can [be viewed here](https://github.com/DefGuard/docs/raw/d
## Quick start
-The easiest way to run your own defguard instance is to use Docker and our [one-line install script](https://docs.defguard.net/features/setting-up-your-instance/one-line-install).
+The easiest way to run your own defguard instance is to use Docker and our [one-line install script](https://docs.defguard.net/getting-started/one-line-install).
Just run the command below in your shell and follow the prompts:
```bash
@@ -96,7 +96,7 @@ Here is a step-by-step video about this process:
-To learn more about the script and available options please see the [documentation](https://docs.defguard.net/features/setting-up-your-instance/one-line-install).
+To learn more about the script and available options please see the [documentation](https://docs.defguard.net/getting-started/one-line-install).
### Setup a VPN server in under 5 minutes !?
@@ -104,9 +104,9 @@ Just follow [this tutorial](http://bit.ly/defguard-setup)
## Manual deployment examples
-- [Standalone system package based install](https://docs.defguard.net/admin-and-features/setting-up-your-instance/standalone-package-based-installation)
-- Using [Docker Compose](https://docs.defguard.net/features/setting-up-your-instance/docker-compose)
-- Using [Kubernetes](https://docs.defguard.net/features/setting-up-your-instance/kubernetes)
+- [Standalone system package based install](https://docs.defguard.net/deployment-strategies/standalone-package-based-installation)
+- Using [Docker Compose](https://docs.defguard.net/deployment-strategies/docker-compose)
+- Using [Kubernetes](https://docs.defguard.net/deployment-strategies/kubernetes)
## Roadmap & Development backlog
@@ -116,27 +116,23 @@ Just follow [this tutorial](http://bit.ly/defguard-setup)
Here is a [dedicated view for **good first bugs**](https://github.com/orgs/DefGuard/projects/5/views/5)
-## Why?
-
-The story and motivation behind defguard [can be found here: https://teonite.com/blog/defguard/](https://teonite.com/blog/defguard/)
-
## Features
* Remote Access: [WireGuard® VPN](https://www.wireguard.com/) server with:
- - [Multi-Factor Authentication](https://docs.defguard.net/help/desktop-client/multi-factor-authentication-mfa-2fa) with TOTP/Email & Pre-Shared Session Keys
+ - [Multi-Factor Authentication](https://docs.defguard.net/features/wireguard/multi-factor-authentication-mfa-2fa) with TOTP/Email & Pre-Shared Session Keys
- multiple VPN Locations (networks/sites) - with defined access (all users or only Admin group)
- multiple [Gateways](https://github.com/DefGuard/gateway) for each VPN Location (**high availability/failover**) - supported on a cluster of routers/firewalls for Linux, FreeBSD/PFSense/OPNSense
- **import your current WireGuard® server configuration (with a wizard!)**
- **most beautiful [Desktop Client!](https://github.com/defguard/client)** (in our opinion ;-))
- automatic IP allocation
- - [automatic and real-time synchronization](https://docs.defguard.net/enterprise/automatic-real-time-desktop-client-configuration) for users' desktop client settings (including all VPNs/locations).
- - control users [ability to manage devices and VPN options](https://docs.defguard.net/enterprise/behavior-customization)
+ - [automatic and real-time synchronization](https://docs.defguard.net/features/remote-user-enrollment/automatic-real-time-desktop-client-configuration) for users' desktop client settings (including all VPNs/locations).
+ - control users [ability to manage devices and VPN options](https://docs.defguard.net/features/wireguard/behavior-customization)
- kernel (Linux, FreeBSD/OPNSense/PFSense) & userspace WireGuard® support with [our Rust library](https://github.com/defguard/wireguard-rs)
- dashboard and statistics overview of connected users/devices for admins
- *defguard is not an official WireGuard® project, and WireGuard is a registered trademark of Jason A. Donenfeld.*
* Identity & Account Management:
- SSO based on OpenID Connect](https://openid.net/developers/how-connect-works/)
- - External SSO: [external OpenID provider support](https://docs.defguard.net/enterprise/external-openid-providers)
+ - External SSO: [external OpenID provider support](https://docs.defguard.net/features/external-openid-providers)
- [Multi-Factor/2FA](https://en.wikipedia.org/wiki/Multi-factor_authentication) Authentication:
- [Time-based One-Time Password Algorithm](https://en.wikipedia.org/wiki/Time-based_one-time_password) (TOTP - e.g. Google Authenticator)
- WebAuthn / FIDO2 - for hardware key authentication support (eg. YubiKey, FaceID, TouchID, ...)
@@ -146,12 +142,12 @@ The story and motivation behind defguard [can be found here: https://teonite.com
- nice UI to manage users
- Users **self-service** (besides typical data management, users can revoke access to granted apps, MFA, WireGuard®, etc.)
* Account Lifecycle Management:
- - Secure remote (over the Internet) [user enrollment](https://docs.defguard.net/help/remote-user-enrollment) - on public web / Desktop Client
- - User [onboarding after enrollment](https://docs.defguard.net/help/remote-user-enrollment/user-onboarding-after-enrollment)
-* SSH & GPG public key management in user profile - with [SSH keys authentication for servers](https://docs.defguard.net/admin-and-features/ssh-authentication)
+ - Secure remote (over the Internet) [user enrollment](https://docs.defguard.net/features/remote-user-enrollment) - on public web / Desktop Client
+ - User [onboarding after enrollment](https://docs.defguard.net/features/remote-user-enrollment/user-onboarding-after-enrollment)
+* SSH & GPG public key management in user profile - with [SSH keys authentication for servers](https://docs.defguard.net/features/ssh-authentication)
* [Yubikey hardware keys](https://www.yubico.com/) provisioning for users by *one click*
-* [Email/SMTP support](https://docs.defguard.net/help/setting-up-smtp-for-email-notifications) for notifications, remote enrollment and onboarding
-* Easy support with [sending debug/support information](https://docs.defguard.net/help/sending-support-info)
+* [Email/SMTP support](https://docs.defguard.net/features/notifications/setting-up-smtp-for-email-notifications) for notifications, remote enrollment and onboarding
+* Easy support with [sending debug/support information](https://docs.defguard.net/support-1/troubleshooting/sending-support-info)
* Webhooks & REST API
* Built with [Rust](https://www.rust-lang.org/) for portability, security, and speed
* [UI Library](https://github.com/defguard/ui) - our beautiful React/TypeScript UI is a collection of React components:
diff --git a/crates/defguard/Cargo.toml b/crates/defguard/Cargo.toml
index a9837db037..8399bb0ae5 100644
--- a/crates/defguard/Cargo.toml
+++ b/crates/defguard/Cargo.toml
@@ -9,9 +9,11 @@ rust-version.workspace = true
[dependencies]
# internal crates
+defguard_common = { workspace = true }
defguard_core = { workspace = true }
defguard_event_router = { workspace = true }
defguard_event_logger = { workspace = true }
+defguard_mail = { workspace = true }
defguard_version = { workspace = true }
# external dependencies
diff --git a/crates/defguard/src/main.rs b/crates/defguard/src/main.rs
index 84a176a73d..3c7576a2ee 100644
--- a/crates/defguard/src/main.rs
+++ b/crates/defguard/src/main.rs
@@ -4,14 +4,17 @@ use std::{
};
use bytes::Bytes;
-use defguard_core::{
- SERVER_CONFIG, VERSION,
- auth::failed_login::FailedLoginMap,
- config::{Command, DefGuardConfig},
+use defguard_common::{
+ VERSION,
+ config::{Command, DefGuardConfig, SERVER_CONFIG},
db::{
- AppEvent, GatewayEvent, Settings, User, init_db,
- models::settings::initialize_current_settings,
+ init_db,
+ models::{Settings, settings::initialize_current_settings},
},
+};
+use defguard_core::{
+ auth::failed_login::FailedLoginMap,
+ db::{AppEvent, GatewayEvent, User},
enterprise::{
activity_log_stream::activity_log_stream_manager::run_activity_log_stream_manager,
license::{License, run_periodic_license_check, set_cached_license},
@@ -23,9 +26,7 @@ use defguard_core::{
gateway::{client_state::ClientMap, map::GatewayMap},
run_grpc_bidi_stream, run_grpc_server,
},
- init_dev_env, init_vpn_location,
- mail::{Mail, run_mail_handler},
- run_web_server,
+ init_dev_env, init_vpn_location, run_web_server,
utility_thread::run_utility_thread,
version::IncompatibleComponents,
wireguard_peer_disconnect::run_periodic_peer_disconnect,
@@ -33,6 +34,7 @@ use defguard_core::{
};
use defguard_event_logger::{message::EventLoggerMessage, run_event_logger};
use defguard_event_router::{RouterReceiverSet, run_event_router};
+use defguard_mail::{Mail, run_mail_handler};
use secrecy::ExposeSecret;
use tokio::sync::{broadcast, mpsc::unbounded_channel};
@@ -109,7 +111,7 @@ async fn main() -> Result<(), anyhow::Error> {
let gateway_state = Arc::new(Mutex::new(GatewayMap::new()));
let client_state = Arc::new(Mutex::new(ClientMap::new()));
- let incompatible_components: Arc> = Default::default();
+ let incompatible_components: Arc> = Arc::default();
// initialize admin user
User::init_admin_user(&pool, config.default_admin_password.expose_secret()).await?;
diff --git a/crates/defguard_common/Cargo.toml b/crates/defguard_common/Cargo.toml
new file mode 100644
index 0000000000..3ab2e155a1
--- /dev/null
+++ b/crates/defguard_common/Cargo.toml
@@ -0,0 +1,39 @@
+[package]
+name = "defguard_common"
+version = "1.5.1"
+edition.workspace = true
+license-file.workspace = true
+homepage.workspace = true
+repository.workspace = true
+rust-version.workspace = true
+
+[dependencies]
+model_derive.workspace = true
+
+anyhow.workspace = true
+base64.workspace = true
+chrono.workspace = true
+clap.workspace = true
+ed25519-dalek = { version = "2.2", features = ["rand_core"] }
+humantime.workspace = true
+ipnetwork.workspace = true
+jsonwebtoken.workspace = true
+openidconnect.workspace = true
+rand.workspace = true
+reqwest.workspace = true
+rsa.workspace = true
+secrecy.workspace = true
+serde.workspace = true
+sqlx.workspace = true
+struct-patch.workspace = true
+thiserror.workspace = true
+tonic.workspace = true
+tracing.workspace = true
+utoipa.workspace = true
+uuid.workspace = true
+
+[dev-dependencies]
+matches.workspace = true
+
+[build-dependencies]
+vergen-git2 = { version = "1.0", features = ["build"] }
diff --git a/crates/defguard_common/build.rs b/crates/defguard_common/build.rs
new file mode 100644
index 0000000000..d1e71d8bbe
--- /dev/null
+++ b/crates/defguard_common/build.rs
@@ -0,0 +1,10 @@
+use vergen_git2::{Emitter, Git2Builder};
+
+fn main() -> Result<(), Box> {
+ // set VERGEN_GIT_SHA env variable based on git commit hash
+ let git2 = Git2Builder::default().branch(true).sha(true).build()?;
+ Emitter::default().add_instructions(&git2)?.emit()?;
+
+ println!("cargo:rerun-if-changed=../../migrations");
+ Ok(())
+}
diff --git a/crates/defguard_common/src/auth/claims.rs b/crates/defguard_common/src/auth/claims.rs
new file mode 100644
index 0000000000..bca84e18e7
--- /dev/null
+++ b/crates/defguard_common/src/auth/claims.rs
@@ -0,0 +1,98 @@
+use std::{
+ env,
+ time::{Duration, SystemTime},
+};
+
+use jsonwebtoken::{
+ DecodingKey, EncodingKey, Header, Validation, decode, encode, errors::Error as JWTError,
+};
+use serde::{Deserialize, Serialize};
+
+pub static JWT_ISSUER: &str = "DefGuard";
+pub static AUTH_SECRET_ENV: &str = "DEFGUARD_AUTH_SECRET";
+pub static GATEWAY_SECRET_ENV: &str = "DEFGUARD_GATEWAY_SECRET";
+pub static YUBIBRIDGE_SECRET_ENV: &str = "DEFGUARD_YUBIBRIDGE_SECRET";
+
+#[derive(Clone, Copy, Default)]
+pub enum ClaimsType {
+ #[default]
+ Auth,
+ Gateway,
+ YubiBridge,
+ DesktopClient,
+}
+
+/// Standard claims: https://www.iana.org/assignments/jwt/jwt.xhtml
+#[derive(Deserialize, Serialize)]
+pub struct Claims {
+ #[serde(skip_serializing, skip_deserializing)]
+ secret: String,
+ // issuer
+ pub iss: String,
+ // subject
+ pub sub: String,
+ // client identifier
+ pub client_id: String,
+ // expiration time
+ pub exp: u64,
+ // not before
+ pub nbf: u64,
+}
+
+impl Claims {
+ #[must_use]
+ pub fn new(claims_type: ClaimsType, sub: String, client_id: String, duration: u64) -> Self {
+ let now = SystemTime::now();
+ let exp = now
+ .checked_add(Duration::from_secs(duration))
+ .expect("valid time")
+ .duration_since(SystemTime::UNIX_EPOCH)
+ .expect("valid timestamp")
+ .as_secs();
+ let nbf = now
+ .duration_since(SystemTime::UNIX_EPOCH)
+ .expect("valid timestamp")
+ .as_secs();
+ Self {
+ secret: Self::get_secret(claims_type),
+ iss: JWT_ISSUER.to_string(),
+ sub,
+ client_id,
+ exp,
+ nbf,
+ }
+ }
+
+ fn get_secret(claims_type: ClaimsType) -> String {
+ let env_var = match claims_type {
+ ClaimsType::Auth | ClaimsType::DesktopClient => AUTH_SECRET_ENV,
+ ClaimsType::Gateway => GATEWAY_SECRET_ENV,
+ ClaimsType::YubiBridge => YUBIBRIDGE_SECRET_ENV,
+ };
+ env::var(env_var).unwrap_or_default()
+ }
+
+ /// Convert claims to JWT.
+ pub fn to_jwt(&self) -> Result {
+ encode(
+ &Header::default(),
+ self,
+ &EncodingKey::from_secret(self.secret.as_bytes()),
+ )
+ }
+
+ /// Verify JWT and, if successful, convert it to claims.
+ pub fn from_jwt(claims_type: ClaimsType, token: &str) -> Result {
+ let secret = Self::get_secret(claims_type);
+ let mut validation = Validation::default();
+ validation.validate_nbf = true;
+ validation.set_issuer(&[JWT_ISSUER]);
+ validation.set_required_spec_claims(&["iss", "sub", "exp", "nbf"]);
+ decode::(
+ token,
+ &DecodingKey::from_secret(secret.as_bytes()),
+ &validation,
+ )
+ .map(|data| data.claims)
+ }
+}
diff --git a/crates/defguard_common/src/auth/mod.rs b/crates/defguard_common/src/auth/mod.rs
new file mode 100644
index 0000000000..c0e708bb12
--- /dev/null
+++ b/crates/defguard_common/src/auth/mod.rs
@@ -0,0 +1 @@
+pub mod claims;
diff --git a/crates/defguard_core/src/config.rs b/crates/defguard_common/src/config.rs
similarity index 97%
rename from crates/defguard_core/src/config.rs
rename to crates/defguard_common/src/config.rs
index e3cf365da5..2549ce610b 100644
--- a/crates/defguard_core/src/config.rs
+++ b/crates/defguard_common/src/config.rs
@@ -1,4 +1,4 @@
-use std::net::IpAddr;
+use std::{net::IpAddr, sync::OnceLock};
use clap::{Args, Parser, Subcommand};
use humantime::Duration;
@@ -12,6 +12,15 @@ use rsa::{
traits::PublicKeyParts,
};
use secrecy::{ExposeSecret, SecretString};
+use serde::Serialize;
+
+pub static SERVER_CONFIG: OnceLock = OnceLock::new();
+
+pub fn server_config() -> &'static DefGuardConfig {
+ SERVER_CONFIG
+ .get()
+ .expect("Server configuration not set yet")
+}
#[derive(Clone, Parser, Serialize, Debug)]
#[command(version)]
@@ -281,7 +290,7 @@ impl DefGuardConfig {
/// Returns configured URL with "auth/callback" appended to the path.
#[must_use]
- pub(crate) fn callback_url(&self) -> Url {
+ pub fn callback_url(&self) -> Url {
let mut url = self.url.clone();
// Append "auth/callback" to the URL.
if let Ok(mut path_segments) = url.path_segments_mut() {
diff --git a/crates/defguard_common/src/csv.rs b/crates/defguard_common/src/csv.rs
new file mode 100644
index 0000000000..1695bafaba
--- /dev/null
+++ b/crates/defguard_common/src/csv.rs
@@ -0,0 +1,17 @@
+pub trait AsCsv {
+ fn as_csv(&self) -> String;
+}
+
+impl AsCsv for I
+where
+ I: ?Sized + std::iter::IntoIterator- ,
+ for<'a> &'a I: IntoIterator
- ,
+ T: ToString,
+{
+ fn as_csv(&self) -> String {
+ self.into_iter()
+ .map(ToString::to_string)
+ .collect::>()
+ .join(",")
+ }
+}
diff --git a/crates/defguard_common/src/db/mod.rs b/crates/defguard_common/src/db/mod.rs
new file mode 100644
index 0000000000..d7ca63d055
--- /dev/null
+++ b/crates/defguard_common/src/db/mod.rs
@@ -0,0 +1,47 @@
+use serde::{Deserialize, Serialize};
+use sqlx::{
+ PgPool,
+ postgres::{PgConnectOptions, PgPoolOptions},
+};
+use tracing::info;
+use utoipa::ToSchema;
+
+pub mod models;
+
+#[derive(Clone, Debug, Deserialize, PartialEq, Serialize, ToSchema, Eq, Default, Hash)]
+pub struct NoId;
+pub type Id = i64;
+
+// helper for easier migration handling with a custom `migration` folder location
+// reference: https://docs.rs/sqlx/latest/sqlx/attr.test.html#automatic-migrations-requires-migrate-feature
+pub static MIGRATOR: sqlx::migrate::Migrator = sqlx::migrate!("../../migrations");
+
+/// Initializes and migrates postgres database. Returns DB pool object.
+pub async fn init_db(host: &str, port: u16, name: &str, user: &str, password: &str) -> PgPool {
+ info!("Initializing DB pool");
+ let opts = PgConnectOptions::new()
+ .host(host)
+ .port(port)
+ .username(user)
+ .password(password)
+ .database(name);
+ let pool = PgPool::connect_with(opts)
+ .await
+ .expect("Database connection failed");
+ MIGRATOR
+ .run(&pool)
+ .await
+ .expect("Cannot run database migrations.");
+ pool
+}
+
+// Helper function to instantiate pool manually as a workaround for issues with `sqlx::test` macro
+// reference: https://github.com/launchbadge/sqlx/issues/2567#issuecomment-2009849261
+pub async fn setup_pool(options: PgConnectOptions) -> PgPool {
+ let pool = PgPoolOptions::new().connect_with(options).await.unwrap();
+ MIGRATOR
+ .run(&pool)
+ .await
+ .expect("Cannot run database migrations.");
+ pool
+}
diff --git a/crates/defguard_core/src/db/models/auth_code.rs b/crates/defguard_common/src/db/models/auth_code.rs
similarity index 50%
rename from crates/defguard_core/src/db/models/auth_code.rs
rename to crates/defguard_common/src/db/models/auth_code.rs
index 6b2fd73b53..b57774c708 100644
--- a/crates/defguard_core/src/db/models/auth_code.rs
+++ b/crates/defguard_common/src/db/models/auth_code.rs
@@ -1,15 +1,16 @@
use chrono::Utc;
use model_derive::Model;
-use sqlx::{Error as SqlxError, PgPool, query_as};
+use sqlx::{PgExecutor, query_as};
use crate::{
db::{Id, NoId},
random::gen_alphanumeric,
};
-#[derive(Model, Clone)]
+#[derive(Model)]
#[table(authorization_code)]
pub struct AuthCode {
+ #[allow(dead_code)]
id: I,
pub user_id: Id,
pub client_id: String,
@@ -46,21 +47,41 @@ impl AuthCode {
}
}
+impl From> for AuthCode {
+ fn from(value: AuthCode) -> Self {
+ Self {
+ id: NoId,
+ user_id: value.user_id,
+ client_id: value.client_id,
+ code: value.code,
+ redirect_uri: value.redirect_uri,
+ scope: value.scope,
+ auth_time: value.auth_time,
+ nonce: value.nonce,
+ code_challenge: value.code_challenge,
+ }
+ }
+}
+
impl AuthCode {
/// Find by code.
- pub async fn find_code(pool: &PgPool, code: &str) -> Result