open auth portal
This commit is contained in:
@@ -41,4 +41,5 @@ pub async fn initialize_session() {
|
||||
webview_window.open_devtools();
|
||||
|
||||
println!("Scene window initialized.");
|
||||
crate::core::services::auth::get_auth_code();
|
||||
}
|
||||
|
||||
@@ -1,8 +1,17 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use ts_rs::TS;
|
||||
|
||||
#[derive(Default, Serialize, Deserialize, Clone, Debug, TS)]
|
||||
#[ts(export)]
|
||||
pub struct AuthConfig {
|
||||
pub audience: String,
|
||||
pub auth_url: String,
|
||||
pub redirect_uri: String,
|
||||
}
|
||||
|
||||
#[derive(Default, Serialize, Deserialize, Clone, Debug, TS)]
|
||||
#[ts(export)]
|
||||
pub struct AppConfig {
|
||||
pub api_base_url: Option<String>,
|
||||
pub auth: AuthConfig,
|
||||
}
|
||||
|
||||
66
src-tauri/src/core/services/auth.rs
Normal file
66
src-tauri/src/core/services/auth.rs
Normal file
@@ -0,0 +1,66 @@
|
||||
use crate::{core::state::FDOLL, lock_r, APP_HANDLE};
|
||||
use base64::{engine::general_purpose::URL_SAFE_NO_PAD, Engine};
|
||||
use rand::{distr::Alphanumeric, Rng};
|
||||
use sha2::{Digest, Sha256};
|
||||
use tauri_plugin_opener::OpenerExt;
|
||||
|
||||
/// Generate a random code verifier (PKCE spec: 43 to 128 chars, here defaulting to 64)
|
||||
fn generate_code_verifier(length: usize) -> String {
|
||||
rand::rng()
|
||||
.sample_iter(&Alphanumeric)
|
||||
.take(length)
|
||||
.map(char::from)
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Generate code challenge from a code verifier
|
||||
fn generate_code_challenge(code_verifier: &str) -> String {
|
||||
let mut hasher = Sha256::new();
|
||||
hasher.update(code_verifier.as_bytes());
|
||||
let result = hasher.finalize();
|
||||
URL_SAFE_NO_PAD.encode(&result)
|
||||
}
|
||||
|
||||
/// Returns the auth pass object, including
|
||||
/// access token, refresh token, expire time etc.
|
||||
#[allow(dead_code)]
|
||||
pub fn get_tokens() {
|
||||
todo!();
|
||||
}
|
||||
|
||||
/// Opens the auth portal in the browser,
|
||||
/// and returns auth code after user logged in.
|
||||
pub fn get_auth_code() {
|
||||
let app_config = lock_r!(FDOLL)
|
||||
.app_config
|
||||
.clone()
|
||||
.expect("Invalid app config");
|
||||
|
||||
let opener = APP_HANDLE.get().unwrap().opener();
|
||||
|
||||
let code_verifier = generate_code_verifier(64);
|
||||
let code_challenge = generate_code_challenge(&code_verifier);
|
||||
let state = generate_code_verifier(16);
|
||||
|
||||
let mut url = url::Url::parse(&app_config.auth.auth_url.as_str()).expect("Invalid app config");
|
||||
url.query_pairs_mut()
|
||||
.append_pair("client_id", &app_config.auth.audience.as_str())
|
||||
.append_pair("response_type", "code")
|
||||
.append_pair("redirect_uri", &app_config.auth.redirect_uri.as_str())
|
||||
.append_pair("scope", "openid email profile")
|
||||
.append_pair("state", &state)
|
||||
.append_pair("code_challenge", &code_challenge)
|
||||
.append_pair("code_challenge_method", "S256");
|
||||
|
||||
match opener.open_url(url, None::<&str>) {
|
||||
Ok(_) => (),
|
||||
Err(e) => panic!("Failed to open auth portal: {}", e),
|
||||
}
|
||||
}
|
||||
|
||||
/// Accepts a refresh token and
|
||||
/// returns a new access token.
|
||||
#[allow(dead_code)]
|
||||
pub fn refresh_token() {
|
||||
todo!();
|
||||
}
|
||||
@@ -1 +1 @@
|
||||
|
||||
pub mod auth;
|
||||
|
||||
@@ -1,7 +1,13 @@
|
||||
// in app-core/src/state.rs
|
||||
use crate::{core::models::app_config::AppConfig, lock_w};
|
||||
use crate::{
|
||||
core::models::app_config::{AppConfig, AuthConfig},
|
||||
lock_w,
|
||||
};
|
||||
use reqwest::Client;
|
||||
use std::sync::{Arc, LazyLock, RwLock};
|
||||
use std::{
|
||||
env,
|
||||
sync::{Arc, LazyLock, RwLock},
|
||||
};
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct AppState {
|
||||
@@ -10,7 +16,6 @@ pub struct AppState {
|
||||
}
|
||||
|
||||
// Global application state
|
||||
// FDOLL = Multiplayer Todo App
|
||||
// Read / write this state via the `lock_r!` / `lock_w!` macros from `fdoll-core::utilities`
|
||||
pub static FDOLL: LazyLock<Arc<RwLock<AppState>>> =
|
||||
LazyLock::new(|| Arc::new(RwLock::new(AppState::default())));
|
||||
@@ -18,9 +23,18 @@ pub static FDOLL: LazyLock<Arc<RwLock<AppState>>> =
|
||||
pub fn init_fdoll_state() {
|
||||
{
|
||||
let mut guard = lock_w!(FDOLL);
|
||||
dotenvy::dotenv().ok();
|
||||
guard.app_config = Some(AppConfig {
|
||||
api_base_url: Some("http://sandbox:3000".to_string()),
|
||||
api_base_url: Some(env::var("API_BASE_URL").expect("API_BASE_URL must be set")),
|
||||
auth: AuthConfig {
|
||||
audience: env::var("JWT_AUDIENCE").expect("JWT_AUDIENCE must be set"),
|
||||
auth_url: env::var("AUTH_URL").expect("AUTH_URL must be set"),
|
||||
redirect_uri: env::var("REDIRECT_URI").expect("REDIRECT_URI must be set"),
|
||||
},
|
||||
});
|
||||
guard.http_client = reqwest::Client::new();
|
||||
guard.http_client = reqwest::ClientBuilder::new()
|
||||
.redirect(reqwest::redirect::Policy::none())
|
||||
.build()
|
||||
.expect("Client should build");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,6 +37,7 @@ pub fn run() {
|
||||
tauri::Builder::default()
|
||||
.plugin(tauri_plugin_opener::init())
|
||||
.plugin(tauri_plugin_positioner::init())
|
||||
.plugin(tauri_plugin_opener::init())
|
||||
.invoke_handler(tauri::generate_handler![channel_cursor_positions])
|
||||
.setup(|app| {
|
||||
APP_HANDLE
|
||||
|
||||
Reference in New Issue
Block a user