use dioxus::prelude::*;
use crate::encryption::key_export::KeyExportDialog;
use crate::encryption::qr_verification::QrVerificationDialog;
use crate::settings::account_deactivation::AccountDeactivationDialog;
use crate::state::app_state::AppState;
#[component]
pub fn SecuritySettings() -> Element {
let state = use_context::<Signal<AppState>>();
let mut show_key_export = use_signal(|| false);
let mut show_qr_verification = use_signal(|| false);
let mut show_deactivate = use_signal(|| false);
let mut cross_signing_status = use_signal(|| "Checking...".to_string());
let mut key_backup_status = use_signal(|| "Checking...".to_string());
let mut identity_trusted = use_signal(|| false);
let mut backup_active = use_signal(|| false);
let mut is_bootstrapping = use_signal(|| false);
let mut is_enabling_backup = use_signal(|| false);
let mut action_error = use_signal(|| Option::<String>::None);
let mut loaded = use_signal(|| false);
if !*loaded.read() {
loaded.set(true);
spawn(async move {
let client = { state.read().client.clone() };
if let Some(client) = client {
let encryption = client.encryption();
match encryption.cross_signing_status().await {
Some(status) => {
let has_master = status.has_master;
let has_self_signing = status.has_self_signing;
let has_user_signing = status.has_user_signing;
if has_master && has_self_signing && has_user_signing {
cross_signing_status.set("Active - all keys present".to_string());
identity_trusted.set(true);
} else {
let mut missing = vec![];
if !has_master { missing.push("master"); }
if !has_self_signing { missing.push("self-signing"); }
if !has_user_signing { missing.push("user-signing"); }
cross_signing_status.set(format!("Partially set up (missing: {})", missing.join(", ")));
}
}
None => {
cross_signing_status.set("Not set up".to_string());
}
}
match encryption.backups().state() {
matrix_sdk::encryption::backups::BackupState::Unknown => {
key_backup_status.set("Unknown".to_string());
}
matrix_sdk::encryption::backups::BackupState::Enabled => {
key_backup_status.set("Active".to_string());
backup_active.set(true);
}
matrix_sdk::encryption::backups::BackupState::Creating => {
key_backup_status.set("Creating...".to_string());
}
matrix_sdk::encryption::backups::BackupState::Resuming => {
key_backup_status.set("Resuming...".to_string());
}
matrix_sdk::encryption::backups::BackupState::Disabling => {
key_backup_status.set("Disabling...".to_string());
}
matrix_sdk::encryption::backups::BackupState::Downloading => {
key_backup_status.set("Downloading keys...".to_string());
}
_ => {
key_backup_status.set("Not set up".to_string());
}
}
}
});
}
rsx! {
div {
class: "security-settings",
h3 { "Security" }
div {
class: "settings-section",
h4 { "End-to-End Encryption" }
div {
class: "security-status",
span { class: "security-status__icon", "🔒" }
div {
class: "security-status__info",
span { class: "security-status__label", "Encryption enabled" }
span {
class: "security-status__description",
"Messages in encrypted rooms are secured with end-to-end encryption."
}
}
}
}
if let Some(ref err) = *action_error.read() {
div {
class: "settings-section",
style: "padding: 8px 12px; background: var(--error-bg, #3a1a1a); color: var(--error-text, #f44336); border-radius: 6px;",
"{err}"
}
}
div {
class: "settings-section",
h4 { "Cross-Signing" }
div {
class: "security-status",
span {
class: if *identity_trusted.read() { "security-status__icon security-status__icon--ok" } else { "security-status__icon" },
if *identity_trusted.read() { "✅" } else { "⚠️" }
}
div {
class: "security-status__info",
span { class: "security-status__label", "Status: {cross_signing_status}" }
span {
class: "security-status__description",
"Cross-signing allows you to verify your identity across all your devices."
}
}
}
if !*identity_trusted.read() {
button {
class: "settings-section__action-btn",
style: "margin-top: 8px; padding: 8px 16px; border: none; border-radius: 6px; background: var(--accent-color, #4a9eff); color: white; cursor: pointer;",
disabled: *is_bootstrapping.read(),
onclick: move |_| {
is_bootstrapping.set(true);
action_error.set(None);
spawn(async move {
let client = { state.read().client.clone() };
if let Some(client) = client {
match client.encryption().bootstrap_cross_signing(None).await {
Ok(_) => {
tracing::info!("Cross-signing bootstrapped successfully");
cross_signing_status.set("Active - all keys present".to_string());
identity_trusted.set(true);
}
Err(e) => {
tracing::error!("Failed to bootstrap cross-signing: {e}");
action_error.set(Some(format!("Failed to set up cross-signing: {e}")));
}
}
}
is_bootstrapping.set(false);
});
},
if *is_bootstrapping.read() { "Setting up..." } else { "Set Up Cross-Signing" }
}
}
button {
class: "settings-section__action-btn",
style: "margin-top: 8px; padding: 8px 16px; border: none; border-radius: 6px; background: var(--accent-color, #4a9eff); color: white; cursor: pointer;",
onclick: move |_| show_qr_verification.set(true),
"Verify This Device with QR"
}
}
if *show_qr_verification.read() {
QrVerificationDialog {
on_close: move |_| show_qr_verification.set(false),
}
}
div {
class: "settings-section",
h4 { "Cryptographic Key Export / Import" }
p {
class: "security-status__description",
"Export your end-to-end encryption keys for backup or import keys from another client."
}
button {
class: "settings-section__action-btn",
style: "margin-top: 8px; padding: 8px 16px; border: none; border-radius: 6px; background: var(--accent-color, #4a9eff); color: white; cursor: pointer;",
onclick: move |_| show_key_export.set(true),
"Export / Import Keys"
}
}
if *show_key_export.read() {
KeyExportDialog {
on_close: move |_| show_key_export.set(false),
}
}
div {
class: "settings-section",
h4 { "Key Backup" }
div {
class: "security-status",
span { class: "security-status__icon", "🔑" }
div {
class: "security-status__info",
span { class: "security-status__label", "Status: {key_backup_status}" }
span {
class: "security-status__description",
"Back up your encryption keys so you can restore them if you lose access to your devices."
}
}
}
if !*backup_active.read() {
button {
class: "settings-section__action-btn",
style: "margin-top: 8px; padding: 8px 16px; border: none; border-radius: 6px; background: var(--accent-color, #4a9eff); color: white; cursor: pointer;",
disabled: *is_enabling_backup.read(),
onclick: move |_| {
is_enabling_backup.set(true);
action_error.set(None);
spawn(async move {
let client = { state.read().client.clone() };
if let Some(client) = client {
match client.encryption().backups().create().await {
Ok(_) => {
tracing::info!("Key backup enabled");
key_backup_status.set("Active".to_string());
backup_active.set(true);
}
Err(e) => {
tracing::error!("Failed to enable key backup: {e}");
action_error.set(Some(format!("Failed to enable backup: {e}")));
}
}
}
is_enabling_backup.set(false);
});
},
if *is_enabling_backup.read() { "Enabling..." } else { "Enable Key Backup" }
}
}
}
div {
class: "settings-section settings-section--danger",
h4 { "Danger Zone" }
p {
class: "security-status__description",
"Deactivating your account is permanent and cannot be undone."
}
button {
class: "btn btn--danger",
onclick: move |_| show_deactivate.set(true),
"Deactivate Account"
}
}
if *show_deactivate.read() {
AccountDeactivationDialog {
on_close: move |_| show_deactivate.set(false),
}
}
}
}
}