diff --git a/hardening/README.md b/hardening/README.md index c46015a1..09dda2d0 100644 --- a/hardening/README.md +++ b/hardening/README.md @@ -52,9 +52,7 @@ hardening/ ├── nixpaks/ # Nixpak application sandboxing │ ├── default.nix │ ├── firefox.nix -│ ├── firefox-desktop-item.nix │ ├── qq.nix -│ ├── qq-desktop-item.nix │ └── modules/ # Reusable nixpak modules │ ├── gui-base.nix │ └── network.nix diff --git a/hardening/nixpaks/default.nix b/hardening/nixpaks/default.nix index 409814ec..06ffd623 100644 --- a/hardening/nixpaks/default.nix +++ b/hardening/nixpaks/default.nix @@ -15,7 +15,7 @@ let (sloth.concat' sloth.homeDir mapdir) ]; }; - wrapper = _pkgs: path: (_pkgs.callPackage path callArgs).config.script; + wrapper = _pkgs: path: (_pkgs.callPackage path callArgs); in { # Add nixpaked Apps into nixpkgs, and reference them in home-manager or other nixos modules @@ -23,13 +23,10 @@ in (_: super: { nixpaks = { qq = wrapper pkgs-patched ./qq.nix; - qq-desktop-item = super.callPackage ./qq-desktop-item.nix { }; wechat = wrapper super ./wechat.nix; - wechat-desktop-item = super.callPackage ./wechat-desktop-item.nix { }; firefox = wrapper super ./firefox.nix; - firefox-desktop-item = super.callPackage ./firefox-desktop-item.nix { }; }; }) ]; diff --git a/hardening/nixpaks/firefox-desktop-item.nix b/hardening/nixpaks/firefox-desktop-item.nix deleted file mode 100644 index 720c1119..00000000 --- a/hardening/nixpaks/firefox-desktop-item.nix +++ /dev/null @@ -1,11 +0,0 @@ -{ makeDesktopItem }: -makeDesktopItem { - name = "firefox"; - desktopName = "firefox"; - exec = "firefox %U"; - terminal = false; - icon = "firefox"; - type = "Application"; - categories = [ "Network" ]; - comment = "firefox boxed"; -} diff --git a/hardening/nixpaks/firefox.nix b/hardening/nixpaks/firefox.nix index c94620b1..df0a3ea7 100644 --- a/hardening/nixpaks/firefox.nix +++ b/hardening/nixpaks/firefox.nix @@ -5,84 +5,136 @@ # - Firefox's flatpak manifest: https://hg.mozilla.org/mozilla-central/file/tip/taskcluster/docker/firefox-flatpak/runme.sh#l151 { lib, - pkgs, + firefox-wayland, mkNixPak, + buildEnv, + makeDesktopItem, ... }: -mkNixPak { - config = - { - config, - sloth, - ... - }: - { - app = { - package = pkgs.firefox-wayland; - binPath = "bin/firefox"; - }; - flatpak.appId = "org.mozilla.firefox"; - imports = [ - ./modules/gui-base.nix - ./modules/network.nix - ]; +let + appId = "org.mozilla.firefox"; + wrapped = mkNixPak { + config = + { + config, + sloth, + ... + }: + { + app = { + package = firefox-wayland; + binPath = "bin/firefox"; + }; + flatpak.appId = appId; - # list all dbus services: - # ls -al /run/current-system/sw/share/dbus-1/services/ - # ls -al /etc/profiles/per-user/ryan/share/dbus-1/services/ - dbus.policies = { - "org.mozilla.firefox.*" = "own"; # firefox - "org.mozilla.firefox_beta.*" = "own"; # firefox beta - "org.mpris.MediaPlayer2.firefox.*" = "own"; - "org.freedesktop.NetworkManager" = "talk"; - - "org.gnome.Shell.Screencast" = "talk"; - # System tray icon - "org.freedesktop.Notifications" = "talk"; - "org.kde.StatusNotifierWatcher" = "talk"; - # File Manager - "org.freedesktop.FileManager1" = "talk"; - # Uses legacy StatusNotifier implementation - "org.kde.*" = "own"; - }; - - bubblewrap = { - # To trace all the home files QQ accesses, you can use the following nushell command: - # just trace-access firefox - # See the Justfile in the root of this repository for more information. - bind.rw = [ - # given the read write permission to the following directories. - # NOTE: sloth.mkdir is used to create the directory if it does not exist! - (sloth.mkdir (sloth.concat' sloth.homeDir "/.mozilla")) - - sloth.xdgDocumentsDir - sloth.xdgDownloadDir - sloth.xdgMusicDir - sloth.xdgVideosDir - ]; - bind.ro = [ - "/sys/bus/pci" - [ - "${config.app.package}/lib/firefox" - "/app/etc/firefox" - ] - - # ================ for browserpass extension =============================== - "/etc/gnupg" - (sloth.concat' sloth.homeDir "/.gnupg") # gpg's config - (sloth.concat' sloth.homeDir "/.local/share/password-store") # my secrets - (sloth.concat' sloth.runtimeDir "/gnupg") # for access gpg-agent socket - - # Unsure - (sloth.concat' sloth.xdgConfigHome "/dconf") + imports = [ + ./modules/gui-base.nix + ./modules/network.nix + ./modules/common.nix ]; - sockets = { - x11 = false; - wayland = true; - pipewire = true; + # list all dbus services: + # ls -al /run/current-system/sw/share/dbus-1/services/ + # ls -al /etc/profiles/per-user/ryan/share/dbus-1/services/ + dbus.policies = { + "org.mozilla.firefox.*" = "own"; # firefox + "org.mozilla.firefox_beta.*" = "own"; # firefox beta + "org.mpris.MediaPlayer2.firefox.*" = "own"; + + "org.gnome.Shell.Screencast" = "talk"; + # System tray icon + "org.freedesktop.Notifications" = "talk"; + "org.kde.StatusNotifierWatcher" = "talk"; + }; + + bubblewrap = { + # To trace all the home files Firefox accesses, you can use the following nushell command: + # just trace-access firefox + # See the Justfile in the root of this repository for more information. + bind.rw = [ + # given the read write permission to the following directories. + # NOTE: sloth.mkdir is used to create the directory if it does not exist! + (sloth.mkdir (sloth.concat' sloth.homeDir "/.mozilla")) + + sloth.xdgDocumentsDir + sloth.xdgDownloadDir + sloth.xdgMusicDir + sloth.xdgVideosDir + ]; + bind.ro = [ + "/sys/bus/pci" + [ + "${config.app.package}/lib/firefox" + "/app/etc/firefox" + ] + + # ================ for browserpass extension =============================== + "/etc/gnupg" + (sloth.concat' sloth.homeDir "/.gnupg") # gpg's config + (sloth.concat' sloth.homeDir "/.local/share/password-store") # my secrets + (sloth.concat' sloth.runtimeDir "/gnupg") # for access gpg-agent socket + + # Unsure + (sloth.concat' sloth.xdgConfigHome "/dconf") + ]; + + sockets = { + x11 = false; + wayland = true; + pipewire = true; + }; }; }; - }; + }; + exePath = lib.getExe wrapped.config.script; +in +buildEnv { + inherit (wrapped.config.script) name meta passthru; + paths = [ + wrapped.config.script + (makeDesktopItem { + name = appId; + desktopName = "Firefox"; + genericName = "Firefox Boxed"; + comment = "Firefox Browser"; + exec = "${exePath} %U"; + icon = "firefox"; + startupNotify = true; + startupWMClass = "firefox"; + terminal = false; + type = "Application"; + categories = [ + "Network" + "WebBrowser" + ]; + mimeTypes = [ + "text/html" + "text/xml" + "application/xhtml+xml" + "application/vnd.mozilla.xul+xml" + "x-scheme-handler/http" + "x-scheme-handler/https" + ]; + + actions = { + new-private-window = { + name = "New Private Window"; + exec = "${exePath} --private-window %U"; + }; + new-window = { + name = "New Window"; + exec = "${exePath} --new-window %U"; + }; + profile-manager-window = { + name = "Profile Manager"; + exec = "${exePath} --ProfileManager"; + }; + }; + + extraConfig = { + X-Flatpak = appId; + }; + }) + ]; } diff --git a/hardening/nixpaks/modules/common.nix b/hardening/nixpaks/modules/common.nix new file mode 100644 index 00000000..3621480b --- /dev/null +++ b/hardening/nixpaks/modules/common.nix @@ -0,0 +1,236 @@ +{ + lib, + pkgs, + sloth, + config, + ... +}: +{ + config = { + dbus = + let + inherit (config.flatpak) appId; + in + { + policies = { + "${appId}" = "own"; + "${appId}.*" = "own"; + "org.freedesktop.DBus" = "talk"; + "org.gtk.vfs.*" = "talk"; + "org.gtk.vfs" = "talk"; + "ca.desrt.dconf" = "talk"; + "org.freedesktop.portal.*" = "talk"; + "org.a11y.Bus" = "talk"; + "org.freedesktop.appearance" = "talk"; + "org.freedesktop.appearance.*" = "talk"; + } + // (builtins.listToAttrs ( + map (id: lib.nameValuePair "org.kde.StatusNotifierItem-${toString id}-1" "own") ( + lib.lists.range 2 11 + ) + )) + // { + # --- MPRIS Media Control --- + # Allows the app to register as a media player. These are derived from the appID. + "org.mpris.MediaPlayer2.${appId}" = "own"; + "org.mpris.MediaPlayer2.${appId}.*" = "own"; + "org.mpris.MediaPlayer2.${lib.lists.last (lib.strings.splitString "." appId)}" = "own"; + "org.mpris.MediaPlayer2.${lib.lists.last (lib.strings.splitString "." appId)}.*" = "own"; + # Conditionally allows a custom, friendlier MPRIS name if 'mprisName' is set. + # "org.mpris.MediaPlayer2.${mprisName}" = "own"; + # "org.mpris.MediaPlayer2.${mprisName}.*" = "own"; + + # --- General Desktop Integration --- + "com.canonical.AppMenu.Registrar" = "talk"; # For Ubuntu AppMenu + "org.freedesktop.FileManager1" = "talk"; + "org.freedesktop.Notifications" = "talk"; + + # --- Accessibility (a11y) --- + "org.a11y.Bus" = "see"; + + # --- Portal Access --- + "org.freedesktop.portal.Documents" = "talk"; + "org.freedesktop.portal.FileTransfer" = "talk"; + "org.freedesktop.portal.FileTransfer.*" = "talk"; + "org.freedesktop.portal.Notification" = "talk"; + "org.freedesktop.portal.OpenURI" = "talk"; + "org.freedesktop.portal.OpenURI.OpenFile" = "talk"; + "org.freedesktop.portal.OpenURI.OpenURI" = "talk"; + "org.freedesktop.portal.Print" = "talk"; + "org.freedesktop.portal.Request" = "see"; + + # --- Input Method Portals --- + "org.freedesktop.portal.Fcitx" = "talk"; + "org.freedesktop.portal.Fcitx.*" = "talk"; + "org.freedesktop.portal.IBus" = "talk"; + "org.freedesktop.portal.IBus.*" = "talk"; + }; + rules = { + # 'call' rules permit specific method calls on D-Bus interfaces. + call = { + # --- Accessibility --- + "org.a11y.Bus" = [ + "org.a11y.Bus.GetAddress@/org/a11y/bus" + "org.freedesktop.DBus.Properties.Get@/org/a11y/bus" + ]; + + # --- General Portal Rules --- + "org.freedesktop.FileManager1" = [ "*" ]; + "org.freedesktop.Notifications.*" = [ "*" ]; + "org.freedesktop.portal.Documents" = [ "*" ]; + "org.freedesktop.portal.FileTransfer" = [ "*" ]; + "org.freedesktop.portal.FileTransfer.*" = [ "*" ]; + "org.freedesktop.portal.Fcitx" = [ "*" ]; + "org.freedesktop.portal.Fcitx.*" = [ "*" ]; + "org.freedesktop.portal.IBus" = [ "*" ]; + "org.freedesktop.portal.IBus.*" = [ "*" ]; + "org.freedesktop.portal.Notification" = [ "*" ]; + "org.freedesktop.portal.OpenURI" = [ "*" ]; + "org.freedesktop.portal.OpenURI.OpenFile" = [ "*" ]; + "org.freedesktop.portal.OpenURI.OpenURI" = [ "*" ]; + "org.freedesktop.portal.Print" = [ "*" ]; + "org.freedesktop.portal.Request" = [ "*" ]; + + # --- Main Desktop Portal Interface --- + # A comprehensive list of permissions for interacting with the desktop environment. + "org.freedesktop.portal.Desktop" = [ + # Device Access + "org.freedesktop.portal.Camera" + "org.freedesktop.portal.Camera.*" + "org.freedesktop.portal.Usb" + "org.freedesktop.portal.Usb.*" + + # File Chooser & Documents + "org.freedesktop.portal.Documents" + "org.freedesktop.portal.Documents.*" + "org.freedesktop.portal.FileChooser" + "org.freedesktop.portal.FileChooser.*" + "org.freedesktop.portal.FileTransfer" + "org.freedesktop.portal.FileTransfer.*" + + # Input Methods + "org.freedesktop.portal.Fcitx" + "org.freedesktop.portal.Fcitx.*" + "org.freedesktop.portal.IBus" + "org.freedesktop.portal.IBus.*" + + # Notifications & Printing + "org.freedesktop.portal.Notification" + "org.freedesktop.portal.Notification.*" + "org.freedesktop.portal.Print" + "org.freedesktop.portal.Print.*" + + # Open/Launch Handlers + "org.freedesktop.portal.Email.ComposeEmail" + "org.freedesktop.portal.OpenURI" + "org.freedesktop.portal.OpenURI.*" + + # Properties & Session Management + "org.freedesktop.DBus.Properties.GetAll" + "org.freedesktop.DBus.Properties.Get@/org/freedesktop/portal/desktop" + "org.freedesktop.portal.Session.Close" + + # Screen Capture & Sharing + "org.freedesktop.portal.RemoteDesktop" + "org.freedesktop.portal.RemoteDesktop.*" + "org.freedesktop.portal.ScreenCast" + "org.freedesktop.portal.ScreenCast.*" + "org.freedesktop.portal.Screenshot" + "org.freedesktop.portal.Screenshot.Screenshot" + + # Secrets (Keyring) + "org.freedesktop.portal.Secret" + "org.freedesktop.portal.Secret.RetrieveSecret" + + # Settings + "org.freedesktop.portal.Settings.Read" + "org.freedesktop.portal.Settings.ReadAll" + + # System Information + "org.freedesktop.portal.Account.GetUserInformation" + "org.freedesktop.portal.NetworkMonitor" + "org.freedesktop.portal.NetworkMonitor.*" + "org.freedesktop.portal.ProxyResolver.Lookup" + "org.freedesktop.portal.ProxyResolver.Lookup.*" + + # Generic Request Fallback + "org.freedesktop.portal.Request" + + # --- Conditional Portal Rules --- + # These would be enabled based on config flags in a real implementation. + + # Enabled if 'allowGlobalShortcuts = true' + "org.freedesktop.portal.GlobalShortcuts" + "org.freedesktop.portal.GlobalShortcuts.*" + + # Enabled if 'allowInhibit = true' + "org.freedesktop.portal.Inhibit" + "org.freedesktop.portal.Inhibit.*" + + # Enabled if 'XDG_CURRENT_DESKTOP = "GNOME"' + "org.freedesktop.portal.Location" + "org.freedesktop.portal.Location.*" + ]; + }; + + # 'broadcast' rules permit receiving signals from D-Bus names. + broadcast = { + "org.freedesktop.portal.*" = [ "@/org/freedesktop/portal/*" ]; + }; + }; + args = [ + "--filter" + "--sloppy-names" + "--log" + ]; + }; + + etc.sslCertificates.enable = true; + bubblewrap = { + network = lib.mkDefault true; + sockets = { + wayland = true; + pulse = true; + }; + + bind.rw = with sloth; [ + [ + (mkdir appDataDir) + xdgDataHome + ] + [ + (mkdir appConfigDir) + xdgConfigHome + ] + [ + (mkdir appCacheDir) + xdgCacheHome + ] + + (sloth.concat [ + sloth.runtimeDir + "/" + (sloth.envOr "WAYLAND_DISPLAY" "no") + ]) + (sloth.concat' sloth.runtimeDir "/at-spi/bus") + (sloth.concat' sloth.runtimeDir "/gvfsd") + (sloth.concat' sloth.runtimeDir "/dconf") + + (sloth.concat' sloth.xdgCacheHome "/fontconfig") + (sloth.concat' sloth.xdgCacheHome "/mesa_shader_cache") + (sloth.concat' sloth.xdgCacheHome "/mesa_shader_cache_db") + (sloth.concat' sloth.xdgCacheHome "/radv_builtin_shaders") + ]; + bind.ro = [ + (sloth.concat' sloth.runtimeDir "/doc") + (sloth.concat' sloth.xdgConfigHome "/kdeglobals") + (sloth.concat' sloth.xdgConfigHome "/gtk-2.0") + (sloth.concat' sloth.xdgConfigHome "/gtk-3.0") + (sloth.concat' sloth.xdgConfigHome "/gtk-4.0") + (sloth.concat' sloth.xdgConfigHome "/fontconfig") + (sloth.concat' sloth.xdgConfigHome "/dconf") + ]; + bind.dev = [ "/dev/shm" ] ++ (map (id: "/dev/video${toString id}") (lib.lists.range 0 9)); + }; + }; +} diff --git a/hardening/nixpaks/modules/gui-base.nix b/hardening/nixpaks/modules/gui-base.nix index b37c3418..c9868fcd 100644 --- a/hardening/nixpaks/modules/gui-base.nix +++ b/hardening/nixpaks/modules/gui-base.nix @@ -16,15 +16,7 @@ in config = { dbus.policies = { "${config.flatpak.appId}" = "own"; - "org.freedesktop.DBus" = "talk"; - "org.gtk.vfs.*" = "talk"; - "org.gtk.vfs" = "talk"; - "ca.desrt.dconf" = "talk"; - "org.a11y.Bus" = "talk"; - - # for default portal & gtk/hyprland's portal - "org.freedesktop.portal.*" = "talk"; - "org.freedesktop.impl.portal.desktop.*" = "talk"; + # we add other policies in ./common.nix }; # https://github.com/nixpak/nixpak/blob/master/modules/gpu.nix # 1. bind readonly - /run/opengl-driver diff --git a/hardening/nixpaks/qq-desktop-item.nix b/hardening/nixpaks/qq-desktop-item.nix deleted file mode 100644 index 96b88afe..00000000 --- a/hardening/nixpaks/qq-desktop-item.nix +++ /dev/null @@ -1,17 +0,0 @@ -{ - makeDesktopItem, - qq, -}: -makeDesktopItem { - name = "qq"; - desktopName = "QQ"; - exec = "qq %U"; - terminal = false; - # To find the icon name(nushell): - # let p = NIXPKGS_ALLOW_UNFREE=1 nix eval --impure nixpkgs#qq.outPath | str trim --char '"' - # tree $"($p)/share/icons" - icon = "${qq}/share/icons/hicolor/512x512/apps/qq.png"; - type = "Application"; - categories = [ "Network" ]; - comment = "QQ boxed"; -} diff --git a/hardening/nixpaks/qq.nix b/hardening/nixpaks/qq.nix index 8ca91cfc..77dc0be5 100644 --- a/hardening/nixpaks/qq.nix +++ b/hardening/nixpaks/qq.nix @@ -5,62 +5,96 @@ # - QQ's flatpak manifest: https://github.com/flathub/com.qq.QQ/blob/master/com.qq.QQ.yaml { lib, - pkgs, + qq, mkNixPak, + buildEnv, + makeDesktopItem, ... }: -mkNixPak { - config = - { sloth, ... }: - { - app = { - package = pkgs.qq; - binPath = "bin/qq"; - }; - flatpak.appId = "com.tencent.qq"; - imports = [ - ./modules/gui-base.nix - ./modules/network.nix - ]; +let + appId = "com.qq.QQ"; - # list all dbus services: - # ls -al /run/current-system/sw/share/dbus-1/services/ - # ls -al /etc/profiles/per-user/ryan/share/dbus-1/services/ - dbus.policies = { - "org.gnome.Shell.Screencast" = "talk"; - # System tray icon - "org.freedesktop.Notifications" = "talk"; - "org.kde.StatusNotifierWatcher" = "talk"; - # File Manager - "org.freedesktop.FileManager1" = "talk"; - # Uses legacy StatusNotifier implementation - "org.kde.*" = "own"; - }; - bubblewrap = { - # To trace all the home files QQ accesses, you can use the following nushell command: - # just trace-access qq - # See the Justfile in the root of this repository for more information. - bind.rw = [ - # given the read write permission to the following directories. - # NOTE: sloth.mkdir is used to create the directory if it does not exist! - (sloth.mkdir ( - sloth.concat [ - sloth.xdgConfigHome - "/QQ" - ] - )) + wrapped = mkNixPak { + config = + { sloth, ... }: + { + app = { + package = qq; + binPath = "bin/qq"; + }; + flatpak.appId = appId; - sloth.xdgDocumentsDir - sloth.xdgDownloadDir - sloth.xdgMusicDir - sloth.xdgVideosDir + imports = [ + ./modules/gui-base.nix + ./modules/network.nix + ./modules/common.nix ]; - sockets = { - x11 = false; - wayland = true; - pipewire = true; + + # list all dbus services: + # ls -al /run/current-system/sw/share/dbus-1/services/ + # ls -al /etc/profiles/per-user/ryan/share/dbus-1/services/ + dbus.policies = { + "org.gnome.Shell.Screencast" = "talk"; + # System tray icon + "org.freedesktop.Notifications" = "talk"; + "org.kde.StatusNotifierWatcher" = "talk"; + # File Manager + "org.freedesktop.FileManager1" = "talk"; + # Uses legacy StatusNotifier implementation + "org.kde.*" = "own"; + }; + bubblewrap = { + # To trace all the home files QQ accesses, you can use the following nushell command: + # just trace-access qq + # See the Justfile in the root of this repository for more information. + bind.rw = [ + # given the read write permission to the following directories. + # NOTE: sloth.mkdir is used to create the directory if it does not exist! + (sloth.mkdir ( + sloth.concat [ + sloth.xdgConfigHome + "/QQ" + ] + )) + + sloth.xdgDocumentsDir + sloth.xdgDownloadDir + sloth.xdgMusicDir + sloth.xdgVideosDir + ]; + sockets = { + x11 = false; + wayland = true; + pipewire = true; + }; }; }; - }; + }; + exePath = lib.getExe wrapped.config.script; +in +buildEnv { + inherit (wrapped.config.script) name meta passthru; + paths = [ + wrapped.config.script + (makeDesktopItem { + name = appId; + desktopName = "QQ"; + genericName = "QQ Boxed"; + comment = "Tencent QQ, also known as QQ, is an instant messaging software service and web portal developed by the Chinese technology company Tencent."; + exec = "${exePath} %U"; + startupNotify = true; + terminal = false; + icon = "${qq}/share/icons/hicolor/512x512/apps/qq.png"; + startupWMClass = "QQ"; + type = "Application"; + categories = [ + "InstantMessaging" + "Network" + ]; + extraConfig = { + X-Flatpak = appId; + }; + }) + ]; } diff --git a/home/linux/gui/base/misc.nix b/home/linux/gui/base/misc.nix index 3cfb43fb..2368fc63 100644 --- a/home/linux/gui/base/misc.nix +++ b/home/linux/gui/base/misc.nix @@ -20,7 +20,6 @@ # my custom hardened packages pkgs.nixpaks.qq - pkgs.nixpaks.qq-desktop-item # qqmusic pkgs.bwraps.wechat ]; diff --git a/home/linux/gui/base/wayland-apps.nix b/home/linux/gui/base/wayland-apps.nix index 4e30cb2d..16e8b82a 100644 --- a/home/linux/gui/base/wayland-apps.nix +++ b/home/linux/gui/base/wayland-apps.nix @@ -6,7 +6,6 @@ home.packages = with pkgs; [ # firefox-wayland nixpaks.firefox - nixpaks.firefox-desktop-item ]; programs = {