mirror of
https://github.com/YGGverse/Yoda.git
synced 2026-04-01 00:55:28 +00:00
178 lines
6.2 KiB
Rust
178 lines
6.2 KiB
Rust
mod widget;
|
|
use widget::{form::list::item::value::Value, Widget};
|
|
|
|
use crate::app::browser::window::Action;
|
|
use crate::profile::Profile;
|
|
use gtk::{
|
|
gio::{prelude::TlsCertificateExt, TlsCertificate},
|
|
glib::Uri,
|
|
prelude::IsA,
|
|
};
|
|
use std::rc::Rc;
|
|
|
|
const DATE_FORMAT: &str = "%Y.%m.%d";
|
|
|
|
pub struct Gemini {
|
|
// profile: Rc<Profile>,
|
|
widget: Rc<Widget>,
|
|
}
|
|
|
|
impl Gemini {
|
|
// Construct
|
|
|
|
/// Create new `Self` for given Profile
|
|
pub fn new(profile: Rc<Profile>, action: Rc<Action>, auth_uri: Uri) -> Self {
|
|
// Init widget
|
|
let widget = Rc::new(Widget::new(profile.clone()));
|
|
|
|
// Init shared URL string from URI
|
|
let url = auth_uri.to_string();
|
|
|
|
// Add guest option
|
|
widget.form.list.append(
|
|
Value::UseGuestSession,
|
|
"Guest session",
|
|
"No identity for this request",
|
|
false,
|
|
);
|
|
|
|
// Add new identity option
|
|
widget.form.list.append(
|
|
Value::GenerateNewAuth,
|
|
"Create new",
|
|
"Generate long-term certificate",
|
|
false,
|
|
);
|
|
|
|
// Add import existing identity option
|
|
widget.form.list.append(
|
|
Value::ImportPem,
|
|
"Import identity",
|
|
"Use existing certificate",
|
|
false,
|
|
);
|
|
|
|
// Collect identities as options from profile database
|
|
// * memory cache synced also and could be faster @TODO
|
|
match profile.identity.gemini.database.records() {
|
|
Ok(identities) => {
|
|
for identity in identities {
|
|
// Get certificate details
|
|
let certificate = match TlsCertificate::from_pem(&identity.pem) {
|
|
Ok(certificate) => certificate,
|
|
Err(reason) => todo!("{reason}"),
|
|
};
|
|
|
|
// Append record option
|
|
widget.form.list.append(
|
|
Value::ProfileIdentityGeminiId(identity.id),
|
|
&certificate.subject_name().unwrap().replace("CN=", ""), // trim prefix
|
|
&format!(
|
|
"{} - {} | auth: {}",
|
|
// certificate validity time
|
|
certificate
|
|
.not_valid_before()
|
|
.unwrap()
|
|
.format(DATE_FORMAT)
|
|
.unwrap(),
|
|
certificate
|
|
.not_valid_after()
|
|
.unwrap()
|
|
.format(DATE_FORMAT)
|
|
.unwrap(),
|
|
// count active certificate sessions
|
|
profile
|
|
.identity
|
|
.gemini
|
|
.auth
|
|
.database
|
|
.records_scope(None)
|
|
.unwrap()
|
|
.iter()
|
|
.filter(|this| this.profile_identity_gemini_id == identity.id)
|
|
.count(),
|
|
),
|
|
// is selected
|
|
profile
|
|
.identity
|
|
.gemini
|
|
.auth
|
|
.memory
|
|
.match_scope(&url)
|
|
.is_some_and(|auth| auth.profile_identity_gemini_id == identity.id),
|
|
);
|
|
}
|
|
}
|
|
Err(e) => todo!("{e}"),
|
|
}
|
|
|
|
// Init events
|
|
widget.on_apply({
|
|
let widget = widget.clone();
|
|
move |response| {
|
|
// Get option match user choice
|
|
let option = match response {
|
|
Value::ProfileIdentityGeminiId(value) => Some(value),
|
|
Value::UseGuestSession => None,
|
|
Value::GenerateNewAuth => Some(
|
|
match profile
|
|
.identity
|
|
.gemini
|
|
.make(None, &widget.form.name.value().unwrap())
|
|
{
|
|
Ok(profile_identity_gemini_id) => profile_identity_gemini_id,
|
|
Err(reason) => todo!("{}", reason.to_string()),
|
|
},
|
|
),
|
|
Value::ImportPem => Some(
|
|
match profile
|
|
.identity
|
|
.gemini
|
|
.add(&widget.form.file.pem.take().unwrap())
|
|
{
|
|
Ok(profile_identity_gemini_id) => profile_identity_gemini_id,
|
|
Err(reason) => todo!("{}", reason.to_string()),
|
|
},
|
|
),
|
|
};
|
|
|
|
// Apply auth
|
|
match option {
|
|
// Activate identity for `auth_uri`
|
|
Some(profile_identity_gemini_id) => {
|
|
if let Err(reason) = profile
|
|
.identity
|
|
.gemini
|
|
.auth
|
|
.apply(profile_identity_gemini_id, &url)
|
|
{
|
|
todo!("{}", reason.to_string())
|
|
};
|
|
}
|
|
// Remove all identity auths for `auth_uri`
|
|
None => {
|
|
if let Err(reason) = profile.identity.gemini.auth.remove_scope(&url) {
|
|
todo!("{}", reason.to_string())
|
|
};
|
|
}
|
|
}
|
|
|
|
// Reload page to apply changes
|
|
action.reload.activate();
|
|
}
|
|
});
|
|
|
|
// Return activated `Self`
|
|
Self {
|
|
// profile,
|
|
widget,
|
|
}
|
|
}
|
|
|
|
// Actions
|
|
|
|
/// Show dialog for parent [Widget](https://docs.gtk.org/gtk4/class.Widget.html)
|
|
pub fn present(&self, parent: Option<&impl IsA<gtk::Widget>>) {
|
|
self.widget.present(parent);
|
|
}
|
|
}
|