{ config, lib, pkgs, ... }: # todo : this needs to be cleaned up with lib; let cfg = config.programs.custom.browser; library = import ../../library { inherit pkgs lib; }; chromiumBin = "${pkgs.chromium}/bin/chromium"; chromeBin = "${pkgs.google-chrome}/bin/google-chrome-stable"; firefoxBin = "${pkgs.firefox}/bin/firefox"; tarBin = "${pkgs.gnutar}/bin/tar"; # desktop file # ------------ # makes it possible to be used by other programs desktopFile = bin: let browserName = bin.name; in pkgs.writeTextFile { name = "${browserName}.desktop"; destination = "/share/applications/${browserName}.desktop"; text = '' [Desktop Entry] Type=Application Exec=${bin}/bin/${browserName} %U Icon=chromium Comment=An open source web browser from Google Terminal=false Name=${browserName} GenericName=Web browser MimeType=text/html;text/xml;application/xhtml+xml;x-scheme-handler/http;x-scheme-handler/https;x-scheme-handler/ftp;x-scheme-handler/webcal;x-scheme-handler/about Categories=Network;WebBrowser StartupWMClass=${browserName} ''; }; killBrowser = name: pkgs.writeShellScriptBin "${name}-kill" "sudo killall -9 -u ${name}"; cleanBrowser = name: browser: home: homeBackup: let backupFile = "${homeBackup}.tar.lzma"; rolloutFile = "${home}.tar.lzma"; lockFile = "${home}-lock"; in pkgs.writeShellScriptBin "${name}-clean" # sh '' sudo killall -9 -u ${name} sudo rm -f ${lockFile} sudo rm -rf ${home} ''; createBrowser = name: user: browser: home: homeBackup: let backupFile = "${homeBackup}.tar.lzma"; rolloutFile = "${home}.tar.lzma"; lockFile = "${home}-lock"; in pkgs.writeShellScriptBin "${name}" # sh '' # set -x if [[ ! -e ${lockFile} ]] then # rollout backup if [[ -e ${backupFile} ]] then if [[ ! -d ${home} ]] then # todo : use make user sudo mkdir -p ${home} sudo chown -R ${user}:users ${home} fi cp ${backupFile} ${rolloutFile} sudo -u ${user} ${tarBin} xf ${rolloutFile} --directory ${home} rm ${rolloutFile} touch ${lockFile} fi fi sudo -u ${user} ${browser} ''; browserExecutableList = let allBrowser = flip mapAttrsToList cfg.configList (name: config: let browser = if config.browserType == "chrome" then ''${chromiumBin} "$@"'' else if config.browserType == "google" then ''${chromeBin} "$@"'' else ''${firefoxBin} "$@"''; in createBrowser name config.user browser config.home config.homeBackup); xclipBrowser = [ (pkgs.writeShellScriptBin "copy-to-xclip" # sh '' echo "$*" | ${pkgs.xclip}/bin/xclip '') ]; in allBrowser ++ xclipBrowser; createBackupScript = name: home: backupHome: pkgs.writeShellScriptBin "${name}-backup" # sh '' sudo -u ${name} \ ${tarBin} \ --exclude=.cache \ --exclude=Downloads \ --create \ --verbos \ --lzma \ --file ${home}.tar.lzma \ --directory ${home} \ . cp ${home}.tar.lzma ${backupHome}.tar.lzma ''; allBackupScripts = let filteredConfigs = filterAttrs (name: browserConfig: browserConfig.homeBackup != null) cfg.configList; in mapAttrsToList (name: browserConfig: createBackupScript name browserConfig.home browserConfig.homeBackup) filteredConfigs; allCleanScripts = let filteredConfigs = filterAttrs (name: browserConfig: browserConfig.homeBackup != null) cfg.configList; in mapAttrsToList (name: browserConfig: cleanBrowser name name browserConfig.home browserConfig.homeBackup) filteredConfigs; allKillScripts = mapAttrsToList (name: _: killBrowser name) cfg.configList; # browser chooser # --------------- browserSelect = pkgs.writeScriptBin "browser-select" '' # select a browser using dmenu # ---------------------------- BROWSER=$( echo -e "${ lib.concatMapStringsSep "\\n" (bin: bin.name) browserExecutableList }" \ | ${pkgs.rofi}/bin/rofi -dmenu ) # start selected browser # ---------------------- case $BROWSER in ${lib.concatStringsSep "\n" (flip map browserExecutableList (bin: "${bin.name}) export BIN=${bin}/bin/${bin.name} ;;"))} esac $BIN "$@" ''; in { options.programs.custom.browser = { enable = mkEnableOption "enable browsers"; configList = mkOption { type = with types; attrsOf (submodule ({ name, ... }: { options = { browserType = mkOption { type = with types; enum [ "firefox" "chrome" "google" ]; default = "chrome"; description = '' the type of browser which is simulated ''; }; home = mkOption { type = with types; str; description = '' Home of the browser. ''; }; gpu = mkOption { type = with types; bool; default = true; description = '' add browser user to video group so give browser rights to use gpu. see : chrome://gpu/ ''; }; user = mkOption { default = name; type = with types; str; description = '' user to run the browser as ''; }; sudoUsers = mkOption { default = [ config.users.users.mainUser.name ]; type = with types; listOf str; description = '' user allowed to run sudo without password to start the browser ''; }; homeBackup = mkOption { type = with types; nullOr str; default = null; example = "~/.my-browser-backup"; description = '' backup of the home, which gets rolled out if the home does not exists. usefull for homes in tmpfs. dont use file endings! ''; }; }; })); }; }; config = mkIf cfg.enable { # add sudo rights security.sudo.extraConfig = let extraRules = flip mapAttrsToList cfg.configList (name: values: concatStringsSep "" (map (sudoUser: '' # sudo configuration to control browser ${sudoUser} ALL=(${values.user}) NOPASSWD: ALL ${sudoUser} ALL=(root) NOPASSWD: /run/current-system/sw/bin/mkdir -p ${values.home} ${sudoUser} ALL=(root) NOPASSWD: /run/current-system/sw/bin/chown -R ${values.user}\:users ${values.home} ${sudoUser} ALL=(root) NOPASSWD: /run/current-system/sw/bin/killall -9 -u ${name} ${sudoUser} ALL=(root) NOPASSWD: /run/current-system/sw/bin/rm -rf ${values.home} ${sudoUser} ALL=(root) NOPASSWD: /run/current-system/sw/bin/rm -f ${values.home}-lock '') values.sudoUsers)); in lib.concatStringsSep "\n" extraRules; # create users users.users = flip mapAttrs cfg.configList (name: config: { home = config.home; createHome = true; initialPassword = "${name}-browser"; shell = pkgs.bashInteractive; isNormalUser = true; group = "users"; # enable video usage extraGroups = if config.gpu then [ "video" "audio" "pipewire" ] else [ "audio" "pipewire" ]; }); # add groups to mainUser system.custom.mainUser.extraGroups = builtins.attrNames cfg.configList; environment.systemPackages = [ browserSelect (desktopFile browserSelect) ] ++ browserExecutableList ++ (map (bin: desktopFile bin) browserExecutableList) ++ allBackupScripts ++ allCleanScripts ++ allKillScripts; }; }