{ pkgs, lib, config, ... }: let inherit (lib) escapeShellArg mkEnableOption mkOption types mkIf ; inherit (builtins) concatStringsSep; cfg = config.services.kiosk; in { options.services.kiosk = { enable = mkEnableOption "acting as a browser-based kiosk"; user = mkOption { description = "Name of user to run kiosk as"; default = "kiosk"; type = types.str; }; group = mkOption { description = "Name of group for kiosk user"; default = "kiosk"; type = types.str; }; home = mkOption { description = "Home directory for the user"; default = "/var/kiosk"; type = types.str; }; urls = mkOption { description = "URLs to open"; default = [ ]; type = types.listOf types.str; }; firefoxCommand = mkOption { description = "Version of firefox to use"; default = "${ pkgs.firefox.override { cfg.speechSynthesisSupport = false; extraPolicies = let lock-false = { Value = false; Status = "locked"; }; lock-true = { Value = true; Status = "locked"; }; in { DisableTelemetry = true; DisableFirefoxStudies = true; EnableTrackingProtection = { Value = true; Locked = true; Cryptomining = true; Fingerprinting = true; }; DisablePocket = true; OverrideFirstRunPage = ""; OverridePostUpdatePage = ""; DontCheckDefaultBrowser = true; DisplayBookmarksToolbar = "never"; # alternatives: "always" or "newtab" DisplayMenuBar = "default-off"; # alternatives: "always", "never" or "default-on" SearchBar = "unified"; # alternative: "separate" DisableFirefoxAccounts = true; DisableFirefoxScreenshots = true; DisableAccounts = true; PasswordManagerEnabled = false; SearchEngines.Remove = [ "Google" ]; Preferences = { # Based on github.com/arkenfox/user.js "extensions.pocket.enabled" = lock-false; # Recommendations "extensions.getAddons.showPane" = lock-false; "extensions.htmlaboutaddons.recommendations.enabled" = lock-false; "browser.discovery.enabled" = lock-false; "browser.shopping.experience2023.enabled" = lock-false; # Telemetry "datareporting.policy.dataSubmissionEnabled" = lock-false; "datareporting.healthreport.uploadEnabled" = lock-false; "toolkit.telemetry.unified" = lock-false; "toolkit.telemetry.enabled" = lock-false; "toolkit.telemetry.server" = "data:"; "toolkit.telemetry.archive.enabled" = lock-false; "toolkit.telemetry.newProfilePing.enabled" = lock-false; "toolkit.telemetry.shutdownPingSender.enabled" = lock-false; "toolkit.telemetry.updatePing.enabled" = lock-false; "toolkit.telemetry.bhrPing.enabled" = lock-false; "toolkit.telemetry.firstShutdownPing.enabled" = lock-false; "toolkit.telemetry.coverage.opt-out" = lock-true; "toolkit.coverage.opt-out" = lock-true; "toolkit.coverage.endpoint.base" = ""; "browser.ping-centre.telemetry" = lock-false; "browser.newtabpage.activity-stream.feeds.telemetry" = lock-false; "browser.newtabpage.activity-stream.telemetry" = lock-false; # Studies "app.shield.optoutstudies.enabled" = lock-false; "app.normandy.enabled" = lock-false; "app.normandy.api_url" = ""; # Autofill "browser.formfill.enable" = lock-false; "signon.autofillForms" = lock-false; "signon.formlessCapture.enabled" = lock-false; # Better SSL error display "browser.xul.error_pages.expert_bad_cert" = lock-true; # Miscellaneous "font.default.x-western" = "sans-serif"; "browser.uitour.enabled" = lock-false; "pdfjs.enableScripting" = lock-false; "browser.sessionrestore.resume_from_crash" = lock-false; "browser.contentblocking.category" = "strict"; "privacy.donottrackheader.enabled" = lock-true; "privacy.globalprivacycontrol.enabled" = lock-true; "privacy.globalprivacycontrol.was-ever-enabled" = lock-true; "signon.rememberSignons" = lock-false; "browser.toolbars.bookmarks.visibility" = "never"; "browser.startup.homepage_override.mstone" = "ignore"; "browser.newtabpage.activity-stream.asrouter.userprefs.cfr.addons" = lock-false; "browser.newtabpage.activity-stream.asrouter.userprefs.cfr.features" = lock-false; "browser.messaging-system.whatsNewPanel.enabled" = lock-false; "toolkit.legacyUserProfileCustomizations.stylesheets" = lock-true; }; }; } }/bin/firefox"; type = types.str; }; }; config = mkIf cfg.enable { users.users.${cfg.user} = { isSystemUser = true; home = cfg.home; group = cfg.group; createHome = true; useDefaultShell = true; }; users.groups.${cfg.group} = { }; services.getty.autologinUser = cfg.user; services.xserver = { enable = true; displayManager.startx.enable = true; }; hardware.opengl = { enable = true; driSupport = true; }; system.activationScripts.kiosk-home = { text = '' mkdir -p ${cfg.home} cat >${cfg.home}/.xinitrc <${cfg.home}/.bash_profile <