From 016f4abb32b288a613ca0ca50a9333876e8af0ea Mon Sep 17 00:00:00 2001 From: 21pages Date: Mon, 22 Jan 2024 16:29:08 +0800 Subject: [PATCH] sciter 2fa setting (#6951) not add qr code text line as it's not selectable, and selectable input will steal the focus. Signed-off-by: 21pages --- Cargo.lock | 33 +++++++++++++++++++++++++++++++++ Cargo.toml | 1 + src/flutter_ffi.rs | 16 ++++------------ src/ui.rs | 26 ++++++++++++++++++++++++++ src/ui/index.tis | 31 +++++++++++++++++++++++++++++++ src/ui_interface.rs | 17 +++++++++++++++++ 6 files changed, 112 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 60617f7a9..9ef856cfd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3036,6 +3036,15 @@ version = "3.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "62adaabb884c94955b19907d60019f4e145d091c75345379e70d1ee696f7854f" +[[package]] +name = "html-escape" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d1ad449764d627e22bfd7cd5e8868264fc9236e07c752972b4080cd351cb476" +dependencies = [ + "utf8-width", +] + [[package]] name = "http" version = "0.2.9" @@ -4828,6 +4837,23 @@ dependencies = [ "bytemuck", ] +[[package]] +name = "qrcode-generator" +version = "4.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d06cb9646c7a14096231a2474d7f21e5e8c13de090c68d13bde6157cfe7f159" +dependencies = [ + "html-escape", + "image", + "qrcodegen", +] + +[[package]] +name = "qrcodegen" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4339fc7a1021c9c1621d87f5e3505f2805c8c105420ba2f2a4df86814590c142" + [[package]] name = "quest" version = "0.3.0" @@ -5436,6 +5462,7 @@ dependencies = [ "pam", "parity-tokio-ipc", "percent-encoding", + "qrcode-generator", "rdev", "repng", "reqwest", @@ -6826,6 +6853,12 @@ dependencies = [ "byteorder", ] +[[package]] +name = "utf8-width" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86bd8d4e895da8537e5315b8254664e6b769c4ff3db18321b297a1e7004392e3" + [[package]] name = "utf8parse" version = "0.2.1" diff --git a/Cargo.toml b/Cargo.toml index adada1bd2..cccfa5f7b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -97,6 +97,7 @@ clipboard = { path = "libs/clipboard" } ctrlc = "3.2" arboard = { version = "3.2", features = ["wayland-data-control"] } system_shutdown = "4.0" +qrcode-generator = "4.1" [target.'cfg(target_os = "windows")'.dependencies] winapi = { version = "0.3", features = ["winuser", "wincrypt", "shellscalingapi", "pdh", "synchapi", "memoryapi"] } diff --git a/src/flutter_ffi.rs b/src/flutter_ffi.rs index 828d76f14..e8e9b953a 100644 --- a/src/flutter_ffi.rs +++ b/src/flutter_ffi.rs @@ -180,10 +180,7 @@ pub fn session_login( } } -pub fn session_send2fa( - session_id: SessionID, - code: String, -) { +pub fn session_send2fa(session_id: SessionID, code: String) { if let Some(session) = sessions::get_session_by_session_id(&session_id) { session.send2fa(code); } @@ -2026,20 +2023,15 @@ pub fn main_supported_input_source() -> SyncReturn { } pub fn main_generate2fa() -> String { - crate::auth_2fa::generate2fa() + generate2fa() } pub fn main_verify2fa(code: String) -> bool { - let res = crate::auth_2fa::verify2fa(code); - if res { - refresh_options(); - } - res + verify2fa(code) } pub fn main_has_valid_2fa_sync() -> SyncReturn { - let raw = get_option("2fa"); - SyncReturn(crate::auth_2fa::get_2fa(Some(raw)).is_some()) + SyncReturn(has_valid_2fa()) } #[cfg(target_os = "android")] diff --git a/src/ui.rs b/src/ui.rs index 3c3bd17e7..4ea1f097a 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -603,6 +603,28 @@ impl UI { fn support_remove_wallpaper(&self) -> bool { support_remove_wallpaper() } + + fn has_valid_2fa(&self) -> bool { + has_valid_2fa() + } + + fn generate2fa(&self) -> String { + generate2fa() + } + + pub fn verify2fa(&self, code: String) -> bool { + verify2fa(code) + } + + fn generate_2fa_img_src(&self, data: String) -> String { + let v = qrcode_generator::to_png_to_vec(data, qrcode_generator::QrCodeEcc::Low, 64) + .unwrap_or_default(); + let s = hbb_common::sodiumoxide::base64::encode( + v, + hbb_common::sodiumoxide::base64::Variant::Original, + ); + format!("data:image/png;base64,{s}") + } } impl sciter::EventHandler for UI { @@ -690,6 +712,10 @@ impl sciter::EventHandler for UI { fn handle_relay_id(String); fn get_login_device_info(); fn support_remove_wallpaper(); + fn has_valid_2fa(); + fn generate2fa(); + fn generate_2fa_img_src(String); + fn verify2fa(String); } } diff --git a/src/ui/index.tis b/src/ui/index.tis index e1f487a15..7b6e15c60 100644 --- a/src/ui/index.tis +++ b/src/ui/index.tis @@ -912,6 +912,8 @@ class PasswordArea: Reactor.Component { { !show_password ? '' :
} { !show_password ? '' :
  • {translate('Set permanent password')}
  • } { !show_password ? '' : } +
    +
  • {svg_checkmark}{translate('enable-2fa-title')}
  • ; } @@ -927,11 +929,14 @@ class PasswordArea: Reactor.Component { var pwd_id = handler.get_option('verification-method'); if (pwd_id != 'use-temporary-password' && pwd_id != 'use-permanent-password') pwd_id = 'use-both-passwords'; + var has_valid_2fa = handler.has_valid_2fa(); for (var el in this.$$(menu#edit-password-context>li)) { if (el.id.indexOf("approve-mode-") == 0) el.attributes.toggleClass("selected", el.id == mode_id); if (el.id.indexOf("use-") == 0) el.attributes.toggleClass("selected", el.id == pwd_id); + if (el.id == "tfa") + el.attributes.toggleClass("selected", has_valid_2fa); } } @@ -984,6 +989,32 @@ class PasswordArea: Reactor.Component { passwordArea.update(); } } + + event click $(li#tfa) { + var me = this; + var has_valid_2fa = handler.has_valid_2fa(); + if (has_valid_2fa) { + handler.set_option('2fa', ''); + me.update(); + } else { + var new2fa = handler.generate2fa(); + var src = handler.generate_2fa_img_src(new2fa); + msgbox("custom-2fa-setting", translate('enable-2fa-title'), +
    +
    {translate('enable-2fa-desc')}
    + +
    +
    + , "", function(res=null) { + if (!res) return; + if (!res.code) return; + if (!handler.verify2fa(res.code)) { + return translate('wrong-2fa-code'); + } + me.update(); + }, 320); + } + } } var password_cache = ["","","",""]; diff --git a/src/ui_interface.rs b/src/ui_interface.rs index 5d76dfafb..73e919140 100644 --- a/src/ui_interface.rs +++ b/src/ui_interface.rs @@ -1301,3 +1301,20 @@ pub fn support_remove_wallpaper() -> bool { #[cfg(not(any(target_os = "windows", target_os = "linux")))] return false; } + +pub fn has_valid_2fa() -> bool { + let raw = get_option("2fa"); + crate::auth_2fa::get_2fa(Some(raw)).is_some() +} + +pub fn generate2fa() -> String { + crate::auth_2fa::generate2fa() +} + +pub fn verify2fa(code: String) -> bool { + let res = crate::auth_2fa::verify2fa(code); + if res { + refresh_options(); + } + res +}