1{ config, lib, pkgs, ... }: 2with lib; 3let 4 inherit (config.security) wrapperDir; 5 cfg = config.services.kbfs; 6 7in { 8 9 ###### interface 10 11 options = { 12 13 services.kbfs = { 14 15 enable = mkOption { 16 type = types.bool; 17 default = false; 18 description = lib.mdDoc "Whether to mount the Keybase filesystem."; 19 }; 20 21 enableRedirector = mkOption { 22 type = types.bool; 23 default = false; 24 description = lib.mdDoc '' 25 Whether to enable the Keybase root redirector service, allowing 26 any user to access KBFS files via `/keybase`, 27 which will show different contents depending on the requester. 28 ''; 29 }; 30 31 mountPoint = mkOption { 32 type = types.str; 33 default = "%h/keybase"; 34 example = "/keybase"; 35 description = lib.mdDoc "Mountpoint for the Keybase filesystem."; 36 }; 37 38 extraFlags = mkOption { 39 type = types.listOf types.str; 40 default = []; 41 example = [ 42 "-label kbfs" 43 "-mount-type normal" 44 ]; 45 description = lib.mdDoc '' 46 Additional flags to pass to the Keybase filesystem on launch. 47 ''; 48 }; 49 50 }; 51 }; 52 53 ###### implementation 54 55 config = mkIf cfg.enable (mkMerge [ 56 { 57 # Upstream: https://github.com/keybase/client/blob/master/packaging/linux/systemd/kbfs.service 58 systemd.user.services.kbfs = { 59 description = "Keybase File System"; 60 61 # Note that the "Requires" directive will cause a unit to be restarted whenever its dependency is restarted. 62 # Do not issue a hard dependency on keybase, because kbfs can reconnect to a restarted service. 63 # Do not issue a hard dependency on keybase-redirector, because it's ok if it fails (e.g., if it is disabled). 64 wants = [ "keybase.service" ] ++ optional cfg.enableRedirector "keybase-redirector.service"; 65 path = [ "/run/wrappers" ]; 66 unitConfig.ConditionUser = "!@system"; 67 68 serviceConfig = { 69 Type = "notify"; 70 # Keybase notifies from a forked process 71 EnvironmentFile = [ 72 "-%E/keybase/keybase.autogen.env" 73 "-%E/keybase/keybase.env" 74 ]; 75 ExecStartPre = [ 76 "${pkgs.coreutils}/bin/mkdir -p \"${cfg.mountPoint}\"" 77 "-${wrapperDir}/fusermount -uz \"${cfg.mountPoint}\"" 78 ]; 79 ExecStart = "${pkgs.kbfs}/bin/kbfsfuse ${toString cfg.extraFlags} \"${cfg.mountPoint}\""; 80 ExecStop = "${wrapperDir}/fusermount -uz \"${cfg.mountPoint}\""; 81 Restart = "on-failure"; 82 PrivateTmp = true; 83 }; 84 wantedBy = [ "default.target" ]; 85 }; 86 87 services.keybase.enable = true; 88 89 environment.systemPackages = [ pkgs.kbfs ]; 90 } 91 92 (mkIf cfg.enableRedirector { 93 security.wrappers."keybase-redirector".source = "${pkgs.kbfs}/bin/redirector"; 94 95 systemd.tmpfiles.rules = [ "d /keybase 0755 root root 0" ]; 96 97 # Upstream: https://github.com/keybase/client/blob/master/packaging/linux/systemd/keybase-redirector.service 98 systemd.user.services.keybase-redirector = { 99 description = "Keybase Root Redirector for KBFS"; 100 wants = [ "keybase.service" ]; 101 unitConfig.ConditionUser = "!@system"; 102 103 serviceConfig = { 104 EnvironmentFile = [ 105 "-%E/keybase/keybase.autogen.env" 106 "-%E/keybase/keybase.env" 107 ]; 108 # Note: The /keybase mount point is not currently configurable upstream. 109 ExecStart = "${wrapperDir}/keybase-redirector /keybase"; 110 Restart = "on-failure"; 111 PrivateTmp = true; 112 }; 113 114 wantedBy = [ "default.target" ]; 115 }; 116 }) 117 ]); 118}