make multi-protocol identity feature

This commit is contained in:
yggverse 2025-01-23 10:57:12 +02:00
parent 92550a2ccc
commit 12d79792d9
33 changed files with 309 additions and 593 deletions

View file

@ -164,7 +164,6 @@ fn handle(
.page
.profile
.identity
.gemini
.match_scope(&uri.to_string())
{
Some(identity) => match identity.to_tls_certificate() {

View file

@ -42,25 +42,20 @@ impl Gemini {
move |response| {
// Get option match user choice
let option = match response {
Value::ProfileIdentityGeminiId(value) => Some(value),
Value::ProfileIdentityId(value) => Some(value),
Value::GuestSession => None,
Value::GeneratePem => Some(
match profile
.identity
.gemini
.make(None, &widget.form.name.value().unwrap())
{
Ok(profile_identity_gemini_id) => profile_identity_gemini_id,
Ok(profile_identity_id) => profile_identity_id,
Err(e) => todo!("{}", e.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,
match profile.identity.add(&widget.form.file.pem.take().unwrap()) {
Ok(profile_identity_id) => profile_identity_id,
Err(e) => todo!("{}", e.to_string()),
},
),
@ -69,19 +64,15 @@ impl Gemini {
// Apply auth
match option {
// Activate identity for `auth_uri`
Some(profile_identity_gemini_id) => {
if let Err(e) = profile
.identity
.gemini
.auth
.apply(profile_identity_gemini_id, &auth_url)
Some(profile_identity_id) => {
if let Err(e) = profile.identity.auth.apply(profile_identity_id, &auth_url)
{
todo!("{}", e.to_string())
};
}
// Remove all identity auths for `auth_uri`
None => {
if let Err(e) = profile.identity.gemini.auth.remove_scope(&auth_url) {
if let Err(e) = profile.identity.auth.remove_scope(&auth_url) {
todo!("{}", e.to_string())
};
}

View file

@ -104,19 +104,16 @@ impl Form {
self.file.update(matches!(value, Value::ImportPem));
match value {
Value::ProfileIdentityGeminiId(profile_identity_gemini_id) => {
Value::ProfileIdentityId(profile_identity_id) => {
self.drop.update(true);
self.exit.update(
true,
self.profile
.identity
.gemini
.auth
.memory
.match_scope(&self.auth_uri.to_string())
.is_some_and(|auth| {
auth.profile_identity_gemini_id == profile_identity_gemini_id
}),
.is_some_and(|auth| auth.profile_identity_id == profile_identity_id),
);
self.save.update(true);
}

View file

@ -45,7 +45,7 @@ impl Drop {
let profile = profile.clone();
move |_| {
match list.selected().value_enum() {
Value::ProfileIdentityGeminiId(profile_identity_gemini_id) => {
Value::ProfileIdentityId(profile_identity_id) => {
// Init sub-widget
let alert_dialog = AlertDialog::builder()
.heading(HEADING)
@ -74,13 +74,9 @@ impl Drop {
let button = button.clone();
let list = list.clone();
let profile = profile.clone();
move |_, _| match profile
.identity
.gemini
.delete(profile_identity_gemini_id)
{
move |_, _| match profile.identity.delete(profile_identity_id) {
Ok(_) => {
if list.remove(profile_identity_gemini_id).is_some() {
if list.remove(profile_identity_id).is_some() {
button.set_css_classes(&["success"]);
button.set_label("Identity successfully deleted")
} else {

View file

@ -58,7 +58,7 @@ impl Exit {
move |_| {
// Get selected identity from holder
match list.selected().value_enum() {
Value::ProfileIdentityGeminiId(profile_identity_gemini_id) => {
Value::ProfileIdentityId(profile_identity_id) => {
// Init sub-widget
let alert_dialog = AlertDialog::builder()
.heading(HEADING)
@ -91,12 +91,7 @@ impl Exit {
let browser_action = browser_action.clone();
let widget_action = widget_action.clone();
move |_, _| {
match profile
.identity
.gemini
.auth
.remove_ref(profile_identity_gemini_id)
{
match profile.identity.auth.remove_ref(profile_identity_id) {
Ok(_) => match list
.selected()
.update(&profile, &auth_uri.to_string())

View file

@ -38,15 +38,12 @@ impl List {
list_store.append(&generate_pem);
list_store.append(&import_pem);
match profile.identity.gemini.database.records() {
match profile.identity.database.records() {
Ok(identities) => {
let mut is_guest_session = true;
for identity in identities {
match Item::new_profile_identity_gemini_id(
profile,
identity.id,
&auth_uri.to_string(),
) {
match Item::new_profile_identity_id(profile, identity.id, &auth_uri.to_string())
{
Ok(item) => {
if item.is_active() {
is_guest_session = false;
@ -178,18 +175,18 @@ impl List {
// Actions
/// Find list item by `profile_identity_gemini_id`
/// Find list item by `profile_identity_id`
/// * return `position` found
pub fn find(&self, profile_identity_gemini_id: i64) -> Option<u32> {
pub fn find(&self, profile_identity_id: i64) -> Option<u32> {
self.list_store.find_with_equal_func(|this| {
profile_identity_gemini_id == this.downcast_ref::<Item>().unwrap().value()
profile_identity_id == this.downcast_ref::<Item>().unwrap().value()
})
}
/// Remove list item by `profile_identity_gemini_id`
/// Remove list item by `profile_identity_id`
/// * return `position` of removed list item
pub fn remove(&self, profile_identity_gemini_id: i64) -> Option<u32> {
match self.find(profile_identity_gemini_id) {
pub fn remove(&self, profile_identity_id: i64) -> Option<u32> {
match self.find(profile_identity_id) {
Some(position) => {
self.list_store.remove(position);
Some(position)

View file

@ -21,7 +21,7 @@ glib::wrapper! {
}
// C-type property `value` conversion for `Item`
// * values > 0 reserved for `profile_identity_gemini_id`
// * values > 0 reserved for `profile_identity_id`
const G_VALUE_GENERATE_PEM: i64 = 0;
const G_VALUE_IMPORT_PEM: i64 = -1;
const G_VALUE_GUEST_SESSION: i64 = -2;
@ -53,42 +53,34 @@ impl Item {
.build()
}
pub fn new_profile_identity_gemini_id(
pub fn new_profile_identity_id(
profile: &Rc<Profile>,
profile_identity_gemini_id: i64,
profile_identity_id: i64,
auth_url: &str,
) -> Result<Self, Error> {
// Get PEM by ID
match profile
.identity
.gemini
.memory
.get(profile_identity_gemini_id)
{
match profile.identity.memory.get(profile_identity_id) {
// Extract certificate details from PEM string
Ok(ref pem) => match TlsCertificate::from_pem(pem) {
// Collect certificate scopes for item
Ok(ref certificate) => match scope(profile, profile_identity_gemini_id) {
Ok(ref certificate) => match scope(profile, profile_identity_id) {
// Ready to build `Item` GObject
Ok(ref scope) => Ok(Object::builder()
.property("value", profile_identity_gemini_id)
.property(
"title",
title::new_for_profile_identity_gemini_id(certificate),
)
.property("value", profile_identity_id)
.property("title", title::new_for_profile_identity_id(certificate))
.property(
"subtitle",
subtitle::new_for_profile_identity_gemini_id(certificate, scope),
subtitle::new_for_profile_identity_id(certificate, scope),
)
.property(
"tooltip",
tooltip::new_for_profile_identity_gemini_id(certificate, scope),
tooltip::new_for_profile_identity_id(certificate, scope),
)
.property(
"is-active",
is_active::new_for_profile_identity_gemini_id(
is_active::new_for_profile_identity_id(
profile,
profile_identity_gemini_id,
profile_identity_id,
auth_url,
),
)
@ -107,36 +99,31 @@ impl Item {
pub fn update(&self, profile: &Rc<Profile>, auth_url: &str) -> Result<(), Error> {
// Update item depending on value type
match self.value_enum() {
Value::ProfileIdentityGeminiId(profile_identity_gemini_id) => {
Value::ProfileIdentityId(profile_identity_id) => {
// Get PEM by ID
match profile
.identity
.gemini
.memory
.get(profile_identity_gemini_id)
{
match profile.identity.memory.get(profile_identity_id) {
// Extract certificate details from PEM string
Ok(ref pem) => match TlsCertificate::from_pem(pem) {
Ok(ref certificate) => {
// Get current scope
let scope = &scope(profile, profile_identity_gemini_id)?;
let scope = &scope(profile, profile_identity_id)?;
// Update properties
self.set_title(title::new_for_profile_identity_gemini_id(certificate));
self.set_title(title::new_for_profile_identity_id(certificate));
self.set_subtitle(subtitle::new_for_profile_identity_gemini_id(
self.set_subtitle(subtitle::new_for_profile_identity_id(
certificate,
scope,
));
self.set_tooltip(tooltip::new_for_profile_identity_gemini_id(
self.set_tooltip(tooltip::new_for_profile_identity_id(
certificate,
scope,
));
self.set_is_active(is_active::new_for_profile_identity_gemini_id(
self.set_is_active(is_active::new_for_profile_identity_id(
profile,
profile_identity_gemini_id,
profile_identity_id,
auth_url,
));
@ -162,21 +149,21 @@ impl Item {
G_VALUE_GENERATE_PEM => Value::GeneratePem,
G_VALUE_GUEST_SESSION => Value::GuestSession,
G_VALUE_IMPORT_PEM => Value::ImportPem,
value => Value::ProfileIdentityGeminiId(value),
value => Value::ProfileIdentityId(value),
}
}
}
// Tools
/// Collect certificate scope vector from `Profile` database for `profile_identity_gemini_id`
fn scope(profile: &Rc<Profile>, profile_identity_gemini_id: i64) -> Result<Vec<String>, Error> {
match profile.identity.gemini.auth.database.records_scope(None) {
/// Collect certificate scope vector from `Profile` database for `profile_identity_id`
fn scope(profile: &Rc<Profile>, profile_identity_id: i64) -> Result<Vec<String>, Error> {
match profile.identity.auth.database.records_scope(None) {
Ok(result) => {
let mut scope = Vec::new();
for auth in result
.iter()
.filter(|this| this.profile_identity_gemini_id == profile_identity_gemini_id)
.filter(|this| this.profile_identity_id == profile_identity_id)
{
scope.push(auth.scope.clone())
}

View file

@ -1,16 +1,15 @@
use crate::profile::Profile;
use std::rc::Rc;
pub fn new_for_profile_identity_gemini_id(
pub fn new_for_profile_identity_id(
profile: &Rc<Profile>,
profile_identity_gemini_id: i64,
profile_identity_id: i64,
auth_url: &str,
) -> bool {
profile
.identity
.gemini
.auth
.memory
.match_scope(auth_url)
.is_some_and(|auth| auth.profile_identity_gemini_id == profile_identity_gemini_id)
.is_some_and(|auth| auth.profile_identity_id == profile_identity_id)
}

View file

@ -2,10 +2,7 @@ use gtk::{gio::TlsCertificate, prelude::TlsCertificateExt};
const DATE_FORMAT: &str = "%Y.%m.%d";
pub fn new_for_profile_identity_gemini_id(
certificate: &TlsCertificate,
scope: &[String],
) -> String {
pub fn new_for_profile_identity_id(certificate: &TlsCertificate, scope: &[String]) -> String {
format!(
"{} - {} | scope: {}",
certificate

View file

@ -1,6 +1,6 @@
use gtk::{gio::TlsCertificate, glib::gformat, prelude::TlsCertificateExt};
pub fn new_for_profile_identity_gemini_id(certificate: &TlsCertificate) -> String {
pub fn new_for_profile_identity_id(certificate: &TlsCertificate) -> String {
certificate
.subject_name()
.unwrap_or(gformat!("Unknown"))

View file

@ -1,9 +1,6 @@
use gtk::{gio::TlsCertificate, prelude::TlsCertificateExt};
pub fn new_for_profile_identity_gemini_id(
certificate: &TlsCertificate,
scope: &[String],
) -> String {
pub fn new_for_profile_identity_id(certificate: &TlsCertificate, scope: &[String]) -> String {
let mut tooltip = "<b>Certificate</b>\n".to_string();
if let Some(subject_name) = certificate.subject_name() {

View file

@ -3,5 +3,5 @@ pub enum Value {
GeneratePem,
GuestSession,
ImportPem,
ProfileIdentityGeminiId(i64),
ProfileIdentityId(i64),
}

View file

@ -40,12 +40,12 @@ impl Save {
move |_| {
// Get selected identity from holder
match list.selected().value_enum() {
Value::ProfileIdentityGeminiId(profile_identity_gemini_id) => {
Value::ProfileIdentityId(profile_identity_id) => {
// Lock open button (prevent double click)
button.set_sensitive(false);
// Create PEM file based on option ID selected
match Certificate::new(profile.clone(), profile_identity_gemini_id) {
match Certificate::new(profile.clone(), profile_identity_id) {
Ok(certificate) => {
// Init file filters related with PEM extension
let filters = ListStore::new::<FileFilter>();

View file

@ -15,13 +15,8 @@ impl Certificate {
// Constructors
/// Create new `Self`
pub fn new(profile: Rc<Profile>, profile_identity_gemini_id: i64) -> Result<Self, Error> {
match profile
.identity
.gemini
.database
.record(profile_identity_gemini_id)
{
pub fn new(profile: Rc<Profile>, profile_identity_id: i64) -> Result<Self, Error> {
match profile.identity.database.record(profile_identity_id) {
Ok(record) => match record {
Some(identity) => match TlsCertificate::from_pem(&identity.pem) {
Ok(certificate) => Ok(Self {
@ -30,7 +25,7 @@ impl Certificate {
}),
Err(e) => Err(Error::TlsCertificate(e)),
},
None => Err(Error::NotFound(profile_identity_gemini_id)),
None => Err(Error::NotFound(profile_identity_id)),
},
Err(e) => Err(Error::Database(e)),
}

View file

@ -14,8 +14,8 @@ impl Display for Error {
Self::Database(e) => {
write!(f, "Database error: {e}")
}
Self::NotFound(profile_identity_gemini_id) => {
write!(f, "Record for `{profile_identity_gemini_id}` not found")
Self::NotFound(profile_identity_id) => {
write!(f, "Record for `{profile_identity_id}` not found")
}
Self::TlsCertificate(e) => {
write!(f, "TLS certificate error: {e}")

View file

@ -79,7 +79,6 @@ impl Navigation {
self.request.update(
self.profile
.identity
.gemini
.auth
.memory
.match_scope(&request)