Skip to content

Conversation

@stefan0xC
Copy link
Contributor

@stefan0xC stefan0xC commented Nov 26, 2025

only validate master password hash if an email is provided and improve the find_by_device lookup by sorting by the most recently used device (i.e. the one last updated, which we make sure by saving the device on each login attempt).

(I think I got rid of the issue by updating the device on each login, if not I can restore the alternative version again.)

@stefan0xC stefan0xC force-pushed the fix-2fa-email-for-sso branch 2 times, most recently from 0216a67 to a3fae81 Compare November 26, 2025 01:57
}}
}

pub async fn find_by_device(device_uuid: &DeviceId, conn: &DbConn) -> Option<Self> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think using the twofactor_incomplete table is a better idea.
Something like:

    pub async fn find_by_incomplete2fa(device_uuid: &DeviceId, conn: &DbConn) -> Option<Self> {
        db_run! { conn: {
            users::table
                .inner_join(twofactor_incomplete::table.on(twofactor_incomplete::user_uuid.eq(users::uuid)))
                .filter(twofactor_incomplete::device_uuid.eq(device_uuid))
                .order_by(twofactor_incomplete::login_time.desc())
                .select(users::all_columns)
                .first::<Self>(conn)
                .ok()
        }}
    }

I wanted to additionally filter with incomplete_2fa_time_limit but:

// Don't update the data for an existing user/device pair, since that

Might prevent a user from login in after an incomplete 2FA.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you're right that this would be better to narrow down the correct user.

device_identifier: DeviceId,
#[serde(alias = "Email")]
email: String,
email: Option<String>,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Client appears to send empty string :(:

{
    "email": "",
    "masterPasswordHash": "",
    "ssoEmail2FaSessionToken": "",
    "deviceIdentifier": "5564adca-55dd-47dc-b8ea-f46d9eed225e",
    "authRequestAccessCode": "",
    "authRequestId": ""
}

Cleanest is probably to use something like:

use serde_with::{serde_as, NoneAsEmptyString};
...
#[serde_as]
#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
struct SendEmailLoginData {
    ...
    
    #[serde(alias = "Email")]
    #[serde_as(as = "NoneAsEmptyString")]
    email: Option<String>,

I believe serde_with is already a transitive dependency.

@stefan0xC stefan0xC marked this pull request as draft November 27, 2025 09:40
@stefan0xC stefan0xC force-pushed the fix-2fa-email-for-sso branch from 254eb55 to 293e1b8 Compare December 2, 2025 02:04
@stefan0xC stefan0xC marked this pull request as ready for review December 2, 2025 02:28
@stefan0xC stefan0xC force-pushed the fix-2fa-email-for-sso branch from dbd9a53 to 72a8313 Compare December 2, 2025 03:00

device.inner_save(conn).await.map(|()| device)
}
pub async fn save(&mut self, update_time: bool, conn: &DbConn) -> EmptyResult {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey,
Not sure it's clear why one should update or not.
I modified the is_new to use the create and update time because for the SSO 2FA email recovery the device had to be created with the first call to token (it used to be created only after the 2FA).

I though it was brittle but at the time I didn't want to add more complexity to the SSO PR.
Might be worth it to just use an additional field now, something like last login could work and be useful ?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe adding a nice comment there with /// will help at least in Graphical editor's i think.
That will be shown upon hovering over the function call.

Other than that, i think this looks ok too me.
So, either way, i think it is fine :)

@BlackDex BlackDex requested a review from dani-garcia December 6, 2025 14:50
@dani-garcia dani-garcia merged commit 4ad8baf into dani-garcia:main Dec 6, 2025
9 checks passed
@stefan0xC stefan0xC deleted the fix-2fa-email-for-sso branch December 6, 2025 21:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants