at main 144 lines 4.8 kB view raw
1use crate::auth::AuthState; 2use crate::fetch::Fetcher; 3use dioxus::prelude::*; 4use jacquard::{ 5 IntoStatic, 6 cowstr::ToCowStr, 7 oauth::{error::OAuthError, types::CallbackParams}, 8 smol_str::SmolStr, 9}; 10use tracing::{error, info}; 11use weaver_api::sh_weaver::actor::profile::Profile as WeaverProfile; 12 13#[component] 14pub fn Callback( 15 state: ReadSignal<SmolStr>, 16 iss: ReadSignal<SmolStr>, 17 code: ReadSignal<SmolStr>, 18) -> Element { 19 let fetcher = use_context::<Fetcher>(); 20 let mut auth = use_context::<Signal<AuthState>>(); 21 #[cfg(feature = "web")] 22 let result = { 23 use_resource(move || { 24 let fetcher = fetcher.clone(); 25 let callback_params = CallbackParams { 26 code: code().to_cowstr(), 27 state: Some(state().to_cowstr()), 28 iss: Some(iss().to_cowstr()), 29 } 30 .into_static(); 31 info!("Auth Callback: {:?}", callback_params); 32 async move { 33 let session = fetcher 34 .client 35 .oauth_client 36 .callback(callback_params) 37 .await?; 38 let (did, session_id) = session.session_info().await; 39 let did_owned = did.into_static(); 40 auth.write() 41 .set_authenticated(did_owned.clone(), session_id); 42 fetcher.upgrade_to_authenticated(session).await; 43 44 // Create weaver profile if it doesn't exist 45 if let Err(e) = ensure_weaver_profile(&fetcher, &did_owned).await { 46 error!("Failed to ensure weaver profile: {:?}", e); 47 } 48 49 Ok::<(), OAuthError>(()) 50 } 51 }) 52 }; 53 #[cfg(not(feature = "web"))] 54 let result = { use_resource(move || async { Ok::<(), OAuthError>(()) }) }; 55 #[cfg(all(target_arch = "wasm32", target_os = "unknown"))] 56 let nav = use_navigator(); 57 58 match &*result.read_unchecked() { 59 Some(Ok(())) => { 60 #[cfg(all(target_arch = "wasm32", target_os = "unknown"))] 61 { 62 use gloo_storage::Storage; 63 let mut prev = gloo_storage::LocalStorage::get::<String>("cached_route").ok(); 64 if let Some(prev) = prev.take() { 65 tracing::info!("Navigating to previous page"); 66 67 gloo_storage::LocalStorage::delete("cached_route"); 68 nav.replace(prev); 69 } 70 } 71 rsx! { 72 div { 73 h1 { "Success" } 74 p { "You have successfully authenticated. You can close this browser window." } 75 } 76 } 77 } 78 Some(Err(err)) => { 79 error!("Auth Error: {}", err); 80 rsx! { 81 82 div { 83 h1 { "Error" } 84 p { "{err}" } 85 } 86 } 87 } 88 None => rsx! { 89 div { 90 h1 { "Loading..." } 91 } 92 }, 93 } 94} 95 96/// Ensures a weaver profile exists for the authenticated user. 97/// If no weaver profile exists, creates one by mirroring the bsky profile. 98#[cfg(feature = "web")] 99async fn ensure_weaver_profile( 100 fetcher: &Fetcher, 101 did: &jacquard::types::string::Did<'_>, 102) -> Result<(), Box<dyn std::error::Error + Send + Sync>> { 103 use jacquard::{ 104 client::AgentSessionExt, 105 types::string::{Datetime, RecordKey}, 106 }; 107 use weaver_api::app_bsky::actor::profile::Profile as BskyProfile; 108 109 let weaver_uri_str = format!("at://{}/sh.weaver.actor.profile/self", did); 110 let weaver_uri = WeaverProfile::uri(&weaver_uri_str)?; 111 112 // Check if weaver profile already exists 113 if fetcher.fetch_record(&weaver_uri).await.is_ok() { 114 info!("Weaver profile already exists for {}", did); 115 return Ok(()); 116 } 117 118 info!( 119 "No weaver profile found for {}, creating from bsky profile", 120 did 121 ); 122 123 // Fetch bsky profile 124 let bsky_uri_str = format!("at://{}/app.bsky.actor.profile/self", did); 125 let bsky_uri = BskyProfile::uri(&bsky_uri_str)?; 126 let bsky_record = fetcher.fetch_record(&bsky_uri).await?; 127 128 // Create weaver profile mirroring bsky 129 let weaver_profile = WeaverProfile::new() 130 .maybe_display_name(bsky_record.value.display_name.clone()) 131 .maybe_description(bsky_record.value.description.clone()) 132 .maybe_avatar(bsky_record.value.avatar.clone()) 133 .maybe_banner(bsky_record.value.banner.clone()) 134 .bluesky(true) 135 .created_at(Datetime::now()) 136 .build(); 137 138 let self_rkey = RecordKey::any("self").expect("self is valid record key"); 139 140 fetcher.put_record(self_rkey, weaver_profile).await?; 141 info!("Created weaver profile for {}", did); 142 143 Ok(()) 144}