diff --git a/.channelStable.json b/.channelStable.json index 36bc925..a6b070e 100644 --- a/.channelStable.json +++ b/.channelStable.json @@ -1,9 +1,9 @@ { "url": "https://github.com/NixOS/nixpkgs.git", - "rev": "e4adbfbab8aadf9d80a93d40fb612cb910073af9", - "date": "2021-01-25T20:25:09+01:00", - "path": "/nix/store/i43dyq07kr5dy1rbn6vqffg1pwcl9hi9-nixpkgs", - "sha256": "0fs32adk4x5xg9m00nykhxhka927wrnwkjx59as673swh46hdvck", + "rev": "2394284537b89471c87065b040d3dedd8b5907fe", + "date": "2021-02-10T23:24:22+01:00", + "path": "/nix/store/rqgraycidchn5wc5mki5sqj8bl5cpx78-nixpkgs", + "sha256": "1j7vp735is5d32mbrgavpxi3fbnsm6d99a01ap8gn30n5ysd14sl", "fetchSubmodules": false, "deepClone": false, "leaveDotGit": false diff --git a/.channelUnstable.json b/.channelUnstable.json index 3b3915d..acadbd1 100644 --- a/.channelUnstable.json +++ b/.channelUnstable.json @@ -1,9 +1,9 @@ { "url": "https://github.com/NixOS/nixpkgs.git", - "rev": "891f607d5301d6730cb1f9dcf3618bcb1ab7f10e", - "date": "2021-01-25T12:54:49+01:00", - "path": "/nix/store/0fdmvrw6pcwqf28ymvl8qfbflc9m65jc-nixpkgs", - "sha256": "1cr39f0sbr0h5d83dv1q34mcpwnkwwbdk5fqlyqp2mnxghzwssng", + "rev": "758b29b5a28b818e311ad540637a5c1e40867489", + "date": "2021-02-10T23:30:20+01:00", + "path": "/nix/store/0d1llmnj9bq8b5wlz2a62ikhy13r9mq9-nixpkgs", + "sha256": "00nk1a002zzi0ij4xp2hf7955wj49qdwsm2wy7mzbpjbgick6scp", "fetchSubmodules": false, "deepClone": false, "leaveDotGit": false diff --git a/configs/pepe/configuration.nix b/configs/pepe/configuration.nix index a8e28b7..955e1b1 100644 --- a/configs/pepe/configuration.nix +++ b/configs/pepe/configuration.nix @@ -17,6 +17,8 @@ ]; + nixpkgs.config.permittedInsecurePackages = [ "homeassistant-0.114.4" ]; + networking.hostName = "pepe"; # fonts diff --git a/configs/pepe/home-assistant/zigbee2mqtt.nix b/configs/pepe/home-assistant/zigbee2mqtt.nix index 8ca2474..3fe2839 100644 --- a/configs/pepe/home-assistant/zigbee2mqtt.nix +++ b/configs/pepe/home-assistant/zigbee2mqtt.nix @@ -28,7 +28,7 @@ in { homeassistant = false; # allow new devices to join - permit_join = true; + permit_join = false; # MQTT settings mqtt = { diff --git a/configs/sterni/packages.nix b/configs/sterni/packages.nix index 16fce04..c69fb8c 100644 --- a/configs/sterni/packages.nix +++ b/configs/sterni/packages.nix @@ -10,7 +10,7 @@ in { #unstable.sonic-visualiser sononym-crawler darktable - haskellPackages.mahlzeit + #haskellPackages.mahlzeit # rust development environment rustup diff --git a/configs/workhorse/configuration.nix b/configs/workhorse/configuration.nix index 3da882b..4d81861 100644 --- a/configs/workhorse/configuration.nix +++ b/configs/workhorse/configuration.nix @@ -31,6 +31,9 @@ ./property.nix ]; + nixpkgs.config.permittedInsecurePackages = + [ "gogs-0.11.91" "nextcloud-19.0.6" ]; + # todo: add this to each file instead summing that here on-failure.plans = { gogs.name = "gogs"; diff --git a/configs/workhorse/nextcloud.nix b/configs/workhorse/nextcloud.nix index be4f76b..56a51b1 100644 --- a/configs/workhorse/nextcloud.nix +++ b/configs/workhorse/nextcloud.nix @@ -7,9 +7,6 @@ let in { - # Nextcloud 19 is still supported, but CVE-2020-8259 & CVE-2020-8152 are unfixed! - nixpkgs.config.permittedInsecurePackages = [ "nextcloud-19.0.6" ]; - containers.nextcloud = { # mount host folders diff --git a/modules/default.nix b/modules/default.nix index 7ba90b1..87f8feb 100644 --- a/modules/default.nix +++ b/modules/default.nix @@ -2,9 +2,6 @@ imports = [ - #./later/syncthing.nix - #./later/nextcloud.nix - ./services/light-control.nix ./services/castget.nix diff --git a/modules/later/nextcloud.nix b/modules/later/nextcloud.nix deleted file mode 100644 index b47e001..0000000 --- a/modules/later/nextcloud.nix +++ /dev/null @@ -1,626 +0,0 @@ -{ config, lib, pkgs, ... }: - -assert lib.versionOlder lib.version "20.09"; - -with lib; - -let - cfg = config.later.services.nextcloud; - fpm = config.services.phpfpm.pools.nextcloud; - - phpPackage = pkgs.php73; - phpPackages = pkgs.php73Packages; - - toKeyValue = generators.toKeyValue { - mkKeyValue = generators.mkKeyValueDefault { } " = "; - }; - - phpOptionsExtensions = '' - ${optionalString cfg.caching.apcu - "extension=${phpPackages.apcu}/lib/php/extensions/apcu.so"} - ${optionalString cfg.caching.redis - "extension=${phpPackages.redis}/lib/php/extensions/redis.so"} - ${optionalString cfg.caching.memcached - "extension=${phpPackages.memcached}/lib/php/extensions/memcached.so"} - extension=${phpPackages.imagick}/lib/php/extensions/imagick.so - zend_extension = opcache.so - opcache.enable = 1 - ''; - phpOptions = { - upload_max_filesize = cfg.maxUploadSize; - post_max_size = cfg.maxUploadSize; - memory_limit = cfg.maxUploadSize; - } // cfg.phpOptions; - phpOptionsStr = phpOptionsExtensions + (toKeyValue phpOptions); - - occ = pkgs.writeScriptBin "nextcloud-occ" '' - #! ${pkgs.stdenv.shell} - cd ${pkgs.nextcloud} - sudo=exec - if [[ "$USER" != nextcloud ]]; then - sudo='exec /run/wrappers/bin/sudo -u nextcloud --preserve-env=NEXTCLOUD_CONFIG_DIR' - fi - export NEXTCLOUD_CONFIG_DIR="${cfg.home}/config" - $sudo \ - ${phpPackage}/bin/php \ - -c ${pkgs.writeText "php.ini" phpOptionsStr}\ - occ $* - ''; - -in { - options.later.services.nextcloud = { - enable = mkEnableOption "nextcloud"; - hostName = mkOption { - type = types.str; - description = "FQDN for the nextcloud instance."; - }; - home = mkOption { - type = types.str; - default = "/var/lib/nextcloud"; - description = "Storage path of nextcloud."; - }; - logLevel = mkOption { - type = types.ints.between 0 4; - default = 2; - description = "Log level value between 0 (DEBUG) and 4 (FATAL)."; - }; - https = mkOption { - type = types.bool; - default = false; - description = "Use https for generated links."; - }; - - maxUploadSize = mkOption { - default = "512M"; - type = types.str; - description = '' - Defines the upload limit for files. This changes the relevant options - in php.ini and nginx if enabled. - ''; - }; - - skeletonDirectory = mkOption { - default = ""; - type = types.str; - description = '' - The directory where the skeleton files are located. These files will be - copied to the data directory of new users. Leave empty to not copy any - skeleton files. - ''; - }; - - nginx.enable = mkOption { - type = types.bool; - default = false; - description = '' - Whether to enable nginx virtual host management. - Further nginx configuration can be done by adapting services.nginx.virtualHosts.<name>. - See for further information. - ''; - }; - - webfinger = mkOption { - type = types.bool; - default = false; - description = '' - Enable this option if you plan on using the webfinger plugin. - The appropriate nginx rewrite rules will be added to your configuration. - ''; - }; - - phpOptions = mkOption { - type = types.attrsOf types.str; - default = { - short_open_tag = "Off"; - expose_php = "Off"; - error_reporting = "E_ALL & ~E_DEPRECATED & ~E_STRICT"; - display_errors = "stderr"; - "opcache.enable_cli" = "1"; - "opcache.interned_strings_buffer" = "8"; - "opcache.max_accelerated_files" = "10000"; - "opcache.memory_consumption" = "128"; - "opcache.revalidate_freq" = "1"; - "opcache.fast_shutdown" = "1"; - "openssl.cafile" = "/etc/ssl/certs/ca-certificates.crt"; - catch_workers_output = "yes"; - }; - description = '' - Options for PHP's php.ini file for nextcloud. - ''; - }; - - poolSettings = mkOption { - type = with types; attrsOf (oneOf [ str int bool ]); - default = { - "pm" = "dynamic"; - "pm.max_children" = "32"; - "pm.start_servers" = "2"; - "pm.min_spare_servers" = "2"; - "pm.max_spare_servers" = "4"; - "pm.max_requests" = "500"; - }; - description = '' - Options for nextcloud's PHP pool. See the documentation on php-fpm.conf for details on configuration directives. - ''; - }; - - poolConfig = mkOption { - type = types.nullOr types.lines; - default = null; - description = '' - Options for nextcloud's PHP pool. See the documentation on php-fpm.conf for details on configuration directives. - ''; - }; - - config = { - dbtype = mkOption { - type = types.enum [ "sqlite" "pgsql" "mysql" ]; - default = "sqlite"; - description = "Database type."; - }; - dbname = mkOption { - type = types.nullOr types.str; - default = "nextcloud"; - description = "Database name."; - }; - dbuser = mkOption { - type = types.nullOr types.str; - default = "nextcloud"; - description = "Database user."; - }; - dbpass = mkOption { - type = types.nullOr types.str; - default = null; - description = '' - Database password. Use dbpassFile to avoid this - being world-readable in the /nix/store. - ''; - }; - dbpassFile = mkOption { - type = types.nullOr types.str; - default = null; - description = '' - The full path to a file that contains the database password. - ''; - }; - dbhost = mkOption { - type = types.nullOr types.str; - default = "localhost"; - description = '' - Database host. - - Note: for using Unix authentication with PostgreSQL, this should be - set to /run/postgresql. - ''; - }; - dbport = mkOption { - type = with types; nullOr (either int str); - default = null; - description = "Database port."; - }; - dbtableprefix = mkOption { - type = types.nullOr types.str; - default = null; - description = "Table prefix in Nextcloud database."; - }; - adminuser = mkOption { - type = types.str; - default = "root"; - description = "Admin username."; - }; - adminpass = mkOption { - type = types.nullOr types.str; - default = null; - description = '' - Admin password. Use adminpassFile to avoid this - being world-readable in the /nix/store. - ''; - }; - adminpassFile = mkOption { - type = types.nullOr types.str; - default = null; - description = '' - The full path to a file that contains the admin's password. - ''; - }; - - extraTrustedDomains = mkOption { - type = types.listOf types.str; - default = [ ]; - description = '' - Trusted domains, from which the nextcloud installation will be - acessible. You don't need to add - services.nextcloud.hostname here. - ''; - }; - - trustedProxies = mkOption { - type = types.listOf types.str; - default = [ ]; - description = '' - Trusted proxies, to provide if the nextcloud installation is being - proxied to secure against e.g. spoofing. - ''; - }; - - overwriteProtocol = mkOption { - type = types.nullOr (types.enum [ "http" "https" ]); - default = null; - example = "https"; - - description = '' - Force Nextcloud to always use HTTPS i.e. for link generation. Nextcloud - uses the currently used protocol by default, but when behind a reverse-proxy, - it may use http for everything although Nextcloud - may be served via HTTPS. - ''; - }; - }; - - caching = { - apcu = mkOption { - type = types.bool; - default = true; - description = '' - Whether to load the APCu module into PHP. - ''; - }; - redis = mkOption { - type = types.bool; - default = false; - description = '' - Whether to load the Redis module into PHP. - You still need to enable Redis in your config.php. - See https://docs.nextcloud.com/server/14/admin_manual/configuration_server/caching_configuration.html - ''; - }; - memcached = mkOption { - type = types.bool; - default = false; - description = '' - Whether to load the Memcached module into PHP. - You still need to enable Memcached in your config.php. - See https://docs.nextcloud.com/server/14/admin_manual/configuration_server/caching_configuration.html - ''; - }; - }; - autoUpdateApps = { - enable = mkOption { - type = types.bool; - default = false; - description = '' - Run regular auto update of all apps installed from the nextcloud app store. - ''; - }; - startAt = mkOption { - type = with types; either str (listOf str); - default = "05:00:00"; - example = "Sun 14:00:00"; - description = '' - When to run the update. See `systemd.services.<name>.startAt`. - ''; - }; - }; - }; - - config = mkIf cfg.enable (mkMerge [ - { - assertions = let acfg = cfg.config; - in [ - { - assertion = !(acfg.dbpass != null && acfg.dbpassFile != null); - message = "Please specify no more than one of dbpass or dbpassFile"; - } - { - assertion = ((acfg.adminpass != null || acfg.adminpassFile != null) - && !(acfg.adminpass != null && acfg.adminpassFile != null)); - message = "Please specify exactly one of adminpass or adminpassFile"; - } - ]; - - warnings = optional (cfg.poolConfig != null) '' - Using config.services.nextcloud.poolConfig is deprecated and will become unsupported in a future release. - Please migrate your configuration to config.services.nextcloud.poolSettings. - ''; - } - - { - systemd.timers.nextcloud-cron = { - wantedBy = [ "timers.target" ]; - timerConfig.OnBootSec = "5m"; - timerConfig.OnUnitActiveSec = "15m"; - timerConfig.Unit = "nextcloud-cron.service"; - }; - - systemd.services = { - nextcloud-setup = let - c = cfg.config; - writePhpArrary = a: - "[${concatMapStringsSep "," (val: ''"${toString val}"'') a}]"; - overrideConfig = pkgs.writeText "nextcloud-config.php" '' - [ - [ 'path' => '${cfg.home}/apps', 'url' => '/apps', 'writable' => false ], - [ 'path' => '${cfg.home}/store-apps', 'url' => '/store-apps', 'writable' => true ], - ], - 'datadirectory' => '${cfg.home}/data', - 'skeletondirectory' => '${cfg.skeletonDirectory}', - ${ - optionalString cfg.caching.apcu - "'memcache.local' => '\\OC\\Memcache\\APCu'," - } - 'log_type' => 'syslog', - 'log_level' => '${builtins.toString cfg.logLevel}', - ${ - optionalString (c.overwriteProtocol != null) - "'overwriteprotocol' => '${c.overwriteProtocol}'," - } - ${optionalString (c.dbname != null) "'dbname' => '${c.dbname}',"} - ${optionalString (c.dbhost != null) "'dbhost' => '${c.dbhost}',"} - ${ - optionalString (c.dbport != null) - "'dbport' => '${toString c.dbport}'," - } - ${optionalString (c.dbuser != null) "'dbuser' => '${c.dbuser}',"} - ${ - optionalString (c.dbtableprefix != null) - "'dbtableprefix' => '${toString c.dbtableprefix}'," - } - ${ - optionalString (c.dbpass != null) - "'dbpassword' => '${c.dbpass}'," - } - ${ - optionalString (c.dbpassFile != null) - "'dbpassword' => nix_read_pwd()," - } - 'dbtype' => '${c.dbtype}', - 'trusted_domains' => ${ - writePhpArrary ([ cfg.hostName ] ++ c.extraTrustedDomains) - }, - 'trusted_proxies' => ${writePhpArrary (c.trustedProxies)}, - ]; - ''; - occInstallCmd = let - dbpass = if c.dbpassFile != null then - ''"$(<"${toString c.dbpassFile}")"'' - else if c.dbpass != null then - ''"${toString c.dbpass}"'' - else - null; - adminpass = if c.adminpassFile != null then - ''"$(<"${toString c.adminpassFile}")"'' - else - ''"${toString c.adminpass}"''; - installFlags = concatStringsSep " \\\n " - (mapAttrsToList (k: v: "${k} ${toString v}") { - "--database" = ''"${c.dbtype}"''; - # The following attributes are optional depending on the type of - # database. Those that evaluate to null on the left hand side - # will be omitted. - ${if c.dbname != null then "--database-name" else null} = - ''"${c.dbname}"''; - ${if c.dbhost != null then "--database-host" else null} = - ''"${c.dbhost}"''; - ${if c.dbport != null then "--database-port" else null} = - ''"${toString c.dbport}"''; - ${if c.dbuser != null then "--database-user" else null} = - ''"${c.dbuser}"''; - ${ - if (any (x: x != null) [ c.dbpass c.dbpassFile ]) then - "--database-pass" - else - null - } = dbpass; - ${ - if c.dbtableprefix != null then - "--database-table-prefix" - else - null - } = ''"${toString c.dbtableprefix}"''; - "--admin-user" = ''"${c.adminuser}"''; - "--admin-pass" = adminpass; - "--data-dir" = ''"${cfg.home}/data"''; - }); - in '' - ${occ}/bin/nextcloud-occ maintenance:install \ - ${installFlags} - ''; - occSetTrustedDomainsCmd = concatStringsSep "\n" (imap0 (i: v: '' - ${occ}/bin/nextcloud-occ config:system:set trusted_domains \ - ${toString i} --value="${toString v}" - '') ([ cfg.hostName ] ++ cfg.config.extraTrustedDomains)); - - in { - wantedBy = [ "multi-user.target" ]; - before = [ "phpfpm-nextcloud.service" ]; - path = [ occ ]; - script = '' - chmod og+x ${cfg.home} - ln -sf ${pkgs.nextcloud}/apps ${cfg.home}/ - mkdir -p ${cfg.home}/config ${cfg.home}/data ${cfg.home}/store-apps - ln -sf ${overrideConfig} ${cfg.home}/config/override.config.php - - chown -R nextcloud:nginx ${cfg.home}/config ${cfg.home}/data ${cfg.home}/store-apps - - # Do not install if already installed - if [[ ! -e ${cfg.home}/config/config.php ]]; then - ${occInstallCmd} - fi - - ${occ}/bin/nextcloud-occ upgrade - - ${occ}/bin/nextcloud-occ config:system:delete trusted_domains - ${occSetTrustedDomainsCmd} - ''; - serviceConfig.Type = "oneshot"; - }; - nextcloud-cron = { - environment.NEXTCLOUD_CONFIG_DIR = "${cfg.home}/config"; - serviceConfig.Type = "oneshot"; - serviceConfig.User = "nextcloud"; - serviceConfig.ExecStart = - "${phpPackage}/bin/php -f ${pkgs.nextcloud}/cron.php"; - }; - nextcloud-update-plugins = mkIf cfg.autoUpdateApps.enable { - serviceConfig.Type = "oneshot"; - serviceConfig.ExecStart = "${occ}/bin/nextcloud-occ app:update --all"; - serviceConfig.User = "nextcloud"; - startAt = cfg.autoUpdateApps.startAt; - }; - }; - - services.phpfpm = { - pools.nextcloud = { - user = "nextcloud"; - group = "nginx"; - phpOptions = phpOptionsStr; - phpPackage = phpPackage; - phpEnv = { - NEXTCLOUD_CONFIG_DIR = "${cfg.home}/config"; - PATH = - "/run/wrappers/bin:/nix/var/nix/profiles/default/bin:/run/current-system/sw/bin:/usr/bin:/bin"; - }; - settings = mapAttrs (name: mkDefault) { - "listen.owner" = "nginx"; - "listen.group" = "nginx"; - } // cfg.poolSettings; - extraConfig = cfg.poolConfig; - }; - }; - - users.extraUsers.nextcloud = { - home = "${cfg.home}"; - group = "nginx"; - createHome = true; - }; - - environment.systemPackages = [ occ ]; - } - - (mkIf cfg.nginx.enable { - services.nginx = { - enable = true; - virtualHosts = { - ${cfg.hostName} = { - root = pkgs.nextcloud; - locations = { - "= /robots.txt" = { - priority = 100; - extraConfig = '' - allow all; - log_not_found off; - access_log off; - ''; - }; - "/" = { - priority = 200; - extraConfig = "rewrite ^ /index.php;"; - }; - "~ ^/store-apps" = { - priority = 201; - extraConfig = "root ${cfg.home};"; - }; - "= /.well-known/carddav" = { - priority = 210; - extraConfig = "return 301 $scheme://$host/remote.php/dav;"; - }; - "= /.well-known/caldav" = { - priority = 210; - extraConfig = "return 301 $scheme://$host/remote.php/dav;"; - }; - "~ ^\\/(?:build|tests|config|lib|3rdparty|templates|data)\\/" = { - priority = 300; - extraConfig = "deny all;"; - }; - "~ ^\\/(?:\\.|autotest|occ|issue|indie|db_|console)" = { - priority = 300; - extraConfig = "deny all;"; - }; - "~ ^\\/(?:index|remote|public|cron|core/ajax\\/update|status|ocs\\/v[12]|updater\\/.+|ocs-provider\\/.+|ocm-provider\\/.+)\\.php(?:$|\\/)" = - { - priority = 500; - extraConfig = '' - include ${config.services.nginx.package}/conf/fastcgi.conf; - fastcgi_split_path_info ^(.+\.php)(\\/.*)$; - try_files $fastcgi_script_name =404; - fastcgi_param PATH_INFO $fastcgi_path_info; - fastcgi_param HTTPS ${if cfg.https then "on" else "off"}; - fastcgi_param modHeadersAvailable true; - fastcgi_param front_controller_active true; - fastcgi_pass unix:${fpm.socket}; - fastcgi_intercept_errors on; - fastcgi_request_buffering off; - fastcgi_read_timeout 120s; - ''; - }; - "~ ^\\/(?:updater|ocs-provider|ocm-provider)(?:$|\\/)".extraConfig = - '' - try_files $uri/ =404; - index index.php; - ''; - "~ \\.(?:css|js|woff2?|svg|gif)$".extraConfig = '' - try_files $uri /index.php$request_uri; - add_header Cache-Control "public, max-age=15778463"; - add_header X-Content-Type-Options nosniff; - add_header X-XSS-Protection "1; mode=block"; - add_header X-Robots-Tag none; - add_header X-Download-Options noopen; - add_header X-Permitted-Cross-Domain-Policies none; - add_header X-Frame-Options sameorigin; - add_header Referrer-Policy no-referrer; - access_log off; - ''; - "~ \\.(?:png|html|ttf|ico|jpg|jpeg)$".extraConfig = '' - try_files $uri /index.php$request_uri; - access_log off; - ''; - }; - extraConfig = '' - add_header X-Content-Type-Options nosniff; - add_header X-XSS-Protection "1; mode=block"; - add_header X-Robots-Tag none; - add_header X-Download-Options noopen; - add_header X-Permitted-Cross-Domain-Policies none; - add_header X-Frame-Options sameorigin; - add_header Referrer-Policy no-referrer; - add_header Strict-Transport-Security "max-age=15552000; includeSubDomains" always; - error_page 403 /core/templates/403.php; - error_page 404 /core/templates/404.php; - client_max_body_size ${cfg.maxUploadSize}; - fastcgi_buffers 64 4K; - fastcgi_hide_header X-Powered-By; - gzip on; - gzip_vary on; - gzip_comp_level 4; - gzip_min_length 256; - gzip_proxied expired no-cache no-store private no_last_modified no_etag auth; - gzip_types application/atom+xml application/javascript application/json application/ld+json application/manifest+json application/rss+xml application/vnd.geo+json application/vnd.ms-fontobject application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/bmp image/svg+xml image/x-icon text/cache-manifest text/css text/plain text/vcard text/vnd.rim.location.xloc text/vtt text/x-component text/x-cross-domain-policy; - - ${optionalString cfg.webfinger '' - rewrite ^/.well-known/host-meta /public.php?service=host-meta last; - rewrite ^/.well-known/host-meta.json /public.php?service=host-meta-json last; - ''} - ''; - }; - }; - }; - }) - ]); - - # meta.doc = ./nextcloud.xml; -} diff --git a/modules/later/syncthing.nix b/modules/later/syncthing.nix deleted file mode 100644 index 49422d3..0000000 --- a/modules/later/syncthing.nix +++ /dev/null @@ -1,505 +0,0 @@ -{ config, lib, pkgs, ... }: - -# assert lib.versionOlder lib.version "20.09"; - -with lib; - -let - cfg = config.services.syncthing; - defaultUser = "syncthing"; - - devices = mapAttrsToList (name: device: { - deviceID = device.id; - inherit (device) name addresses introducer; - }) cfg.declarative.devices; - - folders = mapAttrsToList (_: folder: { - inherit (folder) path id label type; - devices = map (device: { deviceId = cfg.declarative.devices.${device}.id; }) - folder.devices; - rescanIntervalS = folder.rescanInterval; - fsWatcherEnabled = folder.watch; - fsWatcherDelayS = folder.watchDelay; - ignorePerms = folder.ignorePerms; - versioning = folder.versioning; - }) (filterAttrs (_: folder: folder.enable) cfg.declarative.folders); - - # get the api key by parsing the config.xml - getApiKey = pkgs.writers.writeDash "getAPIKey" '' - ${pkgs.libxml2}/bin/xmllint \ - --xpath 'string(configuration/gui/apikey)'\ - ${cfg.configDir}/config.xml - ''; - - updateConfig = pkgs.writers.writeDash "merge-syncthing-config" '' - set -efu - # wait for syncthing port to open - until ${pkgs.curl}/bin/curl -Ss ${cfg.guiAddress} -o /dev/null; do - sleep 1 - done - - API_KEY=$(${getApiKey}) - OLD_CFG=$(${pkgs.curl}/bin/curl -Ss \ - -H "X-API-Key: $API_KEY" \ - ${cfg.guiAddress}/rest/system/config) - - # generate the new config by merging with the nixos config options - NEW_CFG=$(echo "$OLD_CFG" | ${pkgs.jq}/bin/jq -s '.[] as $in | $in * { - "devices": (${builtins.toJSON devices}${ - optionalString (!cfg.declarative.overrideDevices) " + $in.devices" - }), - "folders": (${builtins.toJSON folders}${ - optionalString (!cfg.declarative.overrideFolders) " + $in.folders" - }) - }') - - # POST the new config to syncthing - echo "$NEW_CFG" | ${pkgs.curl}/bin/curl -Ss \ - -H "X-API-Key: $API_KEY" \ - ${cfg.guiAddress}/rest/system/config -d @- - - # restart syncthing after sending the new config - ${pkgs.curl}/bin/curl -Ss \ - -H "X-API-Key: $API_KEY" \ - -X POST \ - ${cfg.guiAddress}/rest/system/restart - ''; -in { - - ###### interface - options = { - test.services.syncthing = { - - enable = mkEnableOption '' - Syncthing - the self-hosted open-source alternative - to Dropbox and Bittorrent Sync. Initial interface will be - available on http://127.0.0.1:8384/. - ''; - - declarative = { - cert = mkOption { - type = types.nullOr types.str; - default = null; - description = '' - Path to users cert.pem file, will be copied into the syncthing's - configDir - ''; - }; - - key = mkOption { - type = types.nullOr types.str; - default = null; - description = '' - Path to users key.pem file, will be copied into the syncthing's - configDir - ''; - }; - - overrideDevices = mkOption { - type = types.bool; - default = true; - description = '' - Whether to delete the devices which are not configured via the - declarative.devices option. - If set to false, devices added via the webinterface will - persist but will have to be deleted manually. - ''; - }; - - devices = mkOption { - default = { }; - description = '' - Peers/devices which syncthing should communicate with. - ''; - example = { - bigbox = { - id = - "7CFNTQM-IMTJBHJ-3UWRDIU-ZGQJFR6-VCXZ3NB-XUH3KZO-N52ITXR-LAIYUAU"; - addresses = [ "tcp://192.168.0.10:51820" ]; - }; - }; - type = types.attrsOf (types.submodule ({ config, ... }: { - options = { - - name = mkOption { - type = types.str; - default = config._module.args.name; - description = '' - Name of the device - ''; - }; - - addresses = mkOption { - type = types.listOf types.str; - default = [ ]; - description = '' - The addresses used to connect to the device. - If this is let empty, dynamic configuration is attempted - ''; - }; - - id = mkOption { - type = types.str; - description = '' - The id of the other peer, this is mandatory. It's documented at - https://docs.syncthing.net/dev/device-ids.html - ''; - }; - - introducer = mkOption { - type = types.bool; - default = false; - description = '' - If the device should act as an introducer and be allowed - to add folders on this computer. - ''; - }; - - }; - })); - }; - - overrideFolders = mkOption { - type = types.bool; - default = true; - description = '' - Whether to delete the folders which are not configured via the - declarative.folders option. - If set to false, folders added via the webinterface will persist - but will have to be deleted manually. - ''; - }; - - folders = mkOption { - default = { }; - description = '' - folders which should be shared by syncthing. - ''; - example = { - "/home/user/sync" = { - id = "syncme"; - devices = [ "bigbox" ]; - }; - }; - type = types.attrsOf (types.submodule ({ config, ... }: { - options = { - - enable = mkOption { - type = types.bool; - default = true; - description = '' - share this folder. - This option is useful when you want to define all folders - in one place, but not every machine should share all folders. - ''; - }; - - path = mkOption { - type = types.str; - default = config._module.args.name; - description = '' - The path to the folder which should be shared. - ''; - }; - - id = mkOption { - type = types.str; - default = config._module.args.name; - description = '' - The id of the folder. Must be the same on all devices. - ''; - }; - - label = mkOption { - type = types.str; - default = config._module.args.name; - description = '' - The label of the folder. - ''; - }; - - devices = mkOption { - type = types.listOf types.str; - default = [ ]; - description = '' - The devices this folder should be shared with. Must be defined - in the declarative.devices attribute. - ''; - }; - - versioning = mkOption { - default = null; - description = '' - how to keep changed/deleted files with syncthing. - there are 4 different types of versioning with different parameters - see https://docs.syncthing.net/users/versioning.html#simple-file-versioning - ''; - example = [ - { - versioning = { - type = "simple"; - params.keep = "10"; - }; - } - { - versioning = { - type = "trashcan"; - params.cleanoutDays = "1000"; - }; - } - { - versioning = { - type = "staggered"; - params = { - cleanInterval = "3600"; - maxAge = "31536000"; - versionsPath = "/syncthing/backup"; - }; - }; - } - { - versioning = { - type = "external"; - params.versionsPath = pkgs.writers.writeBash "backup" '' - folderpath="$1" - filepath="$2" - rm -rf "$folderpath/$filepath" - ''; - }; - } - ]; - type = with types; - nullOr (submodule { - options = { - type = mkOption { - type = - enum [ "external" "simple" "staggered" "trashcan" ]; - }; - params = mkOption { type = attrsOf (either str path); }; - }; - }); - }; - - rescanInterval = mkOption { - type = types.int; - default = 3600; - description = '' - How often the folders should be rescaned for changes. - ''; - }; - - type = mkOption { - type = types.enum [ "sendreceive" "sendonly" "receiveonly" ]; - default = "sendreceive"; - description = '' - Whether to send only changes from this folder, only receive them - or propagate both. - ''; - }; - - watch = mkOption { - type = types.bool; - default = true; - description = '' - Whether the folder should be watched for changes by inotify. - ''; - }; - - watchDelay = mkOption { - type = types.int; - default = 10; - description = '' - The delay after an inotify event is triggered. - ''; - }; - - ignorePerms = mkOption { - type = types.bool; - default = true; - description = '' - Whether to propagate permission changes. - ''; - }; - - }; - })); - }; - }; - - guiAddress = mkOption { - type = types.str; - default = "127.0.0.1:8384"; - description = '' - Address to serve the GUI. - ''; - }; - - systemService = mkOption { - type = types.bool; - default = true; - description = "Auto launch Syncthing as a system service."; - }; - - user = mkOption { - type = types.str; - default = defaultUser; - description = '' - Syncthing will be run under this user (user will be created if it doesn't exist. - This can be your user name). - ''; - }; - - group = mkOption { - type = types.str; - default = defaultUser; - description = '' - Syncthing will be run under this group (group will not be created if it doesn't exist. - This can be your user name). - ''; - }; - - all_proxy = mkOption { - type = with types; nullOr str; - default = null; - example = "socks5://address.com:1234"; - description = '' - Overwrites all_proxy environment variable for the syncthing process to - the given value. This is normaly used to let relay client connect - through SOCKS5 proxy server. - ''; - }; - - dataDir = mkOption { - type = types.path; - default = "/var/lib/syncthing"; - description = '' - Path where synced directories will exist. - ''; - }; - - configDir = mkOption { - type = types.path; - description = '' - Path where the settings and keys will exist. - ''; - default = let - nixos = config.system.stateVersion; - cond = versionAtLeast nixos "19.03"; - in cfg.dataDir + (optionalString cond "/.config/syncthing"); - }; - - openDefaultPorts = mkOption { - type = types.bool; - default = false; - example = literalExample "true"; - description = '' - Open the default ports in the firewall: - - TCP 22000 for transfers - - UDP 21027 for discovery - If multiple users are running syncthing on this machine, you will need to manually open a set of ports for each instance and leave this disabled. - Alternatively, if are running only a single instance on this machine using the default ports, enable this. - ''; - }; - - package = mkOption { - type = types.package; - default = pkgs.syncthing; - defaultText = "pkgs.syncthing"; - example = literalExample "pkgs.syncthing"; - description = '' - Syncthing package to use. - ''; - }; - }; - }; - - #imports = [ - # (mkRemovedOptionModule ["services" "syncthing" "useInotify"] '' - # This option was removed because syncthing now has the inotify functionality included under the name "fswatcher". - # It can be enabled on a per-folder basis through the webinterface. - # '') - #]; - - ###### implementation - - config = mkIf cfg.enable { - - networking.firewall = mkIf cfg.openDefaultPorts { - allowedTCPPorts = [ 22000 ]; - allowedUDPPorts = [ 21027 ]; - }; - - systemd.packages = [ pkgs.syncthing ]; - - users.users = mkIf (cfg.systemService && cfg.user == defaultUser) { - ${defaultUser} = { - group = cfg.group; - home = cfg.dataDir; - createHome = true; - uid = config.ids.uids.syncthing; - description = "Syncthing daemon user"; - }; - }; - - users.groups = mkIf (cfg.systemService && cfg.group == defaultUser) { - ${defaultUser}.gid = config.ids.gids.syncthing; - }; - - systemd.services = { - syncthing = mkIf cfg.systemService { - description = "Syncthing service"; - after = [ "network.target" ]; - environment = { - STNORESTART = "yes"; - STNOUPGRADE = "yes"; - inherit (cfg) all_proxy; - } // config.networking.proxy.envVars; - wantedBy = [ "multi-user.target" ]; - serviceConfig = { - Restart = "on-failure"; - SuccessExitStatus = "2 3 4"; - RestartForceExitStatus = "3 4"; - User = cfg.user; - Group = cfg.group; - ExecStartPre = - mkIf (cfg.declarative.cert != null || cfg.declarative.key != null) - "+${ - pkgs.writers.writeBash "syncthing-copy-keys" '' - install -dm700 -o ${cfg.user} -g ${cfg.group} ${cfg.configDir} - ${optionalString (cfg.declarative.cert != null) '' - install -Dm400 -o ${cfg.user} -g ${cfg.group} ${ - toString cfg.declarative.cert - } ${cfg.configDir}/cert.pem - ''} - ${optionalString (cfg.declarative.key != null) '' - install -Dm400 -o ${cfg.user} -g ${cfg.group} ${ - toString cfg.declarative.key - } ${cfg.configDir}/key.pem - ''} - '' - }"; - ExecStart = '' - ${cfg.package}/bin/syncthing \ - -no-browser \ - -gui-address=${cfg.guiAddress} \ - -home=${cfg.configDir} - ''; - }; - }; - syncthing-init = mkIf - (cfg.declarative.devices != { } || cfg.declarative.folders != { }) { - after = [ "syncthing.service" ]; - wantedBy = [ "multi-user.target" ]; - - serviceConfig = { - User = cfg.user; - RemainAfterExit = true; - Type = "oneshot"; - ExecStart = updateConfig; - }; - }; - - syncthing-resume = { wantedBy = [ "suspend.target" ]; }; - }; - }; -} diff --git a/modules/programs/git.nix b/modules/programs/git.nix index 8912249..c721071 100644 --- a/modules/programs/git.nix +++ b/modules/programs/git.nix @@ -16,6 +16,7 @@ in { environment.systemPackages = with pkgs; [ git tig + lazygit git-crypt gitAndTools.gitflow gitAndTools.gitSVN