// Privacy & Security. // // GNOME's Privacy panel covers screen lock, camera and microphone access, file // history, trash, and device security. Panama covers the parts it genuinely // owns and is explicit about the parts it does not. // // The file-history and trash settings are the notable omission, and the reason // is worth stating: those are GNOME preferences enforced by gsd-housekeeping, // which is not running in a Hyprland session. Offering switches for them would // store a preference, change nothing, and give no sign of it -- the exact // failure this codebase keeps designing against. So they are delegated by name // rather than reimplemented as controls that lie. import QtQuick import qs.config import qs.services SettingsPage { id: root title: "Privacy & Security" lede: DeviceSecurity.scanned && DeviceSecurity.attentionCount === 0 ? "Screen lock, device access, and a machine whose security settings all check out." : "Screen lock, which applications can see you, and how this machine is protected." Component.onCompleted: { if (!DeviceSecurity.scanned) DeviceSecurity.refresh(); if (!Keyring.scanned) Keyring.refresh(); } SettingsCard { title: "Screen lock" subtitle: "The same settings as Power & Lock, which is where the idle timings live." SliderRow { setting: "lockMinutes"; zeroLabel: "Never" } ToggleRow { setting: "lockOnSleep"; divider: false } } // The login keyring, which nothing else surfaces. // // It is unlocked at sign-in by PAM, so this card normally just confirms // that. It earns its place on the rare occasion it is not: a locked keyring // breaks saved passwords everywhere at once, and does it without ever // saying the word "keyring" -- you get a mail account that will not // authenticate and a git push that cannot find its key. SettingsCard { visible: Keyring.scanned title: "Saved passwords" subtitle: !Keyring.available ? "No secret service is answering, so saved passwords are unavailable." : Keyring.locked ? "The login keyring is locked. Saved passwords cannot be read until it is unlocked, and applications that need one will appear to fail for unrelated reasons." : "The login keyring is unlocked, as it is after every normal sign-in." // Two rows rather than one with a conditional button: a locked keyring // needs an action, an unlocked one is a statement of fact, and ActionRow // and TextRow already say exactly those two things. ActionRow { visible: Keyring.available && Keyring.locked label: "Login keyring" detail: "Unlock to restore access to stored passwords and keys" action: Keyring.unlocking ? "Waiting…" : "Unlock" enabled: !Keyring.unlocking divider: Keyring.replacementDaemon || Keyring.lastError !== "" onTriggered: Keyring.unlock() } TextRow { visible: !(Keyring.available && Keyring.locked) label: "Login keyring" detail: Keyring.available ? "Unlocked at sign-in by PAM, the same way GNOME does it" : "No secret service is answering on this session" value: Keyring.available ? "Unlocked" : "Unavailable" divider: Keyring.replacementDaemon || Keyring.lastError !== "" } // Only shown when it is true, because it is a diagnostic rather than a // setting: it means the daemon holding your secrets is not the one PAM // started, so whatever unlocked it will not survive a restart. SettingRow { visible: Keyring.replacementDaemon label: "Keyring service" detail: "The original keyring service was replaced during this session, usually after it crashed. Signing out and back in restores the one PAM unlocks." value: "Replaced" divider: Keyring.lastError !== "" } SettingRow { visible: Keyring.lastError !== "" label: "Keyring problem" detail: Keyring.lastError divider: false } } SettingsCard { title: "Camera & microphone" subtitle: PrivacyState.anyActive ? "In use right now — the bar shows an indicator whenever this is true." : "Nothing is using your camera or microphone." TextRow { label: "Camera" detail: PrivacyState.cameraActive ? "In use by " + (PrivacyState.cameraApp || "an application") : "Not in use" value: PrivacyState.cameraActive ? "Active" : "Idle" } TextRow { label: "Microphone" detail: PrivacyState.microphoneActive ? "In use by " + (PrivacyState.microphoneApp || "an application") : "Not in use" value: PrivacyState.microphoneActive ? "Active" : "Idle" } TextRow { label: "Screen sharing" detail: PrivacyState.screenSharingActive ? "Being shared by " + (PrivacyState.screenSharingApp || "an application") : "Not being shared" value: PrivacyState.screenSharingActive ? "Active" : "Idle" divider: false } } SettingsCard { title: "Device security" subtitle: DeviceSecurity.attentionCount === 0 ? "Everything below is in its recommended state." : DeviceSecurity.attentionCount + " item" + (DeviceSecurity.attentionCount === 1 ? "" : "s") + " below may deserve attention." Repeater { model: DeviceSecurity.facts TextRow { id: factRow required property var modelData required property int index label: factRow.modelData.label detail: factRow.modelData.detail value: factRow.modelData.value divider: factRow.index < DeviceSecurity.facts.length - 1 } } } SettingsCard { title: "Owned by Fedora" subtitle: "File history and trash retention are GNOME preferences, applied by a housekeeping service that does not run in a Hyprland session. They are not offered as switches here, because storing that preference would change nothing." ActionRow { label: "File history & trash" detail: "Opens GNOME Settings, which owns these" action: "Open privacy" divider: false onTriggered: SystemSettings.openGnomePanel("privacy") } } }