Browse Source

sidebar: Show a banner when there is a security issue

merge-requests/1461/merge
Kévin Commaille 2 years ago committed by Kévin Commaille
parent
commit
22c56c4e56
  1. 149
      src/session/view/sidebar/mod.rs
  2. 6
      src/session/view/sidebar/mod.ui

149
src/session/view/sidebar/mod.rs

@ -1,24 +1,25 @@
use adw::{prelude::*, subclass::prelude::*};
use gettextrs::gettext;
use gtk::{gio, glib, glib::clone, CompositeTemplate};
use tracing::error;
mod category_row;
mod icon_item_row;
mod room_row;
mod row;
mod verification_row;
use adw::{prelude::*, subclass::prelude::*};
use gettextrs::gettext;
use gtk::{gio, glib, glib::clone, CompositeTemplate};
use tracing::error;
use self::{
category_row::CategoryRow, icon_item_row::IconItemRow, room_row::RoomRow, row::Row,
verification_row::VerificationRow,
};
use super::{account_settings::AccountSettingsSubpage, AccountSettings};
use crate::{
account_switcher::AccountSwitcherButton,
components::OfflineBanner,
session::model::{
Category, CategoryType, IdentityVerification, Room, RoomType, Selection, SidebarIconItem,
SidebarListModel, User,
Category, CategoryType, CryptoIdentityState, IdentityVerification, RecoveryState, Room,
RoomType, Selection, SessionVerificationState, SidebarIconItem, SidebarListModel, User,
},
utils::expression,
};
@ -37,6 +38,8 @@ mod imp {
#[template(resource = "/org/gnome/Fractal/ui/session/view/sidebar/mod.ui")]
#[properties(wrapper_type = super::Sidebar)]
pub struct Sidebar {
#[template_child]
pub security_banner: TemplateChild<adw::Banner>,
#[template_child]
pub scrolled_window: TemplateChild<gtk::ScrolledWindow>,
#[template_child]
@ -66,6 +69,7 @@ mod imp {
pub list_model: glib::WeakRef<SidebarListModel>,
pub binding: RefCell<Option<glib::Binding>>,
pub expr_watch: RefCell<Option<gtk::ExpressionWatch>>,
session_handlers: RefCell<Vec<glib::SignalHandlerId>>,
}
#[glib::object_subclass]
@ -79,6 +83,8 @@ mod imp {
OfflineBanner::ensure_type();
Self::bind_template(klass);
Self::Type::bind_template_callbacks(klass);
klass.set_css_name("sidebar");
}
@ -146,6 +152,13 @@ mod imp {
if let Some(expr_watch) = self.expr_watch.take() {
expr_watch.unwatch();
}
if let Some(user) = self.user.take() {
let session = user.session();
for handler in self.session_handlers.take() {
session.disconnect(handler);
}
}
}
}
@ -160,7 +173,46 @@ mod imp {
return;
}
if let Some(user) = prev_user {
let session = user.session();
for handler in self.session_handlers.take() {
session.disconnect(handler);
}
}
if let Some(user) = &user {
let session = user.session();
let offline_handler =
session.connect_offline_notify(clone!(@weak self as imp => move |_| {
imp.update_security_banner();
}));
let crypto_identity_handler = session.connect_crypto_identity_state_notify(
clone!(@weak self as imp => move |_| {
imp.update_security_banner();
}),
);
let verification_handler = session.connect_verification_state_notify(
clone!(@weak self as imp => move |_| {
imp.update_security_banner();
}),
);
let recovery_handler =
session.connect_recovery_state_notify(clone!(@weak self as imp => move |_| {
imp.update_security_banner();
}));
self.session_handlers.replace(vec![
offline_handler,
crypto_identity_handler,
verification_handler,
recovery_handler,
]);
}
self.user.replace(user);
self.update_security_banner();
self.obj().notify_user();
}
@ -215,6 +267,61 @@ mod imp {
.map(Into::into)
.unwrap_or_default()
}
/// Update the security banner.
fn update_security_banner(&self) {
let Some(session) = self.user.borrow().as_ref().map(|u| u.session()) else {
return;
};
if session.offline() {
// Only show one banner at a time.
// The user will not be able to solve security issues while offline anyway.
self.security_banner.set_revealed(false);
return;
}
let crypto_identity_state = session.crypto_identity_state();
let verification_state = session.verification_state();
let recovery_state = session.recovery_state();
if crypto_identity_state == CryptoIdentityState::Unknown
|| verification_state == SessionVerificationState::Unknown
|| recovery_state == RecoveryState::Unknown
{
// Do not show the banner prematurely, unknown states should solve themselves.
self.security_banner.set_revealed(false);
return;
}
if verification_state == SessionVerificationState::Verified
&& recovery_state == RecoveryState::Enabled
{
// No need for the banner.
self.security_banner.set_revealed(false);
return;
}
let (title, button) = if crypto_identity_state == CryptoIdentityState::Missing {
(gettext("No crypto identity"), gettext("Enable"))
} else if verification_state == SessionVerificationState::Unverified {
(gettext("Crypto identity incomplete"), gettext("Verify"))
} else {
match recovery_state {
RecoveryState::Disabled => {
(gettext("Account recovery disabled"), gettext("Enable"))
}
RecoveryState::Incomplete => {
(gettext("Account recovery incomplete"), gettext("Recover"))
}
_ => unreachable!(),
}
};
self.security_banner.set_title(&title);
self.security_banner.set_button_label(Some(&button));
self.security_banner.set_revealed(true);
}
}
}
@ -223,6 +330,7 @@ glib::wrapper! {
@extends gtk::Widget, adw::NavigationPage, @implements gtk::Accessible;
}
#[gtk::template_callbacks]
impl Sidebar {
pub fn new() -> Self {
glib::Object::new()
@ -232,6 +340,33 @@ impl Sidebar {
self.imp().room_search.clone()
}
/// Open the proper security flow to fix the current issue.
#[template_callback]
fn fix_security_issue(&self) {
let Some(session) = self.user().map(|u| u.session()) else {
return;
};
let dialog = AccountSettings::new(&session);
// Show the security tab if the user uses the back button.
dialog.set_visible_page_name("security");
let crypto_identity_state = session.crypto_identity_state();
let verification_state = session.verification_state();
let subpage = if crypto_identity_state == CryptoIdentityState::Missing
|| verification_state == SessionVerificationState::Unverified
{
AccountSettingsSubpage::CryptoIdentitySetup
} else {
AccountSettingsSubpage::RecoverySetup
};
dialog.show_subpage(subpage);
dialog.present(self);
}
/// The type of the source that activated drop mode.
pub fn drop_source_type(&self) -> Option<RoomType> {
self.imp().drop_source_type.get()

6
src/session/view/sidebar/mod.ui

@ -127,6 +127,12 @@
</binding>
</object>
</child>
<child>
<object class="AdwBanner" id="security_banner">
<property name="revealed">False</property>
<signal name="button-clicked" handler="fix_security_issue" swapped="yes" />
</object>
</child>
<child>
<object class="GtkScrolledWindow" id="scrolled_window">
<property name="vexpand">True</property>

Loading…
Cancel
Save