feat: optimize nixpaks

This commit is contained in:
Ryan Yin
2025-09-18 23:43:13 +08:00
parent 0c6e5dc32e
commit 8b2b43d28a
10 changed files with 444 additions and 165 deletions

View File

@@ -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

View File

@@ -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 { };
};
})
];

View File

@@ -1,11 +0,0 @@
{ makeDesktopItem }:
makeDesktopItem {
name = "firefox";
desktopName = "firefox";
exec = "firefox %U";
terminal = false;
icon = "firefox";
type = "Application";
categories = [ "Network" ];
comment = "firefox boxed";
}

View File

@@ -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;
};
})
];
}

View File

@@ -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));
};
};
}

View File

@@ -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

View File

@@ -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";
}

View File

@@ -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;
};
})
];
}

View File

@@ -20,7 +20,6 @@
# my custom hardened packages
pkgs.nixpaks.qq
pkgs.nixpaks.qq-desktop-item
# qqmusic
pkgs.bwraps.wechat
];

View File

@@ -6,7 +6,6 @@
home.packages = with pkgs; [
# firefox-wayland
nixpaks.firefox
nixpaks.firefox-desktop-item
];
programs = {