Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 30 additions & 22 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ axum-extra = { version = "0.9", features = [
"cookie-private",
"typed-header",
] }
base32 = "0.5"
base64 = "0.22"
chrono = { version = "0.4", default-features = false, features = [
"clock",
Expand Down
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ COPY web/ .
RUN pnpm run generate-translation-types
RUN pnpm build

FROM rust:1.77 as chef
FROM rust:1.80 as chef

WORKDIR /build

Expand Down
1 change: 0 additions & 1 deletion docker-compose.e2e.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
version: "3.9"
services:
core:
image: ghcr.io/defguard/defguard:current
Expand Down
2 changes: 0 additions & 2 deletions docker-compose.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
version: "3"

services:
core:
image: ghcr.io/defguard/defguard:latest
Expand Down
3 changes: 3 additions & 0 deletions src/auth/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ 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";
pub const TOTP_CODE_VALIDITY_PERIOD: u64 = 30;
pub const EMAIL_CODE_DIGITS: u32 = 6;
pub const TOTP_CODE_DIGITS: u32 = 6;

#[derive(Clone, Copy, Default)]
pub enum ClaimsType {
Expand Down
14 changes: 9 additions & 5 deletions src/db/models/user.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use argon2::{
use axum::http::StatusCode;
use model_derive::Model;
use sqlx::{query, query_as, query_scalar, Error as SqlxError, PgExecutor, Type};
use totp_lite::{totp, totp_custom, Sha1};
use totp_lite::{totp_custom, Sha1};

use super::{
device::{Device, UserDevice},
Expand All @@ -20,15 +20,14 @@ use super::{
DbPool, MFAInfo, OAuth2AuthorizedAppInfo, SecurityKey, WalletInfo,
};
use crate::{
auth::{EMAIL_CODE_DIGITS, TOTP_CODE_DIGITS, TOTP_CODE_VALIDITY_PERIOD},
db::Session,
error::WebError,
hex::to_lower_hex,
random::{gen_alphanumeric, gen_totp_secret},
server_config,
};

const RECOVERY_CODES_COUNT: usize = 8;
const EMAIL_CODE_DIGITS: u32 = 6;

#[derive(Clone, Deserialize, Serialize, PartialEq, Type, Debug)]
#[sqlx(type_name = "mfa_method", rename_all = "snake_case")]
Expand Down Expand Up @@ -181,7 +180,7 @@ impl User {
.execute(executor)
.await?;
}
let secret_base32 = to_lower_hex(&secret);
let secret_base32 = base32::encode(base32::Alphabet::Rfc4648 { padding: false }, &secret);
self.totp_secret = Some(secret);
Ok(secret_base32)
}
Expand Down Expand Up @@ -514,7 +513,12 @@ impl User {
pub fn verify_totp_code(&self, code: &str) -> bool {
if let Some(totp_secret) = &self.totp_secret {
if let Ok(timestamp) = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH) {
let expected_code = totp::<Sha1>(totp_secret, timestamp.as_secs());
let expected_code = totp_custom::<Sha1>(
TOTP_CODE_VALIDITY_PERIOD,
TOTP_CODE_DIGITS,
totp_secret,
timestamp.as_secs(),
);
eprintln!("{expected_code} ?? {code}");
return code == expected_code;
}
Expand Down
18 changes: 14 additions & 4 deletions tests/auth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,12 @@ use chrono::NaiveDateTime;
use claims::assert_err;
use common::fetch_user_details;
use defguard::{
auth::{TOTP_CODE_DIGITS, TOTP_CODE_VALIDITY_PERIOD},
db::{
models::wallet::keccak256, DbPool, MFAInfo, MFAMethod, Settings, User, UserDetails, Wallet,
},
handlers::{Auth, AuthCode, AuthResponse, AuthTotp, WalletChallenge},
hex::{hex_decode, to_lower_hex},
hex::to_lower_hex,
secret::SecretString,
};
use ethers_core::types::transaction::eip712::{Eip712, TypedData};
Expand All @@ -19,7 +20,7 @@ use secp256k1::{rand::rngs::OsRng, All, Message, Secp256k1, SecretKey};
use serde::Deserialize;
use serde_json::json;
use sqlx::query;
use totp_lite::{totp, Sha1};
use totp_lite::{totp_custom, Sha1};
use webauthn_authenticator_rs::{prelude::Url, softpasskey::SoftPasskey, WebauthnAuthenticator};
use webauthn_rs::prelude::{CreationChallengeResponse, RequestChallengeResponse};

Expand Down Expand Up @@ -190,8 +191,17 @@ fn totp_code(auth_totp: &AuthTotp) -> AuthCode {
let timestamp = SystemTime::now()
.duration_since(SystemTime::UNIX_EPOCH)
.unwrap();
let secret = hex_decode(&auth_totp.secret).unwrap();
let code = totp::<Sha1>(&secret, timestamp.as_secs());
let secret = base32::decode(
base32::Alphabet::Rfc4648 { padding: false },
&auth_totp.secret,
)
.unwrap();
let code = totp_custom::<Sha1>(
TOTP_CODE_VALIDITY_PERIOD,
TOTP_CODE_DIGITS,
&secret,
timestamp.as_secs(),
);
AuthCode::new(code)
}

Expand Down
2 changes: 1 addition & 1 deletion web/src/i18n/pl/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ const pl: Translation = {
totpCopied: 'Ścieżka TOTP skopiowana.',
success: 'TOTP Enabled',
},
copyPath: 'Skopiowana ścieżka TOTP',
copyPath: 'Kopiuj ścieżkę TOTP',
form: {
fields: {
code: {
Expand Down
2 changes: 1 addition & 1 deletion web/src/pages/auth/MFARoute/MFAEmail/MFAEmail.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ export const MFAEmail = () => {
const handleValidSubmit: SubmitHandler<FormFields> = (data) => {
const trimmed = trimObjectStrings(data);
verifyMutate({
code: Number.parseInt(trimmed.code),
code: String(trimmed.code),
});
};

Expand Down
2 changes: 1 addition & 1 deletion web/src/pages/auth/MFARoute/MFATOTPAuth/MFATOTPAuth.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ export const MFATOTPAuth = () => {

const handleValidSubmit: SubmitHandler<Inputs> = (values) => {
const trimmed = trimObjectStrings(values);
mutate({ code: Number(trimmed.code) });
mutate({ code: String(trimmed.code) });
};

useEffect(() => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ export const RegisterMFAEmailForm = () => {
const handleValidSubmit: SubmitHandler<FormFields> = (data) => {
data = trimObjectStrings(data);
mutateFinish({
code: Number.parseInt(data.code),
code: String(data.code),
});
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ const TOTPRegisterForm = () => {
const onValidSubmit: SubmitHandler<Inputs> = (values) => {
values = trimObjectStrings(values);
mutate({
code: Number(values.code),
code: String(values.code),
});
};
return (
Expand Down
4 changes: 2 additions & 2 deletions web/src/shared/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -383,7 +383,7 @@ export type ChangePasswordSelfRequest = {
};

export type AuthCodeRequest = {
code: number;
code: string;
};

export type AuthenticationKeyInfo = {
Expand Down Expand Up @@ -997,7 +997,7 @@ export interface Web3StartRequest {
}

export interface TOTPRequest {
code: number;
code: string;
}

export interface WebAuthnRegistrationRequest {
Expand Down