mirror of
https://github.com/lhns/steam-frame-nix.git
synced 2026-10-06 02:00:13 +02:00
Keyring launchers, Firefox default browser, rootless Docker
- keyring.flatpaks / keyring.programs: desktop entries shadowing an app's own that run it on the outer bus (one kwalletd6 for both sessions), with the wallet's D-Bus names as `flatpak run --talk-name` options (no Flatpak overrides), --password-store=kwallet6 for Electron, and login callback schemes as default + recommended handlers. - firefox.defaultBrowser: the launcher as default for http, https and text/html. - docker: rootless dockerd as a user service, socket in the outer runtime dir, CLI with DOCKER_HOST for both sessions.
This commit is contained in:
1 parent
aa9ca183f1
commit
b0131338de
10 files changed
+617
-14
No files matched your search
@@ -0,0 +1,57 @@
|
||||
# Rootless Docker
|
||||
|
||||
`docker.*`, module `docker`. Options:
|
||||
[README, Options](../README.md#options).
|
||||
|
||||
## Problem
|
||||
|
||||
SteamOS has no Docker, and Home Manager can't install the usual root
|
||||
daemon. Rootless Docker's default socket is in `$XDG_RUNTIME_DIR`, which
|
||||
differs between the Frame's [two sessions](../README.md#two-sessions), and
|
||||
the nested desktop can't reach the user service manager.
|
||||
|
||||
## What you get
|
||||
|
||||
- `dockerd` in rootless mode as the systemd user service `docker.service`
|
||||
of the Steam session's user manager, started at login and on switch
|
||||
(never restarted by a switch, which would stop running containers).
|
||||
- The `docker` CLI on `PATH`, whose default `DOCKER_HOST` is the socket in
|
||||
the outer runtime dir (`docker.host`,
|
||||
`unix:///run/user/1000/docker.sock`): it works in both sessions. A
|
||||
`DOCKER_HOST` you set yourself wins.
|
||||
|
||||
SteamOS already has what rootless Docker needs: `newuidmap`/`newgidmap`
|
||||
with their capabilities, `/etc/subuid` and `/etc/subgid` entries for the
|
||||
user, user namespaces and cgroup v2 delegation.
|
||||
|
||||
## Configuration
|
||||
|
||||
```nix
|
||||
steamFrame.docker.enable = true;
|
||||
```
|
||||
|
||||
Then `docker run --rm hello-world`. `docker.package` replaces the Docker
|
||||
package (daemon and CLI).
|
||||
|
||||
## Caveats
|
||||
|
||||
- Rootless limits apply: no ports below 1024 without extra setup,
|
||||
`--network host` is the rootless network namespace, containers can't
|
||||
gain real root.
|
||||
- Images, containers and volumes are app data in `~/.local/share/docker`,
|
||||
see [App data you create](../README.md#app-data-you-create) for how to
|
||||
remove them.
|
||||
- Disabling the module removes the unit but doesn't stop a running daemon:
|
||||
run `systemctl --user stop docker` first (or add `docker.service` to
|
||||
`session.services.stop` for that switch).
|
||||
- Another `docker` package in `home.packages` collides with the wrapped
|
||||
CLI.
|
||||
|
||||
## How it works
|
||||
|
||||
The user unit runs `dockerd-rootless` (RootlessKit) with `PATH=/usr/bin`,
|
||||
for SteamOS's `newuidmap`/`newgidmap`, and `Delegate=yes`. The unit is
|
||||
added to `session.services.start`, so each switch starts it if it isn't
|
||||
running. The CLI is the package's `docker` wrapped with a default
|
||||
`DOCKER_HOST`; nothing is written outside the store (no `daemon.json`, no
|
||||
Docker context).
|
||||
+8
-2
@@ -7,8 +7,10 @@
|
||||
|
||||
In the Steam session gamescope never shows fullscreen windows, so Firefox
|
||||
looks frozen when a page goes fullscreen; sites send AV1, which the Frame
|
||||
decodes in software; and the two sessions can't see each other's Firefox,
|
||||
so a second instance stops at the locked profile.
|
||||
decodes in software; the two sessions can't see each other's Firefox,
|
||||
so a second instance stops at the locked profile; and without a default
|
||||
browser the portal opens links with the first installed `https` handler
|
||||
(e.g. Chromium), in both sessions.
|
||||
|
||||
## What you get
|
||||
|
||||
@@ -26,6 +28,9 @@ ID), so default-browser associations keep working.
|
||||
- **`desktopProfile`** (`"desktop"`): in the nested desktop the launcher
|
||||
uses this separate profile (a normal Firefox profile with its own browser
|
||||
data, created on first use). `null`: the default profile in both sessions.
|
||||
- **`defaultBrowser`** (off): the launcher becomes the default for `http`,
|
||||
`https` and `text/html` (Home Manager's `xdg.mimeApps`, which then owns
|
||||
`~/.config/mimeapps.list`).
|
||||
|
||||
`prefs` and the fixes are *default* values, not user values: `about:config`
|
||||
can still change them per profile, and removing one leaves nothing behind.
|
||||
@@ -37,6 +42,7 @@ Changes take effect at the next start of Firefox.
|
||||
steamFrame.firefox = {
|
||||
enable = true;
|
||||
disableAv1 = true;
|
||||
defaultBrowser = true;
|
||||
prefs."browser.startup.page" = 3; # restore the previous session
|
||||
};
|
||||
```
|
||||
|
||||
+128
@@ -0,0 +1,128 @@
|
||||
# Keyring launchers
|
||||
|
||||
`keyring.flatpaks.<app ID>`, `keyring.programs.<desktop ID>`, module
|
||||
`keyring`. Options: [README, Options](../README.md#options).
|
||||
|
||||
## Problem
|
||||
|
||||
Apps that keep logins or passwords in the KDE wallet lose them between the
|
||||
Frame's [two sessions](../README.md#two-sessions):
|
||||
|
||||
- **A second wallet:** the nested desktop has its own D-Bus. An app started
|
||||
there starts a second `kwalletd6` on that bus; what it stores there is
|
||||
invisible to the same app in the Steam session, which talks to the running
|
||||
`kwalletd6` on the outer bus.
|
||||
- **Electron in the Steam session:** Electron picks its keyring from
|
||||
`XDG_CURRENT_DESKTOP`. In the Steam session that is `gamescope`, which it
|
||||
doesn't know, so it falls back to `basic` (a local, unencrypted store) and
|
||||
the login made in the desktop (stored in the wallet) is gone.
|
||||
- **Flatpak permissions:** many Flatpaks may not talk to the wallet at all
|
||||
(Element), or only to `org.kde.kwalletd6` while their KF6 wallet client
|
||||
reads through the Secret Service `org.freedesktop.secrets` (KRDC: "Password
|
||||
not found").
|
||||
- **Login callbacks:** SSO logins come back through a URL scheme
|
||||
(`io.element.desktop://`, `claude://`) opened by the portal. Unless the app
|
||||
is the default and a recommended handler, the portal opens an app chooser,
|
||||
which isn't shown in VR.
|
||||
|
||||
## What you get
|
||||
|
||||
For each listed app, a desktop entry in `~/.local/share/applications` with
|
||||
the app's own desktop ID, so it replaces the Flatpak's or package's entry in
|
||||
the KDE menu and the "+" menu. It starts the app
|
||||
|
||||
- on the outer bus (`session.busEnv`): one `kwalletd6` for both sessions;
|
||||
- for Flatpaks, with `--talk-name=org.kde.kwalletd6` and
|
||||
`--talk-name=org.freedesktop.secrets` as `flatpak run` options (not a
|
||||
Flatpak override: they apply only to launches from this entry and are
|
||||
gone with it);
|
||||
- with `electron = true`, with `--password-store=kwallet6`;
|
||||
- as the default and recommended handler of its `schemeHandlers`
|
||||
(`xdg.mimeApps`).
|
||||
|
||||
Logins then survive switching between the desktop and VR windows. Changes
|
||||
take effect at the next start of the app.
|
||||
|
||||
## Configuration
|
||||
|
||||
The Flatpak isn't in the Nix store, so its entry can't be read at build
|
||||
time: give the fields you want in menus (`name` is required; `icon`
|
||||
defaults to the app ID, as Flatpaks export it). A Flatpak (installing it is
|
||||
up to you):
|
||||
|
||||
```nix
|
||||
steamFrame.keyring.flatpaks = {
|
||||
"im.riot.Riot" = {
|
||||
name = "Element";
|
||||
electron = true;
|
||||
categories = [ "Network" "InstantMessaging" ];
|
||||
schemeHandlers = [ "element" "io.element.desktop" ]; # SSO callback
|
||||
};
|
||||
"org.kde.krdc" = {
|
||||
name = "KRDC";
|
||||
fieldCode = "%u";
|
||||
categories = [ "Qt" "KDE" "Network" "RemoteAccess" ];
|
||||
mimeTypes = [ "x-scheme-handler/vnc" "x-scheme-handler/rdp" ]; # listed, not made default
|
||||
};
|
||||
};
|
||||
```
|
||||
|
||||
A program from a Nix package: use the package's own desktop ID (without
|
||||
`.desktop`), so the entry replaces the package's:
|
||||
|
||||
```nix
|
||||
{ pkgs, ... }: {
|
||||
home.packages = [ pkgs.claude-desktop ];
|
||||
steamFrame.keyring.programs."com.anthropic.Claude" = {
|
||||
name = "Claude";
|
||||
executable = "${pkgs.claude-desktop}/bin/claude-desktop";
|
||||
icon = "claude-desktop";
|
||||
electron = true;
|
||||
startupWMClass = "com.anthropic.Claude";
|
||||
schemeHandlers = [ "claude" ]; # login callback
|
||||
settings.StartupNotify = "true";
|
||||
actions.NewChat = {
|
||||
name = "New Chat";
|
||||
args = [ ''"claude://claude.ai/new?surface=chat&source=desktop_action"'' ];
|
||||
};
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
`args`, `actions.<name>.args` and `settings` are written into the entry as
|
||||
given (desktop entry syntax: quote yourself). Each app's `command` (read
|
||||
only) is its command line without arguments, to start it from a terminal
|
||||
the same way. The fields each entry takes are in the
|
||||
[options](../README.md#options).
|
||||
|
||||
## Caveats
|
||||
|
||||
- The wallet must be KDE's (`kwalletd6`, and `ksecretd` for the Secret
|
||||
Service), as SteamOS ships it.
|
||||
- Only launches from the entry get the fixes: a Flatpak started with plain
|
||||
`flatpak run`, or a program from `~/.nix-profile/bin`, doesn't.
|
||||
- `schemeHandlers` turns on Home Manager's `xdg.mimeApps`, which then owns
|
||||
`~/.config/mimeapps.list`: set other defaults there too.
|
||||
- A Flatpak's own entry may have fields not given here (translations,
|
||||
`Keywords`, actions); add what you need through `settings` and `actions`.
|
||||
|
||||
## How it works
|
||||
|
||||
For `"im.riot.Riot" = { name = "Element"; electron = true; ... }` the entry's
|
||||
command line is
|
||||
|
||||
```sh
|
||||
env DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus \
|
||||
flatpak run --talk-name=org.kde.kwalletd6 --talk-name=org.freedesktop.secrets \
|
||||
im.riot.Riot --password-store=kwallet6 %U
|
||||
```
|
||||
|
||||
`flatpak run` connects the sandbox's D-Bus proxy to the bus in its own
|
||||
environment, so the prefix (not `--env=`) moves the app to the outer bus.
|
||||
`--talk-name` adds to the Flatpak's permissions for this launch only. The
|
||||
entry also sets `X-Flatpak=<app ID>`. For `programs` the prefix runs
|
||||
`executable` directly.
|
||||
|
||||
`schemeHandlers` go into `xdg.mimeApps.defaultApplications` and
|
||||
`associations.added` (Added Associations, what the portal treats as
|
||||
recommended), and into the entry's `MimeType=` with `mimeTypes`.
|
||||
+3
-2
@@ -23,8 +23,9 @@ running") and skips `reloadSystemd`.
|
||||
and applies `session.services.start` / `stop` / `restart`, which other
|
||||
modules fill (you can add your own units).
|
||||
|
||||
**Configuration:** a launcher for an app that must use the single wallet on
|
||||
the outer bus (see [Two sessions](../README.md#two-sessions)):
|
||||
**Configuration:** apps that keep secrets in the wallet get launchers from
|
||||
[keyring](keyring.md). Another launcher that must reach the outer session
|
||||
(its bus, services or wallet) uses the prefix:
|
||||
|
||||
```nix
|
||||
{ config, ... }: {
|
||||
|
||||
Reference in new issue
Block a user