diff --git a/Cargo.lock b/Cargo.lock index 70344666e..bec83b664 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5250,6 +5250,7 @@ dependencies = [ "serde 1.0.163", "serde_derive", "serde_json 1.0.96", + "serde_repr", "sha2", "shared_memory", "shutdown_hooks", diff --git a/Cargo.toml b/Cargo.toml index eed897e01..9c0834ee5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -43,6 +43,7 @@ hbb_common = { path = "libs/hbb_common" } serde_derive = "1.0" serde = "1.0" serde_json = "1.0" +serde_repr = "0.1" cfg-if = "1.0" lazy_static = "1.4" sha2 = "0.10" diff --git a/flutter/lib/common/widgets/login.dart b/flutter/lib/common/widgets/login.dart index c779cdba1..6e1fe11c6 100644 --- a/flutter/lib/common/widgets/login.dart +++ b/flutter/lib/common/widgets/login.dart @@ -95,11 +95,13 @@ class ConfigOP { class WidgetOP extends StatefulWidget { final ConfigOP config; final RxString curOP; + final RxBool autoLogin; final Function(String) cbLogin; const WidgetOP({ Key? key, required this.config, required this.curOP, + required this.autoLogin, required this.cbLogin, }) : super(key: key); @@ -188,7 +190,7 @@ class _WidgetOPState extends State { onTap: () async { _resetState(); widget.curOP.value = widget.config.op; - await bind.mainAccountAuth(op: widget.config.op); + await bind.mainAccountAuth(op: widget.config.op, rememberMe: widget.autoLogin.value); _beginQueryState(); }, ), @@ -254,12 +256,14 @@ class _WidgetOPState extends State { class LoginWidgetOP extends StatelessWidget { final List ops; final RxString curOP; + final RxBool autoLogin; final Function(String) cbLogin; LoginWidgetOP({ Key? key, required this.ops, required this.curOP, + required this.autoLogin, required this.cbLogin, }) : super(key: key); @@ -270,6 +274,7 @@ class LoginWidgetOP extends StatelessWidget { WidgetOP( config: op, curOP: curOP, + autoLogin: autoLogin, cbLogin: cbLogin, ), const Divider( @@ -500,6 +505,7 @@ Future loginDialog() async { ConfigOP(op: 'Okta', iconWidth: 38), ], curOP: curOP, + autoLogin: autoLogin, cbLogin: (String username) { gFFI.userModel.userName.value = username; close(true); diff --git a/src/flutter_ffi.rs b/src/flutter_ffi.rs index 78a2c0308..bf56c8d29 100644 --- a/src/flutter_ffi.rs +++ b/src/flutter_ffi.rs @@ -1359,10 +1359,10 @@ pub fn install_install_path() -> SyncReturn { SyncReturn(install_path()) } -pub fn main_account_auth(op: String) { +pub fn main_account_auth(op: String, remember_me: bool) { let id = get_id(); let uuid = get_uuid(); - account_auth(op, id, uuid); + account_auth(op, id, uuid, remember_me); } pub fn main_account_auth_cancel() { diff --git a/src/hbbs_http/account.rs b/src/hbbs_http/account.rs index de0c82bb9..95868e194 100644 --- a/src/hbbs_http/account.rs +++ b/src/hbbs_http/account.rs @@ -5,6 +5,7 @@ use hbb_common::{ }; use reqwest::blocking::Client; use serde_derive::{Deserialize, Serialize}; +use serde_repr::{Deserialize_repr, Serialize_repr}; use std::{ collections::HashMap, sync::{Arc, RwLock}, @@ -30,21 +31,80 @@ pub struct OidcAuthUrl { url: Url, } -#[derive(Default, Debug, Clone, Serialize, Deserialize)] +#[derive(Debug, Deserialize, Serialize, Default, Clone)] +pub struct DeviceInfo { + /// Linux , Windows , Android ... + #[serde(default)] + pub os: String, + + /// `browser` or `client` + #[serde(default)] + pub r#type: String, + + /// device name from rustdesk client, + /// browser info(name + version) from browser + #[serde(default)] + pub name: String, +} + +#[derive(Debug, Clone, Serialize, Deserialize, Default)] +pub struct WhitelistItem { + data: String, // ip / device uuid + info: DeviceInfo, + exp: u64, +} + +#[derive(Debug, Clone, Serialize, Deserialize, Default)] +pub struct UserInfo { + #[serde(default)] + pub settings: UserSettings, + #[serde(default)] + pub login_ip_whitelist: Vec, + #[serde(default)] + pub login_device_whitelist: Vec, + #[serde(default)] + pub other: HashMap, +} + +#[derive(Debug, Clone, Serialize, Deserialize, Default)] +pub struct UserSettings { + #[serde(default)] + pub email_verification: bool, + #[serde(default)] + pub email_alarm_notification: bool, +} + +#[derive(Debug, Clone, Copy, PartialEq, Serialize_repr, Deserialize_repr)] +#[repr(i64)] +pub enum UserStatus { + Disabled = 0, + Normal = 1, + Unverified = -1, +} + +#[derive(Debug, Clone, Copy, PartialEq, Serialize_repr, Deserialize_repr)] +#[repr(i64)] +pub enum UserRole { + Owner = 10, + Admin = 1, + Member = 0, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] pub struct UserPayload { - pub id: String, pub name: String, pub email: Option, pub note: Option, - pub status: Option, - pub grp: Option, - pub is_admin: Option, + pub status: UserStatus, + pub info: UserInfo, + pub role: UserRole, + pub is_admin: bool, } #[derive(Debug, Clone, Serialize, Deserialize)] pub struct AuthBody { pub access_token: String, - pub token_type: String, + pub r#type: String, pub user: UserPayload, } @@ -128,7 +188,7 @@ impl OidcSession { std::thread::sleep(std::time::Duration::from_secs_f32(secs)); } - fn auth_task(op: String, id: String, uuid: String) { + fn auth_task(op: String, id: String, uuid: String, remember_me: bool) { let auth_request_res = Self::auth(&op, &id, &uuid); log::info!("Request oidc auth result: {:?}", &auth_request_res); let code_url = match auth_request_res { @@ -167,14 +227,16 @@ impl OidcSession { while OIDC_SESSION.read().unwrap().keep_querying && begin.elapsed() < query_timeout { match Self::query(&code_url.code, &id, &uuid) { Ok(HbbHttpResponse::<_>::Data(auth_body)) => { - LocalConfig::set_option( - "access_token".to_owned(), - auth_body.access_token.clone(), - ); - LocalConfig::set_option( - "user_info".to_owned(), - serde_json::to_string(&auth_body.user).unwrap_or_default(), - ); + if remember_me { + LocalConfig::set_option( + "access_token".to_owned(), + auth_body.access_token.clone(), + ); + LocalConfig::set_option( + "user_info".to_owned(), + serde_json::to_string(&auth_body.user).unwrap_or_default(), + ); + } OIDC_SESSION .write() .unwrap() @@ -226,12 +288,12 @@ impl OidcSession { } } - pub fn account_auth(op: String, id: String, uuid: String) { + pub fn account_auth(op: String, id: String, uuid: String, remember_me: bool) { Self::auth_cancel(); Self::wait_stop_querying(); OIDC_SESSION.write().unwrap().before_task(); - std::thread::spawn(|| { - Self::auth_task(op, id, uuid); + std::thread::spawn(move || { + Self::auth_task(op, id, uuid, remember_me); OIDC_SESSION.write().unwrap().after_task(); }); } diff --git a/src/ui_interface.rs b/src/ui_interface.rs index d2496d4d3..8759f65e6 100644 --- a/src/ui_interface.rs +++ b/src/ui_interface.rs @@ -822,8 +822,8 @@ fn check_connect_status(reconnect: bool) -> mpsc::UnboundedSender { } #[cfg(feature = "flutter")] -pub fn account_auth(op: String, id: String, uuid: String) { - account::OidcSession::account_auth(op, id, uuid); +pub fn account_auth(op: String, id: String, uuid: String, remember_me: bool) { + account::OidcSession::account_auth(op, id, uuid, remember_me); } #[cfg(feature = "flutter")]