yep, more dotfiles
1# Adapted from the original nixpkgs repo 2# 3# It supports static location fallback. This is a workaround waiting for an 4# alternative to MLS (Mozilla Location Services). 5 6# Target interface to manage the static file would be: 7# static = { 8# latitude = 48.8; 9# logitude = 2.3; 10# }; 11# 12# I spent way too much time getting this to work with a submodule. 13 14{ config 15, lib 16, pkgs 17, ... 18}: 19 20let 21 package = pkgs.geoclue2.override { withDemoAgent = config.services.geoclue2.enableDemoAgent; }; 22 23 cfg = config.services.geoclue2; 24 25 defaultWhitelist = [ "gnome-shell" "io.elementary.desktop.agent-geoclue2" ]; 26 27 appConfigModule = lib.types.submodule ({ name, ... }: with lib; { 28 options = { 29 desktopID = mkOption { 30 type = types.str; 31 description = "Desktop ID of the application."; 32 }; 33 34 isAllowed = mkOption { 35 type = types.bool; 36 description = '' 37 Whether the application will be allowed access to location information. 38 ''; 39 }; 40 41 isSystem = mkOption { 42 type = types.bool; 43 description = '' 44 Whether the application is a system component or not. 45 ''; 46 }; 47 48 users = mkOption { 49 type = types.listOf types.str; 50 default = [ ]; 51 description = '' 52 List of UIDs of all users for which this application is allowed location 53 info access, Defaults to an empty string to allow it for all users. 54 ''; 55 }; 56 }; 57 58 config.desktopID = mkDefault name; 59 }); 60 61 # staticModule = types.submodule ({ name, ... }: { 62 # options = { 63 # latitude = mkOption { 64 # type = types.float; 65 # example = 40.6893129; 66 # }; 67 68 # longitude = mkOption { 69 # type = types.float; 70 # example = -74.0445531; 71 # }; 72 73 # altitude = mkOption { 74 # type = types.float; 75 # default = 0; 76 # example = 96; 77 # }; 78 79 # accuracyRadius = mkOption { 80 # type = types.float; 81 # default = 0; 82 # example = 1.83; 83 # }; 84 # }; 85 # }); 86 87 appConfigToINICompatible = _: { desktopID, isAllowed, isSystem, users, ... }: { 88 name = desktopID; 89 value = { 90 allowed = isAllowed; 91 system = isSystem; 92 users = lib.concatStringsSep ";" users; 93 }; 94 }; 95 96in 97{ 98 disabledModules = [ "services/desktops/geoclue2.nix" ]; 99 100 options.services.geoclue2 = with lib; { 101 enable = mkOption { 102 type = types.bool; 103 default = false; 104 description = '' 105 Whether to enable GeoClue 2 daemon, a DBus service 106 that provides location information for accessing. 107 ''; 108 }; 109 110 enableDemoAgent = mkOption { 111 type = types.bool; 112 default = true; 113 description = '' 114 Whether to use the GeoClue demo agent. This should be 115 overridden by desktop environments that provide their own 116 agent. 117 ''; 118 }; 119 120 enableNmea = mkOption { 121 type = types.bool; 122 default = true; 123 description = '' 124 Whether to fetch location from NMEA sources on local network. 125 ''; 126 }; 127 128 enable3G = mkOption { 129 type = types.bool; 130 default = true; 131 description = '' 132 Whether to enable 3G source. 133 ''; 134 }; 135 136 enableCDMA = mkOption { 137 type = types.bool; 138 default = true; 139 description = '' 140 Whether to enable CDMA source. 141 ''; 142 }; 143 144 enableModemGPS = mkOption { 145 type = types.bool; 146 default = true; 147 description = '' 148 Whether to enable Modem-GPS source. 149 ''; 150 }; 151 152 enableWifi = mkOption { 153 type = types.bool; 154 default = true; 155 description = '' 156 Whether to enable WiFi source. 157 ''; 158 }; 159 160 geoProviderUrl = mkOption { 161 type = types.str; 162 default = "https://location.services.mozilla.com/v1/geolocate?key=geoclue"; 163 example = "https://www.googleapis.com/geolocation/v1/geolocate?key=YOUR_KEY"; 164 description = '' 165 The url to the wifi GeoLocation Service. 166 ''; 167 }; 168 169 submitData = mkOption { 170 type = types.bool; 171 default = false; 172 description = '' 173 Whether to submit data to a GeoLocation Service. 174 ''; 175 }; 176 177 submissionUrl = mkOption { 178 type = types.str; 179 default = "https://location.services.mozilla.com/v1/submit?key=geoclue"; 180 description = '' 181 The url to submit data to a GeoLocation Service. 182 ''; 183 }; 184 185 submissionNick = mkOption { 186 type = types.str; 187 default = "geoclue"; 188 description = '' 189 A nickname to submit network data with. 190 Must be 2-32 characters long. 191 ''; 192 }; 193 194 appConfig = mkOption { 195 type = types.attrsOf appConfigModule; 196 default = { }; 197 example = { 198 "com.github.app" = { 199 isAllowed = true; 200 isSystem = true; 201 users = [ "300" ]; 202 }; 203 }; 204 description = '' 205 Specify extra settings per application. 206 ''; 207 }; 208 209 # static = mkOption { 210 # type = types.nullOr (types.attrsOf staticModule); 211 # default = null; 212 # description = '' 213 # Add a fallback location that will be overriden by other location services 214 # ''; 215 # }; 216 217 staticFile = mkOption { 218 type = types.nullOr (types.str); 219 default = null; 220 description = '' 221 Add a fallback location that will be overriden by other location services 222 ''; 223 }; 224 }; 225 226 config = lib.mkIf cfg.enable { 227 environment.systemPackages = [ package ]; 228 229 services.dbus.packages = [ package ]; 230 231 systemd.packages = [ package ]; 232 233 # we cannot use DynamicUser as we need the the geoclue user to exist for the 234 # dbus policy to work 235 users = { 236 users.geoclue = { 237 isSystemUser = true; 238 home = "/var/lib/geoclue"; 239 group = "geoclue"; 240 description = "Geoinformation service"; 241 }; 242 243 groups.geoclue = { }; 244 }; 245 246 systemd.services.geoclue = { 247 wants = lib.optionals cfg.enableWifi [ "network-online.target" ]; 248 after = lib.optionals cfg.enableWifi [ "network-online.target" ]; 249 # restart geoclue service when the configuration changes 250 restartTriggers = [ 251 config.environment.etc."geoclue/geoclue.conf".source 252 ]; 253 serviceConfig.StateDirectory = "geoclue"; 254 }; 255 256 # this needs to run as a user service, since it's associated with the 257 # user who is making the requests 258 systemd.user.services = lib.mkIf cfg.enableDemoAgent { 259 geoclue-agent = { 260 description = "Geoclue agent"; 261 # this should really be `partOf = [ "geoclue.service" ]`, but 262 # we can't be part of a system service, and the agent should 263 # be okay with the main service coming and going 264 wantedBy = [ "default.target" ]; 265 wants = lib.optionals cfg.enableWifi [ "network-online.target" ]; 266 after = lib.optionals cfg.enableWifi [ "network-online.target" ]; 267 unitConfig.ConditionUser = "!@system"; 268 serviceConfig = { 269 Type = "exec"; 270 ExecStart = "${package}/libexec/geoclue-2.0/demos/agent"; 271 Restart = "on-failure"; 272 PrivateTmp = true; 273 }; 274 }; 275 }; 276 277 services.geoclue2.appConfig = { 278 epiphany = { isAllowed = true; isSystem = false; }; 279 firefox = { isAllowed = true; isSystem = false; }; 280 }; 281 282 environment.etc."geoclue/geoclue.conf".text = 283 lib.generators.toINI { } ({ 284 agent = { 285 whitelist = lib.concatStringsSep ";" 286 (lib.optional cfg.enableDemoAgent "geoclue-demo-agent" ++ defaultWhitelist); 287 }; 288 network-nmea = { 289 enable = cfg.enableNmea; 290 }; 291 "3g" = { 292 enable = cfg.enable3G; 293 }; 294 cdma = { 295 enable = cfg.enableCDMA; 296 }; 297 modem-gps = { 298 enable = cfg.enableModemGPS; 299 }; 300 wifi = { 301 enable = cfg.enableWifi; 302 url = cfg.geoProviderUrl; 303 submit-data = lib.boolToString cfg.submitData; 304 submission-url = cfg.submissionUrl; 305 submission-nick = cfg.submissionNick; 306 }; 307 } // lib.mapAttrs' appConfigToINICompatible cfg.appConfig); 308 309 # environment.etc."geolocation" = mkIf (cfg.static != null) { 310 # text = '' 311 # ${toString cfg.static.latitude} 312 # ${toString cfg.static.longitude} 313 # ${toString cfg.static.altitude} 314 # ${toString cfg.static.accuracyRadius} 315 # ''; 316 # }; 317 318 environment.etc."geolocation" = lib.mkIf (cfg.staticFile != null) { text = cfg.staticFile; }; 319 }; 320 321 meta = with lib; { 322 maintainers = with maintainers; [ ] ++ teams.pantheon.members; 323 }; 324}