tina-core 0.0.2

Tina platform
Documentation
//! Google身份验证
use crate::tina::data::AppResult;
use crate::{app_error_from, app_system_error};
use once_cell::sync::Lazy;
use percent_encoding::{utf8_percent_encode, NON_ALPHANUMERIC};
use qrcode::render::svg::Color;
use qrcode::QrCode;
use regex::{Regex, RegexBuilder};
use std::panic::{catch_unwind, AssertUnwindSafe};

type Authenticator = google_authenticator::GoogleAuthenticator;
/// Google身份验证
pub struct GoogleAuthenticator;

impl GoogleAuthenticator {
    /// 生成密钥
    pub fn create_secret() -> AppResult<String> {
        let r = catch_unwind(AssertUnwindSafe(|| {
            let auth = Authenticator::new();
            auth.create_secret(32)
        }));
        r.map_err(|_| app_system_error!("create secret failed"))
    }
    /// 获取二维码
    pub fn get_qrcode_svg(secret: &str, name: &str, title: &str, _width: u32, _height: u32) -> AppResult<String> {
        let r = catch_unwind(AssertUnwindSafe(|| {
            fn create_scheme(name: &str, secret: &str, title: &str) -> String {
                let name = utf8_percent_encode(name, NON_ALPHANUMERIC);
                let title = utf8_percent_encode(title, NON_ALPHANUMERIC);
                format!("otpauth://totp/{}?secret={}&issuer={}", name, secret, title)
            }
            let scheme = create_scheme(name, secret, title);
            let image = QrCode::new(scheme.as_bytes())
                                .map_err(app_error_from!())?
                                .render::<Color>()
                                .dark_color(Color("#000"))
                                .light_color(Color("#FFF")) // adjust colors
                                .quiet_zone(true)          // disable quiet zone (white border)
                                .min_dimensions(180, 180)   // sets minimum image size
                                .build();

            Ok(image) as AppResult<String>
        }));
        let svg: String = r.map_err(|_| app_system_error!("get qrcode failed"))??;
        static SVG_HEADER_REGEX: Lazy<Regex> =
            Lazy::new(|| RegexBuilder::new("^(<\\?.*?\\?>)").case_insensitive(true).build().expect("build SVG_HEADER_REGEX failed"));
        let svg = SVG_HEADER_REGEX.replace(svg.as_str(), "").into_owned();
        Ok(svg)
    }
    /// 检验
    pub fn verify_code(secret: &str, code: &str) -> AppResult<bool> {
        let r = catch_unwind(AssertUnwindSafe(|| {
            let auth = Authenticator::new();
            auth.verify_code(secret, code, 1, 0)
        }));
        r.map_err(|_| app_system_error!("verify code failed"))
    }
}