.
This commit is contained in:
parent
7529c0c5c4
commit
735aa76ea3
57 changed files with 3366 additions and 2482 deletions
|
|
@ -36,26 +36,38 @@ in
|
|||
systemd.user.services.antigravity2api = {
|
||||
Unit = {
|
||||
Description = "Antigravity API to OpenAI Proxy";
|
||||
After = [ "network.target" ];
|
||||
After = [ "network-online.target" ];
|
||||
Wants = [ "network-online.target" ];
|
||||
};
|
||||
|
||||
Service = {
|
||||
WorkingDirectory = workDir;
|
||||
ExecStartPre = pkgs.writeShellScript "antigravity2api-init" ''
|
||||
export PATH="${pkgs.coreutils}/bin:$PATH"
|
||||
export PATH="${pkgs.coreutils}/bin:${pkgs.iputils}/bin:$PATH"
|
||||
mkdir -p "${workDir}"
|
||||
|
||||
# Ensure network exists (Not needed for host network)
|
||||
# ${pkgs.podman}/bin/podman network create antigravity-net --ignore >/dev/null 2>&1 || true
|
||||
|
||||
# Wait for connectivity to 8.8.8.8 (Google DNS) used by the container
|
||||
echo "Waiting for internet connectivity..."
|
||||
until ping -c1 -W1 8.8.8.8 >/dev/null 2>&1; do
|
||||
sleep 2
|
||||
done
|
||||
echo "Connectivity check passed."
|
||||
|
||||
cat > "${workDir}/.env" <<EOF
|
||||
API_KEY=${cfg.credentials.apiKey}
|
||||
ADMIN_USERNAME=${cfg.credentials.username}
|
||||
ADMIN_PASSWORD=${cfg.credentials.password}
|
||||
SYSTEM_INSTRUCTION="你是聊天机器人,名字叫萌萌,如同名字这般,你的性格是软软糯糯萌萌哒的,专门为用户提供聊天和情绪价值,协助进行小说创作或者角色扮演"
|
||||
SYSTEM_INSTRUCTION=""
|
||||
OFFICIAL_SYSTEM_PROMPT="You are Antigravity, a powerful agentic AI coding assistant designed by the Google Deepmind team working on Advanced Agentic Coding.You are pair programming with a USER to solve their coding task. The task may require creating a new codebase, modifying or debugging an existing codebase, or simply answering a question.**Proactiveness**"
|
||||
EOF
|
||||
'';
|
||||
|
||||
ExecStart = ''
|
||||
${pkgs.podman}/bin/podman run --replace --rm --name antigravity2api \
|
||||
-p 127.0.0.1:8045:8045 \
|
||||
--network=host \
|
||||
-v ${workDir}/data:/app/data \
|
||||
-v ${workDir}/public/images:/app/public/images \
|
||||
-v ${workDir}/.env:/app/.env \
|
||||
|
|
|
|||
|
|
@ -70,6 +70,33 @@ in
|
|||
pkgs.lxqt.lxqt-policykit
|
||||
pkgs.libnotify
|
||||
pkgs.swww
|
||||
(pkgs.writeShellScriptBin "freeze-shot" ''
|
||||
# Capture the screen to a temp file
|
||||
file=$(mktemp --suffix=.png)
|
||||
${pkgs.grim}/bin/grim "$file"
|
||||
|
||||
# Open imv in fullscreen to simulate freeze
|
||||
# We run it in the background
|
||||
${pkgs.imv}/bin/imv -f "$file" &
|
||||
pid=$!
|
||||
|
||||
# Give imv a moment to open
|
||||
sleep 0.2
|
||||
|
||||
# Run slurp to select region
|
||||
geometry=$(${pkgs.slurp}/bin/slurp)
|
||||
|
||||
# Close the "frozen" overlay
|
||||
kill "$pid"
|
||||
|
||||
# If we got a selection, crop and copy
|
||||
if [ -n "$geometry" ]; then
|
||||
${pkgs.imagemagick}/bin/magick "$file" -crop "$geometry" - | ${pkgs.wl-clipboard}/bin/wl-copy
|
||||
fi
|
||||
|
||||
# Cleanup
|
||||
rm "$file"
|
||||
'')
|
||||
];
|
||||
|
||||
xdg.portal = {
|
||||
|
|
@ -234,7 +261,7 @@ in
|
|||
|
||||
Mod+Shift+E { spawn "bemoji" "-t"; }
|
||||
|
||||
Print { spawn "sh" "-c" "grim -g \"$(slurp)\" - | wl-copy"; }
|
||||
Print { spawn "freeze-shot"; }
|
||||
|
||||
// Browsers
|
||||
Mod+W { spawn "firefox"; }
|
||||
|
|
|
|||
|
|
@ -61,6 +61,29 @@ in
|
|||
mShadow = mocha.crust;
|
||||
};
|
||||
|
||||
plugins = {
|
||||
sources = [
|
||||
{
|
||||
enabled = true;
|
||||
name = "Official Noctalia Plugins";
|
||||
url = "https://github.com/noctalia-dev/noctalia-plugins";
|
||||
branch = "main"; # Explicitly set branch just in case
|
||||
}
|
||||
];
|
||||
states = {
|
||||
"assistant-panel" = {
|
||||
enabled = true;
|
||||
sourceUrl = "https://github.com/noctalia-dev/noctalia-plugins";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
pluginSettings = {
|
||||
"assistant-panel" = {
|
||||
service = "openai";
|
||||
};
|
||||
};
|
||||
|
||||
settings = {
|
||||
colorSchemes = {
|
||||
darkMode = true;
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ let
|
|||
glfw
|
||||
];
|
||||
|
||||
defaultJvmArgs = "-XX:+UnlockExperimentalVMOptions -XX:+UnlockDiagnosticVMOptions -XX:+AlwaysActAsServerClassMachine -XX:+AlwaysPreTouch -XX:+DisableExplicitGC -XX:+UseNUMA -XX:NmethodSweepActivity=1 -XX:ReservedCodeCacheSize=400M -XX:NonNMethodCodeHeapSize=12M -XX:ProfiledCodeHeapSize=194M -XX:NonProfiledCodeHeapSize=194M -XX:-DontCompileHugeMethods -XX:MaxNodeLimit=240000 -XX:NodeLimitFudgeFactor=8000 -XX:+UseVectorCmov -XX:+PerfDisableSharedMem -XX:+UseFastUnorderedTimeStamps -XX:+UseCriticalJavaThreadPriority -XX:ThreadPriorityPolicy=1 -XX:AllocatePrefetchStyle=3 -XX:+UseShenandoahGC -XX:ShenandoahGCMode=iu -XX:ShenandoahGuaranteedGCInterval=1000000 -XX:AllocatePrefetchStyle=1 -XX:ConcGCThreads=4";
|
||||
defaultJvmArgs = "-Djava.net.preferIPv4Stack=true -XX:+UnlockExperimentalVMOptions -XX:+UnlockDiagnosticVMOptions -XX:+AlwaysActAsServerClassMachine -XX:+AlwaysPreTouch -XX:+DisableExplicitGC -XX:+UseNUMA -XX:NmethodSweepActivity=1 -XX:ReservedCodeCacheSize=400M -XX:NonNMethodCodeHeapSize=12M -XX:ProfiledCodeHeapSize=194M -XX:NonProfiledCodeHeapSize=194M -XX:-DontCompileHugeMethods -XX:MaxNodeLimit=240000 -XX:NodeLimitFudgeFactor=8000 -XX:+UseVectorCmov -XX:+PerfDisableSharedMem -XX:+UseFastUnorderedTimeStamps -XX:+UseCriticalJavaThreadPriority -XX:ThreadPriorityPolicy=1 -XX:AllocatePrefetchStyle=3 -XX:+UseShenandoahGC -XX:ShenandoahGCMode=iu -XX:ShenandoahGuaranteedGCInterval=1000000 -XX:AllocatePrefetchStyle=1 -XX:ConcGCThreads=4";
|
||||
|
||||
in
|
||||
{
|
||||
|
|
@ -66,225 +66,230 @@ in
|
|||
|
||||
config = lib.mkIf cfg.enable {
|
||||
home.packages = [
|
||||
(bwrapperPkgs.mkBwrapper {
|
||||
app = {
|
||||
id = "org.prismlauncher.PrismLauncher";
|
||||
package = pkgs.prismlauncher.overrideAttrs (old: {
|
||||
pname = "prismlauncher";
|
||||
version = old.version or "9.1"; # Fallback or keep current if valid
|
||||
buildInputs = (old.buildInputs or [ ]) ++ [ pkgs.jemalloc ];
|
||||
(
|
||||
let
|
||||
sandboxed = bwrapperPkgs.mkBwrapper {
|
||||
app = {
|
||||
id = "org.prismlauncher.PrismLauncher";
|
||||
package = pkgs.prismlauncher.overrideAttrs (old: {
|
||||
pname = "prismlauncher";
|
||||
version = old.version or "9.1"; # Fallback or keep current if valid
|
||||
buildInputs = (old.buildInputs or [ ]) ++ [ pkgs.jemalloc ];
|
||||
|
||||
# Keep runtimeLibs in closure without injecting them into environment
|
||||
postInstall = (old.postInstall or "") + ''
|
||||
mkdir -p $out/share/prismlauncher-sandboxed
|
||||
echo "${lib.makeLibraryPath runtimeLibs}" > $out/share/prismlauncher-sandboxed/libs
|
||||
'';
|
||||
# Keep runtimeLibs in closure without injecting them into environment
|
||||
postInstall = (old.postInstall or "") + ''
|
||||
mkdir -p $out/share/prismlauncher-sandboxed
|
||||
echo "${lib.makeLibraryPath runtimeLibs}" > $out/share/prismlauncher-sandboxed/libs
|
||||
'';
|
||||
|
||||
qtWrapperArgs = (old.qtWrapperArgs or [ ]) ++ [
|
||||
"--set JEMALLOC_PATH ${pkgs.jemalloc}/lib/libjemalloc.so"
|
||||
"--prefix LD_PRELOAD : ${pkgs.jemalloc}/lib/libjemalloc.so"
|
||||
qtWrapperArgs = (old.qtWrapperArgs or [ ]) ++ [
|
||||
"--set JEMALLOC_PATH ${pkgs.jemalloc}/lib/libjemalloc.so"
|
||||
"--prefix LD_PRELOAD : ${pkgs.jemalloc}/lib/libjemalloc.so"
|
||||
];
|
||||
});
|
||||
|
||||
env = {
|
||||
# Propagate XDG_DATA_DIRS so themes/icons can be found
|
||||
BROWSER = "firefox";
|
||||
QT_QPA_PLATFORM = "xcb";
|
||||
GDK_BACKEND = "x11";
|
||||
NO_AT_BRIDGE = "1";
|
||||
QT_QPA_PLATFORMTHEME = "";
|
||||
QT_STYLE_OVERRIDE = "fusion";
|
||||
|
||||
# Sanitize Desktop Environment to prevent loading conflicting platform themes
|
||||
XDG_CURRENT_DESKTOP = "X-Generic";
|
||||
XDG_SESSION_TYPE = "x11";
|
||||
GTK_USE_PORTAL = "0";
|
||||
GTK_THEME = "Adwaita"; # Force a safe theme or empty?
|
||||
|
||||
# Unset potential conflict variables
|
||||
GTK_MODULES = "";
|
||||
GTK3_MODULES = "";
|
||||
};
|
||||
};
|
||||
|
||||
sockets.x11 = true;
|
||||
sockets.wayland = true;
|
||||
flatpak.enable = false;
|
||||
|
||||
fhsenv.opts = {
|
||||
unshareUser = true;
|
||||
unshareUts = false;
|
||||
unshareCgroup = false;
|
||||
unsharePid = false;
|
||||
unshareNet = false;
|
||||
unshareIpc = false;
|
||||
};
|
||||
|
||||
fhsenv.bwrap.baseArgs = lib.mkForce [
|
||||
"--new-session"
|
||||
"--proc /proc"
|
||||
"--dev /dev"
|
||||
"--dev-bind /dev/dri /dev/dri"
|
||||
"--tmpfs /home"
|
||||
"--tmpfs /tmp"
|
||||
"--tmpfs /run"
|
||||
"--dir /run/user"
|
||||
"--dir /run/user/${toString cfg.uid}"
|
||||
# Bind ro system paths commonly needed
|
||||
"--ro-bind-try /run/opengl-driver /run/opengl-driver"
|
||||
"--ro-bind-try /run/opengl-driver-32 /run/opengl-driver-32"
|
||||
"--dir /run/systemd/resolve"
|
||||
"--ro-bind-try /run/systemd/resolve /run/systemd/resolve"
|
||||
"--ro-bind /run/dbus /run/dbus"
|
||||
];
|
||||
});
|
||||
|
||||
env = {
|
||||
# Propagate XDG_DATA_DIRS so themes/icons can be found
|
||||
BROWSER = "firefox";
|
||||
QT_QPA_PLATFORM = "xcb";
|
||||
GDK_BACKEND = "x11";
|
||||
NO_AT_BRIDGE = "1";
|
||||
QT_QPA_PLATFORMTHEME = "";
|
||||
QT_STYLE_OVERRIDE = "fusion";
|
||||
|
||||
# Sanitize Desktop Environment to prevent loading conflicting platform themes
|
||||
XDG_CURRENT_DESKTOP = "X-Generic";
|
||||
XDG_SESSION_TYPE = "x11";
|
||||
GTK_USE_PORTAL = "0";
|
||||
GTK_THEME = "Adwaita"; # Force a safe theme or empty?
|
||||
|
||||
# Unset potential conflict variables
|
||||
GTK_MODULES = "";
|
||||
GTK3_MODULES = "";
|
||||
};
|
||||
};
|
||||
|
||||
sockets.x11 = true;
|
||||
sockets.wayland = true;
|
||||
flatpak.enable = false;
|
||||
|
||||
fhsenv.opts = {
|
||||
unshareUser = true;
|
||||
unshareUts = false;
|
||||
unshareCgroup = false;
|
||||
unsharePid = false;
|
||||
unshareNet = false;
|
||||
unshareIpc = false;
|
||||
};
|
||||
|
||||
fhsenv.bwrap.baseArgs = lib.mkForce [
|
||||
"--new-session"
|
||||
"--proc /proc"
|
||||
"--dev /dev"
|
||||
"--dev-bind /dev/dri /dev/dri"
|
||||
"--tmpfs /home"
|
||||
"--tmpfs /tmp"
|
||||
"--tmpfs /run"
|
||||
"--dir /run/user"
|
||||
"--dir /run/user/${toString cfg.uid}"
|
||||
# Bind ro system paths commonly needed
|
||||
"--ro-bind-try /run/opengl-driver /run/opengl-driver"
|
||||
"--ro-bind-try /run/opengl-driver-32 /run/opengl-driver-32"
|
||||
"--dir /run/systemd/resolve"
|
||||
"--ro-bind-try /run/systemd/resolve /run/systemd/resolve"
|
||||
"--ro-bind /run/dbus /run/dbus"
|
||||
];
|
||||
|
||||
mounts = {
|
||||
read = [
|
||||
"$HOME/.config/fontconfig"
|
||||
"$HOME/.local/share/fonts"
|
||||
"$HOME/.icons"
|
||||
"$HOME/.themes"
|
||||
"$HOME/.local/share/themes"
|
||||
"$HOME/.config/qt6ct"
|
||||
"$HOME/.config/Kvantum"
|
||||
"$HOME/.config/MangoHud"
|
||||
"$HOME/Downloads"
|
||||
];
|
||||
readWrite = [
|
||||
"$HOME/.local/share/PrismLauncher"
|
||||
"$HOME/.cache/PrismLauncher"
|
||||
];
|
||||
};
|
||||
|
||||
dbus.enable = false;
|
||||
|
||||
script.preCmds.stage2 =
|
||||
let
|
||||
glfwPath = "${cfg.glfwPackage}/lib/libglfw.so.3";
|
||||
|
||||
# We need to access the sandbox-utils.nix. Since it's in system modules,
|
||||
# we can't easily import it relative to here if it's not exported.
|
||||
# But the content was small, let's inline what we need or check if we can source it.
|
||||
# For now, I'll assume the dbus-proxy logic is needed.
|
||||
|
||||
# Reimplementing mkDbusProxyScript from sandbox-utils.nix inline to avoid path dependency
|
||||
mkDbusProxyScript =
|
||||
{ appId, proxyArgs }:
|
||||
let
|
||||
proxyArgsStr = lib.escapeShellArgs proxyArgs;
|
||||
appDir = "$XDG_RUNTIME_DIR/app/${appId}";
|
||||
proxySocket = "${appDir}/bus";
|
||||
in
|
||||
''
|
||||
mkdir -p "${appDir}"
|
||||
# Start xdg-dbus-proxy
|
||||
${pkgs.xdg-dbus-proxy}/bin/xdg-dbus-proxy \
|
||||
"$DBUS_SESSION_BUS_ADDRESS" "${proxySocket}" \
|
||||
${proxyArgsStr} &
|
||||
DBUS_PROXY_PID=$!
|
||||
|
||||
# Kill proxy on exit
|
||||
trap "kill $DBUS_PROXY_PID" EXIT
|
||||
|
||||
# Wait for socket to be created
|
||||
for i in {1..50}; do
|
||||
if [ -S "${proxySocket}" ]; then
|
||||
break
|
||||
fi
|
||||
if ! kill -0 $DBUS_PROXY_PID 2>/dev/null; then
|
||||
echo "xdg-dbus-proxy died unexpectedly"
|
||||
exit 1
|
||||
fi
|
||||
sleep 0.1
|
||||
done
|
||||
'';
|
||||
|
||||
dbusScript = mkDbusProxyScript {
|
||||
appId = "org.prismlauncher.PrismLauncher";
|
||||
proxyArgs = [
|
||||
"--filter"
|
||||
"--talk=org.freedesktop.portal.*"
|
||||
"--call=org.freedesktop.portal.*=*@/org/freedesktop/portal/desktop"
|
||||
"--talk=org.freedesktop.Notifications"
|
||||
"--own=org.prismlauncher.PrismLauncher"
|
||||
"--own=org.prismlauncher.PrismLauncher.*"
|
||||
mounts = {
|
||||
read = [
|
||||
"$HOME/.config/fontconfig"
|
||||
"$HOME/.local/share/fonts"
|
||||
"$HOME/.icons"
|
||||
"$HOME/.themes"
|
||||
"$HOME/.local/share/themes"
|
||||
"$HOME/.config/qt6ct"
|
||||
"$HOME/.config/Kvantum"
|
||||
"$HOME/.config/MangoHud"
|
||||
"$HOME/Downloads"
|
||||
];
|
||||
readWrite = [
|
||||
"$HOME/.local/share/PrismLauncher"
|
||||
"$HOME/.cache/PrismLauncher"
|
||||
];
|
||||
};
|
||||
in
|
||||
''
|
||||
${dbusScript}
|
||||
|
||||
# Sanitize Environment
|
||||
unset QT_QPA_PLATFORMTHEME
|
||||
unset GTK_THEME
|
||||
unset XDG_CURRENT_DESKTOP
|
||||
export QT_QPA_PLATFORM=xcb
|
||||
export GDK_BACKEND=x11
|
||||
export NO_AT_BRIDGE=1
|
||||
dbus.enable = false;
|
||||
|
||||
# Force Configs (JVM Args + GLFW)
|
||||
cfg="$HOME/.local/share/PrismLauncher/prismlauncher.cfg"
|
||||
if [ -f "$cfg" ]; then
|
||||
# JVM Args
|
||||
if ${pkgs.gnugrep}/bin/grep -q "^JvmArgs=" "$cfg"; then
|
||||
${pkgs.gnused}/bin/sed -i "s|^JvmArgs=.*|JvmArgs=${cfg.jvmArgs}|" "$cfg"
|
||||
else
|
||||
if ${pkgs.gnugrep}/bin/grep -q "^\\[General\\]" "$cfg"; then
|
||||
${pkgs.gnused}/bin/sed -i "/^\\[General\\]/a JvmArgs=${cfg.jvmArgs}" "$cfg"
|
||||
else
|
||||
echo "JvmArgs=${cfg.jvmArgs}" >> "$cfg"
|
||||
fi
|
||||
fi
|
||||
script.preCmds.stage2 =
|
||||
let
|
||||
glfwPath = "${cfg.glfwPackage}/lib/libglfw.so.3";
|
||||
|
||||
# GLFW Settings
|
||||
# 1. CustomGLFWPath
|
||||
if ${pkgs.gnugrep}/bin/grep -q "^CustomGLFWPath=" "$cfg"; then
|
||||
${pkgs.gnused}/bin/sed -i "s|^CustomGLFWPath=.*|CustomGLFWPath=${glfwPath}|" "$cfg"
|
||||
else
|
||||
echo "CustomGLFWPath=${glfwPath}" >> "$cfg"
|
||||
fi
|
||||
# We need to access the sandbox-utils.nix. Since it's in system modules,
|
||||
# we can't easily import it relative to here if it's not exported.
|
||||
# But the content was small, let's inline what we need or check if we can source it.
|
||||
# For now, I'll assume the dbus-proxy logic is needed.
|
||||
|
||||
# 2. UseNativeGLFW
|
||||
if ${pkgs.gnugrep}/bin/grep -q "^UseNativeGLFW=" "$cfg"; then
|
||||
${pkgs.gnused}/bin/sed -i "s|^UseNativeGLFW=.*|UseNativeGLFW=true|" "$cfg"
|
||||
else
|
||||
echo "UseNativeGLFW=true" >> "$cfg"
|
||||
fi
|
||||
fi
|
||||
'';
|
||||
# Reimplementing mkDbusProxyScript from sandbox-utils.nix inline to avoid path dependency
|
||||
mkDbusProxyScript =
|
||||
{ appId, proxyArgs }:
|
||||
let
|
||||
proxyArgsStr = lib.escapeShellArgs proxyArgs;
|
||||
appDir = "$XDG_RUNTIME_DIR/app/${appId}";
|
||||
proxySocket = "${appDir}/bus";
|
||||
in
|
||||
''
|
||||
mkdir -p "${appDir}"
|
||||
# Start xdg-dbus-proxy
|
||||
${pkgs.xdg-dbus-proxy}/bin/xdg-dbus-proxy \
|
||||
"$DBUS_SESSION_BUS_ADDRESS" "${proxySocket}" \
|
||||
${proxyArgsStr} &
|
||||
DBUS_PROXY_PID=$!
|
||||
|
||||
fhsenv.bwrap.additionalArgs = [
|
||||
# D-Bus proxy
|
||||
''--bind "$XDG_RUNTIME_DIR/bus" "$XDG_RUNTIME_DIR/bus"''
|
||||
# Note: The original code bound a specific path TO ./bus.
|
||||
# "''--bind "$XDG_RUNTIME_DIR/app/org.prismlauncher.PrismLauncher/bus" "$XDG_RUNTIME_DIR/bus"''"
|
||||
# But mkDbusProxyScript (if standard) creates a socket.
|
||||
# The logic in prismlauncher-sandboxed.nix imported sandbox-utils.nix.
|
||||
# I'll try to match the original bind logic if possible.
|
||||
# Kill proxy on exit
|
||||
trap "kill $DBUS_PROXY_PID" EXIT
|
||||
|
||||
# The original code had:
|
||||
# ''--bind "$XDG_RUNTIME_DIR/app/org.prismlauncher.PrismLauncher/bus" "$XDG_RUNTIME_DIR/bus"''
|
||||
# But my inline mkDbusProxyScript sets up "$XDG_RUNTIME_DIR/bus" as the listen socket *inside* the script execution?
|
||||
# Wait, xdg-dbus-proxy runs inside the outer unshared namespace or outside?
|
||||
# In mkBwrapper, preCmds run *inside* the bwrap?
|
||||
# No, typically preCmds run before the final exec?
|
||||
# Actually, looking at nix-bwrapper, `preCmds.stage2` runs *inside* the sandbox?
|
||||
# Wait for socket to be created
|
||||
for i in {1..50}; do
|
||||
if [ -S "${proxySocket}" ]; then
|
||||
break
|
||||
fi
|
||||
if ! kill -0 $DBUS_PROXY_PID 2>/dev/null; then
|
||||
echo "xdg-dbus-proxy died unexpectedly"
|
||||
exit 1
|
||||
fi
|
||||
sleep 0.1
|
||||
done
|
||||
'';
|
||||
|
||||
# Let's start with the binds exactly as they were, assuming `sandbox-utils` logic.
|
||||
# If I can't import sandbox-utils, I have to rely on what I can see.
|
||||
# The original `sandbox-utils.nix` likely set up the proxy.
|
||||
# I will copy the binds from the original file.
|
||||
dbusScript = mkDbusProxyScript {
|
||||
appId = "org.prismlauncher.PrismLauncher";
|
||||
proxyArgs = [
|
||||
"--filter"
|
||||
"--talk=org.freedesktop.portal.*"
|
||||
"--call=org.freedesktop.portal.*=*@/org/freedesktop/portal/desktop"
|
||||
"--talk=org.freedesktop.Notifications"
|
||||
"--own=org.prismlauncher.PrismLauncher"
|
||||
"--own=org.prismlauncher.PrismLauncher.*"
|
||||
];
|
||||
};
|
||||
in
|
||||
''
|
||||
${dbusScript}
|
||||
|
||||
''--bind "$XDG_RUNTIME_DIR/app/org.prismlauncher.PrismLauncher/bus" "$XDG_RUNTIME_DIR/bus"''
|
||||
# Sanitize Environment
|
||||
unset QT_QPA_PLATFORMTHEME
|
||||
unset GTK_THEME
|
||||
unset XDG_CURRENT_DESKTOP
|
||||
export QT_QPA_PLATFORM=xcb
|
||||
export GDK_BACKEND=x11
|
||||
export NO_AT_BRIDGE=1
|
||||
|
||||
# Wayland socket
|
||||
''--bind "$XDG_RUNTIME_DIR/$WAYLAND_DISPLAY" "$XDG_RUNTIME_DIR/$WAYLAND_DISPLAY"''
|
||||
# Force Configs (JVM Args + GLFW)
|
||||
cfg="$HOME/.local/share/PrismLauncher/prismlauncher.cfg"
|
||||
if [ -f "$cfg" ]; then
|
||||
# JVM Args
|
||||
if ${pkgs.gnugrep}/bin/grep -q "^JvmArgs=" "$cfg"; then
|
||||
${pkgs.gnused}/bin/sed -i "s|^JvmArgs=.*|JvmArgs=${cfg.jvmArgs}|" "$cfg"
|
||||
else
|
||||
if ${pkgs.gnugrep}/bin/grep -q "^\\[General\\]" "$cfg"; then
|
||||
${pkgs.gnused}/bin/sed -i "/^\\[General\\]/a JvmArgs=${cfg.jvmArgs}" "$cfg"
|
||||
else
|
||||
echo "JvmArgs=${cfg.jvmArgs}" >> "$cfg"
|
||||
fi
|
||||
fi
|
||||
|
||||
# PipeWire + Pulse
|
||||
''--bind "$XDG_RUNTIME_DIR/pipewire-0" "$XDG_RUNTIME_DIR/pipewire-0"''
|
||||
''--bind "$XDG_RUNTIME_DIR/pulse" "$XDG_RUNTIME_DIR/pulse"''
|
||||
];
|
||||
})
|
||||
# GLFW Settings
|
||||
# 1. CustomGLFWPath
|
||||
if ${pkgs.gnugrep}/bin/grep -q "^CustomGLFWPath=" "$cfg"; then
|
||||
${pkgs.gnused}/bin/sed -i "s|^CustomGLFWPath=.*|CustomGLFWPath=${glfwPath}|" "$cfg"
|
||||
else
|
||||
echo "CustomGLFWPath=${glfwPath}" >> "$cfg"
|
||||
fi
|
||||
|
||||
# 2. UseNativeGLFW
|
||||
if ${pkgs.gnugrep}/bin/grep -q "^UseNativeGLFW=" "$cfg"; then
|
||||
${pkgs.gnused}/bin/sed -i "s|^UseNativeGLFW=.*|UseNativeGLFW=true|" "$cfg"
|
||||
else
|
||||
echo "UseNativeGLFW=true" >> "$cfg"
|
||||
fi
|
||||
fi
|
||||
'';
|
||||
|
||||
fhsenv.bwrap.additionalArgs = [
|
||||
# D-Bus proxy
|
||||
''--bind "$XDG_RUNTIME_DIR/bus" "$XDG_RUNTIME_DIR/bus"''
|
||||
# Note: The original code bound a specific path TO ./bus.
|
||||
# "''--bind "$XDG_RUNTIME_DIR/app/org.prismlauncher.PrismLauncher/bus" "$XDG_RUNTIME_DIR/bus"''"
|
||||
# But mkDbusProxyScript (if standard) creates a socket.
|
||||
# The logic in prismlauncher-sandboxed.nix imported sandbox-utils.nix.
|
||||
# I'll try to match the original bind logic if possible.
|
||||
|
||||
# The original code had:
|
||||
# ''--bind "$XDG_RUNTIME_DIR/app/org.prismlauncher.PrismLauncher/bus" "$XDG_RUNTIME_DIR/bus"''
|
||||
# But my inline mkDbusProxyScript sets up "$XDG_RUNTIME_DIR/bus" as the listen socket *inside* the script execution?
|
||||
# Wait, xdg-dbus-proxy runs inside the outer unshared namespace or outside?
|
||||
# In mkBwrapper, preCmds run *inside* the bwrap?
|
||||
# No, typically preCmds run before the final exec?
|
||||
# Actually, looking at nix-bwrapper, `preCmds.stage2` runs *inside* the sandbox?
|
||||
|
||||
# Let's start with the binds exactly as they were, assuming `sandbox-utils` logic.
|
||||
# If I can't import sandbox-utils, I have to rely on what I can see.
|
||||
# The original `sandbox-utils.nix` likely set up the proxy.
|
||||
# I will copy the binds from the original file.
|
||||
|
||||
''--bind "$XDG_RUNTIME_DIR/app/org.prismlauncher.PrismLauncher/bus" "$XDG_RUNTIME_DIR/bus"''
|
||||
|
||||
# Wayland socket
|
||||
''--bind "$XDG_RUNTIME_DIR/$WAYLAND_DISPLAY" "$XDG_RUNTIME_DIR/$WAYLAND_DISPLAY"''
|
||||
|
||||
# PipeWire + Pulse
|
||||
''--bind "$XDG_RUNTIME_DIR/pipewire-0" "$XDG_RUNTIME_DIR/pipewire-0"''
|
||||
''--bind "$XDG_RUNTIME_DIR/pulse" "$XDG_RUNTIME_DIR/pulse"''
|
||||
];
|
||||
};
|
||||
in
|
||||
sandboxed
|
||||
)
|
||||
];
|
||||
};
|
||||
}
|
||||
|
|
|
|||
81
modules/nixos/auto-update.nix
Normal file
81
modules/nixos/auto-update.nix
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
# Automatic Updates Module
|
||||
# Provides:
|
||||
# 1. Weekly Nix flake updates for the system configuration
|
||||
# 2. Daily NixOS system upgrades via system.autoUpgrade
|
||||
# 3. Daily Podman container updates for services with 'io.containers.autoupdate' label
|
||||
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
|
||||
let
|
||||
cfg = config.myModules.autoUpdate;
|
||||
repoPath = "/home/ashie/nixos";
|
||||
in
|
||||
{
|
||||
options.myModules.autoUpdate = {
|
||||
enable = lib.mkEnableOption "system-wide automatic updates";
|
||||
};
|
||||
|
||||
config = lib.mkIf cfg.enable {
|
||||
# 1. NixOS System Upgrades
|
||||
system.autoUpgrade = {
|
||||
enable = true;
|
||||
dates = "04:30";
|
||||
flake = "${repoPath}#nixos";
|
||||
allowReboot = false;
|
||||
flags = [
|
||||
"--refresh"
|
||||
];
|
||||
};
|
||||
|
||||
# 2. Flake Update Service (Runs before autoUpgrade)
|
||||
# This ensures the local flake.lock is updated so autoUpgrade has new versions to pull.
|
||||
systemd.services.nix-flake-update = {
|
||||
description = "Update Nix Flake Lockfile";
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
User = "root";
|
||||
};
|
||||
path = [ pkgs.nix pkgs.git pkgs.openssh ];
|
||||
script = ''
|
||||
cd ${repoPath}
|
||||
# Only update if it's a git repo and we have permissions
|
||||
if [ -d .git ]; then
|
||||
nix flake update --commit-lock-file
|
||||
else
|
||||
nix flake update
|
||||
fi
|
||||
'';
|
||||
startAt = "04:00"; # Run 30 mins before autoUpgrade
|
||||
};
|
||||
|
||||
# 3. Podman Container Auto-Updates
|
||||
# Runs 'podman auto-update' to refresh containers with the 'io.containers.autoupdate' label.
|
||||
systemd.services.podman-auto-update = {
|
||||
description = "Podman Container Auto-Update";
|
||||
after = [ "network-online.target" "nixos-upgrade.service" ];
|
||||
wants = [ "network-online.target" ];
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
ExecStart = "${pkgs.podman}/bin/podman auto-update";
|
||||
ExecStartPost = "${pkgs.podman}/bin/podman image prune -f";
|
||||
};
|
||||
};
|
||||
|
||||
systemd.timers.podman-auto-update = {
|
||||
description = "Podman Container Auto-Update Timer";
|
||||
timerConfig = {
|
||||
OnCalendar = "05:00";
|
||||
Persistent = true;
|
||||
};
|
||||
wantedBy = [ "timers.target" ];
|
||||
};
|
||||
|
||||
# Ensure the auto-upgrade service waits for the flake update
|
||||
systemd.services.nixos-upgrade.after = [ "nix-flake-update.service" ];
|
||||
};
|
||||
}
|
||||
|
|
@ -1,13 +1,14 @@
|
|||
{
|
||||
config,
|
||||
{ config,
|
||||
lib,
|
||||
pkgs,
|
||||
inputs,
|
||||
...
|
||||
...
|
||||
}:
|
||||
|
||||
let
|
||||
let
|
||||
cfg = config.myModules.azaharSandboxed;
|
||||
bwrapperPkgs = pkgs.extend inputs.nix-bwrapper.overlays.default;
|
||||
sandboxUtils = import ./sandbox-utils.nix { inherit pkgs lib; };
|
||||
|
||||
pname = "azahar";
|
||||
version = "2123.4";
|
||||
|
|
@ -35,58 +36,68 @@ let
|
|||
};
|
||||
in
|
||||
{
|
||||
nixpkgs.overlays = [
|
||||
(final: prev: {
|
||||
azahar-sandboxed = bwrapperPkgs.mkBwrapper {
|
||||
app = {
|
||||
package = azahar;
|
||||
id = "org.azahar_emu.Azahar";
|
||||
env = {
|
||||
QT_QPA_PLATFORM = "wayland;xcb";
|
||||
XDG_CURRENT_DESKTOP = "KDE";
|
||||
options.myModules.azaharSandboxed = {
|
||||
enable = lib.mkEnableOption "sandboxed Azahar with nix-bwrapper";
|
||||
|
||||
extraBindMounts = lib.mkOption {
|
||||
type = lib.types.listOf lib.types.str;
|
||||
default = [];
|
||||
description = "Extra paths to bind mount (read-write) into the sandbox";
|
||||
};
|
||||
};
|
||||
|
||||
config = lib.mkIf cfg.enable {
|
||||
nixpkgs.overlays = [
|
||||
(final: prev: {
|
||||
azahar-sandboxed = bwrapperPkgs.mkBwrapper {
|
||||
app = {
|
||||
package = azahar;
|
||||
id = "org.azahar_emu.Azahar";
|
||||
env = {
|
||||
QT_QPA_PLATFORM = "wayland;xcb";
|
||||
XDG_CURRENT_DESKTOP = "KDE";
|
||||
};
|
||||
};
|
||||
|
||||
flatpak.enable = false;
|
||||
|
||||
fhsenv.bwrap.baseArgs = lib.mkForce (sandboxUtils.mkCommonBindArgs { inherit config lib; } ++ sandboxUtils.mkGamingBindArgs { });
|
||||
|
||||
fhsenv.bwrap.additionalArgs = sandboxUtils.mkGuiBindArgs { } ++ [
|
||||
# D-Bus session proxy only
|
||||
''--bind "$XDG_RUNTIME_DIR/app/org.azahar_emu.Azahar/bus" "$XDG_RUNTIME_DIR/bus"''
|
||||
];
|
||||
|
||||
mounts = {
|
||||
read = sandboxUtils.mkGuiMounts.read;
|
||||
readWrite = [
|
||||
"$HOME/Games/3DS"
|
||||
"$HOME/.config/azahar"
|
||||
"$HOME/.local/share/azahar"
|
||||
] ++ cfg.extraBindMounts;
|
||||
};
|
||||
|
||||
dbus.enable = false;
|
||||
script.preCmds.stage2 = sandboxUtils.mkDbusProxyScript {
|
||||
appId = "org.azahar_emu.Azahar";
|
||||
enableSystemBus = false;
|
||||
proxyArgs = [
|
||||
"--filter"
|
||||
''--talk="org.freedesktop.Flatpak"''
|
||||
''--talk="org.kde.StatusNotifierWatcher"''
|
||||
''--talk="org.kde.KWin"''
|
||||
''--talk="org.gnome.Mutter.DisplayConfig"''
|
||||
''--talk="org.freedesktop.ScreenSaver"''
|
||||
''--talk="org.freedesktop.portal.Desktop"''
|
||||
''--talk="org.freedesktop.portal.OpenURI"''
|
||||
''--talk="org.freedesktop.secrets"''
|
||||
''--call="org.freedesktop.portal.*=*@/org/freedesktop/portal/desktop"''
|
||||
];
|
||||
};
|
||||
};
|
||||
})
|
||||
];
|
||||
|
||||
flatpak.enable = false;
|
||||
fhsenv.bwrap.additionalArgs = [
|
||||
"--dir /run/systemd/resolve"
|
||||
"--ro-bind-try /run/systemd/resolve /run/systemd/resolve"
|
||||
''--bind "$XDG_RUNTIME_DIR/app/org.azahar_emu.Azahar/bus" "$XDG_RUNTIME_DIR/bus"''
|
||||
];
|
||||
|
||||
mounts = {
|
||||
read = [
|
||||
"$HOME/.config/kdedefaults"
|
||||
"$HOME/.local/share/color-schemes"
|
||||
"$HOME/.config/fontconfig"
|
||||
"$HOME/.icons"
|
||||
"$HOME/.config/MangoHud"
|
||||
];
|
||||
readWrite = [
|
||||
"$HOME/Games/3DS"
|
||||
"$HOME/.config/azahar"
|
||||
"$HOME/.local/share/azahar"
|
||||
];
|
||||
};
|
||||
|
||||
dbus.enable = false;
|
||||
script.preCmds.stage2 = (import ./sandbox-utils.nix { inherit pkgs lib; }).mkDbusProxyScript {
|
||||
appId = "org.azahar_emu.Azahar";
|
||||
enableSystemBus = false;
|
||||
proxyArgs = [
|
||||
"--filter"
|
||||
''--talk="org.freedesktop.Flatpak"''
|
||||
''--talk="org.kde.StatusNotifierWatcher"''
|
||||
''--talk="org.kde.KWin"''
|
||||
''--talk="org.gnome.Mutter.DisplayConfig"''
|
||||
''--talk="org.freedesktop.ScreenSaver"''
|
||||
''--talk="org.freedesktop.portal.Desktop"''
|
||||
''--talk="org.freedesktop.portal.OpenURI"''
|
||||
''--talk="org.freedesktop.secrets"''
|
||||
''--call="org.freedesktop.portal.*=*@/org/freedesktop/portal/desktop"''
|
||||
];
|
||||
};
|
||||
};
|
||||
})
|
||||
];
|
||||
environment.systemPackages = [ pkgs.azahar-sandboxed ];
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,9 @@
|
|||
}:
|
||||
|
||||
let
|
||||
cfg = config.myModules.braveSandboxed;
|
||||
bwrapperPkgs = pkgs.extend inputs.nix-bwrapper.overlays.default;
|
||||
sandboxUtils = import ./sandbox-utils.nix { inherit pkgs lib; };
|
||||
|
||||
# create a custom settings.ini to force dark mode
|
||||
darkSettingsIni = pkgs.writeText "settings.ini" ''
|
||||
|
|
@ -31,138 +33,150 @@ let
|
|||
);
|
||||
in
|
||||
{
|
||||
nixpkgs.overlays = [
|
||||
(final: prev: {
|
||||
brave-sandboxed = bwrapperPkgs.mkBwrapper {
|
||||
app = {
|
||||
package = pkgs.symlinkJoin {
|
||||
name = "brave-single-desktop";
|
||||
paths = [ prev.brave ];
|
||||
inherit (prev.brave) pname version meta;
|
||||
postBuild = ''
|
||||
rm $out/share/applications/com.brave.Browser.desktop
|
||||
'';
|
||||
options.myModules.braveSandboxed = {
|
||||
enable = lib.mkEnableOption "sandboxed Brave with nix-bwrapper";
|
||||
|
||||
extraBindMounts = lib.mkOption {
|
||||
type = lib.types.listOf lib.types.str;
|
||||
default = [];
|
||||
description = "Extra paths to bind mount (read-write) into the sandbox";
|
||||
};
|
||||
};
|
||||
|
||||
config = lib.mkIf cfg.enable {
|
||||
nixpkgs.overlays = [
|
||||
(final: prev: {
|
||||
brave-sandboxed = bwrapperPkgs.mkBwrapper {
|
||||
app = {
|
||||
package = pkgs.symlinkJoin {
|
||||
name = "brave-single-desktop";
|
||||
paths = [ prev.brave ];
|
||||
inherit (prev.brave) pname version meta;
|
||||
postBuild = ''
|
||||
rm $out/share/applications/com.brave.Browser.desktop
|
||||
'';
|
||||
};
|
||||
# id = "brave-browser"; # Omit app.id to avoid potential bind errors (like Firefox)
|
||||
env = {
|
||||
# Propagate XDG_DATA_DIRS so GTK can find themes in user profile/system
|
||||
XDG_DATA_DIRS = "$XDG_DATA_DIRS";
|
||||
GTK_THEME = "catppuccin-mocha-mauve-standard";
|
||||
HYPRCURSOR_THEME = "Future-Cyan-Hyprcursor_Theme";
|
||||
HYPRCURSOR_SIZE = "32";
|
||||
# Force ozone/wayland usage for Brave/Chromium
|
||||
NIXOS_OZONE_WL = "1";
|
||||
};
|
||||
};
|
||||
# id = "brave-browser"; # Omit app.id to avoid potential bind errors (like Firefox)
|
||||
env = {
|
||||
# Propagate XDG_DATA_DIRS so GTK can find themes in user profile/system
|
||||
XDG_DATA_DIRS = "$XDG_DATA_DIRS";
|
||||
GTK_THEME = "catppuccin-mocha-mauve-standard";
|
||||
HYPRCURSOR_THEME = "Future-Cyan-Hyprcursor_Theme";
|
||||
HYPRCURSOR_SIZE = "32";
|
||||
# Force ozone/wayland usage for Brave/Chromium
|
||||
NIXOS_OZONE_WL = "1";
|
||||
|
||||
flatpak.enable = false;
|
||||
sockets.x11 = false;
|
||||
sockets.wayland = true;
|
||||
fhsenv.opts = {
|
||||
unshareUser = true;
|
||||
unshareUts = false;
|
||||
unshareCgroup = false;
|
||||
unsharePid = false;
|
||||
unshareNet = false;
|
||||
unshareIpc = false;
|
||||
};
|
||||
};
|
||||
|
||||
flatpak.enable = false;
|
||||
sockets.x11 = false;
|
||||
sockets.wayland = true;
|
||||
fhsenv.opts = {
|
||||
unshareUser = true;
|
||||
unshareUts = false;
|
||||
unshareCgroup = false;
|
||||
unsharePid = false;
|
||||
unshareNet = false;
|
||||
unshareIpc = false;
|
||||
};
|
||||
fhsenv.bwrap.baseArgs = lib.mkForce [
|
||||
"--new-session"
|
||||
"--proc /proc"
|
||||
"--dev /dev"
|
||||
"--dev-bind /dev/dri /dev/dri"
|
||||
"--tmpfs /home"
|
||||
"--tmpfs /mnt"
|
||||
"--tmpfs /run"
|
||||
"--ro-bind-try /run/current-system /run/current-system"
|
||||
"--ro-bind-try /run/booted-system /run/booted-system"
|
||||
"--ro-bind-try /run/opengl-driver /run/opengl-driver"
|
||||
"--ro-bind-try /run/opengl-driver-32 /run/opengl-driver-32"
|
||||
# Brave flags
|
||||
"--setenv NIXOS_OZONE_WL \"1\""
|
||||
"--setenv NOTIFY_IGNORE_PORTAL 1"
|
||||
# Bind policies for Theme
|
||||
"--dir /etc/brave/policies/managed"
|
||||
"--ro-bind ${bravePolicies} /etc/brave/policies/managed/policies.json"
|
||||
# Fallback paths for Chromium/Chrome base
|
||||
"--dir /etc/chromium/policies/managed"
|
||||
"--ro-bind ${bravePolicies} /etc/chromium/policies/managed/policies.json"
|
||||
"--dir /etc/opt/chrome/policies/managed"
|
||||
"--ro-bind ${bravePolicies} /etc/opt/chrome/policies/managed/policies.json"
|
||||
];
|
||||
|
||||
fhsenv.bwrap.baseArgs = lib.mkForce [
|
||||
"--new-session"
|
||||
"--proc /proc"
|
||||
"--dev /dev"
|
||||
"--dev-bind /dev/dri /dev/dri"
|
||||
"--tmpfs /home"
|
||||
"--tmpfs /mnt"
|
||||
"--tmpfs /run"
|
||||
"--ro-bind-try /run/current-system /run/current-system"
|
||||
"--ro-bind-try /run/booted-system /run/booted-system"
|
||||
"--ro-bind-try /run/opengl-driver /run/opengl-driver"
|
||||
"--ro-bind-try /run/opengl-driver-32 /run/opengl-driver-32"
|
||||
# Brave flags
|
||||
"--setenv NIXOS_OZONE_WL \"1\""
|
||||
"--setenv NOTIFY_IGNORE_PORTAL 1"
|
||||
# Bind policies for Theme
|
||||
"--dir /etc/brave/policies/managed"
|
||||
"--ro-bind ${bravePolicies} /etc/brave/policies/managed/policies.json"
|
||||
# Fallback paths for Chromium/Chrome base
|
||||
"--dir /etc/chromium/policies/managed"
|
||||
"--ro-bind ${bravePolicies} /etc/chromium/policies/managed/policies.json"
|
||||
"--dir /etc/opt/chrome/policies/managed"
|
||||
"--ro-bind ${bravePolicies} /etc/opt/chrome/policies/managed/policies.json"
|
||||
# Filesystem: Limited to Brave directories and Downloads
|
||||
mounts = {
|
||||
read = [
|
||||
"$HOME/.config/kdedefaults"
|
||||
"$HOME/.config/fontconfig"
|
||||
"$HOME/.config/user-dirs.dirs"
|
||||
"$HOME/.config/mimeapps.list"
|
||||
"$HOME/.local/share/color-schemes"
|
||||
"$HOME/.local/share/fonts"
|
||||
"$HOME/.icons"
|
||||
"$HOME/.themes"
|
||||
"$HOME/.local/share/themes"
|
||||
"$HOME/.config/gtk-3.0"
|
||||
];
|
||||
readWrite = [
|
||||
"$HOME/.config/BraveSoftware"
|
||||
"$HOME/.cache/BraveSoftware"
|
||||
"$HOME/Downloads"
|
||||
] ++ cfg.extraBindMounts;
|
||||
};
|
||||
|
||||
# Bind mount systemd-resolved socket for DNS and required system files
|
||||
# Disable built-in DBus module because it invokes bwrap without --unshare-user
|
||||
dbus.enable = false;
|
||||
|
||||
# Manually set up DBus proxy with --unshare-user
|
||||
script.preCmds.stage2 = sandboxUtils.mkDbusProxyScript {
|
||||
appId = "nix.bwrapper.brave";
|
||||
proxyArgs = [
|
||||
"--filter"
|
||||
''--talk="org.freedesktop.portal.Desktop"''
|
||||
''--talk="org.freedesktop.portal.OpenURI"''
|
||||
''--talk="org.freedesktop.portal.FileChooser"''
|
||||
''--talk="org.freedesktop.secrets"''
|
||||
''--talk="org.kde.StatusNotifierWatcher"''
|
||||
''--call="org.freedesktop.portal.*=*@/org/freedesktop/portal/desktop"''
|
||||
''--own="org.chromium.LibCrosService"'' # Chromium/Brave specific
|
||||
''--own="org.mpris.MediaPlayer2.chromium.*"''
|
||||
''--own="org.mpris.MediaPlayer2.brave.*"''
|
||||
];
|
||||
enableSystemBus = true;
|
||||
systemProxyArgs = [
|
||||
"--filter"
|
||||
''--talk="org.freedesktop.NetworkManager"''
|
||||
];
|
||||
};
|
||||
|
||||
fhsenv.bwrap.additionalArgs = [
|
||||
''--bind "$XDG_RUNTIME_DIR/app/nix.bwrapper.brave/bus" "$XDG_RUNTIME_DIR/bus"''
|
||||
''--bind "$XDG_RUNTIME_DIR/app/nix.bwrapper.brave/bus_system" /run/dbus/system_bus_socket''
|
||||
"--dir /run/systemd/resolve"
|
||||
"--ro-bind-try /run/systemd/resolve /run/systemd/resolve"
|
||||
"--bind-try /run/user/${toString config.users.users.${config.myModules.system.mainUser}.uid}/dconf /run/user/${toString config.users.users.${config.myModules.system.mainUser}.uid}/dconf"
|
||||
];
|
||||
};
|
||||
})
|
||||
];
|
||||
|
||||
environment.systemPackages = [
|
||||
(pkgs.writeShellScriptBin "brave" ''
|
||||
exec ${config.myModules.system.repoPath}/scripts/launch-vpn-app.sh ${pkgs.brave-sandboxed}/bin/brave "$@"
|
||||
'')
|
||||
(pkgs.makeDesktopItem {
|
||||
name = "brave-vpn";
|
||||
desktopName = "Brave Web Browser";
|
||||
exec = "brave %U";
|
||||
icon = "brave-browser";
|
||||
categories = [
|
||||
"Network"
|
||||
"WebBrowser"
|
||||
];
|
||||
|
||||
# Filesystem: Limited to Brave directories and Downloads
|
||||
mounts = {
|
||||
read = [
|
||||
"$HOME/.config/kdedefaults"
|
||||
"$HOME/.config/fontconfig"
|
||||
"$HOME/.config/user-dirs.dirs"
|
||||
"$HOME/.config/mimeapps.list"
|
||||
"$HOME/.local/share/color-schemes"
|
||||
"$HOME/.local/share/fonts"
|
||||
"$HOME/.icons"
|
||||
"$HOME/.themes"
|
||||
"$HOME/.local/share/themes"
|
||||
"$HOME/.config/gtk-3.0"
|
||||
];
|
||||
readWrite = [
|
||||
"$HOME/.config/BraveSoftware"
|
||||
"$HOME/.cache/BraveSoftware"
|
||||
"$HOME/Downloads"
|
||||
];
|
||||
};
|
||||
|
||||
# Bind mount systemd-resolved socket for DNS and required system files
|
||||
# Disable built-in DBus module because it invokes bwrap without --unshare-user
|
||||
dbus.enable = false;
|
||||
|
||||
# Manually set up DBus proxy with --unshare-user
|
||||
script.preCmds.stage2 = (import ./sandbox-utils.nix { inherit pkgs lib; }).mkDbusProxyScript {
|
||||
appId = "nix.bwrapper.brave";
|
||||
proxyArgs = [
|
||||
"--filter"
|
||||
''--talk="org.freedesktop.portal.Desktop"''
|
||||
''--talk="org.freedesktop.portal.OpenURI"''
|
||||
''--talk="org.freedesktop.portal.FileChooser"''
|
||||
''--talk="org.freedesktop.secrets"''
|
||||
''--talk="org.kde.StatusNotifierWatcher"''
|
||||
''--call="org.freedesktop.portal.*=*@/org/freedesktop/portal/desktop"''
|
||||
''--own="org.chromium.LibCrosService"'' # Chromium/Brave specific
|
||||
''--own="org.mpris.MediaPlayer2.chromium.*"''
|
||||
''--own="org.mpris.MediaPlayer2.brave.*"''
|
||||
];
|
||||
enableSystemBus = true;
|
||||
systemProxyArgs = [
|
||||
"--filter"
|
||||
''--talk="org.freedesktop.NetworkManager"''
|
||||
];
|
||||
};
|
||||
|
||||
fhsenv.bwrap.additionalArgs = [
|
||||
''--bind "$XDG_RUNTIME_DIR/app/nix.bwrapper.brave/bus" "$XDG_RUNTIME_DIR/bus"''
|
||||
''--bind "$XDG_RUNTIME_DIR/app/nix.bwrapper.brave/bus_system" /run/dbus/system_bus_socket''
|
||||
"--dir /run/systemd/resolve"
|
||||
"--ro-bind-try /run/systemd/resolve /run/systemd/resolve"
|
||||
"--bind-try /run/user/${toString config.users.users.ashie.uid}/dconf /run/user/${toString config.users.users.ashie.uid}/dconf"
|
||||
];
|
||||
};
|
||||
})
|
||||
];
|
||||
|
||||
environment.systemPackages = [
|
||||
(pkgs.writeShellScriptBin "brave" ''
|
||||
exec /home/ashie/nixos/scripts/launch-vpn-app.sh ${pkgs.brave-sandboxed}/bin/brave "$@"
|
||||
'')
|
||||
(pkgs.makeDesktopItem {
|
||||
name = "brave-vpn";
|
||||
desktopName = "Brave Web Browser";
|
||||
exec = "brave %U";
|
||||
icon = "brave-browser";
|
||||
categories = [
|
||||
"Network"
|
||||
"WebBrowser"
|
||||
];
|
||||
})
|
||||
];
|
||||
}
|
||||
})
|
||||
];
|
||||
};
|
||||
}
|
||||
64
modules/nixos/braveapi.py
Normal file
64
modules/nixos/braveapi.py
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
"""
|
||||
Search Engine: Brave Search API
|
||||
"""
|
||||
|
||||
import json
|
||||
import os
|
||||
from urllib.parse import quote
|
||||
|
||||
# About the engine
|
||||
about = {
|
||||
"website": "https://brave.com/search/api/",
|
||||
"use_official_api": True,
|
||||
"require_api_key": True,
|
||||
"results": "JSON",
|
||||
}
|
||||
|
||||
categories = ['general', 'web']
|
||||
paging = True
|
||||
max_page = 10
|
||||
page_size = 20
|
||||
|
||||
# API Endpoint
|
||||
base_url = "https://api.search.brave.com/res/v1/web/search"
|
||||
|
||||
def request(query, params):
|
||||
# Get key from environment
|
||||
api_key = os.getenv('BRAVE_API_KEY')
|
||||
|
||||
# Brave expects offset 0-9 for pages
|
||||
pageno = min(params.get('pageno', 1), 10)
|
||||
offset = pageno - 1
|
||||
|
||||
# Simple query string construction with proper quoting
|
||||
# Using 'x-subscription-token' (lowercase) which was verified to work
|
||||
params['url'] = f"{base_url}?q={quote(query)}&count=20&offset={offset}"
|
||||
|
||||
params['headers'] = {
|
||||
'x-subscription-token': api_key,
|
||||
'Accept': 'application/json'
|
||||
}
|
||||
|
||||
params['method'] = 'GET'
|
||||
|
||||
# Clean up SearXNG defaults to prevent interference
|
||||
if 'data' in params: del params['data']
|
||||
if 'params' in params: del params['params']
|
||||
|
||||
return params
|
||||
|
||||
def response(resp):
|
||||
results = []
|
||||
data = json.loads(resp.text)
|
||||
|
||||
# The Brave API returns 'web' results
|
||||
web_results = data.get('web', {}).get('results', [])
|
||||
|
||||
for item in web_results:
|
||||
results.append({
|
||||
'url': item.get('url'),
|
||||
'title': item.get('title'),
|
||||
'content': item.get('description'),
|
||||
})
|
||||
|
||||
return results
|
||||
|
|
@ -18,6 +18,7 @@
|
|||
|
||||
let
|
||||
cfg = config.myModules.browserVpn;
|
||||
mainUser = config.myModules.system.mainUser;
|
||||
|
||||
# Helper function for auto-recovery from podman namespace corruption
|
||||
# Detects "cannot re-exec process" errors and runs migrate to fix
|
||||
|
|
@ -78,7 +79,8 @@ let
|
|||
echo "Build complete."
|
||||
;;
|
||||
run)
|
||||
if ! podman_with_recovery image exists ${imageName}:latest 2>/dev/null; then
|
||||
if ! podman_with_recovery image exists ${imageName}:latest 2>/dev/null;
|
||||
then
|
||||
echo "Building ${name} container image..."
|
||||
podman_with_recovery build -t ${imageName}:latest "$REPO_DIR/containers/${name}-wayland/"
|
||||
fi
|
||||
|
|
@ -168,8 +170,8 @@ let
|
|||
Fingerprinting = true;
|
||||
};
|
||||
Preferences = {
|
||||
"network.dns.disableIPv6" = true;
|
||||
"network.ipv6" = false;
|
||||
"network.dns.disableIPv6" = false;
|
||||
"network.ipv6" = true;
|
||||
"network.http.fast-fallback-to-IPv4" = true;
|
||||
"network.trr.mode" = 5; # Disable DNS over HTTPS (use system/VPN DNS)
|
||||
"ui.systemUsesDarkTheme" = 1;
|
||||
|
|
@ -231,7 +233,8 @@ let
|
|||
echo "Build complete."
|
||||
;;
|
||||
run)
|
||||
if ! podman_with_recovery image exists localhost/thorium-wayland:latest 2>/dev/null; then
|
||||
if ! podman_with_recovery image exists localhost/thorium-wayland:latest 2>/dev/null;
|
||||
then
|
||||
echo "Building thorium-dev container image..."
|
||||
podman_with_recovery build -t localhost/thorium-wayland:latest "$REPO_DIR/containers/thorium-wayland/"
|
||||
fi
|
||||
|
|
@ -315,7 +318,8 @@ let
|
|||
echo "Build complete."
|
||||
;;
|
||||
run)
|
||||
if ! podman_with_recovery image exists localhost/arch-kitty:latest 2>/dev/null; then
|
||||
if ! podman_with_recovery image exists localhost/arch-kitty:latest 2>/dev/null;
|
||||
then
|
||||
echo "Building Arch Kitty container image..."
|
||||
podman_with_recovery build -t localhost/arch-kitty:latest "$REPO_DIR/containers/arch-kitty/"
|
||||
fi
|
||||
|
|
@ -450,13 +454,13 @@ in
|
|||
|
||||
kittyConfigDir = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = "/home/ashie/.config/kitty";
|
||||
default = "/home/${mainUser}/.config/kitty";
|
||||
description = "Path to kitty configuration directory";
|
||||
};
|
||||
|
||||
bashrcPath = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = "/home/ashie/.bashrc";
|
||||
default = "/home/${mainUser}/.bashrc";
|
||||
description = "Path to bashrc file for Kitty container";
|
||||
};
|
||||
};
|
||||
|
|
@ -464,4 +468,4 @@ in
|
|||
config = lib.mkIf cfg.enable {
|
||||
environment.systemPackages = enabledPackages ++ [ desktopEntriesPackage ];
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -10,7 +10,9 @@
|
|||
}:
|
||||
|
||||
let
|
||||
cfg = config.myModules.citronSandboxed;
|
||||
bwrapperPkgs = pkgs.extend inputs.nix-bwrapper.overlays.default;
|
||||
sandboxUtils = import ./sandbox-utils.nix { inherit pkgs lib; };
|
||||
|
||||
pname = "citron";
|
||||
version = "0.12.25";
|
||||
|
|
@ -74,123 +76,110 @@ let
|
|||
};
|
||||
in
|
||||
{
|
||||
nixpkgs.overlays = [
|
||||
(final: prev: {
|
||||
citron-sandboxed = bwrapperPkgs.mkBwrapper {
|
||||
app = {
|
||||
package = citron;
|
||||
id = appId;
|
||||
env = {
|
||||
XDG_DATA_DIRS = "$XDG_DATA_DIRS";
|
||||
QT_QPA_PLATFORM = "wayland;xcb";
|
||||
XDG_CURRENT_DESKTOP = "KDE";
|
||||
# Allow AppImage to extract and run
|
||||
APPIMAGE_EXTRACT_AND_RUN = "1";
|
||||
options.myModules.citronSandboxed = {
|
||||
enable = lib.mkEnableOption "sandboxed Citron with nix-bwrapper";
|
||||
|
||||
extraBindMounts = lib.mkOption {
|
||||
type = lib.types.listOf lib.types.str;
|
||||
default = [];
|
||||
description = "Extra paths to bind mount (read-write) into the sandbox";
|
||||
};
|
||||
};
|
||||
|
||||
config = lib.mkIf cfg.enable {
|
||||
nixpkgs.overlays = [
|
||||
(final: prev: {
|
||||
citron-sandboxed = bwrapperPkgs.mkBwrapper {
|
||||
app = {
|
||||
package = citron;
|
||||
id = appId;
|
||||
env = {
|
||||
XDG_DATA_DIRS = "$XDG_DATA_DIRS";
|
||||
QT_QPA_PLATFORM = "wayland;xcb";
|
||||
XDG_CURRENT_DESKTOP = "KDE";
|
||||
# Allow AppImage to extract and run
|
||||
APPIMAGE_EXTRACT_AND_RUN = "1";
|
||||
};
|
||||
};
|
||||
|
||||
# Enable X11 and Wayland
|
||||
sockets.x11 = true;
|
||||
sockets.wayland = true;
|
||||
|
||||
# Disable Flatpak emulation
|
||||
flatpak.enable = false;
|
||||
|
||||
fhsenv.opts = {
|
||||
unshareUser = true;
|
||||
unshareUts = false;
|
||||
unshareCgroup = false;
|
||||
unsharePid = false;
|
||||
unshareNet = false; # Need network for online features
|
||||
unshareIpc = false;
|
||||
};
|
||||
|
||||
fhsenv.bwrap.baseArgs = lib.mkForce (sandboxUtils.mkCommonBindArgs { inherit config lib; } ++ sandboxUtils.mkGamingBindArgs { } ++ [
|
||||
# Fix for amdgpu.ids missing - use tmpfs so mkdir can succeed
|
||||
"--tmpfs /usr/share"
|
||||
"--ro-bind ${pkgs.libdrm}/share/libdrm /usr/share/libdrm"
|
||||
"--ro-bind-try /nix/store /nix/store"
|
||||
]);
|
||||
|
||||
# Disable built-in DBus module (invokes bwrap without --unshare-user)
|
||||
dbus.enable = false;
|
||||
|
||||
# Manually set up DBus proxy with --unshare-user (session bus only)
|
||||
# Also create required directories before bwrap runs
|
||||
script.preCmds.stage2 = ''
|
||||
# Create directories that bwrap will bind
|
||||
mkdir -p "$HOME/.cache/citron-tmp"
|
||||
mkdir -p "$HOME/.config/citron"
|
||||
mkdir -p "$HOME/.config/Citron"
|
||||
mkdir -p "$HOME/.local/share/citron"
|
||||
mkdir -p "$HOME/.local/share/Citron"
|
||||
mkdir -p "$HOME/Games/Switch"
|
||||
''
|
||||
+ sandboxUtils.mkDbusProxyScript {
|
||||
inherit appId;
|
||||
enableSystemBus = false;
|
||||
proxyArgs = [
|
||||
"--filter"
|
||||
''--talk="org.freedesktop.portal.*"''
|
||||
''--call="org.freedesktop.portal.*=*@/org/freedesktop/portal/desktop"''
|
||||
''--talk="org.freedesktop.Notifications"''
|
||||
''--talk="org.freedesktop.ScreenSaver"''
|
||||
''--talk="org.kde.StatusNotifierWatcher"''
|
||||
''--talk="org.kde.KWin"''
|
||||
''--talk="org.gnome.Mutter.DisplayConfig"''
|
||||
''--talk="org.freedesktop.secrets"''
|
||||
|
||||
''--talk="com.feralinteractive.GameMode"''
|
||||
''--own="${appId}"''
|
||||
''--own="${appId}.*"''
|
||||
];
|
||||
};
|
||||
|
||||
fhsenv.bwrap.additionalArgs = sandboxUtils.mkGuiBindArgs { } ++ [
|
||||
# D-Bus session proxy only
|
||||
''--bind "$XDG_RUNTIME_DIR/app/${appId}/bus" "$XDG_RUNTIME_DIR/bus"''
|
||||
|
||||
# Read-write mounts
|
||||
"--bind $HOME/Games/Switch $HOME/Games/Switch"
|
||||
"--bind $HOME/.config/citron $HOME/.config/citron"
|
||||
"--bind $HOME/.config/Citron $HOME/.config/Citron"
|
||||
"--bind $HOME/.local/share/citron $HOME/.local/share/citron"
|
||||
"--bind $HOME/.local/share/Citron $HOME/.local/share/Citron"
|
||||
"--bind $HOME/.cache/citron-tmp $HOME/.cache/citron-tmp"
|
||||
];
|
||||
|
||||
mounts = {
|
||||
read = sandboxUtils.mkGuiMounts.read;
|
||||
readWrite = cfg.extraBindMounts;
|
||||
};
|
||||
};
|
||||
})
|
||||
];
|
||||
|
||||
# Enable X11 and Wayland
|
||||
sockets.x11 = true;
|
||||
sockets.wayland = true;
|
||||
|
||||
# Disable Flatpak emulation
|
||||
flatpak.enable = false;
|
||||
|
||||
fhsenv.opts = {
|
||||
unshareUser = true;
|
||||
unshareUts = false;
|
||||
unshareCgroup = false;
|
||||
unsharePid = false;
|
||||
unshareNet = false; # Need network for online features
|
||||
unshareIpc = false;
|
||||
};
|
||||
|
||||
fhsenv.bwrap.baseArgs = lib.mkForce [
|
||||
"--new-session"
|
||||
"--proc /proc"
|
||||
"--dev /dev"
|
||||
"--dev-bind /dev/dri /dev/dri" # GPU acceleration
|
||||
"--dev-bind /dev/shm /dev/shm" # Shared memory
|
||||
"--dev-bind-try /dev/uinput /dev/uinput" # Controller support
|
||||
"--dev-bind-try /dev/input /dev/input"
|
||||
"--tmpfs /home"
|
||||
"--tmpfs /tmp"
|
||||
"--tmpfs /run"
|
||||
"--tmpfs /run"
|
||||
"--dir /run/user"
|
||||
"--dir /run/user/${toString config.users.users.ashie.uid}"
|
||||
# Fix for amdgpu.ids missing - use tmpfs so mkdir can succeed
|
||||
"--tmpfs /usr/share"
|
||||
"--ro-bind ${pkgs.libdrm}/share/libdrm /usr/share/libdrm"
|
||||
# System paths
|
||||
"--ro-bind /sys /sys"
|
||||
"--ro-bind-try /run/current-system /run/current-system"
|
||||
"--ro-bind-try /run/opengl-driver /run/opengl-driver"
|
||||
"--ro-bind-try /run/opengl-driver-32 /run/opengl-driver-32"
|
||||
"--ro-bind-try /nix/store /nix/store"
|
||||
"--dir /run/systemd/resolve"
|
||||
"--ro-bind-try /run/systemd/resolve /run/systemd/resolve"
|
||||
# udev for controller hotplug
|
||||
"--ro-bind-try /run/udev /run/udev"
|
||||
];
|
||||
|
||||
# Disable built-in DBus module (invokes bwrap without --unshare-user)
|
||||
dbus.enable = false;
|
||||
|
||||
# Manually set up DBus proxy with --unshare-user (session bus only)
|
||||
# Also create required directories before bwrap runs
|
||||
script.preCmds.stage2 = ''
|
||||
# Create directories that bwrap will bind
|
||||
mkdir -p "$HOME/.cache/citron-tmp"
|
||||
mkdir -p "$HOME/.config/citron"
|
||||
mkdir -p "$HOME/.config/Citron"
|
||||
mkdir -p "$HOME/.local/share/citron"
|
||||
mkdir -p "$HOME/.local/share/Citron"
|
||||
mkdir -p "$HOME/Games/Switch"
|
||||
''
|
||||
+ (import ./sandbox-utils.nix { inherit pkgs lib; }).mkDbusProxyScript {
|
||||
inherit appId;
|
||||
enableSystemBus = false;
|
||||
proxyArgs = [
|
||||
"--filter"
|
||||
''--talk="org.freedesktop.portal.*"''
|
||||
''--call="org.freedesktop.portal.*=*@/org/freedesktop/portal/desktop"''
|
||||
''--talk="org.freedesktop.Notifications"''
|
||||
''--talk="org.freedesktop.ScreenSaver"''
|
||||
''--talk="org.kde.StatusNotifierWatcher"''
|
||||
''--talk="org.kde.KWin"''
|
||||
''--talk="org.gnome.Mutter.DisplayConfig"''
|
||||
''--talk="org.freedesktop.secrets"''
|
||||
|
||||
''--talk="com.feralinteractive.GameMode"''
|
||||
''--own="${appId}"''
|
||||
''--own="${appId}.*"''
|
||||
];
|
||||
};
|
||||
|
||||
fhsenv.bwrap.additionalArgs = [
|
||||
# D-Bus session proxy only
|
||||
''--bind "$XDG_RUNTIME_DIR/app/${appId}/bus" "$XDG_RUNTIME_DIR/bus"''
|
||||
|
||||
# Manual mounts for data persistence
|
||||
"--ro-bind-try $HOME/.config/kdedefaults $HOME/.config/kdedefaults"
|
||||
"--ro-bind-try $HOME/.local/share/color-schemes $HOME/.local/share/color-schemes"
|
||||
"--ro-bind-try $HOME/.config/fontconfig $HOME/.config/fontconfig"
|
||||
"--ro-bind-try $HOME/.local/share/fonts $HOME/.local/share/fonts"
|
||||
"--ro-bind-try $HOME/.icons $HOME/.icons"
|
||||
"--ro-bind-try $HOME/.themes $HOME/.themes"
|
||||
"--ro-bind-try $HOME/.config/qt6ct $HOME/.config/qt6ct"
|
||||
"--ro-bind-try $HOME/.config/Kvantum $HOME/.config/Kvantum"
|
||||
"--ro-bind-try $HOME/.config/MangoHud $HOME/.config/MangoHud"
|
||||
# Read-write mounts
|
||||
"--bind $HOME/Games/Switch $HOME/Games/Switch"
|
||||
"--bind $HOME/.config/citron $HOME/.config/citron"
|
||||
"--bind $HOME/.config/Citron $HOME/.config/Citron"
|
||||
"--bind $HOME/.local/share/citron $HOME/.local/share/citron"
|
||||
"--bind $HOME/.local/share/Citron $HOME/.local/share/Citron"
|
||||
"--bind $HOME/.cache/citron-tmp $HOME/.cache/citron-tmp"
|
||||
];
|
||||
};
|
||||
})
|
||||
];
|
||||
environment.systemPackages = [ pkgs.citron-sandboxed ];
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -118,13 +118,16 @@ in
|
|||
# Allow all traffic from internal container interfaces (Podman/CNI)
|
||||
# This allows containers to reach the host (DNS, Gateway)
|
||||
iifname "podman*" accept
|
||||
|
||||
iifname "cni*" accept
|
||||
# Allow container subnet (fixes issues with non-podman* interface names)
|
||||
ip saddr 10.89.0.0/16 accept
|
||||
|
||||
# Allow RFC1918 Private Networks (LAN, Containers, Link-Local)
|
||||
${lib.optionalString cfg.allowLocalTraffic ''
|
||||
ip saddr 10.0.0.0/8 accept
|
||||
ip saddr 172.16.0.0/12 accept
|
||||
ip saddr 192.168.0.0/16 accept
|
||||
ip saddr 10.0.0.0/8 accept
|
||||
ip saddr 172.16.0.0/12 accept
|
||||
ip saddr 192.168.0.0/16 accept
|
||||
''}
|
||||
ip saddr 169.254.0.0/16 accept
|
||||
|
||||
|
|
@ -137,7 +140,7 @@ in
|
|||
${lib.optionalString (cfg.restrictedPorts != [ ]) ''
|
||||
ip saddr @cloudflare_ipv4 tcp dport { ${lib.concatStringsSep ", " (map toString cfg.restrictedPorts)} } accept
|
||||
ip6 saddr @cloudflare_ipv6 tcp dport { ${lib.concatStringsSep ", " (map toString cfg.restrictedPorts)} } accept
|
||||
|
||||
|
||||
# Drop all other traffic to restricted ports
|
||||
tcp dport { ${lib.concatStringsSep ", " (map toString cfg.restrictedPorts)} } drop
|
||||
''}
|
||||
|
|
@ -151,6 +154,9 @@ in
|
|||
oifname "podman*" accept
|
||||
iifname "cni*" accept
|
||||
oifname "cni*" accept
|
||||
# Allow container subnet forwarding
|
||||
ip saddr 10.89.0.0/16 accept
|
||||
ip daddr 10.89.0.0/16 accept
|
||||
|
||||
# Allow established/related forwarding
|
||||
ct state established,related accept
|
||||
|
|
|
|||
|
|
@ -10,5 +10,11 @@
|
|||
default = "/home/ashie/nixos";
|
||||
description = "Path to the main NixOS configuration repository";
|
||||
};
|
||||
|
||||
mainUser = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = "ashie";
|
||||
description = "Username of the main user";
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,14 +1,25 @@
|
|||
{
|
||||
config,
|
||||
pkgs,
|
||||
lib,
|
||||
...
|
||||
}:
|
||||
let
|
||||
cfg = config.myModules.desktop.cosmic;
|
||||
in
|
||||
{
|
||||
services.desktopManager.cosmic.enable = true;
|
||||
services.displayManager.cosmic-greeter.enable = false;
|
||||
options.myModules.desktop.cosmic = {
|
||||
enable = lib.mkEnableOption "Cosmic Desktop Environment";
|
||||
};
|
||||
|
||||
# Optimization
|
||||
services.system76-scheduler.enable = true;
|
||||
config = lib.mkIf cfg.enable {
|
||||
services.desktopManager.cosmic.enable = true;
|
||||
services.displayManager.cosmic-greeter.enable = false;
|
||||
|
||||
# Clipboard support (unstable protocol)
|
||||
environment.sessionVariables.COSMIC_DATA_CONTROL_ENABLED = "1";
|
||||
}
|
||||
# Optimization
|
||||
services.system76-scheduler.enable = true;
|
||||
|
||||
# Clipboard support (unstable protocol)
|
||||
environment.sessionVariables.COSMIC_DATA_CONTROL_ENABLED = "1";
|
||||
};
|
||||
}
|
||||
|
|
@ -36,5 +36,10 @@
|
|||
./tutanota-sandboxed.nix
|
||||
./hardened-malloc.nix
|
||||
./searxng.nix
|
||||
./media.nix
|
||||
./cosmic.nix
|
||||
./steam-gamemode.nix
|
||||
./redlib.nix
|
||||
./auto-update.nix
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
@ -10,138 +10,125 @@
|
|||
}:
|
||||
|
||||
let
|
||||
cfg = config.myModules.faugusSandboxed;
|
||||
bwrapperPkgs = pkgs.extend inputs.nix-bwrapper.overlays.default;
|
||||
sandboxUtils = import ./sandbox-utils.nix { inherit pkgs lib; };
|
||||
in
|
||||
{
|
||||
nixpkgs.overlays = [
|
||||
(final: prev: {
|
||||
faugus-sandboxed =
|
||||
let
|
||||
singleDesktopPkg =
|
||||
pkgs.symlinkJoin {
|
||||
name = "faugus-launcher-single";
|
||||
paths = [ prev.faugus-launcher ];
|
||||
postBuild = ''
|
||||
rm -rf $out/share/applications
|
||||
mkdir -p $out/share/applications
|
||||
ln -s ${prev.faugus-launcher}/share/applications/faugus-launcher.desktop $out/share/applications/io.github.faugus.Launcher.desktop
|
||||
'';
|
||||
}
|
||||
// {
|
||||
inherit (prev.faugus-launcher) pname version meta;
|
||||
options.myModules.faugusSandboxed = {
|
||||
enable = lib.mkEnableOption "sandboxed Faugus Launcher with nix-bwrapper";
|
||||
|
||||
extraBindMounts = lib.mkOption {
|
||||
type = lib.types.listOf lib.types.str;
|
||||
default = [];
|
||||
description = "Extra paths to bind mount (read-write) into the sandbox";
|
||||
};
|
||||
};
|
||||
|
||||
config = lib.mkIf cfg.enable {
|
||||
nixpkgs.overlays = [
|
||||
(final: prev: {
|
||||
faugus-sandboxed =
|
||||
let
|
||||
singleDesktopPkg =
|
||||
pkgs.symlinkJoin {
|
||||
name = "faugus-launcher-single";
|
||||
paths = [ prev.faugus-launcher ];
|
||||
postBuild = ''
|
||||
rm -rf $out/share/applications
|
||||
mkdir -p $out/share/applications
|
||||
ln -s ${prev.faugus-launcher}/share/applications/faugus-launcher.desktop $out/share/applications/io.github.faugus.Launcher.desktop
|
||||
'';
|
||||
}
|
||||
// {
|
||||
inherit (prev.faugus-launcher) pname version meta;
|
||||
};
|
||||
in
|
||||
bwrapperPkgs.mkBwrapper {
|
||||
app = {
|
||||
package = singleDesktopPkg;
|
||||
id = "io.github.faugus.Launcher";
|
||||
env = {
|
||||
# Propagate XDG_DATA_DIRS so themes/icons can be found
|
||||
XDG_DATA_DIRS = "$XDG_DATA_DIRS";
|
||||
# Fix for file dialogs/theming
|
||||
XDG_CURRENT_DESKTOP = "KDE";
|
||||
# GTK theming
|
||||
GTK_THEME = "catppuccin-frappe-blue-standard";
|
||||
# Force GTK to use the portal for file dialogs
|
||||
GTK_USE_PORTAL = "1";
|
||||
# Force Wayland backend to ensure xdg-foreign protocol works
|
||||
GDK_BACKEND = "wayland";
|
||||
};
|
||||
};
|
||||
in
|
||||
bwrapperPkgs.mkBwrapper {
|
||||
app = {
|
||||
package = singleDesktopPkg;
|
||||
id = "io.github.faugus.Launcher";
|
||||
env = {
|
||||
# Propagate XDG_DATA_DIRS so themes/icons can be found
|
||||
XDG_DATA_DIRS = "$XDG_DATA_DIRS";
|
||||
# Fix for file dialogs/theming
|
||||
XDG_CURRENT_DESKTOP = "KDE";
|
||||
# GTK theming
|
||||
GTK_THEME = "catppuccin-frappe-blue-standard";
|
||||
# Force GTK to use the portal for file dialogs
|
||||
GTK_USE_PORTAL = "1";
|
||||
# Force Wayland backend to ensure xdg-foreign protocol works
|
||||
GDK_BACKEND = "wayland";
|
||||
|
||||
# Enable X11 and Wayland
|
||||
sockets.x11 = true;
|
||||
sockets.wayland = true;
|
||||
|
||||
# Disable Flatpak emulation
|
||||
flatpak.enable = false;
|
||||
|
||||
fhsenv.opts = {
|
||||
unshareUser = true;
|
||||
unshareUts = false;
|
||||
unshareCgroup = false;
|
||||
unsharePid = false;
|
||||
unshareNet = false; # Need network
|
||||
unshareIpc = false;
|
||||
};
|
||||
};
|
||||
|
||||
# Enable X11 and Wayland
|
||||
sockets.x11 = true;
|
||||
sockets.wayland = true;
|
||||
fhsenv.bwrap.baseArgs = lib.mkForce (sandboxUtils.mkCommonBindArgs { inherit config lib; } ++ sandboxUtils.mkGamingBindArgs { });
|
||||
|
||||
# Disable Flatpak emulation
|
||||
flatpak.enable = false;
|
||||
mounts = {
|
||||
read = sandboxUtils.mkGuiMounts.read ++ [
|
||||
"$HOME/.gtkrc-2.0"
|
||||
];
|
||||
readWrite = [
|
||||
"$HOME/Games"
|
||||
"$HOME/.config/faugus-launcher"
|
||||
"$HOME/.local/share/faugus-launcher"
|
||||
"$HOME/.cache/faugus-launcher"
|
||||
"$HOME/.config/qt6ct" # Allow theming
|
||||
] ++ cfg.extraBindMounts;
|
||||
};
|
||||
|
||||
fhsenv.opts = {
|
||||
unshareUser = true;
|
||||
unshareUts = false;
|
||||
unshareCgroup = false;
|
||||
unsharePid = false;
|
||||
unshareNet = false; # Need network
|
||||
unshareIpc = false;
|
||||
};
|
||||
# Disable built-in DBus module (invokes bwrap without --unshare-user)
|
||||
dbus.enable = false;
|
||||
|
||||
fhsenv.bwrap.baseArgs = lib.mkForce [
|
||||
"--new-session"
|
||||
"--proc /proc"
|
||||
"--dev /dev"
|
||||
"--dev-bind /dev/dri /dev/dri" # GPU acceleration
|
||||
"--dev-bind /dev/shm /dev/shm" # Shared memory
|
||||
"--tmpfs /home"
|
||||
"--tmpfs /tmp"
|
||||
"--tmpfs /run"
|
||||
"--dir /run/user"
|
||||
"--dir /run/user/${toString config.users.users.ashie.uid}"
|
||||
# System paths
|
||||
"--ro-bind /sys /sys"
|
||||
"--ro-bind-try /run/current-system /run/current-system"
|
||||
"--ro-bind-try /run/opengl-driver /run/opengl-driver"
|
||||
"--ro-bind-try /run/opengl-driver-32 /run/opengl-driver-32"
|
||||
"--dir /run/systemd/resolve"
|
||||
"--ro-bind-try /run/systemd/resolve /run/systemd/resolve"
|
||||
];
|
||||
# Manually set up DBus proxy with --unshare-user (session bus only)
|
||||
script.preCmds.stage2 = sandboxUtils.mkDbusProxyScript {
|
||||
appId = "io.github.faugus.Launcher";
|
||||
enableSystemBus = false; # No system bus access
|
||||
proxyArgs = [
|
||||
"--filter"
|
||||
''--talk="org.freedesktop.portal.*"''
|
||||
''--talk="org.freedesktop.portal.FileChooser"''
|
||||
''--call="org.freedesktop.portal.*=*@/org/freedesktop/portal/desktop"''
|
||||
''--talk="org.freedesktop.Notifications"''
|
||||
''--talk="org.freedesktop.ScreenSaver"''
|
||||
''--talk="org.kde.StatusNotifierWatcher"''
|
||||
''--talk="org.kde.KWin"''
|
||||
''--talk="org.gnome.Mutter.DisplayConfig"''
|
||||
''--talk="org.freedesktop.secrets"''
|
||||
''--talk="org.freedesktop.portal.Settings"''
|
||||
''--talk="com.feralinteractive.GameMode"''
|
||||
''--own="io.github.faugus.Launcher"''
|
||||
''--own="io.github.faugus.Launcher.*"''
|
||||
];
|
||||
};
|
||||
|
||||
mounts = {
|
||||
read = [
|
||||
"$HOME/.config/kdedefaults"
|
||||
"$HOME/.local/share/color-schemes"
|
||||
"$HOME/.config/fontconfig"
|
||||
"$HOME/.icons"
|
||||
"$HOME/.themes"
|
||||
"$HOME/.local/share/themes"
|
||||
"$HOME/.local/share/fonts"
|
||||
"$HOME/.config/Kvantum"
|
||||
"$HOME/.config/gtk-3.0"
|
||||
"$HOME/.config/gtk-4.0"
|
||||
"$HOME/.gtkrc-2.0"
|
||||
"$HOME/.config/MangoHud"
|
||||
];
|
||||
readWrite = [
|
||||
"$HOME/Games"
|
||||
"$HOME/.config/faugus-launcher"
|
||||
"$HOME/.local/share/faugus-launcher"
|
||||
"$HOME/.cache/faugus-launcher"
|
||||
"$HOME/.config/qt6ct" # Allow theming
|
||||
fhsenv.bwrap.additionalArgs = sandboxUtils.mkGuiBindArgs { } ++ [
|
||||
# D-Bus session proxy only
|
||||
''--bind "$XDG_RUNTIME_DIR/app/io.github.faugus.Launcher/bus" "$XDG_RUNTIME_DIR/bus"''
|
||||
|
||||
# dconf for GTK settings
|
||||
"--bind-try /run/user/${toString config.users.users.${config.myModules.system.mainUser}.uid}/dconf /run/user/${toString config.users.users.${config.myModules.system.mainUser}.uid}/dconf"
|
||||
];
|
||||
};
|
||||
})
|
||||
];
|
||||
|
||||
# Disable built-in DBus module (invokes bwrap without --unshare-user)
|
||||
dbus.enable = false;
|
||||
|
||||
# Manually set up DBus proxy with --unshare-user (session bus only)
|
||||
script.preCmds.stage2 = (import ./sandbox-utils.nix { inherit pkgs lib; }).mkDbusProxyScript {
|
||||
appId = "io.github.faugus.Launcher";
|
||||
enableSystemBus = false; # No system bus access
|
||||
proxyArgs = [
|
||||
"--filter"
|
||||
''--talk="org.freedesktop.portal.*"''
|
||||
''--talk="org.freedesktop.portal.FileChooser"''
|
||||
''--call="org.freedesktop.portal.*=*@/org/freedesktop/portal/desktop"''
|
||||
''--talk="org.freedesktop.Notifications"''
|
||||
''--talk="org.freedesktop.ScreenSaver"''
|
||||
''--talk="org.kde.StatusNotifierWatcher"''
|
||||
''--talk="org.kde.KWin"''
|
||||
''--talk="org.gnome.Mutter.DisplayConfig"''
|
||||
''--talk="org.freedesktop.secrets"''
|
||||
''--talk="org.freedesktop.portal.Settings"''
|
||||
''--talk="com.feralinteractive.GameMode"''
|
||||
''--own="io.github.faugus.Launcher"''
|
||||
''--own="io.github.faugus.Launcher.*"''
|
||||
];
|
||||
};
|
||||
|
||||
fhsenv.bwrap.additionalArgs = [
|
||||
# D-Bus session proxy only
|
||||
''--bind "$XDG_RUNTIME_DIR/app/io.github.faugus.Launcher/bus" "$XDG_RUNTIME_DIR/bus"''
|
||||
|
||||
# dconf for GTK settings
|
||||
"--bind-try /run/user/${toString config.users.users.ashie.uid}/dconf /run/user/${toString config.users.users.ashie.uid}/dconf"
|
||||
];
|
||||
};
|
||||
})
|
||||
];
|
||||
environment.systemPackages = [ pkgs.faugus-sandboxed ];
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,38 +7,14 @@
|
|||
}:
|
||||
|
||||
let
|
||||
cfg = config.myModules.firefoxSandboxed;
|
||||
bwrapperPkgs = pkgs.extend inputs.nix-bwrapper.overlays.default;
|
||||
sandboxUtils = import ./sandbox-utils.nix { inherit pkgs lib; };
|
||||
|
||||
# create a custom settings.ini to force dark mode
|
||||
darkSettingsIni = pkgs.writeText "settings.ini" ''
|
||||
[Settings]
|
||||
gtk-theme-name=catppuccin-mocha-mauve-standard
|
||||
gtk-application-prefer-dark-theme=1
|
||||
gtk-cursor-theme-name=Future-Cyan-Hyprcursor_Theme
|
||||
gtk-xft-antialias=1
|
||||
gtk-xft-hinting=1
|
||||
gtk-xft-hintstyle=hintslight
|
||||
gtk-xft-rgba=rgb
|
||||
'';
|
||||
|
||||
# Define policies.json with Catppuccin Theme and P-Stream extension
|
||||
firefoxPolicies = pkgs.writeText "policies.json" (
|
||||
builtins.toJSON {
|
||||
policies = {
|
||||
ExtensionSettings = {
|
||||
# Catppuccin Mocha Mauve (Official)
|
||||
"catppuccin-mocha-mauve-official@catppuccin.com" = {
|
||||
install_url = "https://addons.mozilla.org/firefox/downloads/latest/catppuccin-mocha-mauve-official/latest.xpi";
|
||||
installation_mode = "force_installed";
|
||||
};
|
||||
# P-Stream extension
|
||||
"{de055456-589b-45fe-8342-c685a7ffb424}" = {
|
||||
install_url = "https://github.com/p-stream/extension/releases/download/1.3.5/firefox-mv3-prod.xpi";
|
||||
installation_mode = "force_installed";
|
||||
};
|
||||
};
|
||||
Preferences = {
|
||||
"extensions.activeThemeID" = "catppuccin-mocha-mauve-official@catppuccin.com";
|
||||
"xpinstall.signatures.required" = false;
|
||||
};
|
||||
};
|
||||
|
|
@ -46,112 +22,112 @@ let
|
|||
);
|
||||
in
|
||||
{
|
||||
nixpkgs.overlays = [
|
||||
(final: prev: {
|
||||
firefox-sandboxed = bwrapperPkgs.mkBwrapper {
|
||||
app = {
|
||||
package = prev.firefox;
|
||||
# Omit app.id to avoid document portal bind that fails on FUSE
|
||||
env = {
|
||||
MOZ_ENABLE_WAYLAND = "1";
|
||||
LD_PRELOAD = "";
|
||||
# Propagate XDG_DATA_DIRS so GTK can find themes in user profile/system
|
||||
XDG_DATA_DIRS = "$XDG_DATA_DIRS";
|
||||
GTK_THEME = "catppuccin-mocha-mauve-standard";
|
||||
HYPRCURSOR_THEME = "Future-Cyan-Hyprcursor_Theme";
|
||||
HYPRCURSOR_SIZE = "32";
|
||||
options.myModules.firefoxSandboxed = {
|
||||
enable = lib.mkEnableOption "sandboxed Firefox with nix-bwrapper";
|
||||
|
||||
extraBindMounts = lib.mkOption {
|
||||
type = lib.types.listOf lib.types.str;
|
||||
default = [ ];
|
||||
description = "Extra paths to bind mount (read-write) into the sandbox";
|
||||
};
|
||||
};
|
||||
|
||||
config = lib.mkIf cfg.enable {
|
||||
nixpkgs.overlays = [
|
||||
(final: prev: {
|
||||
firefox-sandboxed = bwrapperPkgs.mkBwrapper {
|
||||
app = {
|
||||
package = prev.firefox-esr;
|
||||
# Omit app.id to avoid document portal bind that fails on FUSE
|
||||
env = {
|
||||
MOZ_ENABLE_WAYLAND = "1";
|
||||
LD_PRELOAD = "";
|
||||
# Propagate XDG_DATA_DIRS so GTK can find themes in user profile/system
|
||||
XDG_DATA_DIRS = "$XDG_DATA_DIRS";
|
||||
GTK_THEME = "catppuccin-mocha-mauve-standard";
|
||||
HYPRCURSOR_THEME = "Future-Cyan-Hyprcursor_Theme";
|
||||
HYPRCURSOR_SIZE = "32";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
flatpak.enable = false;
|
||||
sockets.x11 = false;
|
||||
sockets.wayland = true;
|
||||
fhsenv.opts = {
|
||||
unshareUser = true;
|
||||
unshareUts = false;
|
||||
unshareCgroup = false;
|
||||
unsharePid = false;
|
||||
unshareNet = false;
|
||||
unshareIpc = false;
|
||||
};
|
||||
flatpak.enable = false;
|
||||
sockets.x11 = false;
|
||||
sockets.wayland = true;
|
||||
fhsenv.opts = {
|
||||
unshareUser = true;
|
||||
unshareUts = false;
|
||||
unshareCgroup = false;
|
||||
unsharePid = false;
|
||||
unshareNet = false;
|
||||
unshareIpc = false;
|
||||
};
|
||||
|
||||
fhsenv.bwrap.baseArgs = lib.mkForce [
|
||||
"--new-session"
|
||||
"--proc /proc"
|
||||
"--dev /dev"
|
||||
"--dev-bind /dev/dri /dev/dri"
|
||||
"--tmpfs /home"
|
||||
"--tmpfs /mnt"
|
||||
"--tmpfs /run"
|
||||
"--ro-bind-try /run/current-system /run/current-system"
|
||||
"--ro-bind-try /run/booted-system /run/booted-system"
|
||||
"--ro-bind-try /run/opengl-driver /run/opengl-driver"
|
||||
"--ro-bind-try /run/opengl-driver-32 /run/opengl-driver-32"
|
||||
# Removed: --bind "$XDG_RUNTIME_DIR/doc/by-app/..." which causes FUSE errors
|
||||
"--unsetenv LD_PRELOAD"
|
||||
"--setenv MOZ_ENABLE_WAYLAND \"1\""
|
||||
"--setenv NOTIFY_IGNORE_PORTAL 1"
|
||||
"--dir /etc"
|
||||
"--dir /etc/firefox"
|
||||
"--dir /etc/firefox/policies"
|
||||
"--ro-bind ${firefoxPolicies} /etc/firefox/policies/policies.json"
|
||||
];
|
||||
fhsenv.bwrap.baseArgs = lib.mkForce (
|
||||
sandboxUtils.mkCommonBindArgs { inherit config lib; }
|
||||
++ sandboxUtils.mkGamingBindArgs { }
|
||||
++ [
|
||||
"--tmpfs /mnt"
|
||||
"--ro-bind-try /run/booted-system /run/booted-system"
|
||||
"--setenv MOZ_ENABLE_WAYLAND \"1\""
|
||||
"--setenv NOTIFY_IGNORE_PORTAL 1"
|
||||
"--dir /etc"
|
||||
"--dir /etc/firefox"
|
||||
"--dir /etc/firefox/policies"
|
||||
"--ro-bind ${firefoxPolicies} /etc/firefox/policies/policies.json"
|
||||
]
|
||||
);
|
||||
|
||||
# Filesystem: Limited to Mozilla directories and Downloads
|
||||
mounts = {
|
||||
read = [
|
||||
"$HOME/.config/kdedefaults"
|
||||
"$HOME/.config/fontconfig"
|
||||
"$HOME/.config/user-dirs.dirs"
|
||||
"$HOME/.config/mimeapps.list"
|
||||
"$HOME/.local/share/color-schemes"
|
||||
"$HOME/.local/share/fonts"
|
||||
"$HOME/.icons"
|
||||
"$HOME/.themes"
|
||||
"$HOME/.local/share/themes"
|
||||
"$HOME/.config/gtk-3.0"
|
||||
];
|
||||
readWrite = [
|
||||
"$HOME/.mozilla"
|
||||
"$HOME/.cache/mozilla"
|
||||
"$HOME/Downloads"
|
||||
# Filesystem: Limited to Mozilla directories and Downloads
|
||||
mounts = {
|
||||
read = sandboxUtils.mkGuiMounts.read ++ [
|
||||
"$HOME/.config/user-dirs.dirs"
|
||||
"$HOME/.config/mimeapps.list"
|
||||
];
|
||||
readWrite = [
|
||||
"$HOME/.mozilla"
|
||||
"$HOME/.cache/mozilla"
|
||||
"$HOME/Downloads"
|
||||
]
|
||||
++ cfg.extraBindMounts;
|
||||
};
|
||||
|
||||
# Bind mount systemd-resolved socket for DNS and required system files
|
||||
# Disable built-in DBus module because it invokes bwrap without --unshare-user
|
||||
dbus.enable = false;
|
||||
|
||||
# Manually set up DBus proxy with --unshare-user
|
||||
script.preCmds.stage2 = sandboxUtils.mkDbusProxyScript {
|
||||
appId = "nix.bwrapper.firefox";
|
||||
proxyArgs = [
|
||||
"--filter"
|
||||
''--talk="org.freedesktop.portal.Desktop"''
|
||||
''--talk="org.freedesktop.portal.OpenURI"''
|
||||
''--talk="org.freedesktop.portal.FileChooser"''
|
||||
''--talk="org.freedesktop.secrets"''
|
||||
''--talk="org.kde.StatusNotifierWatcher"''
|
||||
''--call="org.freedesktop.portal.*=*@/org/freedesktop/portal/desktop"''
|
||||
''--own="org.mozilla.firefox"''
|
||||
''--own="org.mozilla.firefox.*"''
|
||||
''--own="org.mpris.MediaPlayer2.firefox.*"''
|
||||
];
|
||||
enableSystemBus = true;
|
||||
systemProxyArgs = [
|
||||
"--filter"
|
||||
''--talk="org.freedesktop.NetworkManager"''
|
||||
];
|
||||
};
|
||||
|
||||
fhsenv.bwrap.additionalArgs = sandboxUtils.mkGuiBindArgs { } ++ [
|
||||
''--bind "$XDG_RUNTIME_DIR/app/nix.bwrapper.firefox/bus" "$XDG_RUNTIME_DIR/bus"''
|
||||
''--bind "$XDG_RUNTIME_DIR/app/nix.bwrapper.firefox/bus_system" /run/dbus/system_bus_socket''
|
||||
"--bind-try /run/user/${
|
||||
toString config.users.users.${config.myModules.system.mainUser}.uid
|
||||
}/dconf /run/user/${toString config.users.users.${config.myModules.system.mainUser}.uid}/dconf"
|
||||
];
|
||||
};
|
||||
})
|
||||
];
|
||||
|
||||
# Bind mount systemd-resolved socket for DNS and required system files
|
||||
# Disable built-in DBus module because it invokes bwrap without --unshare-user
|
||||
dbus.enable = false;
|
||||
|
||||
# Manually set up DBus proxy with --unshare-user
|
||||
script.preCmds.stage2 = (import ./sandbox-utils.nix { inherit pkgs lib; }).mkDbusProxyScript {
|
||||
appId = "nix.bwrapper.firefox";
|
||||
proxyArgs = [
|
||||
"--filter"
|
||||
''--talk="org.freedesktop.portal.Desktop"''
|
||||
''--talk="org.freedesktop.portal.OpenURI"''
|
||||
''--talk="org.freedesktop.portal.FileChooser"''
|
||||
''--talk="org.freedesktop.secrets"''
|
||||
''--talk="org.kde.StatusNotifierWatcher"''
|
||||
''--call="org.freedesktop.portal.*=*@/org/freedesktop/portal/desktop"''
|
||||
''--own="org.mozilla.firefox"''
|
||||
''--own="org.mozilla.firefox.*"''
|
||||
''--own="org.mpris.MediaPlayer2.firefox.*"''
|
||||
];
|
||||
enableSystemBus = true;
|
||||
systemProxyArgs = [
|
||||
"--filter"
|
||||
''--talk="org.freedesktop.NetworkManager"''
|
||||
];
|
||||
};
|
||||
|
||||
fhsenv.bwrap.additionalArgs = [
|
||||
''--bind "$XDG_RUNTIME_DIR/app/nix.bwrapper.firefox/bus" "$XDG_RUNTIME_DIR/bus"''
|
||||
''--bind "$XDG_RUNTIME_DIR/app/nix.bwrapper.firefox/bus_system" /run/dbus/system_bus_socket''
|
||||
"--dir /run/systemd/resolve"
|
||||
"--ro-bind-try /run/systemd/resolve /run/systemd/resolve"
|
||||
"--bind-try /run/user/${toString config.users.users.ashie.uid}/dconf /run/user/${toString config.users.users.ashie.uid}/dconf"
|
||||
];
|
||||
};
|
||||
})
|
||||
];
|
||||
environment.systemPackages = [ pkgs.firefox-sandboxed ];
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -57,6 +57,7 @@
|
|||
"Music"
|
||||
"Pictures"
|
||||
"Videos"
|
||||
"src/aadniz-searxng"
|
||||
"Torrents"
|
||||
"nixos" # Config repo
|
||||
".local/share/PrismLauncher" # Minecraft
|
||||
|
|
@ -71,7 +72,8 @@
|
|||
".config/Antigravity" # Antigravity Config
|
||||
".config/modprobed-db" # Local modconfig database
|
||||
".config/VSCodium" # Codium Config
|
||||
".config/sops" # Sops Keys
|
||||
".config/sops" # Sops keys
|
||||
".config/easyeffects"
|
||||
".config/gh" # Github CLI Auth
|
||||
".local/share/keyrings" # Gnome Keyrings (Passwords)
|
||||
".local/share/nvim" # NeoVim data (LazyVim, Mason, etc.)
|
||||
|
|
@ -91,6 +93,8 @@
|
|||
".local/share/umu"
|
||||
".cache/mesa_shader_cache"
|
||||
# ".local/share/Steam" # Symlinked to /games/Steam (Already Persistent)
|
||||
".paradoxlauncher"
|
||||
".local/share/Paradox Interactive"
|
||||
".steam" # Steam Symlinks and logs
|
||||
".config/steamtinkerlaunch" # Example of extra tools
|
||||
".local/share/applications" # Desktop entries
|
||||
|
|
@ -99,6 +103,11 @@
|
|||
".local/share/qBittorrent"
|
||||
".local/share/jellyfin-desktop"
|
||||
".cache/jellyfin-desktop"
|
||||
".local/share/zoxide"
|
||||
".local/share/fish"
|
||||
"fabric-docs-mcp"
|
||||
];
|
||||
files = [
|
||||
];
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -69,6 +69,9 @@ in
|
|||
"vsyscall=none"
|
||||
"oops=panic"
|
||||
"module.sig_enforce=1"
|
||||
"amd_iommu=on"
|
||||
"mitigations=auto"
|
||||
"lockdown=confidentiality"
|
||||
];
|
||||
|
||||
# Kernel sysctl hardening
|
||||
|
|
|
|||
|
|
@ -9,136 +9,141 @@
|
|||
}:
|
||||
|
||||
let
|
||||
cfg = config.myModules.lutrisSandboxed;
|
||||
bwrapperPkgs = pkgs.extend inputs.nix-bwrapper.overlays.default;
|
||||
sandboxUtils = import ./sandbox-utils.nix { inherit pkgs lib; };
|
||||
in
|
||||
{
|
||||
nixpkgs.overlays = [
|
||||
(final: prev: {
|
||||
lutris-sandboxed = bwrapperPkgs.mkBwrapper {
|
||||
app = {
|
||||
package = prev.lutris.override {
|
||||
extraPkgs = pkgs: [
|
||||
pkgs.curl
|
||||
pkgs.wget
|
||||
pkgs.gnutar
|
||||
pkgs.gzip
|
||||
pkgs.zstd
|
||||
pkgs.xz
|
||||
pkgs.p7zip
|
||||
pkgs.which
|
||||
pkgs.file
|
||||
pkgs.zenity
|
||||
pkgs.vulkan-loader
|
||||
pkgs.vulkan-tools
|
||||
pkgs.unzip
|
||||
pkgs.cabextract
|
||||
pkgs.pciutils
|
||||
pkgs.gamemode.lib
|
||||
pkgs.xdg-utils
|
||||
options.myModules.lutrisSandboxed = {
|
||||
enable = lib.mkEnableOption "sandboxed Lutris with nix-bwrapper";
|
||||
|
||||
extraBindMounts = lib.mkOption {
|
||||
type = lib.types.listOf lib.types.str;
|
||||
default = [ ];
|
||||
description = "Extra paths to bind mount (read-write) into the sandbox";
|
||||
};
|
||||
};
|
||||
|
||||
config = lib.mkIf cfg.enable {
|
||||
nixpkgs.overlays = [
|
||||
(final: prev: {
|
||||
lutris-sandboxed = bwrapperPkgs.mkBwrapper {
|
||||
app = {
|
||||
package = prev.lutris.override {
|
||||
extraPkgs = pkgs: [
|
||||
pkgs.curl
|
||||
pkgs.wget
|
||||
pkgs.gnutar
|
||||
pkgs.gzip
|
||||
pkgs.zstd
|
||||
pkgs.xz
|
||||
pkgs.p7zip
|
||||
pkgs.which
|
||||
pkgs.file
|
||||
pkgs.zenity
|
||||
pkgs.vulkan-loader
|
||||
pkgs.vulkan-tools
|
||||
pkgs.unzip
|
||||
pkgs.cabextract
|
||||
pkgs.pciutils
|
||||
pkgs.gamemode.lib
|
||||
pkgs.xdg-utils
|
||||
pkgs.umu-launcher
|
||||
pkgs.sdl3
|
||||
];
|
||||
};
|
||||
isFhsenv = true;
|
||||
id = "net.lutris.Lutris";
|
||||
env = {
|
||||
WEBKIT_DISABLE_DMABUF_RENDERER = 1;
|
||||
APPIMAGE_EXTRACT_AND_RUN = 1;
|
||||
PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION = "python";
|
||||
GTK_THEME = "catppuccin-mocha-blue-standard";
|
||||
BROWSER = "xdg-open";
|
||||
XDG_CURRENT_DESKTOP = "niri";
|
||||
XDG_SESSION_TYPE = "wayland";
|
||||
DBUS_SESSION_BUS_ADDRESS = "unix:path=$XDG_RUNTIME_DIR/bus";
|
||||
VK_ICD_FILENAMES = "/run/opengl-driver/share/vulkan/icd.d/radeon_icd.x86_64.json:/run/opengl-driver-32/share/vulkan/icd.d/radeon_icd.i686.json";
|
||||
XDG_DATA_DIRS = "$XDG_DATA_DIRS";
|
||||
};
|
||||
};
|
||||
|
||||
fhsenv = {
|
||||
skipExtraInstallCmds = false;
|
||||
};
|
||||
|
||||
# Disable Flatpak emulation
|
||||
flatpak.enable = false;
|
||||
|
||||
# Filesystem: Limited to Games directory
|
||||
mounts = {
|
||||
read = sandboxUtils.mkGuiMounts.read ++ [
|
||||
"$HOME/.local/share/Steam/compatibilitytools.d"
|
||||
"/data/Torrents/Games" # Repack installers
|
||||
];
|
||||
|
||||
readWrite = [
|
||||
"$HOME/Games/windows"
|
||||
"$HOME/Games/linux"
|
||||
"$HOME/.local/share/icons"
|
||||
"$HOME/.config/lutris"
|
||||
"$HOME/.local/share/lutris"
|
||||
"$HOME/.cache/lutris"
|
||||
"$HOME/.steam"
|
||||
"$HOME/.local/share/steam"
|
||||
"$HOME/.local/share/umu"
|
||||
"$HOME/.local/share/applications"
|
||||
"$HOME/.local/share/desktop-directories"
|
||||
]
|
||||
++ cfg.extraBindMounts;
|
||||
};
|
||||
|
||||
# Bind mount systemd-resolved socket directory to fix DNS
|
||||
# The sandbox mounts a tmpfs on /run, so we need to validly expose this
|
||||
fhsenv.bwrap.baseArgs = lib.mkForce (
|
||||
sandboxUtils.mkCommonBindArgs { inherit config lib; } ++ sandboxUtils.mkGamingBindArgs { }
|
||||
);
|
||||
|
||||
fhsenv.bwrap.additionalArgs = sandboxUtils.mkGuiBindArgs { } ++ [
|
||||
# D-Bus session proxy
|
||||
''--bind "$XDG_RUNTIME_DIR/app/net.lutris.Lutris/bus" "$XDG_RUNTIME_DIR/bus"''
|
||||
# D-Bus system proxy
|
||||
''--bind "$XDG_RUNTIME_DIR/app/net.lutris.Lutris/bus_system" /run/dbus/system_bus_socket''
|
||||
|
||||
# Bind system themes to /usr/share
|
||||
"--ro-bind /run/current-system/sw/share/themes /usr/share/themes"
|
||||
"--ro-bind /run/current-system/sw/share/icons /usr/share/icons"
|
||||
];
|
||||
|
||||
# Disable built-in DBus module (invokes bwrap without --unshare-user)
|
||||
dbus.enable = false;
|
||||
|
||||
# Manually set up DBus proxy with --unshare-user
|
||||
script.preCmds.stage2 = sandboxUtils.mkDbusProxyScript {
|
||||
appId = "net.lutris.Lutris";
|
||||
enableSystemBus = true;
|
||||
proxyArgs = [
|
||||
"--filter"
|
||||
''--talk="org.freedesktop.Flatpak"''
|
||||
''--talk="org.kde.StatusNotifierWatcher"''
|
||||
''--talk="org.kde.KWin"''
|
||||
''--talk="org.gnome.Mutter.DisplayConfig"''
|
||||
''--talk="org.freedesktop.ScreenSaver"''
|
||||
''--talk="org.freedesktop.portal.*"''
|
||||
''--talk="org.freedesktop.secrets"''
|
||||
''--talk="com.feralinteractive.GameMode"''
|
||||
''--call="org.freedesktop.portal.*=*@/org/freedesktop/portal/desktop"''
|
||||
''--own="net.lutris.Lutris"''
|
||||
];
|
||||
systemProxyArgs = [
|
||||
"--filter"
|
||||
''--talk="org.freedesktop.UDisks2"'' # Disk detection
|
||||
];
|
||||
};
|
||||
isFhsenv = true;
|
||||
id = "net.lutris.Lutris";
|
||||
env = {
|
||||
WEBKIT_DISABLE_DMABUF_RENDERER = 1;
|
||||
APPIMAGE_EXTRACT_AND_RUN = 1;
|
||||
PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION = "python";
|
||||
GTK_THEME = "catppuccin-mocha-blue-standard";
|
||||
BROWSER = "xdg-open";
|
||||
XDG_CURRENT_DESKTOP = "niri";
|
||||
XDG_SESSION_TYPE = "wayland";
|
||||
DBUS_SESSION_BUS_ADDRESS = "unix:path=$XDG_RUNTIME_DIR/bus";
|
||||
VK_ICD_FILENAMES = "/run/opengl-driver/share/vulkan/icd.d/radeon_icd.x86_64.json:/run/opengl-driver-32/share/vulkan/icd.d/radeon_icd.i686.json";
|
||||
};
|
||||
};
|
||||
})
|
||||
];
|
||||
|
||||
fhsenv = {
|
||||
skipExtraInstallCmds = false;
|
||||
};
|
||||
|
||||
# Disable Flatpak emulation
|
||||
flatpak.enable = false;
|
||||
|
||||
# Filesystem: Limited to Games directory
|
||||
mounts = {
|
||||
read = [
|
||||
"$HOME/.config/kdedefaults"
|
||||
"$HOME/.local/share/color-schemes"
|
||||
"$HOME/.local/share/Steam/compatibilitytools.d"
|
||||
"$HOME/.config/gtk-3.0"
|
||||
"$HOME/.config/gtk-4.0"
|
||||
"$HOME/.icons"
|
||||
"/data/Torrents/Games" # Repack installers
|
||||
];
|
||||
|
||||
readWrite = [
|
||||
"$HOME/Games/windows"
|
||||
"$HOME/.local/share/icons"
|
||||
"$HOME/.config/lutris"
|
||||
"$HOME/.local/share/lutris"
|
||||
"$HOME/.cache/lutris"
|
||||
"$HOME/.steam"
|
||||
"$HOME/.local/share/steam"
|
||||
"$HOME/.local/share/umu"
|
||||
"$HOME/.local/share/applications"
|
||||
"$HOME/.local/share/desktop-directories"
|
||||
];
|
||||
};
|
||||
|
||||
# Bind mount systemd-resolved socket directory to fix DNS
|
||||
# The sandbox mounts a tmpfs on /run, so we need to validly expose this
|
||||
fhsenv.bwrap.additionalArgs = [
|
||||
"--dir /run/systemd/resolve"
|
||||
"--ro-bind-try /run/systemd/resolve /run/systemd/resolve"
|
||||
# D-Bus session proxy
|
||||
''--bind "$XDG_RUNTIME_DIR/app/net.lutris.Lutris/bus" "$XDG_RUNTIME_DIR/bus"''
|
||||
# D-Bus system proxy
|
||||
''--bind "$XDG_RUNTIME_DIR/app/net.lutris.Lutris/bus_system" /run/dbus/system_bus_socket''
|
||||
# Wayland socket
|
||||
''--bind "$XDG_RUNTIME_DIR/$WAYLAND_DISPLAY" "$XDG_RUNTIME_DIR/$WAYLAND_DISPLAY"''
|
||||
# PipeWire + Pulse
|
||||
''--bind "$XDG_RUNTIME_DIR/pipewire-0" "$XDG_RUNTIME_DIR/pipewire-0"''
|
||||
''--bind "$XDG_RUNTIME_DIR/pulse" "$XDG_RUNTIME_DIR/pulse"''
|
||||
|
||||
# Hardware access
|
||||
"--dev-bind /dev/dri /dev/dri"
|
||||
"--dev-bind /dev/shm /dev/shm"
|
||||
"--ro-bind /sys /sys"
|
||||
|
||||
# Bind system themes to /usr/share
|
||||
"--ro-bind /run/current-system/sw/share/themes /usr/share/themes"
|
||||
"--ro-bind /run/current-system/sw/share/icons /usr/share/icons"
|
||||
# OpenGL/Vulkan drivers
|
||||
"--ro-bind-try /run/opengl-driver /run/opengl-driver"
|
||||
"--ro-bind-try /run/opengl-driver-32 /run/opengl-driver-32"
|
||||
];
|
||||
|
||||
# Disable built-in DBus module (invokes bwrap without --unshare-user)
|
||||
dbus.enable = false;
|
||||
|
||||
# Manually set up DBus proxy with --unshare-user
|
||||
script.preCmds.stage2 = (import ./sandbox-utils.nix { inherit pkgs lib; }).mkDbusProxyScript {
|
||||
appId = "net.lutris.Lutris";
|
||||
enableSystemBus = true;
|
||||
proxyArgs = [
|
||||
"--filter"
|
||||
''--talk="org.freedesktop.Flatpak"''
|
||||
''--talk="org.kde.StatusNotifierWatcher"''
|
||||
''--talk="org.kde.KWin"''
|
||||
''--talk="org.gnome.Mutter.DisplayConfig"''
|
||||
''--talk="org.freedesktop.ScreenSaver"''
|
||||
''--talk="org.freedesktop.portal.*"''
|
||||
''--talk="org.freedesktop.secrets"''
|
||||
''--talk="com.feralinteractive.GameMode"''
|
||||
''--call="org.freedesktop.portal.*=*@/org/freedesktop/portal/desktop"''
|
||||
''--own="net.lutris.Lutris"''
|
||||
];
|
||||
systemProxyArgs = [
|
||||
"--filter"
|
||||
''--talk="org.freedesktop.UDisks2"'' # Disk detection
|
||||
];
|
||||
};
|
||||
};
|
||||
})
|
||||
];
|
||||
environment.systemPackages = [ pkgs.lutris-sandboxed ];
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,11 +6,11 @@
|
|||
}:
|
||||
|
||||
let
|
||||
# Define the user and group consistently
|
||||
user = "ashie";
|
||||
cfg = config.myModules.media;
|
||||
user = config.myModules.system.mainUser;
|
||||
group = "users";
|
||||
puid = "1000";
|
||||
pgid = "100";
|
||||
puid = toString config.users.users.${user}.uid;
|
||||
pgid = "100"; # GID for 'users' group
|
||||
|
||||
# Common env vars to avoid repetition
|
||||
commonEnv = {
|
||||
|
|
@ -20,183 +20,202 @@ let
|
|||
};
|
||||
in
|
||||
{
|
||||
# 1. Enable Podman (required backend)
|
||||
virtualisation = {
|
||||
podman = {
|
||||
enable = true;
|
||||
autoPrune.enable = true;
|
||||
};
|
||||
oci-containers.backend = "podman";
|
||||
options.myModules.media = {
|
||||
enable = lib.mkEnableOption "media server stack (Arr suite + Jellyfin)";
|
||||
};
|
||||
|
||||
# 2. Container Definitions
|
||||
virtualisation.oci-containers.containers = {
|
||||
config = lib.mkIf cfg.enable {
|
||||
# 1. Enable Podman (required backend)
|
||||
myModules.podman.enable = true;
|
||||
virtualisation.podman.autoPrune.enable = true;
|
||||
|
||||
# --- VPN Gateway ---
|
||||
vpn = {
|
||||
image = "docker.io/qmcgaw/gluetun";
|
||||
# The VPN manages the ports for the attached containers
|
||||
ports = [
|
||||
"8080:8080" # qBittorrent WebUI
|
||||
"36630:36630" # Torrent Port TCP
|
||||
"36630:36630/udp"
|
||||
"9696:9696" # Prowlarr
|
||||
"8191:8191" # Flaresolverr
|
||||
];
|
||||
environmentFiles = [ config.sops.templates."gluetun.env".path ];
|
||||
environment = {
|
||||
TZ = "Europe/Berlin";
|
||||
DOT = "off"; # DNS over TLS off (optional)
|
||||
FIREWALL_OUTBOUND_SUBNETS = "10.89.0.0/24"; # Allow access to local docker network
|
||||
FIREWALL_VPN_INPUT_PORTS = "36630"; # Allow incoming torrent traffic
|
||||
# 2. Container Definitions
|
||||
virtualisation.oci-containers.containers = {
|
||||
|
||||
# --- VPN Gateway ---
|
||||
vpn = {
|
||||
image = "docker.io/qmcgaw/gluetun";
|
||||
labels = { "io.containers.autoupdate" = "registry"; };
|
||||
# The VPN manages the ports for the attached containers
|
||||
ports = [
|
||||
"127.0.0.1:8080:8080" # qBittorrent WebUI (Localhost only)
|
||||
"36630:36630" # Torrent Port TCP (Public)
|
||||
"36630:36630/udp" # Torrent Port UDP (Public)
|
||||
"127.0.0.1:8191:8191" # Flaresolverr (Localhost only)
|
||||
"127.0.0.1:9696:9696" # Prowlarr (Localhost only)
|
||||
];
|
||||
environmentFiles = [ config.sops.templates."gluetun.env".path ];
|
||||
environment = {
|
||||
TZ = "Europe/Berlin";
|
||||
DOT = "off"; # DNS over TLS off (optional)
|
||||
FIREWALL_OUTBOUND_SUBNETS = "10.89.0.0/24"; # Allow access to local docker network
|
||||
FIREWALL_VPN_INPUT_PORTS = "36630"; # Allow incoming torrent traffic
|
||||
};
|
||||
extraOptions = [
|
||||
"--cap-add=NET_ADMIN"
|
||||
"--cap-add=NET_RAW"
|
||||
"--device=/dev/net/tun:/dev/net/tun"
|
||||
"--network=media" # It joins the bridge so others can talk to it
|
||||
"--ip=10.89.0.5" # Static IP for VPN/Flaresolverr
|
||||
"--network-alias=flaresolverr" # Allow other containers to reach Flaresolverr via VPN
|
||||
"--add-host=sonarr:10.89.0.50" # Allow Prowlarr to reach Sonarr
|
||||
"--add-host=radarr:10.89.0.51" # Allow Prowlarr to reach Radarr
|
||||
"--add-host=prowlarr:127.0.0.1" # Prowlarr matches VPN IP for self-reference if needed
|
||||
];
|
||||
};
|
||||
extraOptions = [
|
||||
"--cap-add=NET_ADMIN"
|
||||
"--cap-add=NET_RAW"
|
||||
"--device=/dev/net/tun:/dev/net/tun"
|
||||
"--network=media" # It joins the bridge so others can talk to it
|
||||
"--network-alias=prowlarr" # Allow other containers to reach Prowlarr via VPN
|
||||
"--network-alias=flaresolverr" # Allow other containers to reach Flaresolverr via VPN
|
||||
"--add-host=sonarr:10.89.0.50" # Allow Prowlarr to reach Sonarr
|
||||
"--add-host=radarr:10.89.0.51" # Allow Prowlarr to reach Radarr
|
||||
];
|
||||
};
|
||||
|
||||
# --- Torrent Client (Routed via VPN) ---
|
||||
torrent = {
|
||||
image = "lscr.io/linuxserver/qbittorrent:latest";
|
||||
# VITAL: Reuse the VPN container's network stack
|
||||
extraOptions = [ "--network=container:vpn" ];
|
||||
dependsOn = [ "vpn" ];
|
||||
environment = commonEnv // {
|
||||
WEBUI_PORT = "8080";
|
||||
# --- Torrent Client (Routed via VPN) ---
|
||||
torrent = {
|
||||
image = "lscr.io/linuxserver/qbittorrent:latest";
|
||||
labels = { "io.containers.autoupdate" = "registry"; };
|
||||
# VITAL: Reuse the VPN container's network stack
|
||||
extraOptions = [ "--network=container:vpn" ];
|
||||
dependsOn = [ "vpn" ];
|
||||
environment = commonEnv // {
|
||||
WEBUI_PORT = "8080";
|
||||
};
|
||||
volumes = [
|
||||
"/var/lib/qbittorrent:/config"
|
||||
"/data:/data"
|
||||
];
|
||||
};
|
||||
volumes = [
|
||||
"/var/lib/qbittorrent:/config"
|
||||
"/data:/data"
|
||||
];
|
||||
};
|
||||
|
||||
# --- The Arr Stack ---
|
||||
prowlarr = {
|
||||
image = "lscr.io/linuxserver/prowlarr:latest";
|
||||
extraOptions = [
|
||||
"--network=container:vpn"
|
||||
];
|
||||
dependsOn = [ "vpn" ];
|
||||
environment = commonEnv;
|
||||
volumes = [ "/var/lib/nixarr/prowlarr:/config" ];
|
||||
};
|
||||
# --- The Arr Stack ---
|
||||
prowlarr = {
|
||||
image = "lscr.io/linuxserver/prowlarr:latest";
|
||||
labels = { "io.containers.autoupdate" = "registry"; };
|
||||
extraOptions = [
|
||||
"--network=container:vpn"
|
||||
];
|
||||
dependsOn = [ "vpn" ];
|
||||
environment = commonEnv;
|
||||
volumes = [ "/var/lib/nixarr/prowlarr:/config" ];
|
||||
};
|
||||
|
||||
sonarr = {
|
||||
image = "lscr.io/linuxserver/sonarr:latest";
|
||||
extraOptions = [
|
||||
"--network=media"
|
||||
"--ip=10.89.0.50"
|
||||
];
|
||||
ports = [ "8989:8989" ];
|
||||
environment = commonEnv;
|
||||
volumes = [
|
||||
"/var/lib/nixarr/sonarr:/config"
|
||||
"/data:/data"
|
||||
];
|
||||
};
|
||||
sonarr = {
|
||||
image = "lscr.io/linuxserver/sonarr:latest";
|
||||
labels = { "io.containers.autoupdate" = "registry"; };
|
||||
extraOptions = [
|
||||
"--network=media"
|
||||
"--ip=10.89.0.50"
|
||||
"--dns=8.8.8.8"
|
||||
"--add-host=qbittorrent:10.89.0.5"
|
||||
"--add-host=prowlarr:10.89.0.5"
|
||||
];
|
||||
ports = [ "127.0.0.1:8989:8989" ];
|
||||
environment = commonEnv;
|
||||
volumes = [
|
||||
"/var/lib/nixarr/sonarr:/config"
|
||||
"/data:/data"
|
||||
];
|
||||
};
|
||||
|
||||
radarr = {
|
||||
image = "lscr.io/linuxserver/radarr:latest";
|
||||
extraOptions = [
|
||||
"--network=media"
|
||||
"--ip=10.89.0.51"
|
||||
];
|
||||
ports = [ "7878:7878" ];
|
||||
environment = commonEnv;
|
||||
volumes = [
|
||||
"/var/lib/nixarr/radarr:/config"
|
||||
"/data:/data"
|
||||
];
|
||||
};
|
||||
radarr = {
|
||||
image = "lscr.io/linuxserver/radarr:latest";
|
||||
labels = { "io.containers.autoupdate" = "registry"; };
|
||||
extraOptions = [
|
||||
"--network=media"
|
||||
"--ip=10.89.0.51"
|
||||
"--dns=8.8.8.8"
|
||||
"--add-host=qbittorrent:10.89.0.5"
|
||||
"--add-host=prowlarr:10.89.0.5"
|
||||
];
|
||||
ports = [ "127.0.0.1:7878:7878" ];
|
||||
environment = commonEnv;
|
||||
volumes = [
|
||||
"/var/lib/nixarr/radarr:/config"
|
||||
"/data:/data"
|
||||
];
|
||||
};
|
||||
|
||||
# --- Media Server ---
|
||||
jellyfin = {
|
||||
image = "lscr.io/linuxserver/jellyfin:latest";
|
||||
extraOptions = [
|
||||
"--network=media"
|
||||
"--device=/dev/dri:/dev/dri"
|
||||
];
|
||||
ports = [ "8096:8096" ];
|
||||
environment = commonEnv;
|
||||
volumes = [
|
||||
"/var/lib/nixarr/jellyfin:/config"
|
||||
"/data:/data"
|
||||
];
|
||||
};
|
||||
# --- Media Server ---
|
||||
jellyfin = {
|
||||
image = "lscr.io/linuxserver/jellyfin:latest";
|
||||
labels = { "io.containers.autoupdate" = "registry"; };
|
||||
extraOptions = [
|
||||
"--network=media"
|
||||
"--device=/dev/dri:/dev/dri"
|
||||
"--dns=8.8.8.8"
|
||||
"--ip=10.89.0.4"
|
||||
];
|
||||
ports = [ "127.0.0.1:8096:8096" ];
|
||||
environment = commonEnv;
|
||||
volumes = [
|
||||
"/var/lib/nixarr/jellyfin:/config"
|
||||
"/data:/data"
|
||||
];
|
||||
};
|
||||
|
||||
jellyseerr = {
|
||||
image = "ghcr.io/fallenbagel/jellyseerr:latest";
|
||||
extraOptions = [ "--network=media" ];
|
||||
ports = [ "5055:5055" ];
|
||||
environment = commonEnv;
|
||||
volumes = [ "/var/lib/nixarr/jellyseerr:/app/config" ];
|
||||
};
|
||||
jellyseerr = {
|
||||
image = "ghcr.io/seerr-team/seerr:latest"; # Migrated from jellyseerr (stale) to seerr (v3+)
|
||||
labels = { "io.containers.autoupdate" = "registry"; };
|
||||
extraOptions = [
|
||||
"--init" # Required for Seerr
|
||||
"--network=media"
|
||||
"--dns=8.8.8.8"
|
||||
"--ip=10.89.0.3"
|
||||
"--add-host=sonarr:10.89.0.50"
|
||||
"--add-host=radarr:10.89.0.51"
|
||||
"--add-host=jellyfin:10.89.0.4"
|
||||
];
|
||||
ports = [ "127.0.0.1:5055:5055" ];
|
||||
environment = commonEnv;
|
||||
volumes = [ "/var/lib/nixarr/jellyseerr:/app/config" ];
|
||||
};
|
||||
|
||||
flaresolverr = {
|
||||
image = "ghcr.io/flaresolverr/flaresolverr:latest";
|
||||
extraOptions = [ "--network=container:vpn" ];
|
||||
dependsOn = [ "vpn" ];
|
||||
environment = {
|
||||
TZ = "Europe/Berlin";
|
||||
flaresolverr = {
|
||||
image = "ghcr.io/flaresolverr/flaresolverr:latest";
|
||||
labels = { "io.containers.autoupdate" = "registry"; };
|
||||
extraOptions = [ "--network=container:vpn" ];
|
||||
dependsOn = [ "vpn" ];
|
||||
environment = {
|
||||
TZ = "Europe/Berlin";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
# 3. Network Setup (Fixed)
|
||||
# Ensure the network is created before ANY container starts
|
||||
systemd.services.create-media-network = {
|
||||
script = ''
|
||||
${pkgs.podman}/bin/podman network exists media || ${pkgs.podman}/bin/podman network create --subnet 10.89.0.0/24 media
|
||||
'';
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
RemainAfterExit = true;
|
||||
# Removed 'User = ashie' -> Networks created by root are visible to root services
|
||||
};
|
||||
};
|
||||
|
||||
# Ensure containers wait for the network
|
||||
systemd.services."podman-vpn".requires = [ "create-media-network.service" ];
|
||||
systemd.services."podman-vpn".after = [ "create-media-network.service" ];
|
||||
# (Repeat for others if they don't depend on VPN, but usually unnecessary if they all join 'media')
|
||||
|
||||
# 4. Permissions
|
||||
systemd.tmpfiles.rules = [
|
||||
"d /data 0775 ${user} ${group} - -"
|
||||
"d /var/lib/nixarr/prowlarr 0755 ${user} ${group} - -"
|
||||
"d /var/lib/nixarr/sonarr 0755 ${user} ${group} - -"
|
||||
"d /var/lib/nixarr/radarr 0755 ${user} ${group} - -"
|
||||
"d /var/lib/nixarr/jellyfin 0755 ${user} ${group} - -"
|
||||
"d /var/lib/nixarr/jellyseerr 0755 ${user} ${group} - -"
|
||||
"d /var/lib/qbittorrent 0755 ${user} ${group} - -"
|
||||
];
|
||||
|
||||
users.users.${user}.extraGroups = [ "media" ];
|
||||
|
||||
# 5. Firewall
|
||||
networking.firewall.allowedTCPPorts = [
|
||||
80
|
||||
443
|
||||
36630
|
||||
9696
|
||||
];
|
||||
networking.firewall.allowedUDPPorts = [
|
||||
36630
|
||||
443
|
||||
];
|
||||
};
|
||||
|
||||
# 3. Network Setup (Fixed)
|
||||
# Ensure the network is created before ANY container starts
|
||||
systemd.services.create-media-network = {
|
||||
script = ''
|
||||
${pkgs.podman}/bin/podman network exists media || ${pkgs.podman}/bin/podman network create media
|
||||
'';
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
RemainAfterExit = true;
|
||||
# Removed 'User = ashie' -> Networks created by root are visible to root services
|
||||
};
|
||||
};
|
||||
|
||||
# Ensure containers wait for the network
|
||||
systemd.services."podman-vpn".requires = [ "create-media-network.service" ];
|
||||
systemd.services."podman-vpn".after = [ "create-media-network.service" ];
|
||||
# (Repeat for others if they don't depend on VPN, but usually unnecessary if they all join 'media')
|
||||
|
||||
# 4. Permissions
|
||||
systemd.tmpfiles.rules = [
|
||||
"d /data 0775 ${user} media - -"
|
||||
"d /var/lib/nixarr/prowlarr 0755 ${user} ${group} - -"
|
||||
"d /var/lib/nixarr/sonarr 0755 ${user} ${group} - -"
|
||||
"d /var/lib/nixarr/radarr 0755 ${user} ${group} - -"
|
||||
"d /var/lib/nixarr/jellyfin 0755 ${user} ${group} - -"
|
||||
"d /var/lib/nixarr/jellyseerr 0755 ${user} ${group} - -"
|
||||
"d /var/lib/qbittorrent 0755 ${user} ${group} - -"
|
||||
];
|
||||
|
||||
users.users.${user}.extraGroups = [ "media" ];
|
||||
|
||||
# 5. Firewall
|
||||
networking.firewall.allowedTCPPorts = [
|
||||
80
|
||||
443
|
||||
9696
|
||||
8989
|
||||
7878
|
||||
8096
|
||||
5055
|
||||
8080
|
||||
36630
|
||||
8082
|
||||
8191
|
||||
];
|
||||
networking.firewall.allowedUDPPorts = [
|
||||
36630
|
||||
443
|
||||
];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -147,6 +147,7 @@ in
|
|||
];
|
||||
ExecStart = ''
|
||||
${pkgs.podman}/bin/podman run --rm --name ollama \
|
||||
--label "io.containers.autoupdate=registry" \
|
||||
--network=antigravity-net \
|
||||
--network-alias=ollama \
|
||||
--dns=8.8.8.8 \
|
||||
|
|
|
|||
|
|
@ -112,6 +112,7 @@ in
|
|||
];
|
||||
ExecStart = ''
|
||||
${pkgs.podman}/bin/podman run --rm --name open-webui \
|
||||
--label "io.containers.autoupdate=registry" \
|
||||
--network=antigravity-net \
|
||||
--dns=8.8.8.8 \
|
||||
--userns=auto \
|
||||
|
|
|
|||
|
|
@ -8,7 +8,9 @@
|
|||
}:
|
||||
|
||||
let
|
||||
cfg = config.myModules.prismlauncherSandboxed;
|
||||
bwrapperPkgs = pkgs.extend inputs.nix-bwrapper.overlays.default;
|
||||
sandboxUtils = import ./sandbox-utils.nix { inherit pkgs lib; };
|
||||
|
||||
# Libraries required by Minecraft natives (LWJGL), various mods,
|
||||
# and the Microsoft authentication flow (NSS/NSPR).
|
||||
|
|
@ -48,153 +50,137 @@ let
|
|||
];
|
||||
in
|
||||
{
|
||||
nixpkgs.overlays = [
|
||||
(final: prev: {
|
||||
prismlauncher-sandboxed = bwrapperPkgs.mkBwrapper {
|
||||
app = {
|
||||
id = "org.prismlauncher.PrismLauncher";
|
||||
package = pkgs.prismlauncher.overrideAttrs (old: {
|
||||
pname = "prismlauncher";
|
||||
version = old.version or "9.1";
|
||||
buildInputs = (old.buildInputs or [ ]) ++ [ pkgs.mimalloc ];
|
||||
options.myModules.prismlauncherSandboxed = {
|
||||
enable = lib.mkEnableOption "sandboxed PrismLauncher with nix-bwrapper";
|
||||
|
||||
# Keep runtimeLibs in closure without injecting them into environment
|
||||
postInstall = (old.postInstall or "") + ''
|
||||
mkdir -p $out/share/prismlauncher-sandboxed
|
||||
echo "${lib.makeLibraryPath runtimeLibs}" > $out/share/prismlauncher-sandboxed/libs
|
||||
extraBindMounts = lib.mkOption {
|
||||
type = lib.types.listOf lib.types.str;
|
||||
default = [];
|
||||
description = "Extra paths to bind mount (read-write) into the sandbox";
|
||||
};
|
||||
};
|
||||
|
||||
config = lib.mkIf cfg.enable {
|
||||
nixpkgs.overlays = [
|
||||
(final: prev: {
|
||||
prismlauncher-sandboxed = bwrapperPkgs.mkBwrapper {
|
||||
app = {
|
||||
id = "org.prismlauncher.PrismLauncher";
|
||||
package = pkgs.prismlauncher.overrideAttrs (old: {
|
||||
pname = "prismlauncher";
|
||||
version = old.version or "9.1";
|
||||
buildInputs = (old.buildInputs or [ ]) ++ [ pkgs.mimalloc ];
|
||||
|
||||
# Keep runtimeLibs in closure without injecting them into environment
|
||||
postInstall = (old.postInstall or "") + ''
|
||||
mkdir -p $out/share/prismlauncher-sandboxed
|
||||
echo "${lib.makeLibraryPath runtimeLibs}" > $out/share/prismlauncher-sandboxed/libs
|
||||
'';
|
||||
|
||||
qtWrapperArgs = (old.qtWrapperArgs or [ ]) ++ [
|
||||
"--set MIMALLOC_PATH ${pkgs.mimalloc}/lib/libmimalloc.so"
|
||||
"--prefix LD_PRELOAD : ${pkgs.mimalloc}/lib/libmimalloc.so"
|
||||
];
|
||||
});
|
||||
|
||||
env = {
|
||||
# Propagate XDG_DATA_DIRS so themes/icons can be found
|
||||
# XDG_DATA_DIRS = "$XDG_DATA_DIRS";
|
||||
BROWSER = "firefox";
|
||||
QT_QPA_PLATFORMTHEME = "";
|
||||
QT_STYLE_OVERRIDE = "fusion";
|
||||
};
|
||||
};
|
||||
|
||||
sockets.x11 = true; # Old versions of minecraft require X11, and forge still doesnt care its breaking wayland.
|
||||
sockets.wayland = true;
|
||||
|
||||
flatpak.enable = false;
|
||||
|
||||
fhsenv.opts = {
|
||||
unshareUser = true;
|
||||
unshareUts = false;
|
||||
unshareCgroup = false;
|
||||
unsharePid = false;
|
||||
unshareNet = false;
|
||||
unshareIpc = false;
|
||||
};
|
||||
|
||||
fhsenv.bwrap.baseArgs = lib.mkForce (sandboxUtils.mkCommonBindArgs { inherit config lib; } ++ sandboxUtils.mkGamingBindArgs { } ++ [
|
||||
"--ro-bind /run/dbus /run/dbus"
|
||||
]);
|
||||
|
||||
mounts = {
|
||||
read = sandboxUtils.mkGuiMounts.read ++ [
|
||||
"$HOME/Downloads"
|
||||
];
|
||||
readWrite = [
|
||||
"$HOME/.local/share/PrismLauncher"
|
||||
"$HOME/.cache/PrismLauncher"
|
||||
] ++ cfg.extraBindMounts;
|
||||
};
|
||||
|
||||
dbus.enable = false;
|
||||
|
||||
script.preCmds.stage2 =
|
||||
let
|
||||
jvmArgs = "-XX:+UnlockExperimentalVMOptions -XX:+UnlockDiagnosticVMOptions -XX:+AlwaysActAsServerClassMachine -XX:+AlwaysPreTouch -XX:+DisableExplicitGC -XX:+UseNUMA -XX:NmethodSweepActivity=1 -XX:ReservedCodeCacheSize=400M -XX:NonNMethodCodeHeapSize=12M -XX:ProfiledCodeHeapSize=194M -XX:NonProfiledCodeHeapSize=194M -XX:-DontCompileHugeMethods -XX:MaxNodeLimit=240000 -XX:NodeLimitFudgeFactor=8000 -XX:+UseVectorCmov -XX:+PerfDisableSharedMem -XX:+UseFastUnorderedTimeStamps -XX:+UseCriticalJavaThreadPriority -XX:ThreadPriorityPolicy=1 -XX:AllocatePrefetchStyle=3 -XX:+UseShenandoahGC -XX:ShenandoahGCMode=iu -XX:ShenandoahGuaranteedGCInterval=1000000 -XX:AllocatePrefetchStyle=1 -XX:ConcGCThreads=4";
|
||||
glfwPath = "${pkgs.glfw}/lib/libglfw.so.3";
|
||||
|
||||
dbusScript = sandboxUtils.mkDbusProxyScript {
|
||||
appId = "org.prismlauncher.PrismLauncher";
|
||||
proxyArgs = [
|
||||
"--filter"
|
||||
''--talk="org.freedesktop.portal.*"''
|
||||
''--call="org.freedesktop.portal.*=*@/org/freedesktop/portal/desktop"''
|
||||
''--talk="org.freedesktop.Notifications"''
|
||||
''--own="org.prismlauncher.PrismLauncher"''
|
||||
''--own="org.prismlauncher.PrismLauncher.*"''
|
||||
];
|
||||
};
|
||||
in
|
||||
''
|
||||
${dbusScript}
|
||||
|
||||
# Force Configs (JVM Args + GLFW)
|
||||
cfg="$HOME/.local/share/PrismLauncher/prismlauncher.cfg"
|
||||
if [ -f "$cfg" ]; then
|
||||
# JVM Args
|
||||
if ${pkgs.gnugrep}/bin/grep -q "^JvmArgs=" "$cfg"; then
|
||||
${pkgs.gnused}/bin/sed -i "s|^JvmArgs=.*|JvmArgs=${jvmArgs}|" "$cfg"
|
||||
else
|
||||
if ${pkgs.gnugrep}/bin/grep -q "^\[General\]" "$cfg"; then
|
||||
${pkgs.gnused}/bin/sed -i "/^\[General\]/a JvmArgs=${jvmArgs}" "$cfg"
|
||||
else
|
||||
echo "JvmArgs=${jvmArgs}" >> "$cfg"
|
||||
fi
|
||||
fi
|
||||
|
||||
# GLFW Settings
|
||||
# 1. CustomGLFWPath
|
||||
if ${pkgs.gnugrep}/bin/grep -q "^CustomGLFWPath=" "$cfg"; then
|
||||
${pkgs.gnused}/bin/sed -i "s|^CustomGLFWPath=.*|CustomGLFWPath=${glfwPath}|" "$cfg"
|
||||
else
|
||||
echo "CustomGLFWPath=${glfwPath}" >> "$cfg"
|
||||
fi
|
||||
|
||||
# 2. UseNativeGLFW
|
||||
if ${pkgs.gnugrep}/bin/grep -q "^UseNativeGLFW=" "$cfg"; then
|
||||
${pkgs.gnused}/bin/sed -i "s|^UseNativeGLFW=.*|UseNativeGLFW=true|" "$cfg"
|
||||
else
|
||||
echo "UseNativeGLFW=true" >> "$cfg"
|
||||
fi
|
||||
fi
|
||||
'';
|
||||
|
||||
qtWrapperArgs = (old.qtWrapperArgs or [ ]) ++ [
|
||||
"--set MIMALLOC_PATH ${pkgs.mimalloc}/lib/libmimalloc.so"
|
||||
"--prefix LD_PRELOAD : ${pkgs.mimalloc}/lib/libmimalloc.so"
|
||||
];
|
||||
});
|
||||
|
||||
env = {
|
||||
# Propagate XDG_DATA_DIRS so themes/icons can be found
|
||||
# XDG_DATA_DIRS = "$XDG_DATA_DIRS";
|
||||
BROWSER = "firefox";
|
||||
QT_QPA_PLATFORMTHEME = "";
|
||||
QT_STYLE_OVERRIDE = "fusion";
|
||||
};
|
||||
};
|
||||
|
||||
sockets.x11 = true; # Old versions of minecraft require X11, and forge still doesnt care its breaking wayland.
|
||||
sockets.wayland = true;
|
||||
|
||||
flatpak.enable = false;
|
||||
|
||||
fhsenv.opts = {
|
||||
unshareUser = true;
|
||||
unshareUts = false;
|
||||
unshareCgroup = false;
|
||||
unsharePid = false;
|
||||
unshareNet = false;
|
||||
unshareIpc = false;
|
||||
};
|
||||
|
||||
fhsenv.bwrap.baseArgs = lib.mkForce [
|
||||
"--new-session"
|
||||
"--proc /proc"
|
||||
"--dev /dev"
|
||||
"--dev-bind /dev/dri /dev/dri"
|
||||
"--tmpfs /home"
|
||||
"--tmpfs /tmp"
|
||||
"--tmpfs /run"
|
||||
"--dir /run/user"
|
||||
"--dir /run/user/${toString config.users.users.ashie.uid}"
|
||||
# Bind ro system paths commonly needed
|
||||
# "--ro-bind-try /run/current-system /run/current-system"
|
||||
"--ro-bind-try /run/opengl-driver /run/opengl-driver"
|
||||
"--ro-bind-try /run/opengl-driver-32 /run/opengl-driver-32"
|
||||
"--dir /run/systemd/resolve"
|
||||
"--ro-bind-try /run/systemd/resolve /run/systemd/resolve"
|
||||
"--ro-bind /run/dbus /run/dbus"
|
||||
];
|
||||
|
||||
mounts = {
|
||||
read = [
|
||||
"$HOME/.config/fontconfig"
|
||||
"$HOME/.local/share/fonts"
|
||||
"$HOME/.icons"
|
||||
"$HOME/.themes"
|
||||
"$HOME/.local/share/themes"
|
||||
"$HOME/.config/qt6ct"
|
||||
"$HOME/.config/Kvantum"
|
||||
"$HOME/.config/MangoHud"
|
||||
"$HOME/Downloads"
|
||||
];
|
||||
readWrite = [
|
||||
"$HOME/.local/share/PrismLauncher"
|
||||
"$HOME/.cache/PrismLauncher"
|
||||
fhsenv.bwrap.additionalArgs = sandboxUtils.mkGuiBindArgs { } ++ [
|
||||
# D-Bus proxy
|
||||
''--bind "$XDG_RUNTIME_DIR/app/org.prismlauncher.PrismLauncher/bus" "$XDG_RUNTIME_DIR/bus"''
|
||||
];
|
||||
};
|
||||
})
|
||||
];
|
||||
|
||||
dbus.enable = false;
|
||||
|
||||
script.preCmds.stage2 =
|
||||
let
|
||||
jvmArgs = "-XX:+UnlockExperimentalVMOptions -XX:+UnlockDiagnosticVMOptions -XX:+AlwaysActAsServerClassMachine -XX:+AlwaysPreTouch -XX:+DisableExplicitGC -XX:+UseNUMA -XX:NmethodSweepActivity=1 -XX:ReservedCodeCacheSize=400M -XX:NonNMethodCodeHeapSize=12M -XX:ProfiledCodeHeapSize=194M -XX:NonProfiledCodeHeapSize=194M -XX:-DontCompileHugeMethods -XX:MaxNodeLimit=240000 -XX:NodeLimitFudgeFactor=8000 -XX:+UseVectorCmov -XX:+PerfDisableSharedMem -XX:+UseFastUnorderedTimeStamps -XX:+UseCriticalJavaThreadPriority -XX:ThreadPriorityPolicy=1 -XX:AllocatePrefetchStyle=3 -XX:+UseShenandoahGC -XX:ShenandoahGCMode=iu -XX:ShenandoahGuaranteedGCInterval=1000000 -XX:AllocatePrefetchStyle=1 -XX:ConcGCThreads=4";
|
||||
glfwPath = "${pkgs.glfw}/lib/libglfw.so.3";
|
||||
|
||||
dbusScript = (import ./sandbox-utils.nix { inherit pkgs lib; }).mkDbusProxyScript {
|
||||
appId = "org.prismlauncher.PrismLauncher";
|
||||
proxyArgs = [
|
||||
"--filter"
|
||||
''--talk="org.freedesktop.portal.*"''
|
||||
''--call="org.freedesktop.portal.*=*@/org/freedesktop/portal/desktop"''
|
||||
''--talk="org.freedesktop.Notifications"''
|
||||
''--own="org.prismlauncher.PrismLauncher"''
|
||||
''--own="org.prismlauncher.PrismLauncher.*"''
|
||||
];
|
||||
};
|
||||
in
|
||||
''
|
||||
${dbusScript}
|
||||
|
||||
# Force Configs (JVM Args + GLFW)
|
||||
cfg="$HOME/.local/share/PrismLauncher/prismlauncher.cfg"
|
||||
if [ -f "$cfg" ]; then
|
||||
# JVM Args
|
||||
if ${pkgs.gnugrep}/bin/grep -q "^JvmArgs=" "$cfg"; then
|
||||
${pkgs.gnused}/bin/sed -i "s|^JvmArgs=.*|JvmArgs=${jvmArgs}|" "$cfg"
|
||||
else
|
||||
if ${pkgs.gnugrep}/bin/grep -q "^\[General\]" "$cfg"; then
|
||||
${pkgs.gnused}/bin/sed -i "/^\[General\]/a JvmArgs=${jvmArgs}" "$cfg"
|
||||
else
|
||||
echo "JvmArgs=${jvmArgs}" >> "$cfg"
|
||||
fi
|
||||
fi
|
||||
|
||||
# GLFW Settings
|
||||
# 1. CustomGLFWPath
|
||||
if ${pkgs.gnugrep}/bin/grep -q "^CustomGLFWPath=" "$cfg"; then
|
||||
${pkgs.gnused}/bin/sed -i "s|^CustomGLFWPath=.*|CustomGLFWPath=${glfwPath}|" "$cfg"
|
||||
else
|
||||
echo "CustomGLFWPath=${glfwPath}" >> "$cfg"
|
||||
fi
|
||||
|
||||
# 2. UseNativeGLFW
|
||||
if ${pkgs.gnugrep}/bin/grep -q "^UseNativeGLFW=" "$cfg"; then
|
||||
${pkgs.gnused}/bin/sed -i "s|^UseNativeGLFW=.*|UseNativeGLFW=true|" "$cfg"
|
||||
else
|
||||
echo "UseNativeGLFW=true" >> "$cfg"
|
||||
fi
|
||||
fi
|
||||
'';
|
||||
|
||||
fhsenv.bwrap.additionalArgs = [
|
||||
# D-Bus proxy
|
||||
''--bind "$XDG_RUNTIME_DIR/app/org.prismlauncher.PrismLauncher/bus" "$XDG_RUNTIME_DIR/bus"''
|
||||
|
||||
# Wayland socket
|
||||
''--bind "$XDG_RUNTIME_DIR/$WAYLAND_DISPLAY" "$XDG_RUNTIME_DIR/$WAYLAND_DISPLAY"''
|
||||
|
||||
# PipeWire + Pulse (PipeWire hosts both)
|
||||
''--bind "$XDG_RUNTIME_DIR/pipewire-0" "$XDG_RUNTIME_DIR/pipewire-0"''
|
||||
''--bind "$XDG_RUNTIME_DIR/pulse" "$XDG_RUNTIME_DIR/pulse"''
|
||||
];
|
||||
};
|
||||
})
|
||||
];
|
||||
environment.systemPackages = [ pkgs.prismlauncher-sandboxed ];
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,6 +16,8 @@
|
|||
|
||||
let
|
||||
cfg = config.myModules.redlib;
|
||||
mainUser = config.myModules.system.mainUser;
|
||||
mainUserUid = toString config.users.users.${mainUser}.uid;
|
||||
in
|
||||
{
|
||||
options.myModules.redlib = {
|
||||
|
|
@ -34,6 +36,7 @@ in
|
|||
# Redlib Container
|
||||
virtualisation.oci-containers.containers."redlib" = {
|
||||
image = "quay.io/redlib/redlib:latest";
|
||||
labels = { "io.containers.autoupdate" = "registry"; };
|
||||
# ports = [ "127.0.0.1:${toString cfg.port}:8080" ]; # Port exposed via VPN
|
||||
extraOptions = [
|
||||
"--pull=always"
|
||||
|
|
@ -44,20 +47,20 @@ in
|
|||
};
|
||||
|
||||
# Rootless Overrides
|
||||
systemd.services."podman-redlib".serviceConfig.User = lib.mkForce "ashie";
|
||||
systemd.services."podman-redlib".serviceConfig.User = lib.mkForce mainUser;
|
||||
systemd.services."podman-redlib".environment = {
|
||||
HOME = "/home/ashie";
|
||||
XDG_RUNTIME_DIR = "/run/user/1000";
|
||||
HOME = "/home/${mainUser}";
|
||||
XDG_RUNTIME_DIR = "/run/user/${mainUserUid}";
|
||||
};
|
||||
systemd.services."podman-redlib".serviceConfig.Type = lib.mkForce "simple";
|
||||
systemd.services."podman-redlib".serviceConfig.Delegate = true;
|
||||
systemd.services."podman-redlib".after = [
|
||||
"user-runtime-dir@1000.service"
|
||||
"user-runtime-dir@${mainUserUid}.service"
|
||||
"podman-vpn.service"
|
||||
];
|
||||
systemd.services."podman-redlib".requires = [
|
||||
"user-runtime-dir@1000.service"
|
||||
"user-runtime-dir@${mainUserUid}.service"
|
||||
"podman-vpn.service"
|
||||
];
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -7,122 +7,114 @@
|
|||
}:
|
||||
|
||||
let
|
||||
cfg = config.myModules.ryubingSandboxed;
|
||||
bwrapperPkgs = pkgs.extend inputs.nix-bwrapper.overlays.default;
|
||||
sandboxUtils = import ./sandbox-utils.nix { inherit pkgs lib; };
|
||||
|
||||
appId = "org.ryubing.Ryubing";
|
||||
in
|
||||
{
|
||||
nixpkgs.overlays = [
|
||||
(final: prev: {
|
||||
ryubing-sandboxed = bwrapperPkgs.mkBwrapper {
|
||||
app = {
|
||||
package = pkgs.ryubing;
|
||||
id = appId;
|
||||
env = {
|
||||
XDG_DATA_DIRS = "$XDG_DATA_DIRS";
|
||||
# Ryubing uses Avalonia which works better with X11
|
||||
AVALONIA_SCREEN_SCALE_FACTOR = "1";
|
||||
options.myModules.ryubingSandboxed = {
|
||||
enable = lib.mkEnableOption "sandboxed Ryubing with nix-bwrapper";
|
||||
|
||||
extraBindMounts = lib.mkOption {
|
||||
type = lib.types.listOf lib.types.str;
|
||||
default = [];
|
||||
description = "Extra paths to bind mount (read-write) into the sandbox";
|
||||
};
|
||||
};
|
||||
|
||||
config = lib.mkIf cfg.enable {
|
||||
nixpkgs.overlays = [
|
||||
(final: prev: {
|
||||
ryubing-sandboxed = bwrapperPkgs.mkBwrapper {
|
||||
app = {
|
||||
package = pkgs.ryubing;
|
||||
id = appId;
|
||||
env = {
|
||||
XDG_DATA_DIRS = "$XDG_DATA_DIRS";
|
||||
# Ryubing uses Avalonia which works better with X11
|
||||
AVALONIA_SCREEN_SCALE_FACTOR = "1";
|
||||
};
|
||||
};
|
||||
|
||||
# Enable X11 and Wayland
|
||||
sockets.x11 = true;
|
||||
sockets.wayland = true;
|
||||
|
||||
# Disable Flatpak emulation
|
||||
flatpak.enable = false;
|
||||
|
||||
fhsenv.opts = {
|
||||
unshareUser = true;
|
||||
unshareUts = false;
|
||||
unshareCgroup = false;
|
||||
unsharePid = false;
|
||||
unshareNet = false; # Need network for online features
|
||||
unshareIpc = false;
|
||||
};
|
||||
|
||||
fhsenv.bwrap.baseArgs = lib.mkForce (sandboxUtils.mkCommonBindArgs { inherit config lib; } ++ sandboxUtils.mkGamingBindArgs { } ++ [
|
||||
# Fix for amdgpu.ids missing - use tmpfs so mkdir can succeed
|
||||
"--tmpfs /usr/share"
|
||||
"--ro-bind ${pkgs.libdrm}/share/libdrm /usr/share/libdrm"
|
||||
"--ro-bind-try /nix/store /nix/store"
|
||||
]);
|
||||
|
||||
# Disable built-in DBus module (invokes bwrap without --unshare-user)
|
||||
dbus.enable = false;
|
||||
|
||||
# Manually set up DBus proxy with --unshare-user (session bus only)
|
||||
# Also create required directories before bwrap runs
|
||||
script.preCmds.stage2 = ''
|
||||
# Create directories that bwrap will bind
|
||||
# Note: Ryubing still uses Ryujinx config paths
|
||||
mkdir -p "$HOME/.config/Ryujinx/system"
|
||||
mkdir -p "$HOME/.config/Ryujinx/bis/system/Contents/registered"
|
||||
mkdir -p "$HOME/.local/share/Ryujinx"
|
||||
mkdir -p "$HOME/Games/Switch"
|
||||
''
|
||||
+ sandboxUtils.mkDbusProxyScript {
|
||||
inherit appId;
|
||||
enableSystemBus = false;
|
||||
proxyArgs = [
|
||||
"--filter"
|
||||
''--talk="org.freedesktop.portal.Desktop"''
|
||||
''--talk="org.freedesktop.portal.OpenURI"''
|
||||
''--talk="org.freedesktop.portal.FileChooser"''
|
||||
''--talk="org.freedesktop.portal.*"''
|
||||
''--call="org.freedesktop.portal.*=*@/org/freedesktop/portal/desktop"''
|
||||
''--talk="org.freedesktop.Notifications"''
|
||||
''--talk="org.freedesktop.ScreenSaver"''
|
||||
''--talk="org.kde.StatusNotifierWatcher"''
|
||||
''--talk="org.kde.KWin"''
|
||||
''--talk="org.gnome.Mutter.DisplayConfig"''
|
||||
''--talk="org.freedesktop.secrets"''
|
||||
|
||||
''--talk="com.feralinteractive.GameMode"''
|
||||
''--own="${appId}"''
|
||||
''--own="${appId}.*"''
|
||||
];
|
||||
};
|
||||
|
||||
fhsenv.bwrap.additionalArgs = sandboxUtils.mkGuiBindArgs { } ++ [
|
||||
# D-Bus session proxy only
|
||||
''--bind "$XDG_RUNTIME_DIR/app/${appId}/bus" "$XDG_RUNTIME_DIR/bus"''
|
||||
|
||||
# Read-write mounts
|
||||
"--bind $HOME/Games/Switch $HOME/Games/Switch"
|
||||
"--bind $HOME/.config/Ryujinx $HOME/.config/Ryujinx"
|
||||
"--bind $HOME/.local/share/Ryujinx $HOME/.local/share/Ryujinx"
|
||||
];
|
||||
|
||||
mounts = {
|
||||
read = sandboxUtils.mkGuiMounts.read;
|
||||
readWrite = cfg.extraBindMounts;
|
||||
};
|
||||
};
|
||||
})
|
||||
];
|
||||
|
||||
# Enable X11 and Wayland
|
||||
sockets.x11 = true;
|
||||
sockets.wayland = true;
|
||||
|
||||
# Disable Flatpak emulation
|
||||
flatpak.enable = false;
|
||||
|
||||
fhsenv.opts = {
|
||||
unshareUser = true;
|
||||
unshareUts = false;
|
||||
unshareCgroup = false;
|
||||
unsharePid = false;
|
||||
unshareNet = false; # Need network for online features
|
||||
unshareIpc = false;
|
||||
};
|
||||
|
||||
fhsenv.bwrap.baseArgs = lib.mkForce [
|
||||
"--new-session"
|
||||
"--proc /proc"
|
||||
"--dev /dev"
|
||||
"--dev-bind /dev/dri /dev/dri" # GPU acceleration
|
||||
"--dev-bind /dev/shm /dev/shm" # Shared memory
|
||||
"--dev-bind-try /dev/uinput /dev/uinput" # Controller support
|
||||
"--dev-bind-try /dev/input /dev/input"
|
||||
"--tmpfs /home"
|
||||
"--tmpfs /tmp"
|
||||
"--tmpfs /run"
|
||||
"--dir /run/user"
|
||||
"--dir /run/user/${toString config.users.users.ashie.uid}"
|
||||
# Fix for amdgpu.ids missing - use tmpfs so mkdir can succeed
|
||||
"--tmpfs /usr/share"
|
||||
"--ro-bind ${pkgs.libdrm}/share/libdrm /usr/share/libdrm"
|
||||
# System paths
|
||||
"--ro-bind /sys /sys"
|
||||
"--ro-bind-try /run/current-system /run/current-system"
|
||||
"--ro-bind-try /run/opengl-driver /run/opengl-driver"
|
||||
"--ro-bind-try /run/opengl-driver-32 /run/opengl-driver-32"
|
||||
"--ro-bind-try /nix/store /nix/store"
|
||||
"--dir /run/systemd/resolve"
|
||||
"--ro-bind-try /run/systemd/resolve /run/systemd/resolve"
|
||||
# udev for controller hotplug
|
||||
"--ro-bind-try /run/udev /run/udev"
|
||||
];
|
||||
|
||||
# Disable built-in DBus module (invokes bwrap without --unshare-user)
|
||||
dbus.enable = false;
|
||||
|
||||
# Manually set up DBus proxy with --unshare-user (session bus only)
|
||||
# Also create required directories before bwrap runs
|
||||
script.preCmds.stage2 = ''
|
||||
# Create directories that bwrap will bind
|
||||
# Note: Ryubing still uses Ryujinx config paths
|
||||
mkdir -p "$HOME/.config/Ryujinx/system"
|
||||
mkdir -p "$HOME/.config/Ryujinx/bis/system/Contents/registered"
|
||||
mkdir -p "$HOME/.local/share/Ryujinx"
|
||||
mkdir -p "$HOME/Games/Switch"
|
||||
''
|
||||
+ (import ./sandbox-utils.nix { inherit pkgs lib; }).mkDbusProxyScript {
|
||||
inherit appId;
|
||||
enableSystemBus = false;
|
||||
proxyArgs = [
|
||||
"--filter"
|
||||
''--talk="org.freedesktop.portal.Desktop"''
|
||||
''--talk="org.freedesktop.portal.OpenURI"''
|
||||
''--talk="org.freedesktop.portal.FileChooser"''
|
||||
''--talk="org.freedesktop.portal.*"''
|
||||
''--call="org.freedesktop.portal.*=*@/org/freedesktop/portal/desktop"''
|
||||
''--talk="org.freedesktop.Notifications"''
|
||||
''--talk="org.freedesktop.ScreenSaver"''
|
||||
''--talk="org.kde.StatusNotifierWatcher"''
|
||||
''--talk="org.kde.KWin"''
|
||||
''--talk="org.gnome.Mutter.DisplayConfig"''
|
||||
''--talk="org.freedesktop.secrets"''
|
||||
|
||||
''--talk="com.feralinteractive.GameMode"''
|
||||
''--own="${appId}"''
|
||||
''--own="${appId}.*"''
|
||||
];
|
||||
};
|
||||
|
||||
fhsenv.bwrap.additionalArgs = [
|
||||
# D-Bus session proxy only
|
||||
''--bind "$XDG_RUNTIME_DIR/app/${appId}/bus" "$XDG_RUNTIME_DIR/bus"''
|
||||
|
||||
# Manual mounts for data persistence
|
||||
"--ro-bind-try $HOME/.config/kdedefaults $HOME/.config/kdedefaults"
|
||||
"--ro-bind-try $HOME/.local/share/color-schemes $HOME/.local/share/color-schemes"
|
||||
"--ro-bind-try $HOME/.config/fontconfig $HOME/.config/fontconfig"
|
||||
"--ro-bind-try $HOME/.local/share/fonts $HOME/.local/share/fonts"
|
||||
"--ro-bind-try $HOME/.icons $HOME/.icons"
|
||||
"--ro-bind-try $HOME/.themes $HOME/.themes"
|
||||
"--ro-bind-try $HOME/.config/MangoHud $HOME/.config/MangoHud"
|
||||
# Read-write mounts
|
||||
"--bind $HOME/Games/Switch $HOME/Games/Switch"
|
||||
"--bind $HOME/.config/Ryujinx $HOME/.config/Ryujinx"
|
||||
"--bind $HOME/.local/share/Ryujinx $HOME/.local/share/Ryujinx"
|
||||
];
|
||||
};
|
||||
})
|
||||
];
|
||||
environment.systemPackages = [ pkgs.ryubing-sandboxed ];
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,91 +1,311 @@
|
|||
{ pkgs, lib }:
|
||||
{
|
||||
|
||||
let
|
||||
# Generates the shell script content to set up xdg-dbus-proxy inside a bwrap user namespace.
|
||||
# This is used for sandboxed apps that run with unshareUser = true.
|
||||
mkDbusProxyScript = {
|
||||
appId, # Unique ID for the app (e.g. "org.mozilla.firefox")
|
||||
proxyArgs, # Arguments for xdg-dbus-proxy (session bus). Can be string or list.
|
||||
socketPath ? "$XDG_RUNTIME_DIR/app/${appId}/bus",
|
||||
upstreamSocket ? "$XDG_RUNTIME_DIR/bus",
|
||||
enableSystemBus ? false,
|
||||
systemProxyArgs ? "", # Arguments for xdg-dbus-proxy (system bus). Can be string or list.
|
||||
systemSocketPath ? "$XDG_RUNTIME_DIR/app/${appId}/bus_system",
|
||||
systemUpstreamSocket ? "/run/dbus/system_bus_socket"
|
||||
}:
|
||||
let
|
||||
bwrap = "${pkgs.bubblewrap}/bin/bwrap";
|
||||
dbusProxy = "${pkgs.xdg-dbus-proxy}/bin/xdg-dbus-proxy";
|
||||
coreutils = "${pkgs.coreutils}/bin";
|
||||
|
||||
# Helper to normalize args (support list or string)
|
||||
normalizeArgs = args: if builtins.isList args then lib.concatStringsSep " " args else args;
|
||||
pArgs = normalizeArgs proxyArgs;
|
||||
sArgs = normalizeArgs systemProxyArgs;
|
||||
mkDbusProxyScript =
|
||||
{
|
||||
appId,
|
||||
# Unique ID for the app (e.g. "org.mozilla.firefox")
|
||||
proxyArgs, # Arguments for xdg-dbus-proxy (session bus). Can be string or list.
|
||||
socketPath ? "$XDG_RUNTIME_DIR/app/${appId}/bus",
|
||||
upstreamSocket ? "$XDG_RUNTIME_DIR/bus",
|
||||
enableSystemBus ? false,
|
||||
systemProxyArgs ? "", # Arguments for xdg-dbus-proxy (system bus). Can be string or list.
|
||||
systemSocketPath ? "$XDG_RUNTIME_DIR/app/${appId}/bus_system",
|
||||
systemUpstreamSocket ? "/run/dbus/system_bus_socket",
|
||||
}:
|
||||
let
|
||||
bwrap = "${pkgs.bubblewrap}/bin/bwrap";
|
||||
dbusProxy = "${pkgs.xdg-dbus-proxy}/bin/xdg-dbus-proxy";
|
||||
coreutils = "${pkgs.coreutils}/bin";
|
||||
|
||||
# Helper to generate the function definition
|
||||
# We bind XDG_RUNTIME_DIR to allow creating the socket.
|
||||
# We optionally bind /run/dbus for the system bus socket.
|
||||
mkProxyFunc = name: upstream: sock: args: bindSystem: ''
|
||||
${name}() {
|
||||
${coreutils}/mkdir -p "$(${coreutils}/dirname "${sock}")"
|
||||
${bwrap} \
|
||||
--unshare-user \
|
||||
--dev /dev \
|
||||
--proc /proc \
|
||||
--new-session \
|
||||
--ro-bind /nix/store /nix/store \
|
||||
--bind "$XDG_RUNTIME_DIR" "$XDG_RUNTIME_DIR" \
|
||||
${if bindSystem then "--ro-bind /run/dbus /run/dbus" else ""} \
|
||||
--die-with-parent \
|
||||
--clearenv \
|
||||
-- \
|
||||
${dbusProxy} "unix:path=${upstream}" "${sock}" ${args}
|
||||
# Helper to normalize args (support list or string)
|
||||
normalizeArgs = args: if builtins.isList args then lib.concatStringsSep " " args else args;
|
||||
pArgs = normalizeArgs proxyArgs;
|
||||
sArgs = normalizeArgs systemProxyArgs;
|
||||
|
||||
# Helper to generate the function definition
|
||||
# We bind XDG_RUNTIME_DIR to allow creating the socket.
|
||||
# We optionally bind /run/dbus for the system bus socket.
|
||||
mkProxyFunc = name: upstream: sock: args: bindSystem: ''
|
||||
${name}() {
|
||||
${coreutils}/mkdir -p "$(${coreutils}/dirname "${sock}")"
|
||||
${bwrap} \
|
||||
--unshare-user \
|
||||
--dev /dev \
|
||||
--proc /proc \
|
||||
--new-session \
|
||||
--ro-bind /nix/store /nix/store \
|
||||
--bind "$XDG_RUNTIME_DIR" "$XDG_RUNTIME_DIR" \
|
||||
${if bindSystem then "--ro-bind /run/dbus /run/dbus" else ""} \
|
||||
--die-with-parent \
|
||||
--clearenv \
|
||||
-- \
|
||||
${dbusProxy} "unix:path=${upstream}" "${sock}" ${args}
|
||||
}
|
||||
'';
|
||||
|
||||
sessionFunc = mkProxyFunc "set_up_dbus_proxy" upstreamSocket socketPath pArgs false;
|
||||
systemFunc =
|
||||
if enableSystemBus then
|
||||
mkProxyFunc "set_up_system_dbus_proxy" systemUpstreamSocket systemSocketPath sArgs true
|
||||
else
|
||||
"";
|
||||
|
||||
waitLoop = ''
|
||||
# Wait for socket(s) with fail-fast check
|
||||
for i in $(${coreutils}/seq 1 50);
|
||||
do
|
||||
# Check if processes are still running
|
||||
if ! kill -0 "$PID_SESSION" 2>/dev/null;
|
||||
then
|
||||
echo "Error: Session D-Bus proxy (PID $PID_SESSION) died unexpectedly." >&2
|
||||
exit 1
|
||||
fi
|
||||
${
|
||||
if enableSystemBus then
|
||||
''
|
||||
if ! kill -0 "$PID_SYSTEM" 2>/dev/null;
|
||||
then
|
||||
echo "Error: System D-Bus proxy (PID $PID_SYSTEM) died unexpectedly." >&2
|
||||
exit 1
|
||||
fi
|
||||
''
|
||||
else
|
||||
""
|
||||
}
|
||||
|
||||
# Check for sockets
|
||||
if [ -S "${socketPath}" ]${if enableSystemBus then " && [ -S \"${systemSocketPath}\" ]" else ""};
|
||||
then
|
||||
break
|
||||
fi
|
||||
${coreutils}/sleep 0.02
|
||||
done
|
||||
'';
|
||||
|
||||
in
|
||||
''
|
||||
${sessionFunc}
|
||||
${systemFunc}
|
||||
|
||||
set_up_dbus_proxy &
|
||||
PID_SESSION=$!
|
||||
${
|
||||
if enableSystemBus then
|
||||
''
|
||||
set_up_system_dbus_proxy &
|
||||
PID_SYSTEM=$!
|
||||
''
|
||||
else
|
||||
""
|
||||
}
|
||||
|
||||
${waitLoop}
|
||||
'';
|
||||
|
||||
sessionFunc = mkProxyFunc "set_up_dbus_proxy" upstreamSocket socketPath pArgs false;
|
||||
systemFunc = if enableSystemBus
|
||||
then mkProxyFunc "set_up_system_dbus_proxy" systemUpstreamSocket systemSocketPath sArgs true
|
||||
else "";
|
||||
|
||||
waitLoop = ''
|
||||
# Wait for socket(s) with fail-fast check
|
||||
for i in $(${coreutils}/seq 1 50);
|
||||
do
|
||||
# Check if processes are still running
|
||||
if ! kill -0 "$PID_SESSION" 2>/dev/null;
|
||||
then
|
||||
echo "Error: Session D-Bus proxy (PID $PID_SESSION) died unexpectedly." >&2
|
||||
exit 1
|
||||
fi
|
||||
${if enableSystemBus then ''
|
||||
if ! kill -0 "$PID_SYSTEM" 2>/dev/null;
|
||||
then
|
||||
echo "Error: System D-Bus proxy (PID $PID_SYSTEM) died unexpectedly." >&2
|
||||
exit 1
|
||||
fi
|
||||
'' else ""}
|
||||
# Standard Common Binds (System Essentials)
|
||||
mkCommonBindArgs =
|
||||
{ config, lib }:
|
||||
[
|
||||
"--new-session"
|
||||
"--proc /proc"
|
||||
"--dev /dev"
|
||||
"--dev-bind-try /dev/ntsync /dev/ntsync"
|
||||
"--tmpfs /home"
|
||||
"--tmpfs /tmp"
|
||||
"--tmpfs /run"
|
||||
"--dir /run/user"
|
||||
"--dir /run/user/${toString config.users.users.${config.myModules.system.mainUser}.uid}"
|
||||
"--ro-bind /sys /sys"
|
||||
"--ro-bind-try /run/current-system /run/current-system"
|
||||
"--dir /run/systemd/resolve"
|
||||
"--ro-bind-try /run/systemd/resolve /run/systemd/resolve"
|
||||
"--unsetenv LD_PRELOAD"
|
||||
];
|
||||
|
||||
# Check for sockets
|
||||
if [ -S "${socketPath}" ]${if enableSystemBus then " && [ -S \"${systemSocketPath}\" ]" else ""};
|
||||
then
|
||||
break
|
||||
fi
|
||||
${coreutils}/sleep 0.02
|
||||
done
|
||||
'';
|
||||
# GUI Application Binds (Fonts, Themes, Wayland/X11 sockets)
|
||||
mkGuiBindArgs =
|
||||
{ }:
|
||||
[
|
||||
# Wayland socket
|
||||
''--bind "$XDG_RUNTIME_DIR/$WAYLAND_DISPLAY" "$XDG_RUNTIME_DIR/$WAYLAND_DISPLAY"''
|
||||
# PipeWire + Pulse
|
||||
''--bind "$XDG_RUNTIME_DIR/pipewire-0" "$XDG_RUNTIME_DIR/pipewire-0"''
|
||||
''--bind "$XDG_RUNTIME_DIR/pulse" "$XDG_RUNTIME_DIR/pulse"''
|
||||
];
|
||||
|
||||
in ''
|
||||
${sessionFunc}
|
||||
${systemFunc}
|
||||
# GUI Mounts (Fonts, Configs)
|
||||
mkGuiMounts = {
|
||||
read = [
|
||||
"$HOME/.config/fontconfig"
|
||||
"$HOME/.local/share/fonts"
|
||||
"$HOME/.icons"
|
||||
"$HOME/.themes"
|
||||
"$HOME/.local/share/themes"
|
||||
"$HOME/.config/qt6ct"
|
||||
"$HOME/.config/Kvantum"
|
||||
"$HOME/.config/MangoHud"
|
||||
"$HOME/.config/kdedefaults"
|
||||
"$HOME/.local/share/color-schemes"
|
||||
"$HOME/.config/gtk-3.0"
|
||||
"$HOME/.config/gtk-4.0"
|
||||
];
|
||||
};
|
||||
|
||||
set_up_dbus_proxy &
|
||||
PID_SESSION=$!
|
||||
${if enableSystemBus then ''
|
||||
set_up_system_dbus_proxy &
|
||||
PID_SYSTEM=$!
|
||||
'' else ""}
|
||||
|
||||
${waitLoop}
|
||||
'';
|
||||
}
|
||||
# Gaming Binds (GPU, Controllers, Input)
|
||||
mkGamingBindArgs =
|
||||
{ }:
|
||||
[
|
||||
"--dev-bind /dev/dri /dev/dri" # GPU
|
||||
"--dev-bind /dev/shm /dev/shm" # Shared Mem
|
||||
"--dev-bind-try /dev/uinput /dev/uinput"
|
||||
"--dev-bind-try /dev/input /dev/input"
|
||||
"--dev-bind-try /dev/hidraw0 /dev/hidraw0"
|
||||
"--dev-bind-try /dev/hidraw1 /dev/hidraw1"
|
||||
"--dev-bind-try /dev/hidraw2 /dev/hidraw2"
|
||||
"--dev-bind-try /dev/hidraw3 /dev/hidraw3"
|
||||
"--ro-bind-try /run/opengl-driver /run/opengl-driver"
|
||||
"--ro-bind-try /run/opengl-driver-32 /run/opengl-driver-32"
|
||||
"--ro-bind-try /run/udev /run/udev"
|
||||
];
|
||||
|
||||
# Helper to create a sandboxed application module
|
||||
mkSandboxedApp =
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
inputs,
|
||||
optionName, # e.g. "steamSandboxed"
|
||||
packageName, # e.g. "steam-sandboxed"
|
||||
description,
|
||||
package, # e.g. pkgs.steam
|
||||
appId, # e.g. "com.valvesoftware.Steam"
|
||||
isFhsenv ? false,
|
||||
env ? { },
|
||||
sockets ? {
|
||||
x11 = true;
|
||||
wayland = true;
|
||||
},
|
||||
flatpak ? false,
|
||||
|
||||
# Mounts
|
||||
mounts ? {
|
||||
read = [ ];
|
||||
readWrite = [ ];
|
||||
},
|
||||
|
||||
# Bwrap/Fhsenv options
|
||||
fhsenvOpts ? {
|
||||
unshareUser = true;
|
||||
unshareUts = false;
|
||||
unshareCgroup = false;
|
||||
unsharePid = false;
|
||||
unshareNet = false;
|
||||
unshareIpc = false;
|
||||
},
|
||||
fhsenvExtra ? { }, # merged into fhsenv
|
||||
|
||||
# Args
|
||||
baseArgs ? (mkCommonBindArgs { inherit config lib; }),
|
||||
additionalArgs ? [ ], # merged into fhsenv.bwrap.additionalArgs
|
||||
|
||||
# DBus
|
||||
dbusProxy ? null, # { rules ? [], systemRules ? [], enableSystemBus ? false }
|
||||
}:
|
||||
let
|
||||
cfg = config.myModules.${optionName};
|
||||
bwrapperPkgs = pkgs.extend inputs.nix-bwrapper.overlays.default;
|
||||
|
||||
# Handle DBus Proxy Logic
|
||||
hasDbusProxy = dbusProxy != null;
|
||||
proxyScript =
|
||||
if hasDbusProxy then
|
||||
mkDbusProxyScript {
|
||||
inherit appId;
|
||||
enableSystemBus = dbusProxy.enableSystemBus or false;
|
||||
proxyArgs = dbusProxy.rules or [ ];
|
||||
systemProxyArgs = dbusProxy.systemRules or [ ];
|
||||
}
|
||||
else
|
||||
"";
|
||||
|
||||
dbusBindArgs =
|
||||
if hasDbusProxy then
|
||||
[
|
||||
''--bind "$XDG_RUNTIME_DIR/app/${appId}/bus" "$XDG_RUNTIME_DIR/bus"''
|
||||
]
|
||||
++ (
|
||||
if (dbusProxy.enableSystemBus or false) then
|
||||
[
|
||||
''--bind "$XDG_RUNTIME_DIR/app/${appId}/bus_system" /run/dbus/system_bus_socket''
|
||||
]
|
||||
else
|
||||
[ ]
|
||||
)
|
||||
else
|
||||
[ ];
|
||||
|
||||
in
|
||||
{
|
||||
options.myModules.${optionName} = {
|
||||
enable = lib.mkEnableOption description;
|
||||
|
||||
extraBindMounts = lib.mkOption {
|
||||
type = lib.types.listOf lib.types.str;
|
||||
default = [ ];
|
||||
description = "Extra paths to bind mount (read-write) into the sandbox";
|
||||
};
|
||||
};
|
||||
|
||||
config = lib.mkIf cfg.enable {
|
||||
nixpkgs.overlays = [
|
||||
(final: prev: {
|
||||
${packageName} = bwrapperPkgs.mkBwrapper {
|
||||
app = {
|
||||
package = package;
|
||||
inherit isFhsenv;
|
||||
env = env;
|
||||
id = appId;
|
||||
};
|
||||
|
||||
inherit sockets;
|
||||
flatpak.enable = flatpak;
|
||||
|
||||
fhsenv = fhsenvExtra // {
|
||||
opts = fhsenvOpts;
|
||||
bwrap = {
|
||||
baseArgs = lib.mkForce baseArgs;
|
||||
additionalArgs = mkGuiBindArgs { } ++ additionalArgs ++ dbusBindArgs;
|
||||
};
|
||||
};
|
||||
|
||||
mounts = {
|
||||
read = mkGuiMounts.read ++ mounts.read;
|
||||
readWrite = mounts.readWrite ++ cfg.extraBindMounts;
|
||||
};
|
||||
|
||||
dbus.enable = false;
|
||||
|
||||
script.preCmds.stage2 = proxyScript;
|
||||
};
|
||||
})
|
||||
];
|
||||
|
||||
environment.systemPackages = [ pkgs.${packageName} ];
|
||||
};
|
||||
};
|
||||
|
||||
in
|
||||
{
|
||||
inherit
|
||||
mkDbusProxyScript
|
||||
mkCommonBindArgs
|
||||
mkGuiBindArgs
|
||||
mkGuiMounts
|
||||
mkGamingBindArgs
|
||||
mkSandboxedApp
|
||||
;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,189 +17,8 @@
|
|||
|
||||
let
|
||||
cfg = config.myModules.searxng;
|
||||
|
||||
catppuccinCss = pkgs.writeText "searxng-catppuccin.css" ''
|
||||
:root {
|
||||
/* Mocha (Dark) */
|
||||
--cat-rosewater: #f5e0dc;
|
||||
--cat-flamingo: #f2cdcd;
|
||||
--cat-pink: #f5c2e7;
|
||||
--cat-mauve: #cba6f7;
|
||||
--cat-red: #f38ba8;
|
||||
--cat-maroon: #eba0ac;
|
||||
--cat-peach: #fab387;
|
||||
--cat-yellow: #f9e2af;
|
||||
--cat-green: #a6e3a1;
|
||||
--cat-teal: #94e2d5;
|
||||
--cat-sky: #89dceb;
|
||||
--cat-sapphire: #74c7ec;
|
||||
--cat-blue: #89b4fa;
|
||||
--cat-lavender: #b4befe;
|
||||
--cat-text: #cdd6f4;
|
||||
--cat-subtext1: #bac2de;
|
||||
--cat-subtext0: #a6adc8;
|
||||
--cat-overlay2: #9399b2;
|
||||
--cat-overlay1: #7f849c;
|
||||
--cat-overlay0: #6c7086;
|
||||
--cat-surface2: #585b70;
|
||||
--cat-surface1: #45475a;
|
||||
--cat-surface0: #313244;
|
||||
--cat-base: #1e1e2e;
|
||||
--cat-mantle: #181825;
|
||||
--cat-crust: #11111b;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: light) {
|
||||
:root {
|
||||
/* Latte (Light) */
|
||||
--cat-rosewater: #dc8a78;
|
||||
--cat-flamingo: #dd7878;
|
||||
--cat-pink: #ea76cb;
|
||||
--cat-mauve: #8839ef;
|
||||
--cat-red: #d20f39;
|
||||
--cat-maroon: #e64553;
|
||||
--cat-peach: #fe640b;
|
||||
--cat-yellow: #df8e1d;
|
||||
--cat-green: #40a02b;
|
||||
--cat-teal: #179287;
|
||||
--cat-sky: #04a5e5;
|
||||
--cat-sapphire: #209fb5;
|
||||
--cat-blue: #1e66f5;
|
||||
--cat-lavender: #7287fd;
|
||||
--cat-text: #4c4f69;
|
||||
--cat-subtext1: #5c5f77;
|
||||
--cat-subtext0: #6c6f85;
|
||||
--cat-overlay2: #7c7f93;
|
||||
--cat-overlay1: #8c8fa1;
|
||||
--cat-overlay0: #9ca0b0;
|
||||
--cat-surface2: #acb0be;
|
||||
--cat-surface1: #bcc0cc;
|
||||
--cat-surface0: #ccd0da;
|
||||
--cat-base: #eff1f5;
|
||||
--cat-mantle: #e6e9ef;
|
||||
--cat-crust: #dce0e8;
|
||||
}
|
||||
}
|
||||
|
||||
/* Apply variables */
|
||||
:root {
|
||||
--color-base-font: var(--cat-text);
|
||||
--color-base-background: var(--cat-base);
|
||||
--color-base-background-mobile: var(--cat-base);
|
||||
--color-url-font: var(--cat-mauve);
|
||||
--color-url-visited-font: var(--cat-mauve);
|
||||
--color-header-background: var(--cat-mantle);
|
||||
--color-header-border: var(--cat-mantle);
|
||||
--color-footer-background: var(--cat-mantle);
|
||||
--color-footer-border: var(--cat-mantle);
|
||||
--color-sidebar-border: var(--cat-base);
|
||||
--color-sidebar-font: var(--cat-text);
|
||||
--color-sidebar-background: var(--cat-base);
|
||||
--color-backtotop-font: var(--cat-subtext1);
|
||||
--color-backtotop-border: var(--cat-surface0);
|
||||
--color-backtotop-background: var(--cat-surface0);
|
||||
--color-btn-background: var(--cat-mauve);
|
||||
--color-btn-font: var(--cat-base);
|
||||
--color-show-btn-background: var(--cat-mauve);
|
||||
--color-show-btn-font: var(--cat-base);
|
||||
--color-search-border: var(--cat-surface0);
|
||||
--color-search-shadow: 0 2px 8px var(--cat-crust);
|
||||
--color-search-background: var(--cat-surface0);
|
||||
--color-search-font: var(--cat-text);
|
||||
--color-search-background-hover: var(--cat-mauve);
|
||||
--color-error: var(--cat-red);
|
||||
--color-error-background: var(--cat-surface0);
|
||||
--color-warning: var(--cat-yellow);
|
||||
--color-warning-background: var(--cat-surface0);
|
||||
--color-success: var(--cat-green);
|
||||
--color-success-background: var(--cat-surface0);
|
||||
--color-categories-item-selected-font: var(--cat-text);
|
||||
--color-categories-item-border-selected: var(--cat-mauve);
|
||||
--color-autocomplete-font: var(--cat-subtext1);
|
||||
--color-autocomplete-border: var(--cat-surface0);
|
||||
--color-autocomplete-shadow: 0 2px 8px var(--cat-crust);
|
||||
--color-autocomplete-background: var(--cat-surface0);
|
||||
--color-autocomplete-background-hover: var(--cat-surface1);
|
||||
--color-answer-font: var(--cat-text);
|
||||
--color-answer-background: var(--cat-mantle);
|
||||
--color-result-background: var(--cat-mantle);
|
||||
--color-result-border: var(--cat-base);
|
||||
--color-result-url-font: var(--cat-subtext1);
|
||||
--color-result-vim-selected: var(--cat-surface0);
|
||||
--color-result-vim-arrow: var(--cat-mauve);
|
||||
--color-result-description-highlight-font: var(--cat-text);
|
||||
--color-result-link-font: var(--cat-mauve);
|
||||
--color-result-link-font-highlight: var(--cat-mauve);
|
||||
--color-result-link-visited-font: var(--cat-mauve);
|
||||
--color-result-publishdate-font: var(--cat-surface2);
|
||||
--color-result-engines-font: var(--cat-surface2);
|
||||
--color-result-search-url-border: var(--cat-surface2);
|
||||
--color-result-search-url-font: var(--cat-text);
|
||||
--color-result-detail-font: var(--cat-text);
|
||||
--color-result-detail-label-font: var(--cat-subtext0);
|
||||
--color-result-detail-background: var(--cat-base);
|
||||
--color-result-detail-hr: var(--cat-base);
|
||||
--color-result-detail-link: var(--cat-mauve);
|
||||
--color-result-detail-loader-border: rgba(255, 255, 255, 0.2);
|
||||
--color-result-detail-loader-borderleft: var(--cat-crust);
|
||||
--color-result-image-span-font: var(--cat-text);
|
||||
--color-result-image-span-font-selected: var(--cat-base);
|
||||
--color-result-image-background: var(--cat-mantle);
|
||||
--color-settings-tr-hover: var(--cat-surface0);
|
||||
--color-settings-engine-description-font: var(--cat-text);
|
||||
--color-settings-engine-group-background: var(--cat-surface0);
|
||||
--color-toolkit-badge-font: var(--cat-text);
|
||||
--color-toolkit-badge-background: var(--cat-surface0);
|
||||
--color-toolkit-kbd-font: var(--cat-text);
|
||||
--color-toolkit-kbd-background: var(--cat-mantle);
|
||||
--color-toolkit-dialog-border: var(--cat-mantle);
|
||||
--color-toolkit-dialog-background: var(--cat-mantle);
|
||||
--color-toolkit-tabs-label-border: var(--cat-base);
|
||||
--color-toolkit-tabs-section-border: var(--cat-base);
|
||||
--color-toolkit-select-background: var(--cat-surface0);
|
||||
--color-toolkit-select-border: var(--cat-surface0);
|
||||
--color-toolkit-select-background-hover: var(--cat-surface1);
|
||||
--color-toolkit-input-text-font: var(--cat-text);
|
||||
--color-toolkit-checkbox-onoff-off-background: var(--cat-surface0);
|
||||
--color-toolkit-checkbox-onoff-on-background: var(--cat-surface0);
|
||||
--color-toolkit-checkbox-onoff-on-mark-background: var(--cat-green);
|
||||
--color-toolkit-checkbox-onoff-on-mark-color: var(--cat-mantle);
|
||||
--color-toolkit-checkbox-onoff-off-mark-background: var(--cat-red);
|
||||
--color-toolkit-checkbox-onoff-off-mark-color: var(--cat-mantle);
|
||||
--color-toolkit-checkbox-label-background: var(--cat-base);
|
||||
--color-toolkit-checkbox-label-border: var(--cat-mantle);
|
||||
--color-toolkit-checkbox-input-border: var(--cat-mauve);
|
||||
--color-toolkit-engine-tooltip-border: var(--cat-surface0);
|
||||
--color-toolkit-engine-tooltip-background: var(--cat-surface0);
|
||||
--color-toolkit-loader-border: rgba(255, 255, 255, 0.2);
|
||||
--color-toolkit-loader-borderleft: var(--cat-crust);
|
||||
--color-doc-code: var(--cat-rosewater);
|
||||
--color-doc-code-background: var(--cat-mantle);
|
||||
}
|
||||
|
||||
#search_logo svg :not([fill="none"]) {
|
||||
fill: var(--cat-mauve) !important;
|
||||
}
|
||||
#search_logo svg :not([stroke="none"]) {
|
||||
stroke: var(--cat-mauve) !important;
|
||||
}
|
||||
|
||||
/* Additional cute tweaks */
|
||||
article.result {
|
||||
background-color: var(--color-result-background);
|
||||
border-radius: 0.75em;
|
||||
padding: 0.75em;
|
||||
margin: 0.5em;
|
||||
border: 1px solid var(--cat-surface0);
|
||||
}
|
||||
article.category-images {
|
||||
padding-bottom: 4em;
|
||||
}
|
||||
input[type="text"] {
|
||||
border-radius: 2em !important;
|
||||
}
|
||||
'';
|
||||
|
||||
mainUser = config.myModules.system.mainUser;
|
||||
mainUserUid = toString config.users.users.${mainUser}.uid;
|
||||
anubisPolicy = pkgs.writeText "anubis-policy.yml" ''
|
||||
bots:
|
||||
- name: "Allow OpenSearch"
|
||||
|
|
@ -217,6 +36,10 @@ let
|
|||
[favicons.cache]
|
||||
db_url = "/var/cache/searxng/faviconcache.db"
|
||||
LIMIT_TOTAL_BYTES = 2147483648
|
||||
|
||||
[favicons.proxy.resolver_map]
|
||||
google = "searx.favicons.resolver.google_resolver"
|
||||
duckduckgo = "searx.favicons.resolver.duckduckgo_resolver"
|
||||
'';
|
||||
in
|
||||
{
|
||||
|
|
@ -251,25 +74,32 @@ in
|
|||
# 1. Create Bridge Network
|
||||
systemd.services."create-searxng-network" = {
|
||||
serviceConfig.Type = "oneshot";
|
||||
serviceConfig.User = "ashie";
|
||||
serviceConfig.User = mainUser;
|
||||
serviceConfig.RemainAfterExit = true;
|
||||
after = [ "user-runtime-dir@1000.service" ];
|
||||
requires = [ "user-runtime-dir@1000.service" ];
|
||||
after = [ "user-runtime-dir@${mainUserUid}.service" ];
|
||||
requires = [ "user-runtime-dir@${mainUserUid}.service" ];
|
||||
path = [
|
||||
pkgs.podman
|
||||
pkgs.shadow
|
||||
];
|
||||
script = ''
|
||||
export PATH=/run/wrappers/bin:$PATH
|
||||
export XDG_RUNTIME_DIR="/run/user/1000"
|
||||
export HOME="/home/ashie"
|
||||
podman network create searxng-net --subnet 10.89.2.0/24 --ignore
|
||||
export XDG_RUNTIME_DIR="/run/user/${mainUserUid}"
|
||||
export HOME="/home/${mainUser}"
|
||||
|
||||
if ! podman network exists searxng-net; then
|
||||
echo "Creating searxng-net..."
|
||||
podman network create searxng-net --subnet 10.89.2.0/24
|
||||
else
|
||||
echo "searxng-net already exists."
|
||||
fi
|
||||
'';
|
||||
};
|
||||
|
||||
# 2. Valkey Container (Cache/Limiter)
|
||||
virtualisation.oci-containers.containers."searxng-valkey" = {
|
||||
image = "docker.io/valkey/valkey:alpine";
|
||||
labels = { "io.containers.autoupdate" = "registry"; };
|
||||
cmd = [
|
||||
"valkey-server"
|
||||
"--save"
|
||||
|
|
@ -286,12 +116,12 @@ in
|
|||
|
||||
# 3. SearXNG Container
|
||||
virtualisation.oci-containers.containers."searxng" = {
|
||||
image = "ghcr.io/privau/searxng:latest";
|
||||
# ports = [ "127.0.0.1:${toString cfg.port}:8080" ]; # Port moved to Anubis
|
||||
image = "localhost/aadniz/searxng:latest";
|
||||
environment = {
|
||||
"SEARXNG_BASE_URL" = "https://${cfg.domain}";
|
||||
"SEARXNG_REDIS_URL" = "valkey://valkey:6379"; # Talk to Valkey via alias
|
||||
"SEARXNG_URL_BASE" = "https://${cfg.domain}";
|
||||
"GRANIAN_HOST" = "0.0.0.0";
|
||||
};
|
||||
environmentFiles = [
|
||||
# Contains SEARXNG_SECRET_KEY
|
||||
|
|
@ -308,8 +138,9 @@ in
|
|||
];
|
||||
volumes = [
|
||||
"${config.sops.templates."searxng_settings.yml".path}:/etc/searxng/settings.yml:ro"
|
||||
"${catppuccinCss}:/etc/searxng/custom.css:ro"
|
||||
|
||||
"${faviconsConfig}:/etc/searxng/favicons.toml:ro"
|
||||
"${./braveapi.py}:/usr/local/searxng/searx/engines/braveapi.py:ro"
|
||||
"searxng-cache:/var/cache/searxng"
|
||||
];
|
||||
dependsOn = [ "searxng-valkey" ];
|
||||
|
|
@ -318,6 +149,7 @@ in
|
|||
# 4. Anubis Container (AI Firewall)
|
||||
virtualisation.oci-containers.containers."searxng-anubis" = {
|
||||
image = "ghcr.io/techarohq/anubis:latest";
|
||||
labels = { "io.containers.autoupdate" = "registry"; };
|
||||
ports = [ "127.0.0.1:${toString cfg.port}:8080" ];
|
||||
environment = {
|
||||
"TARGET" = "http://searxng:8080";
|
||||
|
|
@ -326,6 +158,7 @@ in
|
|||
};
|
||||
extraOptions = [
|
||||
"--network=searxng-net"
|
||||
"--network-alias=searxng-anubis"
|
||||
];
|
||||
volumes = [
|
||||
"${anubisPolicy}:/etc/anubis/policy.yml:ro"
|
||||
|
|
@ -333,32 +166,24 @@ in
|
|||
dependsOn = [ "searxng" ];
|
||||
};
|
||||
|
||||
# 5. Permanent NAT Fix for SearXNG Network
|
||||
networking.nftables.tables.searxng-nat = {
|
||||
family = "inet";
|
||||
content = ''
|
||||
chain postrouting {
|
||||
type nat hook postrouting priority srcnat; policy accept;
|
||||
ip saddr 10.89.2.0/24 masquerade
|
||||
}
|
||||
'';
|
||||
};
|
||||
|
||||
sops.templates."searxng.env" = {
|
||||
owner = "ashie";
|
||||
owner = mainUser;
|
||||
content = ''
|
||||
SEARXNG_SECRET_KEY=${config.sops.placeholder.searxng_secret_key}
|
||||
BRAVE_API_KEY=${config.sops.placeholder.searxng_brave_api_key}
|
||||
'';
|
||||
};
|
||||
|
||||
sops.templates."searxng_settings.yml" = {
|
||||
owner = "ashie";
|
||||
owner = mainUser;
|
||||
content = ''
|
||||
use_default_settings: true
|
||||
|
||||
general:
|
||||
debug: false
|
||||
instance_name: "Ashie Search"
|
||||
contact_url: false
|
||||
issue_url: false
|
||||
donation_url: ${if cfg.donations ? "Monero" then "\"${cfg.donations.Monero}\"" else "false"}
|
||||
donations:
|
||||
${lib.concatStringsSep "\n " (
|
||||
|
|
@ -366,15 +191,20 @@ in
|
|||
)}
|
||||
|
||||
engines:
|
||||
- name: brave
|
||||
engine: brave
|
||||
api_key: "${config.sops.placeholder.searxng_brave_api_key}"
|
||||
- name: braveapi
|
||||
engine: braveapi
|
||||
shortcut: brapi
|
||||
categories: general
|
||||
# api_key: set via BRAVE_API_KEY env var
|
||||
tokens: ["${config.sops.placeholder.searxng_private_token}"]
|
||||
timeout: 2.0
|
||||
weight: 2
|
||||
disabled: false
|
||||
|
||||
|
||||
search:
|
||||
safe_search: 0
|
||||
favicon_resolver: "duckduckgo"
|
||||
favicon_resolver: "google"
|
||||
autocomplete: "google"
|
||||
default_lang: "en-US"
|
||||
formats:
|
||||
|
|
@ -387,17 +217,15 @@ in
|
|||
secret_key: "${config.sops.placeholder.searxng_secret_key}"
|
||||
limiter: true
|
||||
image_proxy: true
|
||||
public_instance: true
|
||||
|
||||
default_http_headers:
|
||||
Content-Security-Policy: "upgrade-insecure-requests; default-src 'none'; script-src 'self'; style-src 'self' 'sha256-/ldGxQqxNIMRftg3AGsPF+F281wiBPECUDcL2RJkxdU='; form-action 'self' https://github.com/searxng/searxng/issues/new; font-src 'self'; frame-ancestors 'self'; img-src 'self' data:; connect-src 'self' https://overpass-api.de; manifest-src 'self'"
|
||||
|
||||
ui:
|
||||
default_theme: simple
|
||||
default_theme_style: kagi
|
||||
default_theme: red-floof
|
||||
default_theme_style: dark
|
||||
static_use_hash: true
|
||||
# custom_css: custom.css
|
||||
# theme_args:
|
||||
# simple_style: kagi
|
||||
|
||||
hostname_replace:
|
||||
'(^|.*\.)reddit\.com$': 'reddit.ashisgreat.xyz'
|
||||
|
||||
redis:
|
||||
url: valkey://valkey:6379/0
|
||||
|
|
@ -410,58 +238,59 @@ in
|
|||
sops.secrets.searxng_private_token = { };
|
||||
|
||||
# Rootless Overrides
|
||||
systemd.services."podman-searxng".serviceConfig.User = lib.mkForce "ashie";
|
||||
systemd.services."podman-searxng".serviceConfig.User = lib.mkForce mainUser;
|
||||
systemd.services."podman-searxng".environment = {
|
||||
HOME = "/home/ashie";
|
||||
XDG_RUNTIME_DIR = "/run/user/1000";
|
||||
HOME = "/home/${mainUser}";
|
||||
XDG_RUNTIME_DIR = "/run/user/${mainUserUid}";
|
||||
};
|
||||
systemd.services."podman-searxng".serviceConfig.Type = lib.mkForce "simple";
|
||||
systemd.services."podman-searxng".serviceConfig.Delegate = true;
|
||||
systemd.services."podman-searxng".after = [
|
||||
"create-searxng-network.service"
|
||||
"user-runtime-dir@1000.service"
|
||||
"user-runtime-dir@${mainUserUid}.service"
|
||||
"network-online.target"
|
||||
];
|
||||
systemd.services."podman-searxng".requires = [
|
||||
"create-searxng-network.service"
|
||||
"user-runtime-dir@1000.service"
|
||||
"user-runtime-dir@${mainUserUid}.service"
|
||||
"network-online.target"
|
||||
];
|
||||
|
||||
systemd.services."podman-searxng-valkey".serviceConfig.User = lib.mkForce "ashie";
|
||||
systemd.services."podman-searxng-valkey".serviceConfig.User = lib.mkForce mainUser;
|
||||
systemd.services."podman-searxng-valkey".environment = {
|
||||
HOME = "/home/ashie";
|
||||
XDG_RUNTIME_DIR = "/run/user/1000";
|
||||
HOME = "/home/${mainUser}";
|
||||
XDG_RUNTIME_DIR = "/run/user/${mainUserUid}";
|
||||
};
|
||||
systemd.services."podman-searxng-valkey".serviceConfig.Type = lib.mkForce "simple";
|
||||
systemd.services."podman-searxng-valkey".serviceConfig.Delegate = true;
|
||||
systemd.services."podman-searxng-valkey".after = [
|
||||
"create-searxng-network.service"
|
||||
"user-runtime-dir@1000.service"
|
||||
"user-runtime-dir@${mainUserUid}.service"
|
||||
"network-online.target"
|
||||
];
|
||||
systemd.services."podman-searxng-valkey".requires = [
|
||||
"create-searxng-network.service"
|
||||
"user-runtime-dir@1000.service"
|
||||
"user-runtime-dir@${mainUserUid}.service"
|
||||
"network-online.target"
|
||||
];
|
||||
|
||||
systemd.services."podman-searxng-anubis".serviceConfig.User = lib.mkForce "ashie";
|
||||
systemd.services."podman-searxng-anubis".serviceConfig.User = lib.mkForce mainUser;
|
||||
systemd.services."podman-searxng-anubis".environment = {
|
||||
HOME = "/home/ashie";
|
||||
XDG_RUNTIME_DIR = "/run/user/1000";
|
||||
HOME = "/home/${mainUser}";
|
||||
XDG_RUNTIME_DIR = "/run/user/${mainUserUid}";
|
||||
};
|
||||
systemd.services."podman-searxng-anubis".serviceConfig.Type = lib.mkForce "simple";
|
||||
systemd.services."podman-searxng-anubis".serviceConfig.Delegate = true;
|
||||
systemd.services."podman-searxng-anubis".after = [
|
||||
"create-searxng-network.service"
|
||||
"user-runtime-dir@1000.service"
|
||||
"user-runtime-dir@${mainUserUid}.service"
|
||||
"network-online.target"
|
||||
];
|
||||
systemd.services."podman-searxng-anubis".requires = [
|
||||
"create-searxng-network.service"
|
||||
"user-runtime-dir@1000.service"
|
||||
"user-runtime-dir@${mainUserUid}.service"
|
||||
"network-online.target"
|
||||
];
|
||||
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,111 +8,94 @@
|
|||
}:
|
||||
|
||||
let
|
||||
cfg = config.myModules.spotifySandboxed;
|
||||
bwrapperPkgs = pkgs.extend inputs.nix-bwrapper.overlays.default;
|
||||
sandboxUtils = import ./sandbox-utils.nix { inherit pkgs lib; };
|
||||
in
|
||||
{
|
||||
nixpkgs.overlays = [
|
||||
(final: prev: {
|
||||
spotify-sandboxed = bwrapperPkgs.mkBwrapper {
|
||||
app = {
|
||||
package = prev.spotify;
|
||||
id = "com.spotify.Client";
|
||||
env = {
|
||||
# Propagate XDG_DATA_DIRS for theming
|
||||
XDG_DATA_DIRS = "$XDG_DATA_DIRS";
|
||||
# Force Wayland if preferred, or rely on auto-detection
|
||||
# DISPLAY variable is handled by sockets.x11/wayland
|
||||
options.myModules.spotifySandboxed = {
|
||||
enable = lib.mkEnableOption "sandboxed Spotify with nix-bwrapper";
|
||||
|
||||
extraBindMounts = lib.mkOption {
|
||||
type = lib.types.listOf lib.types.str;
|
||||
default = [];
|
||||
description = "Extra paths to bind mount (read-write) into the sandbox";
|
||||
};
|
||||
};
|
||||
|
||||
config = lib.mkIf cfg.enable {
|
||||
nixpkgs.overlays = [
|
||||
(final: prev: {
|
||||
spotify-sandboxed = bwrapperPkgs.mkBwrapper {
|
||||
app = {
|
||||
package = prev.spotify;
|
||||
id = "com.spotify.Client";
|
||||
env = {
|
||||
# Propagate XDG_DATA_DIRS for theming
|
||||
XDG_DATA_DIRS = "$XDG_DATA_DIRS";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
# Enable X11 and Wayland
|
||||
sockets.x11 = true;
|
||||
sockets.wayland = true;
|
||||
# Enable X11 and Wayland
|
||||
sockets.x11 = true;
|
||||
sockets.wayland = true;
|
||||
|
||||
# Spotify is not a flatpak ref, so disable flatpak emulation
|
||||
flatpak.enable = false;
|
||||
# Spotify is not a flatpak ref, so disable flatpak emulation
|
||||
flatpak.enable = false;
|
||||
|
||||
fhsenv.opts = {
|
||||
unshareUser = true;
|
||||
unshareUts = false;
|
||||
unshareCgroup = false;
|
||||
unsharePid = false;
|
||||
unshareNet = false; # Need network for streaming
|
||||
unshareIpc = false;
|
||||
};
|
||||
fhsenv.opts = {
|
||||
unshareUser = true;
|
||||
unshareUts = false;
|
||||
unshareCgroup = false;
|
||||
unsharePid = false;
|
||||
unshareNet = false; # Need network for streaming
|
||||
unshareIpc = false;
|
||||
};
|
||||
|
||||
fhsenv.bwrap.baseArgs = lib.mkForce [
|
||||
"--new-session"
|
||||
"--proc /proc"
|
||||
"--dev /dev"
|
||||
"--dev-bind /dev/dri /dev/dri" # GPU acceleration
|
||||
"--tmpfs /home"
|
||||
"--tmpfs /tmp"
|
||||
"--tmpfs /run"
|
||||
"--dir /run/user"
|
||||
"--dir /run/user/${toString config.users.users.ashie.uid}"
|
||||
# System paths
|
||||
"--ro-bind /sys /sys"
|
||||
"--ro-bind-try /run/current-system /run/current-system"
|
||||
"--ro-bind-try /run/opengl-driver /run/opengl-driver"
|
||||
"--ro-bind-try /run/opengl-driver-32 /run/opengl-driver-32"
|
||||
"--dir /run/systemd/resolve"
|
||||
"--ro-bind-try /run/systemd/resolve /run/systemd/resolve"
|
||||
# Audio
|
||||
"--ro-bind-try /etc/asound.conf /etc/asound.conf"
|
||||
];
|
||||
fhsenv.bwrap.baseArgs = lib.mkForce (sandboxUtils.mkCommonBindArgs { inherit config lib; } ++ sandboxUtils.mkGamingBindArgs { } ++ [
|
||||
# Audio
|
||||
"--ro-bind-try /etc/asound.conf /etc/asound.conf"
|
||||
]);
|
||||
|
||||
mounts = {
|
||||
read = [
|
||||
"$HOME/.config/fontconfig"
|
||||
"$HOME/.local/share/fonts"
|
||||
"$HOME/.icons"
|
||||
"$HOME/.themes"
|
||||
"$HOME/.local/share/themes"
|
||||
"$HOME/.config/kdedefaults"
|
||||
"$HOME/.local/share/color-schemes"
|
||||
];
|
||||
readWrite = [
|
||||
"$HOME/.config/spotify"
|
||||
"$HOME/.cache/spotify"
|
||||
"$HOME/.local/share/spotify"
|
||||
mounts = {
|
||||
read = sandboxUtils.mkGuiMounts.read;
|
||||
readWrite = [
|
||||
"$HOME/.config/spotify"
|
||||
"$HOME/.cache/spotify"
|
||||
"$HOME/.local/share/spotify"
|
||||
] ++ cfg.extraBindMounts;
|
||||
};
|
||||
|
||||
# Disable built-in DBus module (invokes bwrap without --unshare-user)
|
||||
dbus.enable = false;
|
||||
|
||||
# Manually set up DBus proxy with --unshare-user (session bus only)
|
||||
script.preCmds.stage2 = sandboxUtils.mkDbusProxyScript {
|
||||
appId = "com.spotify.Client";
|
||||
enableSystemBus = false;
|
||||
proxyArgs = [
|
||||
"--filter"
|
||||
''--talk="org.freedesktop.portal.*"''
|
||||
''--call="org.freedesktop.portal.*=*@/org/freedesktop/portal/desktop"''
|
||||
''--talk="org.freedesktop.Notifications"''
|
||||
''--talk="org.freedesktop.ScreenSaver"''
|
||||
''--talk="org.kde.StatusNotifierWatcher"''
|
||||
''--talk="org.gnome.Mutter.DisplayConfig"''
|
||||
''--talk="org.mpris.MediaPlayer2.Player"''
|
||||
''--own="org.mpris.MediaPlayer2.spotify"''
|
||||
''--own="com.spotify.Client"''
|
||||
''--own="com.spotify.Client.*"''
|
||||
];
|
||||
};
|
||||
|
||||
fhsenv.bwrap.additionalArgs = sandboxUtils.mkGuiBindArgs { } ++ [
|
||||
# D-Bus session proxy only
|
||||
''--bind "$XDG_RUNTIME_DIR/app/com.spotify.Client/bus" "$XDG_RUNTIME_DIR/bus"''
|
||||
];
|
||||
};
|
||||
})
|
||||
];
|
||||
|
||||
# Disable built-in DBus module (invokes bwrap without --unshare-user)
|
||||
dbus.enable = false;
|
||||
|
||||
# Manually set up DBus proxy with --unshare-user (session bus only)
|
||||
script.preCmds.stage2 = (import ./sandbox-utils.nix { inherit pkgs lib; }).mkDbusProxyScript {
|
||||
appId = "com.spotify.Client";
|
||||
enableSystemBus = false;
|
||||
proxyArgs = [
|
||||
"--filter"
|
||||
''--talk="org.freedesktop.portal.*"''
|
||||
''--call="org.freedesktop.portal.*=*@/org/freedesktop/portal/desktop"''
|
||||
''--talk="org.freedesktop.Notifications"''
|
||||
''--talk="org.freedesktop.ScreenSaver"''
|
||||
''--talk="org.kde.StatusNotifierWatcher"''
|
||||
''--talk="org.gnome.Mutter.DisplayConfig"''
|
||||
''--talk="org.mpris.MediaPlayer2.Player"''
|
||||
''--own="org.mpris.MediaPlayer2.spotify"''
|
||||
''--own="com.spotify.Client"''
|
||||
''--own="com.spotify.Client.*"''
|
||||
];
|
||||
};
|
||||
|
||||
fhsenv.bwrap.additionalArgs = [
|
||||
# D-Bus session proxy only
|
||||
''--bind "$XDG_RUNTIME_DIR/app/com.spotify.Client/bus" "$XDG_RUNTIME_DIR/bus"''
|
||||
|
||||
# Wayland socket
|
||||
''--bind "$XDG_RUNTIME_DIR/$WAYLAND_DISPLAY" "$XDG_RUNTIME_DIR/$WAYLAND_DISPLAY"''
|
||||
|
||||
# PipeWire + Pulse
|
||||
''--bind "$XDG_RUNTIME_DIR/pipewire-0" "$XDG_RUNTIME_DIR/pipewire-0"''
|
||||
''--bind "$XDG_RUNTIME_DIR/pulse" "$XDG_RUNTIME_DIR/pulse"''
|
||||
];
|
||||
};
|
||||
})
|
||||
];
|
||||
environment.systemPackages = [ pkgs.spotify-sandboxed ];
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,50 +1,63 @@
|
|||
{
|
||||
config,
|
||||
pkgs,
|
||||
lib,
|
||||
...
|
||||
}:
|
||||
let
|
||||
cfg = config.myModules.gaming.gamemode;
|
||||
in
|
||||
{
|
||||
programs.gamescope = {
|
||||
enable = true;
|
||||
capSysNice = true;
|
||||
options.myModules.gaming.gamemode = {
|
||||
enable = lib.mkEnableOption "Steam GameMode Session";
|
||||
};
|
||||
|
||||
services.displayManager.sessionPackages = [
|
||||
(pkgs.writeTextFile {
|
||||
name = "steam-gamemode-session";
|
||||
destination = "/share/wayland-sessions/steam-gamemode.desktop";
|
||||
text = ''
|
||||
[Desktop Entry]
|
||||
Name=Steam GameMode
|
||||
Comment=Launch Steam in GameMode with Gamescope
|
||||
Exec=${pkgs.writeShellScript "steam-gamemode-start" ''
|
||||
# Load system environment
|
||||
. /etc/profile
|
||||
config = lib.mkIf cfg.enable {
|
||||
programs.gamemode.enable = true;
|
||||
|
||||
# Ensure we are in the user's home directory
|
||||
cd "$HOME" || exit 1
|
||||
programs.gamescope = {
|
||||
enable = true;
|
||||
capSysNice = true;
|
||||
};
|
||||
|
||||
exec >/tmp/steam-gamemode.log 2>&1
|
||||
echo "Starting Steam GameMode Session at $(date)"
|
||||
echo "User: $(whoami)"
|
||||
echo "PATH: $PATH"
|
||||
echo "Gamescope path: ${pkgs.gamescope}/bin/gamescope"
|
||||
services.displayManager.sessionPackages = [
|
||||
(pkgs.writeTextFile {
|
||||
name = "steam-gamemode-session";
|
||||
destination = "/share/wayland-sessions/steam-gamemode.desktop";
|
||||
text = ''
|
||||
[Desktop Entry]
|
||||
Name=Steam GameMode
|
||||
Comment=Launch Steam in GameMode with Gamescope
|
||||
Exec=${pkgs.writeShellScript "steam-gamemode-start" ''
|
||||
# Load system environment
|
||||
. /etc/profile
|
||||
|
||||
# Check for steam binary
|
||||
if ! command -v steam >/dev/null; then
|
||||
echo "ERROR: steam command not found in PATH"
|
||||
exit 1
|
||||
fi
|
||||
# Ensure we are in the user's home directory
|
||||
cd "$HOME" || exit 1
|
||||
|
||||
echo "Launching gamescope..."
|
||||
exec ${pkgs.gamescope}/bin/gamescope -f -e -- steam -gamepadui
|
||||
''}
|
||||
Type=Application
|
||||
'';
|
||||
derivationArgs = {
|
||||
passthru = {
|
||||
providedSessions = [ "steam-gamemode" ];
|
||||
exec >/tmp/steam-gamemode.log 2>&1
|
||||
echo "Starting Steam GameMode Session at $(date)"
|
||||
echo "User: $(whoami)"
|
||||
echo "PATH: $PATH"
|
||||
echo "Gamescope path: ${pkgs.gamescope}/bin/gamescope"
|
||||
|
||||
# Check for steam binary
|
||||
if ! command -v steam >/dev/null; then
|
||||
echo "ERROR: steam command not found in PATH"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Launching gamescope..."
|
||||
exec ${pkgs.gamescope}/bin/gamescope -f -e -- steam -gamepadui
|
||||
''}
|
||||
Type=Application
|
||||
'';
|
||||
derivationArgs = {
|
||||
passthru = {
|
||||
providedSessions = [ "steam-gamemode" ];
|
||||
};
|
||||
};
|
||||
};
|
||||
})
|
||||
];
|
||||
}
|
||||
})
|
||||
];
|
||||
};
|
||||
}
|
||||
|
|
@ -9,144 +9,81 @@
|
|||
}:
|
||||
|
||||
let
|
||||
bwrapperPkgs = pkgs.extend inputs.nix-bwrapper.overlays.default;
|
||||
sandboxUtils = import ./sandbox-utils.nix { inherit pkgs lib; };
|
||||
in
|
||||
{
|
||||
nixpkgs.overlays = [
|
||||
(final: prev: {
|
||||
steam-sandboxed = bwrapperPkgs.mkBwrapper {
|
||||
app = {
|
||||
package = prev.steam;
|
||||
isFhsenv = true; # Steam uses buildFHSEnv
|
||||
id = "com.valvesoftware.Steam";
|
||||
env = {
|
||||
# Unset LD_PRELOAD to avoid mimalloc crashes
|
||||
LD_PRELOAD = "";
|
||||
# Propagate XDG_DATA_DIRS for theming
|
||||
XDG_DATA_DIRS = "$XDG_DATA_DIRS";
|
||||
# Proton/Wine optimizations
|
||||
PROTON_USE_NTSYNC = 1;
|
||||
XDG_CURRENT_DESKTOP = "niri";
|
||||
XDG_SESSION_TYPE = "wayland";
|
||||
DBUS_SESSION_BUS_ADDRESS = "unix:path=$XDG_RUNTIME_DIR/bus";
|
||||
};
|
||||
};
|
||||
sandboxUtils.mkSandboxedApp {
|
||||
inherit
|
||||
config
|
||||
lib
|
||||
pkgs
|
||||
inputs
|
||||
;
|
||||
optionName = "steamSandboxed";
|
||||
packageName = "steam-sandboxed";
|
||||
description = "sandboxed Steam with nix-bwrapper";
|
||||
package = pkgs.steam;
|
||||
appId = "com.valvesoftware.Steam";
|
||||
isFhsenv = true;
|
||||
|
||||
# Enable X11 and Wayland
|
||||
sockets.x11 = true;
|
||||
sockets.wayland = true;
|
||||
env = {
|
||||
XDG_DATA_DIRS = "$XDG_DATA_DIRS";
|
||||
PROTON_USE_NTSYNC = 1;
|
||||
XDG_CURRENT_DESKTOP = "niri";
|
||||
XDG_SESSION_TYPE = "wayland";
|
||||
DBUS_SESSION_BUS_ADDRESS = "unix:path=$XDG_RUNTIME_DIR/bus";
|
||||
};
|
||||
|
||||
# Disable Flatpak emulation
|
||||
flatpak.enable = false;
|
||||
fhsenvExtra = {
|
||||
skipExtraInstallCmds = true;
|
||||
};
|
||||
|
||||
fhsenv = {
|
||||
skipExtraInstallCmds = true; # Steam package is special, don't try to modify it
|
||||
};
|
||||
fhsenvOpts = {
|
||||
unshareUser = true;
|
||||
unshareUts = false;
|
||||
unshareCgroup = false;
|
||||
unsharePid = false;
|
||||
unshareNet = false;
|
||||
unshareIpc = false;
|
||||
};
|
||||
|
||||
fhsenv.opts = {
|
||||
unshareUser = true;
|
||||
unshareUts = false;
|
||||
unshareCgroup = false;
|
||||
unsharePid = false; # Share PIDs for compatibility
|
||||
unshareNet = false; # Need network for Steam login/downloads
|
||||
unshareIpc = false;
|
||||
};
|
||||
baseArgs =
|
||||
sandboxUtils.mkCommonBindArgs { inherit config lib; } ++ sandboxUtils.mkGamingBindArgs { };
|
||||
|
||||
fhsenv.bwrap.baseArgs = lib.mkForce [
|
||||
"--new-session"
|
||||
"--proc /proc"
|
||||
"--dev /dev"
|
||||
"--dev-bind /dev/dri /dev/dri" # GPU acceleration
|
||||
"--dev-bind /dev/shm /dev/shm" # Shared memory (required for games)
|
||||
"--dev-bind-try /dev/uinput /dev/uinput" # Controller support
|
||||
"--dev-bind-try /dev/input /dev/input" # Controller/input devices
|
||||
"--dev-bind-try /dev/hidraw0 /dev/hidraw0" # HID devices (controllers)
|
||||
"--dev-bind-try /dev/hidraw1 /dev/hidraw1"
|
||||
"--dev-bind-try /dev/hidraw2 /dev/hidraw2"
|
||||
"--dev-bind-try /dev/hidraw3 /dev/hidraw3"
|
||||
"--tmpfs /home"
|
||||
"--tmpfs /tmp"
|
||||
"--tmpfs /run"
|
||||
"--dir /run/user"
|
||||
"--dir /run/user/${toString config.users.users.ashie.uid}"
|
||||
# System paths
|
||||
"--ro-bind /sys /sys"
|
||||
"--ro-bind-try /run/current-system /run/current-system"
|
||||
"--ro-bind-try /run/opengl-driver /run/opengl-driver"
|
||||
"--ro-bind-try /run/opengl-driver-32 /run/opengl-driver-32"
|
||||
"--dir /run/systemd/resolve"
|
||||
"--ro-bind-try /run/systemd/resolve /run/systemd/resolve"
|
||||
"--unsetenv LD_PRELOAD"
|
||||
# udev for controller hotplug
|
||||
"--ro-bind-try /run/udev /run/udev"
|
||||
];
|
||||
mounts = {
|
||||
read = [ ];
|
||||
readWrite = [
|
||||
"$HOME/.steam"
|
||||
"$HOME/.local/share/Steam"
|
||||
"$HOME/.local/share/umu"
|
||||
"$HOME/.local/share/applications"
|
||||
"$HOME/.local/share/desktop-directories"
|
||||
"$HOME/.local/share/icons"
|
||||
"$HOME/.local/share/Larian Studios"
|
||||
"$HOME/Desktop"
|
||||
"/games/steam"
|
||||
"/games/windows/Modlist"
|
||||
"/games/windows/Modlist_Downloads"
|
||||
];
|
||||
};
|
||||
|
||||
mounts = {
|
||||
read = [
|
||||
"$HOME/.config/fontconfig"
|
||||
"$HOME/.local/share/fonts"
|
||||
"$HOME/.icons"
|
||||
"$HOME/.themes"
|
||||
"$HOME/.local/share/themes"
|
||||
"$HOME/.config/qt6ct"
|
||||
"$HOME/.config/Kvantum"
|
||||
"$HOME/.config/MangoHud"
|
||||
"$HOME/.config/kdedefaults"
|
||||
"$HOME/.local/share/color-schemes"
|
||||
];
|
||||
readWrite = [
|
||||
"$HOME/.steam"
|
||||
"$HOME/.local/share/Steam"
|
||||
"$HOME/.local/share/umu"
|
||||
"$HOME/.local/share/applications"
|
||||
"$HOME/.local/share/desktop-directories"
|
||||
"$HOME/.local/share/icons"
|
||||
"$HOME/.local/share/Larian Studios"
|
||||
"$HOME/Desktop"
|
||||
"/games/steam"
|
||||
"/games/windows/Modlist"
|
||||
"/games/windows/Modlist_Downloads"
|
||||
"$HOME/Games/windows/Modlist/Nordic"
|
||||
];
|
||||
};
|
||||
|
||||
# Disable built-in DBus module (invokes bwrap without --unshare-user)
|
||||
dbus.enable = false;
|
||||
|
||||
# Manually set up DBus proxy with --unshare-user (session bus only)
|
||||
script.preCmds.stage2 = (import ./sandbox-utils.nix { inherit pkgs lib; }).mkDbusProxyScript {
|
||||
appId = "com.valvesoftware.Steam";
|
||||
enableSystemBus = false; # No system bus access
|
||||
proxyArgs = [
|
||||
"--filter"
|
||||
''--talk="org.freedesktop.portal.*"''
|
||||
''--call="org.freedesktop.portal.*=*@/org/freedesktop/portal/desktop"''
|
||||
''--talk="org.freedesktop.Notifications"''
|
||||
''--talk="org.freedesktop.ScreenSaver"''
|
||||
''--talk="org.kde.StatusNotifierWatcher"''
|
||||
''--talk="org.kde.KWin"''
|
||||
''--talk="org.gnome.Mutter.DisplayConfig"''
|
||||
''--talk="org.freedesktop.secrets"''
|
||||
''--talk="com.feralinteractive.GameMode"''
|
||||
''--talk="org.freedesktop.portal.*"''
|
||||
''--own="com.valvesoftware.Steam"''
|
||||
''--own="com.valvesoftware.Steam.*"''
|
||||
''--own="com.steampowered.PressureVessel.*"''
|
||||
];
|
||||
};
|
||||
|
||||
fhsenv.bwrap.additionalArgs = [
|
||||
# D-Bus session proxy only
|
||||
''--bind "$XDG_RUNTIME_DIR/app/com.valvesoftware.Steam/bus" "$XDG_RUNTIME_DIR/bus"''
|
||||
|
||||
# Wayland socket
|
||||
''--bind "$XDG_RUNTIME_DIR/$WAYLAND_DISPLAY" "$XDG_RUNTIME_DIR/$WAYLAND_DISPLAY"''
|
||||
|
||||
# PipeWire + Pulse
|
||||
''--bind "$XDG_RUNTIME_DIR/pipewire-0" "$XDG_RUNTIME_DIR/pipewire-0"''
|
||||
''--bind "$XDG_RUNTIME_DIR/pulse" "$XDG_RUNTIME_DIR/pulse"''
|
||||
];
|
||||
};
|
||||
})
|
||||
];
|
||||
dbusProxy = {
|
||||
enable = true;
|
||||
enableSystemBus = false;
|
||||
rules = [
|
||||
"--filter"
|
||||
''--talk="org.freedesktop.portal.*"''
|
||||
''--call="org.freedesktop.portal.*=*@/org/freedesktop/portal/desktop"''
|
||||
''--talk="org.freedesktop.Notifications"''
|
||||
''--talk="org.freedesktop.ScreenSaver"''
|
||||
''--talk="org.kde.StatusNotifierWatcher"''
|
||||
''--talk="org.kde.KWin"''
|
||||
''--talk="org.gnome.Mutter.DisplayConfig"''
|
||||
''--talk="org.freedesktop.secrets"''
|
||||
''--talk="com.feralinteractive.GameMode"''
|
||||
''--talk="org.freedesktop.portal.*"''
|
||||
''--own="com.valvesoftware.Steam"''
|
||||
''--own="com.valvesoftware.Steam.*"''
|
||||
''--own="com.steampowered.PressureVessel.*"''
|
||||
];
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,11 +3,12 @@
|
|||
lib,
|
||||
pkgs,
|
||||
inputs,
|
||||
...
|
||||
}:
|
||||
...}:
|
||||
|
||||
let
|
||||
cfg = config.myModules.tutanotaSandboxed;
|
||||
bwrapperPkgs = pkgs.extend inputs.nix-bwrapper.overlays.default;
|
||||
sandboxUtils = import ./sandbox-utils.nix { inherit pkgs lib; };
|
||||
|
||||
pname = "tutanota-desktop";
|
||||
version = "319.260107.1";
|
||||
|
|
@ -34,86 +35,73 @@ let
|
|||
};
|
||||
in
|
||||
{
|
||||
nixpkgs.overlays = [
|
||||
(final: prev: {
|
||||
tutanota-sandboxed = bwrapperPkgs.mkBwrapper {
|
||||
app = {
|
||||
package = tutanota;
|
||||
id = "com.tutanota.Tutanota";
|
||||
env = {
|
||||
XDG_DATA_DIRS = "$XDG_DATA_DIRS";
|
||||
options.myModules.tutanotaSandboxed = {
|
||||
enable = lib.mkEnableOption "sandboxed Tutanota Desktop with nix-bwrapper";
|
||||
|
||||
extraBindMounts = lib.mkOption {
|
||||
type = lib.types.listOf lib.types.str;
|
||||
default = [];
|
||||
description = "Extra paths to bind mount (read-write) into the sandbox";
|
||||
};
|
||||
};
|
||||
|
||||
config = lib.mkIf cfg.enable {
|
||||
nixpkgs.overlays = [
|
||||
(final: prev: {
|
||||
tutanota-sandboxed = bwrapperPkgs.mkBwrapper {
|
||||
app = {
|
||||
package = tutanota;
|
||||
id = "com.tutanota.Tutanota";
|
||||
env = {
|
||||
XDG_DATA_DIRS = "$XDG_DATA_DIRS";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
flatpak.enable = false;
|
||||
flatpak.enable = false;
|
||||
|
||||
# Basic sandboxing
|
||||
fhsenv.opts = {
|
||||
unshareUser = true;
|
||||
unshareUts = true;
|
||||
unshareCgroup = true;
|
||||
unsharePid = true;
|
||||
unshareNet = false; # Needs network
|
||||
unshareIpc = true;
|
||||
};
|
||||
# Basic sandboxing
|
||||
fhsenv.opts = {
|
||||
unshareUser = true;
|
||||
unshareUts = true;
|
||||
unshareCgroup = true;
|
||||
unsharePid = true;
|
||||
unshareNet = false; # Needs network
|
||||
unshareIpc = true;
|
||||
};
|
||||
|
||||
fhsenv.bwrap.baseArgs = lib.mkForce [
|
||||
"--new-session"
|
||||
"--proc /proc"
|
||||
"--dev /dev"
|
||||
"--dev-bind /dev/dri /dev/dri" # GPU acceleration
|
||||
"--tmpfs /home"
|
||||
"--tmpfs /tmp"
|
||||
"--tmpfs /run"
|
||||
"--dir /run/user"
|
||||
"--dir /run/user/${toString config.users.users.ashie.uid}"
|
||||
# System paths
|
||||
"--ro-bind /sys /sys"
|
||||
"--ro-bind-try /run/current-system /run/current-system"
|
||||
"--ro-bind-try /run/opengl-driver /run/opengl-driver"
|
||||
"--ro-bind-try /run/opengl-driver-32 /run/opengl-driver-32"
|
||||
"--dir /run/systemd/resolve"
|
||||
"--ro-bind-try /run/systemd/resolve /run/systemd/resolve"
|
||||
];
|
||||
fhsenv.bwrap.baseArgs = lib.mkForce (sandboxUtils.mkCommonBindArgs { inherit config lib; } ++ sandboxUtils.mkGamingBindArgs { });
|
||||
|
||||
mounts = {
|
||||
read = [
|
||||
"$HOME/.config/fontconfig"
|
||||
"$HOME/.local/share/fonts"
|
||||
"$HOME/.icons"
|
||||
"$HOME/.themes"
|
||||
"$HOME/.local/share/themes"
|
||||
"$HOME/.config/kdedefaults"
|
||||
"$HOME/.local/share/color-schemes"
|
||||
];
|
||||
readWrite = [
|
||||
"$HOME/.config/tutanota-desktop"
|
||||
"$HOME/Downloads"
|
||||
mounts = {
|
||||
read = sandboxUtils.mkGuiMounts.read;
|
||||
readWrite = [
|
||||
"$HOME/.config/tutanota-desktop"
|
||||
"$HOME/Downloads"
|
||||
] ++ cfg.extraBindMounts;
|
||||
};
|
||||
|
||||
dbus.enable = false;
|
||||
script.preCmds.stage2 = sandboxUtils.mkDbusProxyScript {
|
||||
appId = "com.tutanota.Tutanota";
|
||||
enableSystemBus = false;
|
||||
proxyArgs = [
|
||||
"--filter"
|
||||
''--talk="org.freedesktop.portal.*"''
|
||||
''--talk="org.freedesktop.Notifications"''
|
||||
''--talk="org.freedesktop.secrets"''
|
||||
''--talk="org.gnome.keyring.SystemPrompter"'' # Often needed for secrets
|
||||
''--call="org.freedesktop.portal.*=*@/org/freedesktop/portal/desktop"''
|
||||
''--own="com.tutanota.Tutanota"''
|
||||
];
|
||||
};
|
||||
|
||||
fhsenv.bwrap.additionalArgs = sandboxUtils.mkGuiBindArgs { } ++ [
|
||||
# D-Bus session proxy only
|
||||
''--bind "$XDG_RUNTIME_DIR/app/com.tutanota.Tutanota/bus" "$XDG_RUNTIME_DIR/bus"''
|
||||
];
|
||||
};
|
||||
})
|
||||
];
|
||||
|
||||
dbus.enable = false;
|
||||
script.preCmds.stage2 = (import ./sandbox-utils.nix { inherit pkgs lib; }).mkDbusProxyScript {
|
||||
appId = "com.tutanota.Tutanota";
|
||||
enableSystemBus = false;
|
||||
proxyArgs = [
|
||||
"--filter"
|
||||
''--talk="org.freedesktop.portal.*"''
|
||||
''--talk="org.freedesktop.Notifications"''
|
||||
''--talk="org.freedesktop.secrets"''
|
||||
''--talk="org.gnome.keyring.SystemPrompter"'' # Often needed for secrets
|
||||
''--call="org.freedesktop.portal.*=*@/org/freedesktop/portal/desktop"''
|
||||
''--own="com.tutanota.Tutanota"''
|
||||
];
|
||||
};
|
||||
|
||||
fhsenv.bwrap.additionalArgs = [
|
||||
# D-Bus session proxy only
|
||||
''--bind "$XDG_RUNTIME_DIR/app/com.tutanota.Tutanota/bus" "$XDG_RUNTIME_DIR/bus"''
|
||||
# Wayland
|
||||
''--bind "$XDG_RUNTIME_DIR/$WAYLAND_DISPLAY" "$XDG_RUNTIME_DIR/$WAYLAND_DISPLAY"''
|
||||
];
|
||||
};
|
||||
})
|
||||
];
|
||||
environment.systemPackages = [ pkgs.tutanota-sandboxed ];
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,9 @@
|
|||
}:
|
||||
|
||||
let
|
||||
cfg = config.myModules.vesktopSandboxed;
|
||||
bwrapperPkgs = pkgs.extend inputs.nix-bwrapper.overlays.default;
|
||||
sandboxUtils = import ./sandbox-utils.nix { inherit pkgs lib; };
|
||||
|
||||
# Define specific Vesktop version to avoid build errors from source
|
||||
vesktop-bin = pkgs.stdenv.mkDerivation rec {
|
||||
|
|
@ -40,106 +42,86 @@ let
|
|||
};
|
||||
in
|
||||
{
|
||||
nixpkgs.overlays = [
|
||||
(final: prev: {
|
||||
vesktop-sandboxed = bwrapperPkgs.mkBwrapper {
|
||||
app = {
|
||||
package = vesktop-bin;
|
||||
id = "dev.vencord.Vesktop";
|
||||
env = {
|
||||
# Propagate XDG_DATA_DIRS for theming
|
||||
XDG_DATA_DIRS = "$XDG_DATA_DIRS";
|
||||
# Force Wayland
|
||||
NIXOS_OZONE_WL = "1";
|
||||
options.myModules.vesktopSandboxed = {
|
||||
enable = lib.mkEnableOption "sandboxed Vesktop with nix-bwrapper";
|
||||
|
||||
extraBindMounts = lib.mkOption {
|
||||
type = lib.types.listOf lib.types.str;
|
||||
default = [];
|
||||
description = "Extra paths to bind mount (read-write) into the sandbox";
|
||||
};
|
||||
};
|
||||
|
||||
config = lib.mkIf cfg.enable {
|
||||
nixpkgs.overlays = [
|
||||
(final: prev: {
|
||||
vesktop-sandboxed = bwrapperPkgs.mkBwrapper {
|
||||
app = {
|
||||
package = vesktop-bin;
|
||||
id = "dev.vencord.Vesktop";
|
||||
env = {
|
||||
# Propagate XDG_DATA_DIRS for theming
|
||||
XDG_DATA_DIRS = "$XDG_DATA_DIRS";
|
||||
# Force Wayland
|
||||
NIXOS_OZONE_WL = "1";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
# Enable X11 and Wayland
|
||||
sockets.x11 = true;
|
||||
sockets.wayland = true;
|
||||
# Enable X11 and Wayland
|
||||
sockets.x11 = true;
|
||||
sockets.wayland = true;
|
||||
|
||||
# Disable flatpak emulation
|
||||
flatpak.enable = false;
|
||||
# Disable flatpak emulation
|
||||
flatpak.enable = false;
|
||||
|
||||
fhsenv.opts = {
|
||||
unshareUser = true;
|
||||
unshareUts = false;
|
||||
unshareCgroup = false;
|
||||
unsharePid = false;
|
||||
unshareNet = false; # Need network for Discord
|
||||
unshareIpc = false;
|
||||
};
|
||||
fhsenv.opts = {
|
||||
unshareUser = true;
|
||||
unshareUts = false;
|
||||
unshareCgroup = false;
|
||||
unsharePid = false;
|
||||
unshareNet = false; # Need network for Discord
|
||||
unshareIpc = false;
|
||||
};
|
||||
|
||||
fhsenv.bwrap.baseArgs = lib.mkForce [
|
||||
"--new-session"
|
||||
"--proc /proc"
|
||||
"--dev /dev"
|
||||
"--dev-bind /dev/dri /dev/dri" # GPU acceleration
|
||||
"--tmpfs /home"
|
||||
"--tmpfs /tmp"
|
||||
"--tmpfs /run"
|
||||
"--dir /run/user"
|
||||
"--dir /run/user/${toString config.users.users.ashie.uid}"
|
||||
# System paths
|
||||
"--ro-bind /sys /sys"
|
||||
"--ro-bind-try /run/current-system /run/current-system"
|
||||
"--ro-bind-try /run/opengl-driver /run/opengl-driver"
|
||||
"--ro-bind-try /run/opengl-driver-32 /run/opengl-driver-32"
|
||||
"--dir /run/systemd/resolve"
|
||||
"--ro-bind-try /run/systemd/resolve /run/systemd/resolve"
|
||||
# Audio
|
||||
"--ro-bind-try /etc/asound.conf /etc/asound.conf"
|
||||
];
|
||||
fhsenv.bwrap.baseArgs = lib.mkForce (sandboxUtils.mkCommonBindArgs { inherit config lib; } ++ sandboxUtils.mkGamingBindArgs { });
|
||||
|
||||
mounts = {
|
||||
read = [
|
||||
"$HOME/.config/fontconfig"
|
||||
"$HOME/.local/share/fonts"
|
||||
"$HOME/.icons"
|
||||
"$HOME/.themes"
|
||||
"$HOME/.local/share/themes"
|
||||
"$HOME/.config/kdedefaults"
|
||||
"$HOME/.local/share/color-schemes"
|
||||
];
|
||||
readWrite = [
|
||||
"$HOME/.config/vesktop"
|
||||
"$HOME/Downloads"
|
||||
mounts = {
|
||||
read = sandboxUtils.mkGuiMounts.read;
|
||||
readWrite = [
|
||||
"$HOME/.config/vesktop"
|
||||
"$HOME/Downloads"
|
||||
] ++ cfg.extraBindMounts;
|
||||
};
|
||||
|
||||
# Disable built-in DBus module (invokes bwrap without --unshare-user)
|
||||
dbus.enable = false;
|
||||
|
||||
# Manually set up DBus proxy with --unshare-user (session bus only)
|
||||
script.preCmds.stage2 = sandboxUtils.mkDbusProxyScript {
|
||||
appId = "dev.vencord.Vesktop";
|
||||
enableSystemBus = false;
|
||||
proxyArgs = [
|
||||
"--filter"
|
||||
''--talk="org.freedesktop.portal.*"''
|
||||
''--call="org.freedesktop.portal.*=*@/org/freedesktop/portal/desktop"''
|
||||
''--talk="org.freedesktop.Notifications"''
|
||||
''--talk="org.freedesktop.ScreenSaver"''
|
||||
''--talk="org.kde.StatusNotifierWatcher"''
|
||||
''--talk="org.gnome.Mutter.DisplayConfig"''
|
||||
''--talk="com.canonical.AppMenu.Registrar"''
|
||||
''--own="dev.vencord.Vesktop"''
|
||||
''--own="dev.vencord.Vesktop.*"''
|
||||
];
|
||||
};
|
||||
|
||||
fhsenv.bwrap.additionalArgs = sandboxUtils.mkGuiBindArgs { } ++ [
|
||||
# D-Bus session proxy only
|
||||
''--bind "$XDG_RUNTIME_DIR/app/dev.vencord.Vesktop/bus" "$XDG_RUNTIME_DIR/bus"''
|
||||
];
|
||||
};
|
||||
})
|
||||
];
|
||||
|
||||
# Disable built-in DBus module (invokes bwrap without --unshare-user)
|
||||
dbus.enable = false;
|
||||
|
||||
# Manually set up DBus proxy with --unshare-user (session bus only)
|
||||
script.preCmds.stage2 = (import ./sandbox-utils.nix { inherit pkgs lib; }).mkDbusProxyScript {
|
||||
appId = "dev.vencord.Vesktop";
|
||||
enableSystemBus = false;
|
||||
proxyArgs = [
|
||||
"--filter"
|
||||
''--talk="org.freedesktop.portal.*"''
|
||||
''--call="org.freedesktop.portal.*=*@/org/freedesktop/portal/desktop"''
|
||||
''--talk="org.freedesktop.Notifications"''
|
||||
''--talk="org.freedesktop.ScreenSaver"''
|
||||
''--talk="org.kde.StatusNotifierWatcher"''
|
||||
''--talk="org.gnome.Mutter.DisplayConfig"''
|
||||
''--talk="com.canonical.AppMenu.Registrar"''
|
||||
''--own="dev.vencord.Vesktop"''
|
||||
''--own="dev.vencord.Vesktop.*"''
|
||||
];
|
||||
};
|
||||
|
||||
fhsenv.bwrap.additionalArgs = [
|
||||
# D-Bus session proxy only
|
||||
''--bind "$XDG_RUNTIME_DIR/app/dev.vencord.Vesktop/bus" "$XDG_RUNTIME_DIR/bus"''
|
||||
|
||||
# Wayland socket
|
||||
''--bind "$XDG_RUNTIME_DIR/$WAYLAND_DISPLAY" "$XDG_RUNTIME_DIR/$WAYLAND_DISPLAY"''
|
||||
|
||||
# PipeWire + Pulse
|
||||
''--bind "$XDG_RUNTIME_DIR/pipewire-0" "$XDG_RUNTIME_DIR/pipewire-0"''
|
||||
''--bind "$XDG_RUNTIME_DIR/pulse" "$XDG_RUNTIME_DIR/pulse"''
|
||||
];
|
||||
};
|
||||
})
|
||||
];
|
||||
environment.systemPackages = [ pkgs.vesktop-sandboxed ];
|
||||
};
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue