@@ -98,9 +101,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/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)
## Roadmap & Development backlog
@@ -116,7 +119,7 @@ The story and motivation behind defguard [can be found here: https://teonite.com
## Features
-* Remote Access: [WireGuard® VPN](https://www.wireguard.com/) server with:
+- 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
- 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
@@ -127,37 +130,37 @@ The story and motivation behind defguard [can be found here: https://teonite.com
- control users [ability to manage devices and VPN options](https://docs.defguard.net/enterprise/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:
+ - _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/)
- Extenal SSO: [external OpenID provider support](https://docs.defguard.net/enterprise/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, ...)
- - Email based TOTP
+ - [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, ...)
+ - Email based TOTP
- LDAP (tested on [OpenLDAP](https://www.openldap.org/)) synchronization
- [forward auth](https://docs.defguard.net/features/forward-auth) for reverse proxies (tested with Traefik and Caddy)
- 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:
+- 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)
-* [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)
-* 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:
+- SSH & GPG public key management in user profile - with [SSH keys authentication for servers](https://docs.defguard.net/admin-and-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)
+- 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:
- a set of custom and beautiful components for the layout
- Responsive Web Design (supporting mobile phones, tablets, etc..)
- [iOS Web App](https://www.macrumors.com/how-to/use-web-apps-iphone-ipad/)
-* **Checked by professional security researchers** (see [comprehensive security report](https://defguard.net/images/decap/isec-defguard.pdf))
-* End2End tests
+- **Checked by professional security researchers** (see [comprehensive security report](https://defguard.net/images/decap/isec-defguard.pdf))
+- End2End tests
## Documentation
-See the [documentation](https://defguard.gitbook.io) for more information.
+See the [documentation](https://docs.defguard.net/) for more information.
## Community and Support
@@ -181,4 +184,5 @@ Please review the [Contributing guide](https://docs.defguard.net/for-developers/
# Legal
+
WireGuard® is [registered trademarks](https://www.wireguard.com/trademark-policy/) of Jason A. Donenfeld.
diff --git a/defguard.service b/defguard.service
index 49e572123..a3cf590d7 100644
--- a/defguard.service
+++ b/defguard.service
@@ -1,6 +1,6 @@
[Unit]
Description=defguard core service
-Documentation=https://defguard.gitbook.io/defguard/
+Documentation=https://docs.defguard.net/
Wants=network-online.target
After=network-online.target
diff --git a/migrations/20241119105926_disable_wallet_mfa.down.sql b/migrations/20241119105926_disable_wallet_mfa.down.sql
new file mode 100644
index 000000000..e69de29bb
diff --git a/migrations/20241119105926_disable_wallet_mfa.up.sql b/migrations/20241119105926_disable_wallet_mfa.up.sql
new file mode 100644
index 000000000..9e5266fd7
--- /dev/null
+++ b/migrations/20241119105926_disable_wallet_mfa.up.sql
@@ -0,0 +1 @@
+UPDATE wallet SET use_for_mfa = false;
diff --git a/src/enterprise/handlers/openid_login.rs b/src/enterprise/handlers/openid_login.rs
index 847e93c1b..3da1b72fc 100644
--- a/src/enterprise/handlers/openid_login.rs
+++ b/src/enterprise/handlers/openid_login.rs
@@ -375,7 +375,7 @@ pub(crate) async fn auth_callback(
.remove(Cookie::from(CSRF_COOKIE_NAME));
let config = server_config();
- let user = user_from_claims(
+ let mut user = user_from_claims(
&appstate.pool,
Nonce::new(cookie_nonce),
payload.code,
@@ -389,7 +389,7 @@ pub(crate) async fn auth_callback(
&appstate.mail_tx,
ip_address,
user_agent.as_str(),
- &user,
+ &mut user,
)
.await?;
diff --git a/src/handlers/auth.rs b/src/handlers/auth.rs
index ef139def5..d08f0dc88 100644
--- a/src/handlers/auth.rs
+++ b/src/handlers/auth.rs
@@ -54,7 +54,7 @@ pub(crate) async fn create_session(
mail_tx: &UnboundedSender
,
ip_address: IpAddr,
user_agent: &str,
- user: &User,
+ user: &mut User,
) -> Result<(Session, Option, Option), WebError> {
let agent = USER_AGENT_PARSER.parse(user_agent);
let device_info = get_user_agent_device(&agent);
@@ -74,6 +74,9 @@ pub(crate) async fn create_session(
let login_event_type = "AUTHENTICATION".to_string();
+ // Check that MFA state is correct before proceeding further
+ user.verify_mfa_state(pool).await?;
+
info!("Authenticated user {}", user.username);
if user.mfa_enabled {
debug!(
@@ -85,7 +88,7 @@ pub(crate) async fn create_session(
pool,
mail_tx,
&session,
- &user,
+ user,
ip_address.to_string(),
login_event_type,
agent,
@@ -104,13 +107,13 @@ pub(crate) async fn create_session(
"User {} has MFA disabled, returning user info for login.",
user.username
);
- let user_info = UserInfo::from_user(pool, &user).await?;
+ let user_info = UserInfo::from_user(pool, user).await?;
check_new_device_login(
pool,
mail_tx,
&session,
- &user,
+ user,
ip_address.to_string(),
login_event_type,
agent,
@@ -138,7 +141,7 @@ pub(crate) async fn authenticate(
// check if user can proceed with login
check_username(&appstate.failed_logins, &username)?;
- let user = match User::find_by_username(&appstate.pool, &username).await {
+ let mut user = match User::find_by_username(&appstate.pool, &username).await {
Ok(Some(user)) => match user.verify_password(&data.password) {
Ok(()) => {
if user.is_active {
@@ -202,7 +205,7 @@ pub(crate) async fn authenticate(
&appstate.mail_tx,
ip_address,
user_agent.as_str(),
- &user,
+ &mut user,
)
.await?;
diff --git a/src/handlers/openid_flow.rs b/src/handlers/openid_flow.rs
index 0c166ed25..e87df21d6 100644
--- a/src/handlers/openid_flow.rs
+++ b/src/handlers/openid_flow.rs
@@ -405,9 +405,14 @@ pub async fn authorization(
let _result = session.delete(&appstate.pool).await;
Ok(login_redirect(&data, private_cookies))
} else {
- let user = User::find_by_id(&appstate.pool, session.user_id)
- .await?
- .ok_or(WebError::Authorization("User not found".into()))?;
+ let mut user =
+ User::find_by_id(&appstate.pool, session.user_id)
+ .await?
+ .ok_or(WebError::Authorization(
+ "User not found".into(),
+ ))?;
+
+ user.verify_mfa_state(&appstate.pool).await?;
// Session exists even if user hasn't completed MFA verification yet,
// thus we need to check if MFA is enabled and the verification is done.
diff --git a/templates/mail_enrollment_start.tera b/templates/mail_enrollment_start.tera
index e04543b11..e44916772 100644
--- a/templates/mail_enrollment_start.tera
+++ b/templates/mail_enrollment_start.tera
@@ -7,7 +7,7 @@ token -> enrollment token
{% extends "base.tera" %}
{% import "macros.tera" as macros %}
{% block mail_content %}
-{% set client_docs_url="https://defguard.gitbook.io/defguard/features/desktop-client" %}
+{% set client_docs_url="https://docs.defguard.net/help/desktop-client" %}
{% set client_docs_link=macros::link(content=client_docs_url, href=client_docs_url) %}
{% set release_url="https://defguard.net/download/" %}
{% set release_link=macros::link(content=release_url, href=release_url) %}
diff --git a/templates/mail_password_reset_start.tera b/templates/mail_password_reset_start.tera
index 7bd2fd595..30f4b9bc0 100644
--- a/templates/mail_password_reset_start.tera
+++ b/templates/mail_password_reset_start.tera
@@ -7,9 +7,9 @@ token -> enrollment token
{% extends "base.tera" %}
{% import "macros.tera" as macros %}
{% block mail_content %}
-{% set client_docs_url="https://defguard.gitbook.io/defguard/features/desktop-client" %}
+{% set client_docs_url="https://docs.defguard.net/help/desktop-client" %}
{% set client_docs_link=macros::link(content=client_docs_url, href=client_docs_url) %}
-{% set release_url="https://github.com/DefGuard/client/releases/latest" %}
+{% set release_url="https://defguard.net/download/" %}
{% set release_link=macros::link(content=release_url, href=release_url) %}
{% set section_content = [
macros::paragraph(content="Password reset"),
diff --git a/web/src/i18n/en/index.ts b/web/src/i18n/en/index.ts
index cb169e2ea..2e7d7ebf3 100644
--- a/web/src/i18n/en/index.ts
+++ b/web/src/i18n/en/index.ts
@@ -376,7 +376,7 @@ const en: BaseTranslation = {
},
enableEnrollment: {
label: 'Use user self-enrollment process',
- link: 'more information here',
+ link: 'more information here',
},
},
},
@@ -443,7 +443,7 @@ const en: BaseTranslation = {
title: 'Add device',
helpers: {
setupOpt: `You can add a device using this wizard. Opt for our native application "defguard" or any other WireGuard client. If you're unsure, we recommend using defguard for simplicity.`,
- client: `Please download defguard desktop client here and then follow this guide.`,
+ client: `Please download defguard desktop client here and then follow this guide.`,
},
messages: {
deviceAdded: 'Device added',
@@ -1595,7 +1595,7 @@ const en: BaseTranslation = {
noConnection: `No connection established, please run provided command.`,
connected: `Gateway connected.`,
statusError: 'Failed to get gateway status',
- oneLineInstall: `If you are doing one line install: https://defguard.gitbook.io/defguard/admin-and-features/setting-up-your-instance/one-line-install
+ oneLineInstall: `If you are doing one line install: https://docs.defguard.net/admin-and-features/setting-up-your-instance/one-line-install
you don't need to do anything.`,
fromPackage: `Install the package available at https://github.com/DefGuard/gateway/releases/latest and configure \`/etc/defguard/gateway.toml\`
according to the [documentation]({setupGatewayDocs:string}).`,
@@ -1821,7 +1821,7 @@ If you need assistance or you were asked to generate support data by our team (f
supportCard: {
title: 'Support',
body: `
-Before contacting or submitting any issues to GitHub please get familiar with Defguard documentation available at [defguard.gitbook.io/defguard](https://defguard.gitbook.io/defguard/)
+Before contacting or submitting any issues to GitHub please get familiar with Defguard documentation available at [docs.defguard.net](https://docs.defguard.net/)
To submit:
* Bugs - please go to [GitHub](https://github.com/DefGuard/defguard/issues/new?assignees=&labels=bug&template=bug_report.md&title=)
diff --git a/web/src/i18n/i18n-types.ts b/web/src/i18n/i18n-types.ts
index 86102479e..7f2efec6e 100644
--- a/web/src/i18n/i18n-types.ts
+++ b/web/src/i18n/i18n-types.ts
@@ -884,7 +884,7 @@ type RootTranslation = {
*/
label: string
/**
- * <a href="https://defguard.gitbook.io/defguard/help/enrollment" target="_blank">more information here</a>
+ * <a href="https://docs.defguard.net/help/enrollment" target="_blank">more information here</a>
*/
link: string
}
@@ -1036,7 +1036,7 @@ type RootTranslation = {
*/
setupOpt: string
/**
- * Please download defguard desktop client <a href="https://defguard.net/download" target="_blank">here</a> and then follow <a href="https://defguard.gitbook.io/defguard/help/configuring-vpn/add-new-instance" target="_blank">this guide</a>.
+ * Please download defguard desktop client <a href="https://defguard.net/download" target="_blank">here</a> and then follow <a href="https://docs.defguard.net/help/configuring-vpn/add-new-instance" target="_blank">this guide</a>.
*/
client: string
}
@@ -3795,7 +3795,7 @@ type RootTranslation = {
*/
statusError: string
/**
- * If you are doing one line install: https://defguard.gitbook.io/defguard/admin-and-features/setting-up-your-instance/one-line-install
+ * If you are doing one line install: https://docs.defguard.net/admin-and-features/setting-up-your-instance/one-line-install
you don't need to do anything.
*/
oneLineInstall: string
@@ -4295,7 +4295,7 @@ type RootTranslation = {
title: string
/**
*
- Before contacting or submitting any issues to GitHub please get familiar with Defguard documentation available at [defguard.gitbook.io/defguard](https://defguard.gitbook.io/defguard/)
+ Before contacting or submitting any issues to GitHub please get familiar with Defguard documentation available at [docs.defguard.net](https://docs.defguard.net/)
To submit:
* Bugs - please go to [GitHub](https://github.com/DefGuard/defguard/issues/new?assignees=&labels=bug&template=bug_report.md&title=)
@@ -5167,7 +5167,7 @@ export type TranslationFunctions = {
*/
label: () => LocalizedString
/**
- * more information here
+ * more information here
*/
link: () => LocalizedString
}
@@ -5318,7 +5318,7 @@ export type TranslationFunctions = {
*/
setupOpt: () => LocalizedString
/**
- * Please download defguard desktop client here and then follow this guide.
+ * Please download defguard desktop client here and then follow this guide.
*/
client: () => LocalizedString
}
@@ -8059,7 +8059,7 @@ export type TranslationFunctions = {
*/
statusError: () => LocalizedString
/**
- * If you are doing one line install: https://defguard.gitbook.io/defguard/admin-and-features/setting-up-your-instance/one-line-install
+ * If you are doing one line install: https://docs.defguard.net/admin-and-features/setting-up-your-instance/one-line-install
you don't need to do anything.
*/
oneLineInstall: () => LocalizedString
@@ -8556,7 +8556,7 @@ export type TranslationFunctions = {
title: () => LocalizedString
/**
*
- Before contacting or submitting any issues to GitHub please get familiar with Defguard documentation available at [defguard.gitbook.io/defguard](https://defguard.gitbook.io/defguard/)
+ Before contacting or submitting any issues to GitHub please get familiar with Defguard documentation available at [docs.defguard.net](https://docs.defguard.net/)
To submit:
* Bugs - please go to [GitHub](https://github.com/DefGuard/defguard/issues/new?assignees=&labels=bug&template=bug_report.md&title=)
diff --git a/web/src/i18n/ko/index.ts b/web/src/i18n/ko/index.ts
index eeacc0cc0..802a99cd3 100644
--- a/web/src/i18n/ko/index.ts
+++ b/web/src/i18n/ko/index.ts
@@ -376,7 +376,7 @@ const ko: BaseTranslation = {
},
enableEnrollment: {
label: '등록 프로세스 사용',
- link: '자세한 정보는 여기를 참고하세요',
+ link: '자세한 정보는 여기를 참고하세요',
},
},
},
@@ -443,7 +443,7 @@ const ko: BaseTranslation = {
title: '장치 추가',
helpers: {
setupOpt: `이 마법사를 사용하여 장치를 추가할 수 있습니다. 당사의 기본 애플리케이션인 "defguard" 또는 다른 WireGuard 클라이언트를 선택하세요. 잘 모르시겠다면 간편하게 defguard를 사용하는 것을 권장합니다.`,
- client: `defguard 데스크톱 클라이언트는 여기에서 다운로드하고 이 가이드를 따르세요.`,
+ client: `defguard 데스크톱 클라이언트는 여기에서 다운로드하고 이 가이드를 따르세요.`,
},
messages: {
deviceAdded: '장치가 추가되었습니다',
@@ -1572,7 +1572,7 @@ const ko: BaseTranslation = {
noConnection: `연결이 설정되지 않았습니다. 제공된 명령을 실행하십시오.`,
connected: `게이트웨이가 연결되었습니다.`,
statusError: '게이트웨이 상태를 가져오지 못했습니다',
- oneLineInstall: `한 줄 설치를 수행하는 경우: https://defguard.gitbook.io/defguard/admin-and-features/setting-up-your-instance/one-line-install
+ oneLineInstall: `한 줄 설치를 수행하는 경우: https://docs.defguard.net/admin-and-features/setting-up-your-instance/one-line-install
아무 것도 할 필요가 없습니다.`,
fromPackage: `https://github.com/DefGuard/gateway/releases/latest에서 사용 가능한 패키지를 설치하고 [문서]({setupGatewayDocs:string})에 따라 \`/etc/defguard/gateway.toml\`을 구성하십시오.
`,
@@ -1797,7 +1797,7 @@ const ko: BaseTranslation = {
supportCard: {
title: '지원',
body: `
-GitHub에 문의하거나 문제를 제출하기 전에 [defguard.gitbook.io/defguard](https://defguard.gitbook.io/defguard/)에서 제공되는 Defguard 문서를 숙지하십시오.
+GitHub에 문의하거나 문제를 제출하기 전에 [docs.defguard.net](https://docs.defguard.net/)에서 제공되는 Defguard 문서를 숙지하십시오.
제출하려면:
* 버그 - [GitHub](https://github.com/DefGuard/defguard/issues/new?assignees=&labels=bug&template=bug_report.md&title=)로 이동하십시오.
diff --git a/web/src/i18n/pl/index.ts b/web/src/i18n/pl/index.ts
index 8fc91cd7b..f903b08b9 100644
--- a/web/src/i18n/pl/index.ts
+++ b/web/src/i18n/pl/index.ts
@@ -378,7 +378,7 @@ const pl: Translation = {
},
enableEnrollment: {
label: 'Użyj zdalnej rejestracji',
- link: 'więcej informacji tutaj',
+ link: 'więcej informacji tutaj',
},
},
},
@@ -448,7 +448,7 @@ const pl: Translation = {
},
helpers: {
setupOpt: `Możesz dodać urządzenie używając naszego klienta lub samemu skonfigurwać urządzenie.`,
- client: `Pobierz klienta defguard tutaj, a następnie postępuj zgodnie z instrukcją w celu jego konfiguracji.`,
+ client: `Pobierz klienta defguard tutaj, a następnie postępuj zgodnie z instrukcją w celu jego konfiguracji.`,
},
steps: {
@@ -1583,7 +1583,7 @@ Uwaga, podane tutaj konfiguracje nie posiadają klucza prywatnego. Musisz uzupe
noConnection: `Brak połączenia proszę uruchom poniższą komendę.`,
connected: `Gateway połączony.`,
statusError: 'Nie udało się uzyskać statusu',
- oneLineInstall: `Jeśli wykonujesz instalację w jednej linii: https://defguard.gitbook.io/defguard/admin-and-features/setting-up-your-instance/one-line-install
+ oneLineInstall: `Jeśli wykonujesz instalację w jednej linii: https://docs.defguard.net/admin-and-features/setting-up-your-instance/one-line-install
nie ma potrzeby wykonywania dalszych kroków.`,
fromPackage: `Zainstaluj pakiet dostępny na https://github.com/DefGuard/gateway/releases/latest i skonfiguruj \`/etc/defguard/gateway.toml\`
na podstawie [dokumentacji]({setupGatewayDocs}).`,
@@ -1811,7 +1811,7 @@ Jeśli potrzebujesz pomocy lub zostałeś poproszony przez nasz zespół o utwor
supportCard: {
title: 'Wsparcie',
body: `
-Przed zgłoszeniem problemów na GitHub należy zapoznać z dokumentacją dostępną na [defguard.gitbook.io/defguard](https://defguard.gitbook.io/defguard/)
+Przed zgłoszeniem problemów na GitHub należy zapoznać z dokumentacją dostępną na [docs.defguard.net](https://docs.defguard.net/)
Aby zgłosić:
* Problem - przejdź do [GitHub](https://github.com/DefGuard/defguard/issues/new?assignees=&labels=bug&template=bug_report.md&title=)
diff --git a/web/src/main.tsx b/web/src/main.tsx
index 4b104ecac..530ad8725 100644
--- a/web/src/main.tsx
+++ b/web/src/main.tsx
@@ -7,7 +7,6 @@ import { createRoot } from 'react-dom/client';
import { AppLoader } from './components/AppLoader';
import { TranslationProvider } from './shared/components/providers/TranslationProvider';
-import { Web3ContextProvider } from './shared/web3/Web3ContextProvider/Web3ContextProvider';
const queryClient = new QueryClient();
const root = createRoot(document.getElementById('root') as HTMLElement);
@@ -15,9 +14,7 @@ root.render(
-
-
-
+
,
diff --git a/web/src/pages/auth/AuthPage.tsx b/web/src/pages/auth/AuthPage.tsx
index 97015e791..93a50c06f 100644
--- a/web/src/pages/auth/AuthPage.tsx
+++ b/web/src/pages/auth/AuthPage.tsx
@@ -90,9 +90,6 @@ export const AuthPage = () => {
setMFAStore(mfa);
let mfaUrl = '';
switch (mfa.mfa_method) {
- case UserMFAMethod.WEB3:
- mfaUrl = '/auth/mfa/web3';
- break;
case UserMFAMethod.WEB_AUTH_N:
mfaUrl = '/auth/mfa/webauthn';
break;
diff --git a/web/src/pages/auth/MFARoute/MFANav/MFANav.tsx b/web/src/pages/auth/MFARoute/MFANav/MFANav.tsx
index ee6ef0e58..a7474fbe7 100644
--- a/web/src/pages/auth/MFARoute/MFANav/MFANav.tsx
+++ b/web/src/pages/auth/MFARoute/MFANav/MFANav.tsx
@@ -16,20 +16,14 @@ export const MFANav = () => {
const localLL = LL.loginPage.mfa;
const totpRoute = useMatch('/auth/mfa/totp');
- const web3Route = useMatch('/auth/mfa/web3');
const webAuthNRoute = useMatch('/auth/mfa/webauthn');
const emailRoute = useMatch('/auth/mfa/email');
const recoveryRoute = useMatch('/auth/mfa/recovery');
const navigate = useNavigate();
- const [emailAvailable, totpAvailable, web3Available, webauthnAvailable] = useMFAStore(
- (state) => [
- state.email_available,
- state.totp_available,
- state.web3_available,
- state.webauthn_available,
- ],
+ const [emailAvailable, totpAvailable, webauthnAvailable] = useMFAStore(
+ (state) => [state.email_available, state.totp_available, state.webauthn_available],
shallow,
);
@@ -44,17 +38,12 @@ export const MFANav = () => {
if (webauthnAvailable && !webAuthNRoute) {
res.push(UserMFAMethod.WEB_AUTH_N);
}
- if (web3Available && !web3Route) {
- res.push(UserMFAMethod.WEB3);
- }
return res;
}, [
totpRoute,
emailRoute,
totpAvailable,
emailAvailable,
- web3Available,
- web3Route,
webauthnAvailable,
webAuthNRoute,
]);
@@ -79,12 +68,6 @@ export const MFANav = () => {
link: '/auth/mfa/webauthn',
type: UserMFAMethod.WEB_AUTH_N,
},
- {
- key: 3,
- text: localLL.controls.useWallet(),
- link: '/auth/mfa/web3',
- type: UserMFAMethod.WEB3,
- },
];
res = res.filter((link) => availableMethods.includes(link.type));
diff --git a/web/src/pages/auth/MFARoute/MFARecovery/MFARecovery.tsx b/web/src/pages/auth/MFARoute/MFARecovery/MFARecovery.tsx
index 7bf2ab228..ed3c4214f 100644
--- a/web/src/pages/auth/MFARoute/MFARecovery/MFARecovery.tsx
+++ b/web/src/pages/auth/MFARoute/MFARecovery/MFARecovery.tsx
@@ -22,13 +22,8 @@ import { useMFAStore } from '../../shared/hooks/useMFAStore';
export const MFARecovery = () => {
const navigate = useNavigate();
- const [totpAvailable, web3Available, webauthnAvailable, emailAvailable] = useMFAStore(
- (state) => [
- state.totp_available,
- state.web3_available,
- state.webauthn_available,
- state.email_available,
- ],
+ const [totpAvailable, webauthnAvailable, emailAvailable] = useMFAStore(
+ (state) => [state.totp_available, state.webauthn_available, state.email_available],
shallow,
);
const loginSubject = useAuthStore((state) => state.loginSubject);
@@ -73,7 +68,7 @@ export const MFARecovery = () => {
});
useEffect(() => {
- if (!totpAvailable && !web3Available && !webauthnAvailable && !emailAvailable) {
+ if (!totpAvailable && !webauthnAvailable && !emailAvailable) {
navigate('../');
}
// eslint-disable-next-line react-hooks/exhaustive-deps
diff --git a/web/src/pages/auth/MFARoute/MFARoute.tsx b/web/src/pages/auth/MFARoute/MFARoute.tsx
index d2a625828..276bbf63f 100644
--- a/web/src/pages/auth/MFARoute/MFARoute.tsx
+++ b/web/src/pages/auth/MFARoute/MFARoute.tsx
@@ -10,7 +10,6 @@ import { MFAEmail } from './MFAEmail/MFAEmail';
import { MFANav } from './MFANav/MFANav';
import { MFARecovery } from './MFARecovery/MFARecovery';
import { MFATOTPAuth } from './MFATOTPAuth/MFATOTPAuth';
-import { MFAWeb3 } from './MFAWeb3/MFAWeb3';
import { MFAWebAuthN } from './MFAWebAuthN/MFAWebAuthN';
export const MFARoute = () => {
@@ -22,7 +21,6 @@ export const MFARoute = () => {
} />
} />
} />
- } />
} />
} />
} />
@@ -38,9 +36,6 @@ const RedirectToDefaultMFA = () => {
useEffect(() => {
switch (defaultMFAMethod) {
- case UserMFAMethod.WEB3:
- navigate('/auth/mfa/web3', { replace: true });
- break;
case UserMFAMethod.WEB_AUTH_N:
navigate('/auth/mfa/webauthn', { replace: true });
break;
diff --git a/web/src/pages/settings/components/GlobalSettings/GlobalSettings.tsx b/web/src/pages/settings/components/GlobalSettings/GlobalSettings.tsx
index 6025d59c0..f6c107d99 100644
--- a/web/src/pages/settings/components/GlobalSettings/GlobalSettings.tsx
+++ b/web/src/pages/settings/components/GlobalSettings/GlobalSettings.tsx
@@ -1,7 +1,6 @@
import { BrandingSettings } from './components/BrandingSettings/BrandingSettings';
import { LicenseSettings } from './components/LicenseSettings/LicenseSettings';
import { ModulesSettings } from './components/ModulesSettings/ModulesSettings';
-import { Web3Settings } from './components/Web3Settings/Web3Settings';
export const GlobalSettings = () => (
<>
@@ -11,7 +10,6 @@ export const GlobalSettings = () => (
(null);
const queryClient = useQueryClient();
const docsLink =
- 'https://defguard.gitbook.io/defguard/admin-and-features/external-openid-providers';
+ // eslint-disable-next-line max-len
+ 'https://docs.defguard.net/enterprise/all-enteprise-features/external-openid-providers';
const enterpriseEnabled = useAppStore((state) => state.enterprise_status?.enabled);
const {
diff --git a/web/src/pages/users/UserProfile/UserAuthInfo/UserAuthInfoMFA.tsx b/web/src/pages/users/UserProfile/UserAuthInfo/UserAuthInfoMFA.tsx
index bf9103739..099aa6356 100644
--- a/web/src/pages/users/UserProfile/UserAuthInfo/UserAuthInfoMFA.tsx
+++ b/web/src/pages/users/UserProfile/UserAuthInfo/UserAuthInfoMFA.tsx
@@ -1,5 +1,5 @@
import { useMutation, useQueryClient } from '@tanstack/react-query';
-import { cloneDeep, isUndefined } from 'lodash-es';
+import { cloneDeep } from 'lodash-es';
import { useMemo } from 'react';
import { useI18nContext } from '../../../../i18n/i18n-react';
@@ -49,11 +49,6 @@ export const UserAuthInfoMFA = () => {
[userProfile],
);
- const mfaWeb3Enabled = useMemo(
- () => !isUndefined(userProfile?.wallets.find((w) => w.use_for_mfa === true)),
- [userProfile],
- );
-
const toaster = useToaster();
const { mutate: disableMFA } = useMutation([MutationKeys.DISABLE_MFA], disable, {
@@ -164,28 +159,6 @@ export const UserAuthInfoMFA = () => {
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [userProfile, locale]);
- const getWalletsInfoText = useMemo(() => {
- if (userProfile) {
- const userAuthorizedWallets = userProfile.wallets.filter((w) => w.use_for_mfa);
- if (userAuthorizedWallets && userAuthorizedWallets.length) {
- const res = [
- `${userAuthorizedWallets.length} ${
- userAuthorizedWallets.length > 1
- ? LL.userPage.userAuthInfo.mfa.wallet.plural()
- : LL.userPage.userAuthInfo.mfa.wallet.singular()
- }`,
- ];
- if (userProfile.user.mfa_method === UserMFAMethod.WEB3) {
- res.push(`(${LL.userPage.userAuthInfo.mfa.default()})`);
- }
- return res.join(' ');
- }
- return LL.userPage.userAuthInfo.mfa.disabled();
- }
- return '';
- // eslint-disable-next-line react-hooks/exhaustive-deps
- }, [userProfile, locale]);
-
return (
@@ -301,21 +274,6 @@ export const UserAuthInfoMFA = () => {
-
- {LL.userPage.userAuthInfo.mfa.labels.wallets()}
-
- {getWalletsInfoText}
-
- changeDefaultMFAMethod(UserMFAMethod.WEB3)}
- />
-
-
-
>
) : (
<>
@@ -333,10 +291,6 @@ export const UserAuthInfoMFA = () => {
{LL.userPage.userAuthInfo.mfa.labels.webauth()}
{getWebAuthNInfoText}
-
-
{LL.userPage.userAuthInfo.mfa.labels.wallets()}
-
{getWalletsInfoText}
-
>
)}
diff --git a/web/src/pages/users/UserProfile/UserProfile.tsx b/web/src/pages/users/UserProfile/UserProfile.tsx
index fc44b44b0..ae820377c 100644
--- a/web/src/pages/users/UserProfile/UserProfile.tsx
+++ b/web/src/pages/users/UserProfile/UserProfile.tsx
@@ -29,7 +29,6 @@ import { ProfileDetails } from './ProfileDetails/ProfileDetails';
import { UserAuthenticationKeys } from './UserAuthenticationKeys/UserAuthenticationKeys';
import { UserAuthInfo } from './UserAuthInfo/UserAuthInfo';
import { UserDevices } from './UserDevices/UserDevices';
-import { UserWallets } from './UserWallets/UserWallets';
export const UserProfile = () => {
const toaster = useToaster();
@@ -92,7 +91,6 @@ export const UserProfile = () => {
-
diff --git a/web/src/pages/users/UserProfile/UserWallets/AddWalletModal/AddWalletModal.tsx b/web/src/pages/users/UserProfile/UserWallets/AddWalletModal/AddWalletModal.tsx
deleted file mode 100644
index ee68a3d1b..000000000
--- a/web/src/pages/users/UserProfile/UserWallets/AddWalletModal/AddWalletModal.tsx
+++ /dev/null
@@ -1,29 +0,0 @@
-import './style.scss';
-
-import { useI18nContext } from '../../../../../i18n/i18n-react';
-import { MessageBox } from '../../../../../shared/defguard-ui/components/Layout/MessageBox/MessageBox';
-import { MessageBoxType } from '../../../../../shared/defguard-ui/components/Layout/MessageBox/types';
-import { ModalWithTitle } from '../../../../../shared/defguard-ui/components/Layout/modals/ModalWithTitle/ModalWithTitle';
-import { useModalStore } from '../../../../../shared/hooks/store/useModalStore';
-import { AddWalletModalForm } from './AddWalletModalForm';
-
-export const AddWalletModal = () => {
- const { LL } = useI18nContext();
- const open = useModalStore((state) => state.addWalletModal.visible);
- const setModalsState = useModalStore((state) => state.setState);
-
- return (
-
- setModalsState({ addWalletModal: { visible: visibility } })
- }
- backdrop
- >
-
-
-
- );
-};
diff --git a/web/src/pages/users/UserProfile/UserWallets/AddWalletModal/AddWalletModalForm.tsx b/web/src/pages/users/UserProfile/UserWallets/AddWalletModal/AddWalletModalForm.tsx
deleted file mode 100644
index c9cefb503..000000000
--- a/web/src/pages/users/UserProfile/UserWallets/AddWalletModal/AddWalletModalForm.tsx
+++ /dev/null
@@ -1,172 +0,0 @@
-import { zodResolver } from '@hookform/resolvers/zod';
-import { useMutation, useQueryClient } from '@tanstack/react-query';
-import { isUndefined, omit } from 'lodash-es';
-import { useEffect, useMemo, useState } from 'react';
-import { SubmitHandler, useForm } from 'react-hook-form';
-import { z } from 'zod';
-
-import { useI18nContext } from '../../../../../i18n/i18n-react';
-import { FormInput } from '../../../../../shared/defguard-ui/components/Form/FormInput/FormInput';
-import { Button } from '../../../../../shared/defguard-ui/components/Layout/Button/Button';
-import {
- ButtonSize,
- ButtonStyleVariant,
-} from '../../../../../shared/defguard-ui/components/Layout/Button/types';
-import { useModalStore } from '../../../../../shared/hooks/store/useModalStore';
-import { useUserProfileStore } from '../../../../../shared/hooks/store/useUserProfileStore';
-import useApi from '../../../../../shared/hooks/useApi';
-import { MutationKeys } from '../../../../../shared/mutations';
-import { QueryKeys } from '../../../../../shared/queries';
-import { chainName } from '../../../../../shared/utils/chainName';
-import { trimObjectStrings } from '../../../../../shared/utils/trimObjectStrings';
-import { useWeb3Account } from '../../../../../shared/web3/hooks/useWeb3Account';
-import { useWeb3Connection } from '../../../../../shared/web3/hooks/useWeb3Connection';
-import { useWeb3Signer } from '../../../../../shared/web3/hooks/useWeb3Signer';
-
-interface FormValues {
- name: string;
- address: string;
-}
-
-const defaultValues = {
- name: 'My wallet',
- address: '',
-};
-
-export const AddWalletModalForm = () => {
- const user = useUserProfileStore((state) => state.userProfile?.user);
- const setModalsState = useModalStore((state) => state.setState);
- const {
- user: { walletChallenge, setWallet },
- } = useApi();
- const { LL } = useI18nContext();
-
- const queryClient = useQueryClient();
-
- const { isConnected } = useWeb3Connection();
- const { address, chainId } = useWeb3Account();
- const { signer } = useWeb3Signer();
-
- const [isSigning, setIsSigning] = useState(false);
-
- const AddWalletMutation = useMutation(setWallet, {
- mutationKey: [MutationKeys.SET_WALLET],
-
- onSuccess: () => {
- setModalsState({ addWalletModal: { visible: false } });
- queryClient.invalidateQueries([QueryKeys.FETCH_USER_PROFILE]);
- },
-
- onError: () => {
- setModalsState({ addWalletModal: { visible: false } });
- },
- });
-
- const WalletChallengeMutation = useMutation(walletChallenge, {
- mutationKey: [MutationKeys.WALLET_CHALLENGE],
- onSuccess: async (data, variables) => {
- if (isUndefined(chainId) || !signer) return;
- const message = JSON.parse(data.message);
- const types = omit(message.types, ['EIP712Domain']);
- const domain = message.domain;
- const value = message.message;
- setIsSigning(true);
- const signature = await signer.signTypedData(domain, types, value).catch((e) => {
- setIsSigning(false);
- console.error(e);
- return undefined;
- });
- if (signature) {
- AddWalletMutation.mutate({
- name: variables.name || 'My wallet',
- chain_id: chainId,
- username: variables.username,
- address: variables.address,
- signature,
- });
- }
- },
- });
-
- const zodSchema = useMemo(
- () =>
- z.object({
- name: z.string().min(1, LL.form.error.required()),
- address: z.string().min(1, LL.form.error.required()),
- }),
- [LL.form.error],
- );
-
- const defaultFormValues = useMemo((): FormValues => {
- if (address && chainId) {
- const mappedName = chainName(chainId);
- return {
- name: mappedName || 'My wallet',
- address: address || '',
- };
- }
- return defaultValues;
- }, [address, chainId]);
-
- const { handleSubmit, control, reset } = useForm
({
- resolver: zodResolver(zodSchema),
- mode: 'all',
- defaultValues: defaultFormValues,
- });
-
- const onSubmit: SubmitHandler = async (values) => {
- const trimmed = trimObjectStrings(values);
- if (user?.username && chainId) {
- WalletChallengeMutation.mutate({
- name: trimmed.name,
- username: user.username,
- address: trimmed.address,
- chainId,
- });
- }
- };
-
- // makes sure default values are set upon mount
- useEffect(() => {
- reset();
- }, [defaultFormValues, reset]);
-
- return (
-
- );
-};
diff --git a/web/src/pages/users/UserProfile/UserWallets/AddWalletModal/style.scss b/web/src/pages/users/UserProfile/UserWallets/AddWalletModal/style.scss
deleted file mode 100644
index ce02514b7..000000000
--- a/web/src/pages/users/UserProfile/UserWallets/AddWalletModal/style.scss
+++ /dev/null
@@ -1,18 +0,0 @@
-#add-wallet-modal {
- & > .content {
- & > * {
- width: 100%;
- }
- & > .message-box {
- width: calc(100% - 6rem);
- margin: 0 3rem;
- margin-bottom: 2.4rem;
- }
-
- form {
- & > * {
- width: 100%;
- }
- }
- }
-}
diff --git a/web/src/pages/users/UserProfile/UserWallets/UserWallets.tsx b/web/src/pages/users/UserProfile/UserWallets/UserWallets.tsx
deleted file mode 100644
index 87bb873c4..000000000
--- a/web/src/pages/users/UserProfile/UserWallets/UserWallets.tsx
+++ /dev/null
@@ -1,96 +0,0 @@
-import './style.scss';
-
-import { isUndefined } from 'lodash-es';
-import { alphabetical } from 'radash';
-import { useMemo } from 'react';
-import Skeleton from 'react-loading-skeleton';
-
-import { useI18nContext } from '../../../../i18n/i18n-react';
-import { useModalStore } from '../../../../shared/hooks/store/useModalStore';
-import { useUserProfileStore } from '../../../../shared/hooks/store/useUserProfileStore';
-import { useToaster } from '../../../../shared/hooks/useToaster';
-import { useWeb3Account } from '../../../../shared/web3/hooks/useWeb3Account';
-import { useWeb3Connection } from '../../../../shared/web3/hooks/useWeb3Connection';
-import { AddComponentBox } from '../../shared/components/AddComponentBox/AddComponentBox';
-import { AddWalletModal } from './AddWalletModal/AddWalletModal';
-import { WalletCard } from './WalletCard/WalletCard';
-
-export const UserWallets = () => {
- const { address } = useWeb3Account();
- const { isConnected, isConnecting, connect } = useWeb3Connection();
- const { LL } = useI18nContext();
- const userProfile = useUserProfileStore((state) => state.userProfile);
- const isMe = useUserProfileStore((state) => state.isMe);
- const setModalsState = useModalStore((state) => state.setState);
- const toaster = useToaster();
-
- const sortedWallet = useMemo(() => {
- if (userProfile && userProfile.wallets) {
- return alphabetical(userProfile.wallets, (w) => w.name);
- }
- return [];
- }, [userProfile]);
-
- const handleAddWallet = () => {
- if (
- address &&
- isConnected &&
- userProfile &&
- !isUndefined(userProfile.wallets.find((w) => w.address === address))
- ) {
- toaster.warning(
- LL.userPage.wallets.messages.duplicate.primary(),
- LL.userPage.wallets.messages.duplicate.sub(),
- );
- } else {
- setModalsState({ addWalletModal: { visible: true } });
- }
- };
-
- return (
-
-
- {LL.userPage.wallets.header()}
-
- {!userProfile && (
-
-
-
-
-
- )}
- {userProfile && sortedWallet && sortedWallet.length > 0 && (
-
- {sortedWallet.map((wallet) => (
-
- ))}
-
- )}
- {userProfile && (
- {
- if (!isConnected && connect) {
- connect()
- .then(() => {
- handleAddWallet();
- })
- .catch((e) => {
- console.error(e);
- });
- } else {
- handleAddWallet();
- }
- }}
- text={LL.userPage.wallets.addWallet()}
- />
- )}
-
-
- );
-};
diff --git a/web/src/pages/users/UserProfile/UserWallets/WalletCard/WalletCard.tsx b/web/src/pages/users/UserProfile/UserWallets/WalletCard/WalletCard.tsx
deleted file mode 100644
index 5daa3c443..000000000
--- a/web/src/pages/users/UserProfile/UserWallets/WalletCard/WalletCard.tsx
+++ /dev/null
@@ -1,170 +0,0 @@
-import './style.scss';
-
-import { useMutation, useQueryClient } from '@tanstack/react-query';
-import { useCallback, useState } from 'react';
-import { useBreakpoint } from 'use-breakpoint';
-
-import { useI18nContext } from '../../../../../i18n/i18n-react';
-import IconEth from '../../../../../shared/components/svg/IconEth';
-import { deviceBreakpoints } from '../../../../../shared/constants';
-import { AvatarBox } from '../../../../../shared/defguard-ui/components/Layout/AvatarBox/AvatarBox';
-import { Badge } from '../../../../../shared/defguard-ui/components/Layout/Badge/Badge';
-import { BadgeStyleVariant } from '../../../../../shared/defguard-ui/components/Layout/Badge/types';
-import { Card } from '../../../../../shared/defguard-ui/components/Layout/Card/Card';
-import { EditButton } from '../../../../../shared/defguard-ui/components/Layout/EditButton/EditButton';
-import { EditButtonOption } from '../../../../../shared/defguard-ui/components/Layout/EditButton/EditButtonOption';
-import { EditButtonOptionStyleVariant } from '../../../../../shared/defguard-ui/components/Layout/EditButton/types';
-import { Label } from '../../../../../shared/defguard-ui/components/Layout/Label/Label';
-import { useModalStore } from '../../../../../shared/hooks/store/useModalStore';
-import { useUserProfileStore } from '../../../../../shared/hooks/store/useUserProfileStore';
-import useApi from '../../../../../shared/hooks/useApi';
-import { useClipboard } from '../../../../../shared/hooks/useClipboard';
-import { useToaster } from '../../../../../shared/hooks/useToaster';
-import { MutationKeys } from '../../../../../shared/mutations';
-import { QueryKeys } from '../../../../../shared/queries';
-import { WalletInfo } from '../../../../../shared/types';
-
-interface Props {
- wallet: WalletInfo;
- connected?: boolean;
- showMFA?: boolean;
-}
-
-export const WalletCard = ({ wallet, connected = false, showMFA = false }: Props) => {
- const { writeToClipboard } = useClipboard();
- const { LL } = useI18nContext();
- const { breakpoint } = useBreakpoint(deviceBreakpoints);
- const setModalsState = useModalStore((state) => state.setState);
- const toaster = useToaster();
- const [hovered, setHovered] = useState(false);
- const {
- user: { deleteWallet },
- auth: {
- mfa: {
- web3: { updateWalletMFA },
- },
- },
- } = useApi();
- const queryClient = useQueryClient();
- const user = useUserProfileStore((state) => state.userProfile?.user);
-
- const { mutate: deleteWalletMutation } = useMutation(
- [MutationKeys.DELETE_WALLET],
- deleteWallet,
- {
- onSuccess: () => {
- queryClient.invalidateQueries([QueryKeys.FETCH_USER_PROFILE]);
- toaster.success(LL.userPage.wallets.card.messages.deleteSuccess());
- },
- onError: (err) => {
- toaster.error(LL.messages.error());
- console.error(err);
- },
- },
- );
-
- const { mutate: updateWalletMFAMutation } = useMutation(
- [MutationKeys.EDIT_WALLET_MFA],
- updateWalletMFA,
- {
- onSuccess: (data, props) => {
- queryClient.invalidateQueries([QueryKeys.FETCH_USER_PROFILE]);
- if (props.use_for_mfa) {
- toaster.success(LL.userPage.wallets.card.messages.enableMFA());
- } else {
- toaster.success(LL.userPage.wallets.card.messages.disableMFA());
- }
- if (data && data.codes) {
- setModalsState({
- recoveryCodesModal: { visible: true, codes: data.codes },
- });
- }
- },
- onError: (err) => {
- toaster.error(LL.messages.error());
- console.error(err);
- },
- },
- );
-
- const copyWalletAddress = useCallback(() => {
- writeToClipboard(wallet.address, LL.userPage.wallets.messages.addressCopied());
- }, [LL.userPage.wallets.messages, wallet.address, writeToClipboard]);
-
- return (
- setHovered(true)}
- onHoverEnd={() => setHovered(false)}
- >
-
-
- {!wallet.use_for_mfa && showMFA && (
- {
- if (user) {
- updateWalletMFAMutation({
- username: user.username,
- address: wallet.address,
- use_for_mfa: true,
- });
- }
- }}
- />
- )}
- {wallet.use_for_mfa && showMFA && (
- {
- if (user) {
- updateWalletMFAMutation({
- username: user.username,
- address: wallet.address,
- use_for_mfa: false,
- });
- }
- }}
- />
- )}
- {
- if (user) {
- deleteWalletMutation({
- username: user.username,
- address: wallet.address,
- chainId: wallet.chain_id,
- name: wallet.name,
- });
- }
- }}
- />
-
-
-
-
-
-
{wallet.name}
- {connected && (
-
- )}
- {wallet.use_for_mfa && (
-
- )}
-
-
-
-
{wallet.address}
-
-
- );
-};
diff --git a/web/src/pages/users/UserProfile/UserWallets/WalletCard/style.scss b/web/src/pages/users/UserProfile/UserWallets/WalletCard/style.scss
deleted file mode 100644
index 96b71ceea..000000000
--- a/web/src/pages/users/UserProfile/UserWallets/WalletCard/style.scss
+++ /dev/null
@@ -1,42 +0,0 @@
-.card {
- &.wallet-card {
- box-sizing: border-box;
- padding: 2rem 2rem 2rem 1.7rem;
- position: relative;
-
- & > .edit-button {
- position: absolute;
- top: 2rem;
- right: 2rem;
- }
-
- & > .top {
- display: flex;
- flex-flow: row nowrap;
- column-gap: 1rem;
- margin-bottom: 2rem;
- align-items: center;
- align-content: flex-start;
- justify-content: flex-start;
-
- & > h3 {
- @include small-header;
- }
- }
-
- & > .bottom {
- label {
- margin-bottom: 1rem;
- }
-
- p {
- @include typography-legacy(14px, 17px, medium, var(--text-main));
-
- max-width: 100%;
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
- }
- }
- }
-}
diff --git a/web/src/pages/users/UserProfile/UserWallets/style.scss b/web/src/pages/users/UserProfile/UserWallets/style.scss
deleted file mode 100644
index cd2a2e4be..000000000
--- a/web/src/pages/users/UserProfile/UserWallets/style.scss
+++ /dev/null
@@ -1,35 +0,0 @@
-#user-wallets {
- & > header {
- margin-bottom: 2rem;
-
- & > h2 {
- @include card-header;
- }
- }
-
- & > .skeletons {
- width: 100%;
- display: flex;
- flex-flow: column;
- row-gap: 20px;
- .react-loading-skeleton {
- height: 70px;
- }
- }
-
- & > .wallets {
- display: flex;
- flex-flow: column nowrap;
- row-gap: 1rem;
- margin-bottom: 1rem;
-
- @include media-breakpoint-up(md) {
- row-gap: 1.5rem;
- margin-bottom: 1.5rem;
- }
- }
-
- & > .add-component {
- height: 80px;
- }
-}
diff --git a/web/src/shared/links.ts b/web/src/shared/links.ts
index 563796d47..7832a056c 100644
--- a/web/src/shared/links.ts
+++ b/web/src/shared/links.ts
@@ -2,16 +2,16 @@
// Static links to other services
export const externalLink = {
- defguardReleases: `https://github.com/DefGuard/client/releases`,
+ defguardReleases: `https://defguard.net/download/`,
gitbook: {
- base: 'https://defguard.gitbook.io/defguard/',
+ base: 'https://docs.defguard.net/',
setup: {
gateway:
- 'https://defguard.gitbook.io/defguard/features/setting-up-your-instance/gateway',
+ 'https://docs.defguard.net/admin-and-features/setting-up-your-instance/gateway',
},
wireguard: {
addDevices:
- 'https://defguard.gitbook.io/defguard/features/wireguard/adding-wireguard-devices',
+ 'https://docs.defguard.net/help/configuring-vpn/adding-wireguard-devices',
},
},
defguardSite: 'https://defguard.net',
From c4f6fd4de5164d900be78ffce8cee4eae24a56ff Mon Sep 17 00:00:00 2001
From: Adam
Date: Tue, 19 Nov 2024 15:26:18 +0100
Subject: [PATCH 8/8] Remove mfa in wallet (#858)
* Remove MFA in Wallet
* cleanup
---------
Co-authored-by: Aleksander <170264518+t-aleksander@users.noreply.github.com>
---
...91c51a3af0d260bf8e726c1c54966e11a9711.json | 22 --
...95ecb9c0fcb8762c25aa960e7b5a2e49963b.json} | 10 +-
...19fc184af94f52cb135c4c8bd2830c92a47db.json | 14 -
...f8698c283d3158c7b6806a24d777819c7e64.json} | 10 +-
...6304eab840ddfce68b9c3950683b3951ba7f.json} | 7 +-
...89525bfaedcf7f3e025ec9fc80ae734681e0.json} | 12 +-
...5d81d565b02d86af3e2a8eabc08f9ca2cbfbb.json | 22 ++
...2cc2b97916326f416adc5ae0de1e73f0fa60.json} | 7 +-
...0a4a495830071f9b2d68f5e0ff14b186a182.json} | 12 +-
...85dfde04b4c28fa8901a040d9286c020cc93.json} | 12 +-
...20241119105926_disable_wallet_mfa.down.sql | 1 +
.../20241119105926_disable_wallet_mfa.up.sql | 2 +-
src/db/models/mod.rs | 13 +-
src/db/models/user.rs | 8 +-
src/db/models/wallet.rs | 18 +-
src/handlers/auth.rs | 58 ---
src/handlers/user.rs | 81 +----
src/lib.rs | 5 +-
tests/auth.rs | 343 +-----------------
tests/openid_login.rs | 4 +-
web/src/shared/types.ts | 2 -
21 files changed, 62 insertions(+), 601 deletions(-)
delete mode 100644 .sqlx/query-18caaf9ec8c752b1ed530f8fb2991c51a3af0d260bf8e726c1c54966e11a9711.json
rename .sqlx/{query-2e73d767e5c98702de3d5340e9f0818f346d9d25547aedd4dc388347b7620cfd.json => query-1c220b1ba44ec49ad6423e97635995ecb9c0fcb8762c25aa960e7b5a2e49963b.json} (59%)
delete mode 100644 .sqlx/query-1feeccc3729029c40d9cbecd21919fc184af94f52cb135c4c8bd2830c92a47db.json
rename .sqlx/{query-7faf2df7356d7887e9780894568b76674eef0d3848f3805778291df5d4fa3537.json => query-5aaac5fbf3656a825ab33f07dd9bf8698c283d3158c7b6806a24d777819c7e64.json} (72%)
rename .sqlx/{query-560de8bc16c1bcc80d31c99dc4b788bf5eeef60689d104448989726a5999eb42.json => query-94d004eec19959acba27847ff30d6304eab840ddfce68b9c3950683b3951ba7f.json} (72%)
rename .sqlx/{query-e48af3ee182c0f3829a2248faf705626b1ad29755fef9758f88353e786a1b2ed.json => query-b120af63a9a1faaa8f64db27ca2989525bfaedcf7f3e025ec9fc80ae734681e0.json} (82%)
create mode 100644 .sqlx/query-c4e2279ae22667242ddab424cb35d81d565b02d86af3e2a8eabc08f9ca2cbfbb.json
rename .sqlx/{query-7d202e1f66e134a78fbd808e578e295afcdc4daf5f3be7cca0be247e47133794.json => query-ca812bc6c7fc8d13f0c40031408f2cc2b97916326f416adc5ae0de1e73f0fa60.json} (68%)
rename .sqlx/{query-054e9d1f22c77a3b793616e92ab97e16fc9d6814e41f8d30e3e2a8431181c347.json => query-e20ee95915d744a046e0f6aaf9610a4a495830071f9b2d68f5e0ff14b186a182.json} (82%)
rename .sqlx/{query-c4aae1903dfd0c63be33d58794f805c685a6d61c231dcbb4ce92fb3333a41a0d.json => query-eda201202a33aeda6c2d5589d21985dfde04b4c28fa8901a040d9286c020cc93.json} (82%)
diff --git a/.sqlx/query-18caaf9ec8c752b1ed530f8fb2991c51a3af0d260bf8e726c1c54966e11a9711.json b/.sqlx/query-18caaf9ec8c752b1ed530f8fb2991c51a3af0d260bf8e726c1c54966e11a9711.json
deleted file mode 100644
index f39f37c8f..000000000
--- a/.sqlx/query-18caaf9ec8c752b1ed530f8fb2991c51a3af0d260bf8e726c1c54966e11a9711.json
+++ /dev/null
@@ -1,22 +0,0 @@
-{
- "db_name": "PostgreSQL",
- "query": "SELECT totp_enabled OR email_mfa_enabled OR coalesce(bool_or(wallet.use_for_mfa), FALSE) OR count(webauthn.id) > 0 \"bool!\" FROM \"user\" LEFT JOIN wallet ON wallet.user_id = \"user\".id LEFT JOIN webauthn ON webauthn.user_id = \"user\".id WHERE \"user\".id = $1 GROUP BY totp_enabled, email_mfa_enabled;",
- "describe": {
- "columns": [
- {
- "ordinal": 0,
- "name": "bool!",
- "type_info": "Bool"
- }
- ],
- "parameters": {
- "Left": [
- "Int8"
- ]
- },
- "nullable": [
- null
- ]
- },
- "hash": "18caaf9ec8c752b1ed530f8fb2991c51a3af0d260bf8e726c1c54966e11a9711"
-}
diff --git a/.sqlx/query-2e73d767e5c98702de3d5340e9f0818f346d9d25547aedd4dc388347b7620cfd.json b/.sqlx/query-1c220b1ba44ec49ad6423e97635995ecb9c0fcb8762c25aa960e7b5a2e49963b.json
similarity index 59%
rename from .sqlx/query-2e73d767e5c98702de3d5340e9f0818f346d9d25547aedd4dc388347b7620cfd.json
rename to .sqlx/query-1c220b1ba44ec49ad6423e97635995ecb9c0fcb8762c25aa960e7b5a2e49963b.json
index 827af9731..69f000106 100644
--- a/.sqlx/query-2e73d767e5c98702de3d5340e9f0818f346d9d25547aedd4dc388347b7620cfd.json
+++ b/.sqlx/query-1c220b1ba44ec49ad6423e97635995ecb9c0fcb8762c25aa960e7b5a2e49963b.json
@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
- "query": "SELECT address \"address!\", name, chain_id, use_for_mfa FROM wallet WHERE user_id = $1 AND validation_timestamp IS NOT NULL",
+ "query": "SELECT address \"address!\", name, chain_id FROM wallet WHERE user_id = $1 AND validation_timestamp IS NOT NULL",
"describe": {
"columns": [
{
@@ -17,11 +17,6 @@
"ordinal": 2,
"name": "chain_id",
"type_info": "Int8"
- },
- {
- "ordinal": 3,
- "name": "use_for_mfa",
- "type_info": "Bool"
}
],
"parameters": {
@@ -30,11 +25,10 @@
]
},
"nullable": [
- false,
false,
false,
false
]
},
- "hash": "2e73d767e5c98702de3d5340e9f0818f346d9d25547aedd4dc388347b7620cfd"
+ "hash": "1c220b1ba44ec49ad6423e97635995ecb9c0fcb8762c25aa960e7b5a2e49963b"
}
diff --git a/.sqlx/query-1feeccc3729029c40d9cbecd21919fc184af94f52cb135c4c8bd2830c92a47db.json b/.sqlx/query-1feeccc3729029c40d9cbecd21919fc184af94f52cb135c4c8bd2830c92a47db.json
deleted file mode 100644
index 20ef03c47..000000000
--- a/.sqlx/query-1feeccc3729029c40d9cbecd21919fc184af94f52cb135c4c8bd2830c92a47db.json
+++ /dev/null
@@ -1,14 +0,0 @@
-{
- "db_name": "PostgreSQL",
- "query": "UPDATE wallet SET use_for_mfa = FALSE WHERE user_id = $1",
- "describe": {
- "columns": [],
- "parameters": {
- "Left": [
- "Int8"
- ]
- },
- "nullable": []
- },
- "hash": "1feeccc3729029c40d9cbecd21919fc184af94f52cb135c4c8bd2830c92a47db"
-}
diff --git a/.sqlx/query-7faf2df7356d7887e9780894568b76674eef0d3848f3805778291df5d4fa3537.json b/.sqlx/query-5aaac5fbf3656a825ab33f07dd9bf8698c283d3158c7b6806a24d777819c7e64.json
similarity index 72%
rename from .sqlx/query-7faf2df7356d7887e9780894568b76674eef0d3848f3805778291df5d4fa3537.json
rename to .sqlx/query-5aaac5fbf3656a825ab33f07dd9bf8698c283d3158c7b6806a24d777819c7e64.json
index b5d5b92a2..2ec55bf90 100644
--- a/.sqlx/query-7faf2df7356d7887e9780894568b76674eef0d3848f3805778291df5d4fa3537.json
+++ b/.sqlx/query-5aaac5fbf3656a825ab33f07dd9bf8698c283d3158c7b6806a24d777819c7e64.json
@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
- "query": "SELECT mfa_method \"mfa_method: _\", totp_enabled totp_available, email_mfa_enabled email_available, (SELECT count(*) > 0 FROM wallet WHERE user_id = $1 AND wallet.use_for_mfa) \"web3_available!\", (SELECT count(*) > 0 FROM webauthn WHERE user_id = $1) \"webauthn_available!\" FROM \"user\" WHERE \"user\".id = $1",
+ "query": "SELECT mfa_method \"mfa_method: _\", totp_enabled totp_available, email_mfa_enabled email_available, (SELECT count(*) > 0 FROM webauthn WHERE user_id = $1) \"webauthn_available!\" FROM \"user\" WHERE \"user\".id = $1",
"describe": {
"columns": [
{
@@ -33,11 +33,6 @@
},
{
"ordinal": 3,
- "name": "web3_available!",
- "type_info": "Bool"
- },
- {
- "ordinal": 4,
"name": "webauthn_available!",
"type_info": "Bool"
}
@@ -51,9 +46,8 @@
false,
false,
false,
- null,
null
]
},
- "hash": "7faf2df7356d7887e9780894568b76674eef0d3848f3805778291df5d4fa3537"
+ "hash": "5aaac5fbf3656a825ab33f07dd9bf8698c283d3158c7b6806a24d777819c7e64"
}
diff --git a/.sqlx/query-560de8bc16c1bcc80d31c99dc4b788bf5eeef60689d104448989726a5999eb42.json b/.sqlx/query-94d004eec19959acba27847ff30d6304eab840ddfce68b9c3950683b3951ba7f.json
similarity index 72%
rename from .sqlx/query-560de8bc16c1bcc80d31c99dc4b788bf5eeef60689d104448989726a5999eb42.json
rename to .sqlx/query-94d004eec19959acba27847ff30d6304eab840ddfce68b9c3950683b3951ba7f.json
index bdf9168f9..18d6e656a 100644
--- a/.sqlx/query-560de8bc16c1bcc80d31c99dc4b788bf5eeef60689d104448989726a5999eb42.json
+++ b/.sqlx/query-94d004eec19959acba27847ff30d6304eab840ddfce68b9c3950683b3951ba7f.json
@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
- "query": "UPDATE \"wallet\" SET \"user_id\" = $2,\"address\" = $3,\"name\" = $4,\"chain_id\" = $5,\"challenge_message\" = $6,\"challenge_signature\" = $7,\"creation_timestamp\" = $8,\"validation_timestamp\" = $9,\"use_for_mfa\" = $10 WHERE id = $1",
+ "query": "UPDATE \"wallet\" SET \"user_id\" = $2,\"address\" = $3,\"name\" = $4,\"chain_id\" = $5,\"challenge_message\" = $6,\"challenge_signature\" = $7,\"creation_timestamp\" = $8,\"validation_timestamp\" = $9 WHERE id = $1",
"describe": {
"columns": [],
"parameters": {
@@ -13,11 +13,10 @@
"Text",
"Text",
"Timestamp",
- "Timestamp",
- "Bool"
+ "Timestamp"
]
},
"nullable": []
},
- "hash": "560de8bc16c1bcc80d31c99dc4b788bf5eeef60689d104448989726a5999eb42"
+ "hash": "94d004eec19959acba27847ff30d6304eab840ddfce68b9c3950683b3951ba7f"
}
diff --git a/.sqlx/query-e48af3ee182c0f3829a2248faf705626b1ad29755fef9758f88353e786a1b2ed.json b/.sqlx/query-b120af63a9a1faaa8f64db27ca2989525bfaedcf7f3e025ec9fc80ae734681e0.json
similarity index 82%
rename from .sqlx/query-e48af3ee182c0f3829a2248faf705626b1ad29755fef9758f88353e786a1b2ed.json
rename to .sqlx/query-b120af63a9a1faaa8f64db27ca2989525bfaedcf7f3e025ec9fc80ae734681e0.json
index d72c99d11..fa090ee21 100644
--- a/.sqlx/query-e48af3ee182c0f3829a2248faf705626b1ad29755fef9758f88353e786a1b2ed.json
+++ b/.sqlx/query-b120af63a9a1faaa8f64db27ca2989525bfaedcf7f3e025ec9fc80ae734681e0.json
@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
- "query": "SELECT id, user_id, address, name, chain_id, challenge_message, challenge_signature, creation_timestamp, validation_timestamp, use_for_mfa FROM wallet WHERE user_id = $1 AND address = $2",
+ "query": "SELECT id, user_id, address, name, chain_id, challenge_message, challenge_signature, creation_timestamp, validation_timestamp FROM wallet WHERE user_id = $1 AND address = $2",
"describe": {
"columns": [
{
@@ -47,11 +47,6 @@
"ordinal": 8,
"name": "validation_timestamp",
"type_info": "Timestamp"
- },
- {
- "ordinal": 9,
- "name": "use_for_mfa",
- "type_info": "Bool"
}
],
"parameters": {
@@ -69,9 +64,8 @@
false,
true,
false,
- true,
- false
+ true
]
},
- "hash": "e48af3ee182c0f3829a2248faf705626b1ad29755fef9758f88353e786a1b2ed"
+ "hash": "b120af63a9a1faaa8f64db27ca2989525bfaedcf7f3e025ec9fc80ae734681e0"
}
diff --git a/.sqlx/query-c4e2279ae22667242ddab424cb35d81d565b02d86af3e2a8eabc08f9ca2cbfbb.json b/.sqlx/query-c4e2279ae22667242ddab424cb35d81d565b02d86af3e2a8eabc08f9ca2cbfbb.json
new file mode 100644
index 000000000..ebfe58956
--- /dev/null
+++ b/.sqlx/query-c4e2279ae22667242ddab424cb35d81d565b02d86af3e2a8eabc08f9ca2cbfbb.json
@@ -0,0 +1,22 @@
+{
+ "db_name": "PostgreSQL",
+ "query": "SELECT totp_enabled OR email_mfa_enabled OR count(webauthn.id) > 0 \"bool!\" FROM \"user\" LEFT JOIN webauthn ON webauthn.user_id = \"user\".id WHERE \"user\".id = $1 GROUP BY totp_enabled, email_mfa_enabled;",
+ "describe": {
+ "columns": [
+ {
+ "ordinal": 0,
+ "name": "bool!",
+ "type_info": "Bool"
+ }
+ ],
+ "parameters": {
+ "Left": [
+ "Int8"
+ ]
+ },
+ "nullable": [
+ null
+ ]
+ },
+ "hash": "c4e2279ae22667242ddab424cb35d81d565b02d86af3e2a8eabc08f9ca2cbfbb"
+}
diff --git a/.sqlx/query-7d202e1f66e134a78fbd808e578e295afcdc4daf5f3be7cca0be247e47133794.json b/.sqlx/query-ca812bc6c7fc8d13f0c40031408f2cc2b97916326f416adc5ae0de1e73f0fa60.json
similarity index 68%
rename from .sqlx/query-7d202e1f66e134a78fbd808e578e295afcdc4daf5f3be7cca0be247e47133794.json
rename to .sqlx/query-ca812bc6c7fc8d13f0c40031408f2cc2b97916326f416adc5ae0de1e73f0fa60.json
index 6376a5fac..27dfbff51 100644
--- a/.sqlx/query-7d202e1f66e134a78fbd808e578e295afcdc4daf5f3be7cca0be247e47133794.json
+++ b/.sqlx/query-ca812bc6c7fc8d13f0c40031408f2cc2b97916326f416adc5ae0de1e73f0fa60.json
@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
- "query": "INSERT INTO \"wallet\" (\"user_id\",\"address\",\"name\",\"chain_id\",\"challenge_message\",\"challenge_signature\",\"creation_timestamp\",\"validation_timestamp\",\"use_for_mfa\") VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9) RETURNING id",
+ "query": "INSERT INTO \"wallet\" (\"user_id\",\"address\",\"name\",\"chain_id\",\"challenge_message\",\"challenge_signature\",\"creation_timestamp\",\"validation_timestamp\") VALUES ($1,$2,$3,$4,$5,$6,$7,$8) RETURNING id",
"describe": {
"columns": [
{
@@ -18,13 +18,12 @@
"Text",
"Text",
"Timestamp",
- "Timestamp",
- "Bool"
+ "Timestamp"
]
},
"nullable": [
false
]
},
- "hash": "7d202e1f66e134a78fbd808e578e295afcdc4daf5f3be7cca0be247e47133794"
+ "hash": "ca812bc6c7fc8d13f0c40031408f2cc2b97916326f416adc5ae0de1e73f0fa60"
}
diff --git a/.sqlx/query-054e9d1f22c77a3b793616e92ab97e16fc9d6814e41f8d30e3e2a8431181c347.json b/.sqlx/query-e20ee95915d744a046e0f6aaf9610a4a495830071f9b2d68f5e0ff14b186a182.json
similarity index 82%
rename from .sqlx/query-054e9d1f22c77a3b793616e92ab97e16fc9d6814e41f8d30e3e2a8431181c347.json
rename to .sqlx/query-e20ee95915d744a046e0f6aaf9610a4a495830071f9b2d68f5e0ff14b186a182.json
index 4002b0276..619d6c2b2 100644
--- a/.sqlx/query-054e9d1f22c77a3b793616e92ab97e16fc9d6814e41f8d30e3e2a8431181c347.json
+++ b/.sqlx/query-e20ee95915d744a046e0f6aaf9610a4a495830071f9b2d68f5e0ff14b186a182.json
@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
- "query": "SELECT id, \"user_id\",\"address\",\"name\",\"chain_id\",\"challenge_message\",\"challenge_signature\",\"creation_timestamp\",\"validation_timestamp\",\"use_for_mfa\" FROM \"wallet\"",
+ "query": "SELECT id, \"user_id\",\"address\",\"name\",\"chain_id\",\"challenge_message\",\"challenge_signature\",\"creation_timestamp\",\"validation_timestamp\" FROM \"wallet\"",
"describe": {
"columns": [
{
@@ -47,11 +47,6 @@
"ordinal": 8,
"name": "validation_timestamp",
"type_info": "Timestamp"
- },
- {
- "ordinal": 9,
- "name": "use_for_mfa",
- "type_info": "Bool"
}
],
"parameters": {
@@ -66,9 +61,8 @@
false,
true,
false,
- true,
- false
+ true
]
},
- "hash": "054e9d1f22c77a3b793616e92ab97e16fc9d6814e41f8d30e3e2a8431181c347"
+ "hash": "e20ee95915d744a046e0f6aaf9610a4a495830071f9b2d68f5e0ff14b186a182"
}
diff --git a/.sqlx/query-c4aae1903dfd0c63be33d58794f805c685a6d61c231dcbb4ce92fb3333a41a0d.json b/.sqlx/query-eda201202a33aeda6c2d5589d21985dfde04b4c28fa8901a040d9286c020cc93.json
similarity index 82%
rename from .sqlx/query-c4aae1903dfd0c63be33d58794f805c685a6d61c231dcbb4ce92fb3333a41a0d.json
rename to .sqlx/query-eda201202a33aeda6c2d5589d21985dfde04b4c28fa8901a040d9286c020cc93.json
index 9a93f3484..117365f60 100644
--- a/.sqlx/query-c4aae1903dfd0c63be33d58794f805c685a6d61c231dcbb4ce92fb3333a41a0d.json
+++ b/.sqlx/query-eda201202a33aeda6c2d5589d21985dfde04b4c28fa8901a040d9286c020cc93.json
@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
- "query": "SELECT id, \"user_id\",\"address\",\"name\",\"chain_id\",\"challenge_message\",\"challenge_signature\",\"creation_timestamp\",\"validation_timestamp\",\"use_for_mfa\" FROM \"wallet\" WHERE id = $1",
+ "query": "SELECT id, \"user_id\",\"address\",\"name\",\"chain_id\",\"challenge_message\",\"challenge_signature\",\"creation_timestamp\",\"validation_timestamp\" FROM \"wallet\" WHERE id = $1",
"describe": {
"columns": [
{
@@ -47,11 +47,6 @@
"ordinal": 8,
"name": "validation_timestamp",
"type_info": "Timestamp"
- },
- {
- "ordinal": 9,
- "name": "use_for_mfa",
- "type_info": "Bool"
}
],
"parameters": {
@@ -68,9 +63,8 @@
false,
true,
false,
- true,
- false
+ true
]
},
- "hash": "c4aae1903dfd0c63be33d58794f805c685a6d61c231dcbb4ce92fb3333a41a0d"
+ "hash": "eda201202a33aeda6c2d5589d21985dfde04b4c28fa8901a040d9286c020cc93"
}
diff --git a/migrations/20241119105926_disable_wallet_mfa.down.sql b/migrations/20241119105926_disable_wallet_mfa.down.sql
index e69de29bb..7341d953f 100644
--- a/migrations/20241119105926_disable_wallet_mfa.down.sql
+++ b/migrations/20241119105926_disable_wallet_mfa.down.sql
@@ -0,0 +1 @@
+ALTER TABLE wallet ADD COLUMN use_for_mfa boolean NOT NULL DEFAULT true;
diff --git a/migrations/20241119105926_disable_wallet_mfa.up.sql b/migrations/20241119105926_disable_wallet_mfa.up.sql
index 9e5266fd7..110466238 100644
--- a/migrations/20241119105926_disable_wallet_mfa.up.sql
+++ b/migrations/20241119105926_disable_wallet_mfa.up.sql
@@ -1 +1 @@
-UPDATE wallet SET use_for_mfa = false;
+ALTER TABLE wallet DROP use_for_mfa;
diff --git a/src/db/models/mod.rs b/src/db/models/mod.rs
index d13db81b3..77e289c08 100644
--- a/src/db/models/mod.rs
+++ b/src/db/models/mod.rs
@@ -40,12 +40,11 @@ pub struct NewOpenIDClient {
pub enabled: bool,
}
-#[derive(Debug, Deserialize, Serialize)]
+#[derive(Debug, Deserialize, Serialize, ToSchema)]
pub struct WalletInfo {
pub address: String,
pub name: String,
pub chain_id: Id,
- pub use_for_mfa: bool,
}
#[derive(Deserialize, Serialize, Debug, Clone)]
@@ -217,7 +216,6 @@ impl UserDetails {
pub struct MFAInfo {
mfa_method: MFAMethod,
totp_available: bool,
- web3_available: bool,
webauthn_available: bool,
email_available: bool,
}
@@ -227,7 +225,6 @@ impl MFAInfo {
query_as!(
Self,
"SELECT mfa_method \"mfa_method: _\", totp_enabled totp_available, email_mfa_enabled email_available, \
- (SELECT count(*) > 0 FROM wallet WHERE user_id = $1 AND wallet.use_for_mfa) \"web3_available!\", \
(SELECT count(*) > 0 FROM webauthn WHERE user_id = $1) \"webauthn_available!\" \
FROM \"user\" WHERE \"user\".id = $1",
user.id
@@ -236,10 +233,7 @@ impl MFAInfo {
#[must_use]
pub fn mfa_available(&self) -> bool {
- self.webauthn_available
- || self.totp_available
- || self.web3_available
- || self.email_available
+ self.webauthn_available || self.totp_available || self.email_available
}
#[must_use]
@@ -257,9 +251,6 @@ impl MFAInfo {
if self.webauthn_available {
methods.push(MFAMethod::Webauthn);
}
- if self.web3_available {
- methods.push(MFAMethod::Web3);
- }
if self.totp_available {
methods.push(MFAMethod::OneTimePassword);
}
diff --git a/src/db/models/user.rs b/src/db/models/user.rs
index 77c76dbb1..6315d5d81 100644
--- a/src/db/models/user.rs
+++ b/src/db/models/user.rs
@@ -15,7 +15,6 @@ use totp_lite::{totp_custom, Sha1};
use super::{
device::{Device, UserDevice},
group::Group,
- wallet::Wallet,
webauthn::WebAuthn,
MFAInfo, OAuth2AuthorizedAppInfo, SecurityKey, WalletInfo,
};
@@ -234,7 +233,6 @@ impl User {
/// Check if any of the multi-factor authentication methods is on.
/// - TOTP is enabled
- /// - a [`Wallet`] flagged `use_for_mfa`
/// - a security key for Webauthn
async fn check_mfa_enabled<'e, E>(&self, executor: E) -> Result
where
@@ -246,9 +244,8 @@ impl User {
}
query_scalar!(
- "SELECT totp_enabled OR email_mfa_enabled OR coalesce(bool_or(wallet.use_for_mfa), FALSE) \
+ "SELECT totp_enabled OR email_mfa_enabled \
OR count(webauthn.id) > 0 \"bool!\" FROM \"user\" \
- LEFT JOIN wallet ON wallet.user_id = \"user\".id \
LEFT JOIN webauthn ON webauthn.user_id = \"user\".id \
WHERE \"user\".id = $1 GROUP BY totp_enabled, email_mfa_enabled;",
self.id
@@ -360,7 +357,6 @@ impl User {
)
.execute(pool)
.await?;
- Wallet::disable_mfa_for_user(pool, self.id).await?;
WebAuthn::delete_all_for_user(pool, self.id).await?;
self.totp_secret = None;
@@ -727,7 +723,7 @@ impl User {
{
query_as!(
WalletInfo,
- "SELECT address \"address!\", name, chain_id, use_for_mfa \
+ "SELECT address \"address!\", name, chain_id \
FROM wallet WHERE user_id = $1 AND validation_timestamp IS NOT NULL",
self.id
)
diff --git a/src/db/models/wallet.rs b/src/db/models/wallet.rs
index 557395ccd..8537c66b2 100644
--- a/src/db/models/wallet.rs
+++ b/src/db/models/wallet.rs
@@ -71,7 +71,6 @@ pub struct Wallet {
pub challenge_signature: Option,
pub creation_timestamp: NaiveDateTime,
pub validation_timestamp: Option,
- pub use_for_mfa: bool,
}
impl Wallet {
@@ -93,7 +92,6 @@ impl Wallet {
challenge_signature: None,
creation_timestamp: Utc::now().naive_utc(),
validation_timestamp: None,
- use_for_mfa: false,
}
}
@@ -199,7 +197,7 @@ impl Wallet {
query_as!(
Self,
"SELECT id, user_id, address, name, chain_id, challenge_message, challenge_signature, \
- creation_timestamp, validation_timestamp, use_for_mfa FROM wallet \
+ creation_timestamp, validation_timestamp FROM wallet \
WHERE user_id = $1 AND address = $2",
user_id,
address
@@ -207,18 +205,4 @@ impl Wallet {
.fetch_optional(executor)
.await
}
-
- pub async fn disable_mfa_for_user<'e, E>(executor: E, user_id: Id) -> Result<(), SqlxError>
- where
- E: PgExecutor<'e>,
- {
- query!(
- "UPDATE wallet SET use_for_mfa = FALSE WHERE user_id = $1",
- user_id
- )
- .execute(executor)
- .await?;
-
- Ok(())
- }
}
diff --git a/src/handlers/auth.rs b/src/handlers/auth.rs
index d08f0dc88..0f26c316f 100644
--- a/src/handlers/auth.rs
+++ b/src/handlers/auth.rs
@@ -754,70 +754,12 @@ pub async fn web3auth_start(
/// Finish Web3 authentication
pub async fn web3auth_end(
- private_cookies: PrivateCookieJar,
- mut session: Session,
- State(appstate): State,
Json(signature): Json,
) -> Result<(PrivateCookieJar, ApiResponse), WebError> {
debug!(
"Finishing web3 authentication for wallet {}",
signature.address
);
- if let Some(ref challenge) = session.web3_challenge {
- if let Some(wallet) =
- Wallet::find_by_user_and_address(&appstate.pool, session.user_id, &signature.address)
- .await?
- {
- if wallet.use_for_mfa {
- return match wallet.verify_address(challenge, &signature.signature) {
- Ok(true) => {
- session
- .set_state(&appstate.pool, SessionState::MultiFactorVerified)
- .await?;
- if let Some(user) =
- User::find_by_id(&appstate.pool, session.user_id).await?
- {
- let username = user.username.clone();
- let user_info = UserInfo::from_user(&appstate.pool, &user).await?;
- info!(
- "User {username} authenticated with wallet {}",
- signature.address
- );
- if let Some(openid_cookie) = private_cookies.get(SIGN_IN_COOKIE_NAME) {
- debug!("Found openid session cookie.");
- let redirect_url = openid_cookie.value().to_string();
- let private_cookies = private_cookies.remove(openid_cookie);
- Ok((
- private_cookies,
- ApiResponse {
- json: json!(AuthResponse {
- user: user_info,
- url: Some(redirect_url),
- }),
- status: StatusCode::OK,
- },
- ))
- } else {
- Ok((
- private_cookies,
- ApiResponse {
- json: json!(AuthResponse {
- user: user_info,
- url: None,
- }),
- status: StatusCode::OK,
- },
- ))
- }
- } else {
- Ok((private_cookies, ApiResponse::default()))
- }
- }
- _ => Err(WebError::Authorization("Signature not verified".into())),
- };
- }
- }
- }
Err(WebError::Http(StatusCode::BAD_REQUEST))
}
diff --git a/src/handlers/user.rs b/src/handlers/user.rs
index 4bb32f35e..8aff5cd94 100644
--- a/src/handlers/user.rs
+++ b/src/handlers/user.rs
@@ -3,13 +3,11 @@ use axum::{
http::StatusCode,
};
use serde_json::json;
-use utoipa::ToSchema;
use super::{
- mail::{send_mfa_configured_email, EMAIL_PASSOWRD_RESET_START_SUBJECT},
- user_for_admin_or_self, AddUserData, ApiResponse, ApiResult, PasswordChange,
- PasswordChangeSelf, RecoveryCodes, StartEnrollmentRequest, Username, WalletChallenge,
- WalletChange, WalletSignature,
+ mail::EMAIL_PASSOWRD_RESET_START_SUBJECT, user_for_admin_or_self, AddUserData, ApiResponse,
+ ApiResult, PasswordChange, PasswordChangeSelf, StartEnrollmentRequest, Username,
+ WalletChallenge, WalletSignature,
};
use crate::{
appstate::AppState,
@@ -18,9 +16,10 @@ use crate::{
models::{
device::DeviceInfo,
enrollment::{Token, PASSWORD_RESET_TOKEN_TYPE},
+ WalletInfo,
},
- AppEvent, GatewayEvent, MFAMethod, OAuth2AuthorizedApp, Settings, User, UserDetails,
- UserInfo, Wallet, WebAuthn, WireguardNetwork,
+ AppEvent, GatewayEvent, OAuth2AuthorizedApp, Settings, User, UserDetails, UserInfo, Wallet,
+ WebAuthn, WireguardNetwork,
},
enterprise::limits::update_counts,
error::WebError,
@@ -984,14 +983,6 @@ pub async fn reset_password(
}
}
-/// Similar to [`models::WalletInfo`] but without `use_for_mfa`.
-#[derive(Deserialize, ToSchema)]
-pub struct WalletInfoShort {
- pub address: String,
- pub name: String,
- pub chain_id: i64,
-}
-
/// Wallet challenge
///
/// Endpoint allows to generate a wallet challenge for ownership verification.
@@ -1020,7 +1011,7 @@ pub async fn wallet_challenge(
session: SessionInfo,
State(appstate): State,
Path(username): Path,
- Query(wallet_info): Query,
+ Query(wallet_info): Query,
) -> ApiResult {
debug!(
"User {} generating wallet challenge for user {username}",
@@ -1157,68 +1148,12 @@ pub async fn set_wallet(
pub async fn update_wallet(
session: SessionInfo,
Path((username, address)): Path<(String, String)>,
- State(appstate): State,
- Json(data): Json,
) -> ApiResult {
debug!(
"User {} updating wallet {address} for user {username}",
session.user.username,
);
- let mut user = user_for_admin_or_self(&appstate.pool, &session, &username).await?;
- if let Some(mut wallet) =
- Wallet::find_by_user_and_address(&appstate.pool, user.id, &address).await?
- {
- if wallet.user_id == user.id {
- let mfa_change = wallet.use_for_mfa != data.use_for_mfa;
- wallet.use_for_mfa = data.use_for_mfa;
- wallet.save(&appstate.pool).await?;
- if mfa_change {
- if data.use_for_mfa {
- debug!("Wallet {} MFA flag enabled", wallet.address);
- if !user.mfa_enabled {
- // send notification email about enabled MFA
- send_mfa_configured_email(
- Some(&session.session),
- &user,
- &MFAMethod::Web3,
- &appstate.mail_tx,
- )?;
- user.set_mfa_method(&appstate.pool, MFAMethod::Web3).await?;
- let recovery_codes = user.get_recovery_codes(&appstate.pool).await?;
- info!("User {} MFA enabled", username);
- info!(
- "User {} updated wallet {address} for user {username}",
- session.user.username,
- );
- return Ok(ApiResponse {
- json: json!(RecoveryCodes::new(recovery_codes)),
- status: StatusCode::OK,
- });
- }
- } else {
- debug!("Wallet {} MFA flag removed", wallet.address);
- user.verify_mfa_state(&appstate.pool).await?;
- }
- }
- info!(
- "User {} updated wallet {address} for user {username}",
- session.user.username,
- );
- Ok(ApiResponse::default())
- } else {
- error!(
- "User {} failed to update wallet {address} for user {username} (id: {}), the owner id is {}",
- session.user.username, user.id, wallet.user_id
- );
- Err(WebError::ObjectNotFound("wrong wallet".into()))
- }
- } else {
- error!(
- "User {} failed to update wallet {address} for user {username}, wallet not found",
- session.user.username
- );
- Err(WebError::ObjectNotFound("wallet not found".into()))
- }
+ Err(WebError::ObjectNotFound("deprecated wallet update".into()))
}
/// Delete wallet.
diff --git a/src/lib.rs b/src/lib.rs
index aecf9e6ff..c40fc74ce 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -160,8 +160,7 @@ mod openapi {
use error::WebError;
use handlers::{
group::{self, BulkAssignToGroupsRequest, Groups},
- user::{self, WalletInfoShort},
- wireguard as device,
+ user, wireguard as device,
wireguard::AddDeviceResult,
ApiResponse, EditGroupInfo, GroupInfo, PasswordChange, PasswordChangeSelf,
StartEnrollmentRequest, Username, WalletChange, WalletSignature,
@@ -213,7 +212,7 @@ mod openapi {
),
components(
schemas(
- ApiResponse, UserInfo, WebError, UserDetails, UserDevice, Groups, Username, StartEnrollmentRequest, PasswordChangeSelf, PasswordChange, WalletInfoShort, WalletSignature, WalletChange, AddDevice, AddDeviceResult, Device, ModifyDevice, BulkAssignToGroupsRequest, GroupInfo, EditGroupInfo
+ ApiResponse, UserInfo, WebError, UserDetails, UserDevice, Groups, Username, StartEnrollmentRequest, PasswordChangeSelf, PasswordChange, WalletSignature, WalletChange, AddDevice, AddDeviceResult, Device, ModifyDevice, BulkAssignToGroupsRequest, GroupInfo, EditGroupInfo
),
),
tags(
diff --git a/tests/auth.rs b/tests/auth.rs
index 0270c45d9..4e9281cb2 100644
--- a/tests/auth.rs
+++ b/tests/auth.rs
@@ -7,14 +7,11 @@ use claims::{assert_err, assert_ok};
use common::fetch_user_details;
use defguard::{
auth::{TOTP_CODE_DIGITS, TOTP_CODE_VALIDITY_PERIOD},
- db::{models::wallet::keccak256, MFAInfo, MFAMethod, Settings, User, UserDetails, Wallet},
- handlers::{Auth, AuthCode, AuthResponse, AuthTotp, WalletChallenge},
- hex::to_lower_hex,
+ db::{MFAInfo, MFAMethod, Settings, User, UserDetails},
+ handlers::{Auth, AuthCode, AuthResponse, AuthTotp},
secret::SecretString,
};
-use ethers_core::types::transaction::eip712::{Eip712, TypedData};
use reqwest::{header::USER_AGENT, StatusCode};
-use secp256k1::{rand::rngs::OsRng, All, Message, Secp256k1, SecretKey};
use serde::Deserialize;
use serde_json::json;
use sqlx::{query, PgPool};
@@ -32,67 +29,20 @@ pub struct RecoveryCodes {
}
async fn make_client() -> TestClient {
- let (client, client_state) = make_test_client().await;
-
- Wallet::new_for_user(
- client_state.test_user.id,
- "0x4aF8803CBAD86BA65ED347a3fbB3fb50e96eDD3e",
- "test",
- 5,
- "",
- )
- .save(&client_state.pool)
- .await
- .unwrap();
-
+ let (client, _) = make_test_client().await;
client
}
async fn make_client_with_db() -> (TestClient, PgPool) {
let (client, client_state) = make_test_client().await;
-
- Wallet::new_for_user(
- client_state.test_user.id,
- "0x4aF8803CBAD86BA65ED347a3fbB3fb50e96eDD3e",
- "test",
- 5,
- "",
- )
- .save(&client_state.pool)
- .await
- .unwrap();
-
(client, client_state.pool)
}
async fn make_client_with_state() -> (TestClient, ClientState) {
let (client, client_state) = make_test_client().await;
-
- Wallet::new_for_user(
- client_state.test_user.id,
- "0x4aF8803CBAD86BA65ED347a3fbB3fb50e96eDD3e",
- "test",
- 5,
- "",
- )
- .save(&client_state.pool)
- .await
- .unwrap();
-
(client, client_state)
}
-async fn make_client_with_wallet(address: &str) -> TestClient {
- let (client, client_state) = make_test_client().await;
-
- Wallet::new_for_user(client_state.test_user.id, address, "test", 5, "")
- .save(&client_state.pool)
- .await
- .unwrap();
-
- client
-}
-
#[tokio::test]
async fn test_logout() {
let mut client = make_client().await;
@@ -717,293 +667,6 @@ async fn test_mfa_method_is_updated_when_removing_last_webauthn_passkey() {
assert_eq!(mfa_info.current_mfa_method(), &MFAMethod::OneTimePassword);
}
-#[derive(Deserialize)]
-struct Challenge {
- challenge: String,
-}
-
-// helper to perform login using a wallet
-async fn wallet_login(
- client: &TestClient,
- wallet_address: String,
- secp: &Secp256k1,
- secret_key: SecretKey,
-) {
- let wallet_address_request = json!({
- "address": wallet_address.clone(),
- });
-
- // obtain challenge message
- let response = client
- .post("/api/v1/auth/web3/start")
- .json(&wallet_address_request)
- .send()
- .await;
- assert_eq!(response.status(), StatusCode::OK);
- let data: Challenge = response.json().await;
-
- let parsed_data: TypedData = serde_json::from_str(&data.challenge).unwrap();
- let parsed_message = parsed_data.message;
-
- let challenge_message = "Please read this carefully:
-
-Click to sign to prove you are in possesion of your private key to the account.
-This request will not trigger a blockchain transaction or cost any gas fees.";
- let message: String = format!(
- r#"{{
- "domain": {{ "name": "Defguard", "version": "1" }},
- "types": {{
- "EIP712Domain": [
- {{ "name": "name", "type": "string" }},
- {{ "name": "version", "type": "string" }}
- ],
- "ProofOfOwnership": [
- {{ "name": "wallet", "type": "address" }},
- {{ "name": "content", "type": "string" }},
- {{ "name": "nonce", "type": "string" }}
- ]
- }},
- "primaryType": "ProofOfOwnership",
- "message": {{
- "wallet": "{wallet_address}",
- "content": "{challenge_message}",
- "nonce": {}
- }}}}
- "#,
- parsed_message.get("nonce").unwrap(),
- )
- .chars()
- .filter(|c| *c != ' ' && *c != '\r' && *c != '\n' && *c != '\t')
- .collect::();
- let challenge = data
- .challenge
- .chars()
- .filter(|c| *c != ' ' && *c != '\r' && *c != '\n' && *c != '\t')
- .collect::();
- assert_eq!(challenge, message);
-
- // Sign message
- let signature = sign_message(&data.challenge, secp, secret_key);
-
- // Check if invalid signature results into 401
- let invalid_request_response = client
- .post("/api/v1/auth/web3")
- .json(&json!({
- "address": wallet_address.clone(),
- "signature": "0x00"
- }))
- .send()
- .await;
-
- assert_eq!(invalid_request_response.status(), StatusCode::UNAUTHORIZED);
-
- // Web3 authentication
- let response = client
- .post("/api/v1/auth/web3")
- .json(&json!({
- "address": wallet_address.clone(),
- "signature": signature,
- }))
- .send()
- .await;
-
- assert_eq!(response.status(), StatusCode::OK);
-}
-
-fn sign_message(message: &str, secp: &Secp256k1, secret_key: SecretKey) -> String {
- let typed_data: TypedData = serde_json::from_str(message).unwrap();
- let hash_msg = typed_data.encode_eip712().unwrap();
- let message = Message::from_digest_slice(&hash_msg).unwrap();
- let sig_r = secp.sign_ecdsa_recoverable(&message, &secret_key);
- let (rec_id, sig) = sig_r.serialize_compact();
-
- // Create recoverable_signature array
- let mut sig_arr = [0; 65];
- sig_arr[0..64].copy_from_slice(&sig[0..64]);
- sig_arr[64] = rec_id.to_i32() as u8;
-
- to_lower_hex(&sig_arr)
-}
-
-#[tokio::test]
-async fn test_web3() {
- let secp = Secp256k1::new();
- let (secret_key, public_key) = secp.generate_keypair(&mut OsRng);
-
- // create eth wallet address
- let public_key = public_key.serialize_uncompressed();
- let hash = keccak256(&public_key[1..]);
- let addr = &hash[hash.len() - 20..];
- let wallet_address = to_lower_hex(addr);
-
- // create client
- let client = make_client_with_wallet(&wallet_address).await;
-
- // login
- let auth = Auth::new("hpotter", "pass123");
- let response = client.post("/api/v1/auth").json(&auth).send().await;
- assert_eq!(response.status(), StatusCode::OK);
-
- // set wallet for MFA
- let response = client
- .put(format!("/api/v1/user/hpotter/wallet/{wallet_address}"))
- .json(&json!({
- "use_for_mfa": true
- }))
- .send()
- .await;
- assert_eq!(response.status(), StatusCode::OK);
-
- // check recovery codes
- let recovery_codes: RecoveryCodes = response.json().await;
- assert_eq!(recovery_codes.codes.unwrap().len(), 8); // RECOVERY_CODES_COUNT
-
- // enable MFA
- let response = client.put("/api/v1/auth/mfa").send().await;
- assert_eq!(response.status(), StatusCode::OK);
-
- // login with wallet
- let auth = Auth::new("hpotter", "pass123");
- let response = client.post("/api/v1/auth").json(&auth).send().await;
- assert_eq!(response.status(), StatusCode::CREATED);
- wallet_login(&client, wallet_address, &secp, secret_key).await;
-
- // disable MFA
- let response = client.delete("/api/v1/auth/mfa").send().await;
- assert_eq!(response.status(), StatusCode::OK);
-
- // login again
- let auth = Auth::new("hpotter", "pass123");
- let response = client.post("/api/v1/auth").json(&auth).send().await;
- assert_eq!(response.status(), StatusCode::OK);
-}
-
-#[tokio::test]
-async fn test_re_adding_wallet() {
- let secp = Secp256k1::new();
- let (secret_key, public_key) = secp.generate_keypair(&mut OsRng);
-
- // create eth wallet address
- let public_key = public_key.serialize_uncompressed();
- let hash = keccak256(&public_key[1..]);
- let addr = &hash[hash.len() - 20..];
- let wallet_address = to_lower_hex(addr);
-
- // create client
- let client = make_client().await;
-
- // login
- let auth = Auth::new("hpotter", "pass123");
- let response = client.post("/api/v1/auth").json(&auth).send().await;
- assert_eq!(response.status(), StatusCode::OK);
-
- // add wallet
- let response = client
- .get(format!(
- "/api/v1/user/hpotter/challenge?address={}&name=TestWallet&chain_id=1",
- &wallet_address
- ))
- .send()
- .await;
- let challenge: WalletChallenge = response.json().await;
- let signature = sign_message(&challenge.message, &secp, secret_key);
- let response = client
- .put("/api/v1/user/hpotter/wallet")
- .json(&json!({
- "address": wallet_address,
- "chain_id": 1,
- "name": "TestWallet",
- "signature": signature
- }))
- .send()
- .await;
- assert_eq!(response.status(), StatusCode::OK);
-
- // enable wallet for MFA
- let response = client
- .put(format!("/api/v1/user/hpotter/wallet/{}", &wallet_address))
- .json(&json!({
- "use_for_mfa": true
- }))
- .send()
- .await;
- assert_eq!(response.status(), StatusCode::OK);
-
- // check recovery codes
- let recovery_codes: RecoveryCodes = response.json().await;
- assert_eq!(recovery_codes.codes.unwrap().len(), 8); // RECOVERY_CODES_COUNT
-
- // enable MFA
- let response = client.put("/api/v1/auth/mfa").send().await;
- assert_eq!(response.status(), StatusCode::OK);
-
- // login with wallet
- let auth = Auth::new("hpotter", "pass123");
- let response = client.post("/api/v1/auth").json(&auth).send().await;
- assert_eq!(response.status(), StatusCode::CREATED);
- wallet_login(&client, wallet_address.clone(), &secp, secret_key).await;
-
- // remove wallet
- let response = client
- .delete(format!("/api/v1/user/hpotter/wallet/{}", &wallet_address))
- .send()
- .await;
- assert_eq!(response.status(), StatusCode::OK);
-
- // logout
- let response = client.post("/api/v1/auth/logout").send().await;
- assert_eq!(response.status(), StatusCode::OK);
-
- // login without MFA
- let auth = Auth::new("hpotter", "pass123");
- let response = client.post("/api/v1/auth").json(&auth).send().await;
- assert_eq!(response.status(), StatusCode::OK);
-
- // add the same wallet and enable MFA
- let response = client
- .get(format!(
- "/api/v1/user/hpotter/challenge?address={}&name=TestWallet&chain_id=1",
- &wallet_address
- ))
- .send()
- .await;
- let challenge: WalletChallenge = response.json().await;
- let signature = sign_message(&challenge.message, &secp, secret_key);
- let response = client
- .put("/api/v1/user/hpotter/wallet")
- .json(&json!({
- "address": wallet_address,
- "chain_id": 1,
- "name": "TestWallet",
- "signature": signature
- }))
- .send()
- .await;
- assert_eq!(response.status(), StatusCode::OK);
- let response = client
- .put(format!("/api/v1/user/hpotter/wallet/{}", &wallet_address))
- .json(&json!({
- "use_for_mfa": true
- }))
- .send()
- .await;
- assert_eq!(response.status(), StatusCode::OK);
-
- // check recovery codes
- let recovery_codes: RecoveryCodes = response.json().await;
- assert_eq!(recovery_codes.codes.unwrap().len(), 8); // RECOVERY_CODES_COUNT
-
- // enable MFA
- let response = client.put("/api/v1/auth/mfa").send().await;
- assert_eq!(response.status(), StatusCode::OK);
-
- // login with wallet
- let auth = Auth::new("hpotter", "pass123");
- let response = client.post("/api/v1/auth").json(&auth).send().await;
- assert_eq!(response.status(), StatusCode::CREATED);
- wallet_login(&client, wallet_address.clone(), &secp, secret_key).await;
-}
-
#[tokio::test]
async fn test_mfa_method_totp_enabled_mail() {
let (client, state) = make_test_client().await;
diff --git a/tests/openid_login.rs b/tests/openid_login.rs
index aee2b4baa..4b09725dd 100644
--- a/tests/openid_login.rs
+++ b/tests/openid_login.rs
@@ -1,9 +1,7 @@
use chrono::{Duration, Utc};
use common::{exceed_enterprise_limits, make_test_client};
-use defguard::db::{models::oauth2client::OAuth2Client, Id};
use defguard::enterprise::license::get_cached_license;
use defguard::{
- db::models::NewOpenIDClient,
enterprise::{
handlers::openid_providers::AddProviderData,
license::{set_cached_license, License},
@@ -11,7 +9,7 @@ use defguard::{
handlers::Auth,
};
use reqwest::{StatusCode, Url};
-use serde::{Deserialize, Serialize};
+use serde::Deserialize;
mod common;
use self::common::client::TestClient;
diff --git a/web/src/shared/types.ts b/web/src/shared/types.ts
index b536b3494..f8d23147d 100644
--- a/web/src/shared/types.ts
+++ b/web/src/shared/types.ts
@@ -79,7 +79,6 @@ export interface WalletInfo {
address: string;
chain_id: number;
name: string;
- use_for_mfa: boolean;
}
export type AddDeviceResponseDevice = Omit;
@@ -295,7 +294,6 @@ export interface UserEditRequest {
export interface EditWalletMFARequest {
username: string;
address: string;
- use_for_mfa: boolean;
}
export interface MFALoginResponse {