You are an expert in writing code in many different languages. Your goal is to perform code completion for the following code, keeping in mind the rest of the code and the file meta data.
    Metadata details:
    filename: duo.rs
    path of file: ./repos/vaultwarden/src/api/core/two_factor
    
    the code of the file until where you have to start completion: use chrono::Utc;
use data_encoding::BASE64;
use rocket::serde::json::Json;
use rocket::Route;

use crate::{
    api::{
        core::log_user_event, core::two_factor::_generate_recover_code, ApiResult, EmptyResult, JsonResult, JsonUpcase,
        PasswordOrOtpData,
    },
    auth::Headers,
    crypto,
    db::{
        models::{EventType, TwoFactor, TwoFactorType, User},
        DbConn,
    },
    error::MapResult,
    util::get_reqwest_client,
    CONFIG,
};

pub fn routes() -> Vec<Route> {
    routes![get_duo, activate_d
    
pub async fn validate_duo_login(email: &str, response: &str, conn: &mut DbConn) -> EmptyResult {
    // email is as entered by the user, so it needs to be normalized before
    // comparison with auth_user below.
    let email = &email.to_lowercase();

    let split: Vec<&str> = response.split(':').collect();
    if split.len() != 2 {
        err!(
            "Invalid response length",
            ErrorEvent {
                event: EventType::UserFailedLogIn2fa
            }
        );
    }

    let auth_sig = split[0];
    let app_sig = split[1];

    let now = Utc::now().timestamp();

    let (ik, sk, ak, _host) = get_duo_keys_email(email, conn).await?;

    let auth_user = parse_duo_values(&sk, auth_sig, &ik, AUTH_PREFIX, now)?;
    let app_user = parse_duo_values(&ak, app_sig, &ik, APP_PREFIX, now)?;

    if !crypto::ct_eq(&auth_user, app_user) || !crypto::ct_eq(&auth_user, email) {
        err!(
            "Error validating duo authentication",
            ErrorEvent {
                event: EventType::UserFailedLogIn2fa
            }
        )
    }

    Ok(())
}