summaryrefslogtreecommitdiffstats
path: root/3modules/tv
diff options
context:
space:
mode:
Diffstat (limited to '3modules/tv')
-rw-r--r--3modules/tv/consul.nix1
-rw-r--r--3modules/tv/default.nix9
-rw-r--r--3modules/tv/git.nix483
-rw-r--r--3modules/tv/github-hosts-sync.nix83
-rw-r--r--3modules/tv/identity.nix88
-rw-r--r--3modules/tv/nginx.nix71
-rw-r--r--3modules/tv/retiolum.nix222
-rw-r--r--3modules/tv/urlwatch.nix136
8 files changed, 9 insertions, 1084 deletions
diff --git a/3modules/tv/consul.nix b/3modules/tv/consul.nix
index 312faa02..4e54c2ab 100644
--- a/3modules/tv/consul.nix
+++ b/3modules/tv/consul.nix
@@ -10,7 +10,6 @@ let
cfg = config.tv.consul;
out = {
- imports = [ ../../3modules/tv/iptables.nix ];
options.tv.consul = api;
config = mkIf cfg.enable (mkMerge [
imp
diff --git a/3modules/tv/default.nix b/3modules/tv/default.nix
new file mode 100644
index 00000000..bb10d826
--- /dev/null
+++ b/3modules/tv/default.nix
@@ -0,0 +1,9 @@
+_:
+
+{
+ imports = [
+ ./consul.nix
+ ./ejabberd.nix
+ ./iptables.nix
+ ];
+}
diff --git a/3modules/tv/git.nix b/3modules/tv/git.nix
deleted file mode 100644
index 8c73d035..00000000
--- a/3modules/tv/git.nix
+++ /dev/null
@@ -1,483 +0,0 @@
-{ config, pkgs, lib, ... }:
-
-# TODO unify logging of shell scripts to user and journal
-# TODO move all scripts to ${etcDir}, so ControlMaster connections
-# immediately pick up new authenticators
-# TODO when authorized_keys changes, then restart ssh
-# (or kill already connected users somehow)
-
-with builtins;
-with lib;
-let
- cfg = config.tv.git;
-
- out = {
- imports = [
- ../../3modules/tv/nginx.nix
- ];
- options.tv.git = api;
- config = mkIf cfg.enable (mkMerge [
- (mkIf cfg.cgit cgit-imp)
- git-imp
- ]);
- };
-
- api = {
- enable = mkEnableOption "tv.git";
-
- cgit = mkOption {
- type = types.bool;
- default = true;
- description = "Enable cgit."; # TODO better desc; talk about nginx
- };
- dataDir = mkOption {
- type = types.str;
- default = "/var/lib/git";
- description = "Directory used to store repositories.";
- };
- etcDir = mkOption {
- type = types.str;
- default = "/etc/git";
- };
- repos = mkOption {
- type = types.attrsOf (types.submodule ({
- options = {
- desc = mkOption {
- type = types.nullOr types.str;
- default = null;
- description = ''
- Repository description.
- '';
- };
- section = mkOption {
- type = types.nullOr types.str;
- default = null;
- description = ''
- Repository section.
- '';
- };
- name = mkOption {
- type = types.str;
- description = ''
- Repository name.
- '';
- };
- hooks = mkOption {
- type = types.attrsOf types.str;
- description = ''
- Repository-specific hooks.
- '';
- };
- public = mkOption {
- type = types.bool;
- default = false;
- description = ''
- Allow everybody to read the repository via HTTP if cgit enabled.
- '';
- # TODO allow every configured user to fetch the repository via SSH.
- };
- };
- }));
-
- default = {};
-
- example = literalExample ''
- {
- testing = {
- name = "testing";
- hooks.post-update = '''
- #! /bin/sh
- set -euf
- echo post-update hook: $* >&2
- ''';
- };
- testing2 = { name = "testing2"; };
- }
- '';
-
- description = ''
- Repositories.
- '';
- };
- root-desc = mkOption {
- type = types.nullOr types.str;
- default = null;
- description = ''
- Text printed below the heading on the repository index page.
- Default value: "a fast webinterface for the git dscm".
- '';
- };
- root-title = mkOption {
- type = types.nullOr types.str;
- default = null;
- description = ''
- Text printed as heading on the repository index page.
- Default value: "Git Repository Browser".
- '';
- };
- rules = mkOption {
- type = types.unspecified;
- };
- users = mkOption {
- type = types.unspecified;
- };
- };
-
- git-imp = {
- system.activationScripts.git-init = "${init-script}";
-
- # TODO maybe put all scripts here and then use PATH?
- environment.etc."${etc-base}".source =
- scriptFarm "git-ssh-authorizers" {
- authorize-command = makeAuthorizeScript (map ({ repo, user, perm }: [
- (map getName (ensureList user))
- (map getName (ensureList repo))
- (map getName perm.allow-commands)
- ]) cfg.rules);
-
- authorize-push = makeAuthorizeScript (map ({ repo, user, perm }: [
- (map getName (ensureList user))
- (map getName (ensureList repo))
- (ensureList perm.allow-receive-ref)
- (map getName perm.allow-receive-modes)
- ]) (filter (x: hasAttr "allow-receive-ref" x.perm) cfg.rules));
- };
-
- users.extraUsers = singleton {
- description = "Git repository hosting user";
- name = "git";
- shell = "/bin/sh";
- openssh.authorizedKeys.keys =
- mapAttrsToList (_: makeAuthorizedKey git-ssh-command) cfg.users;
- uid = 129318403; # genid git
- };
- };
-
- cgit-imp = {
- users.extraUsers = lib.singleton {
- inherit (fcgitwrap-user) group name uid;
- home = toString (pkgs.runCommand "empty" {} "mkdir -p $out");
- };
-
- users.extraGroups = lib.singleton {
- inherit (fcgitwrap-group) gid name;
- };
-
- services.fcgiwrap = {
- enable = true;
- user = fcgitwrap-user.name;
- group = fcgitwrap-user.group;
- # socketAddress = "/run/fcgiwrap.sock" (default)
- # socketType = "unix" (default)
- };
-
- environment.etc."cgitrc".text = ''
- css=/static/cgit.css
- logo=/static/cgit.png
-
- # if you do not want that webcrawler (like google) index your site
- robots=noindex, nofollow
-
- virtual-root=/
-
- # TODO make this nicer (and/or somewhere else)
- cache-root=/tmp/cgit
-
- cache-size=1000
- enable-commit-graph=1
- enable-index-links=1
- enable-index-owner=0
- enable-log-filecount=1
- enable-log-linecount=1
- enable-remote-branches=1
-
- ${optionalString (cfg.root-title != null) "root-title=${cfg.root-title}"}
- ${optionalString (cfg.root-desc != null) "root-desc=${cfg.root-desc}"}
-
- snapshots=0
- max-stats=year
-
- ${concatMapStringsSep "\n" (repo: ''
- repo.url=${repo.name}
- repo.path=${cfg.dataDir}/${repo.name}
- ${optionalString (repo.section != null) "repo.section=${repo.section}"}
- ${optionalString (repo.desc != null) "repo.desc=${repo.desc}"}
- '') (filter isPublicRepo (attrValues cfg.repos))}
- '';
-
- system.activationScripts.cgit = ''
- mkdir -m 0700 -p /tmp/cgit
- chown ${toString fcgitwrap-user.uid}:${toString fcgitwrap-group.gid} /tmp/cgit
- '';
-
- tv.nginx = {
- enable = true;
- servers.cgit = {
- server-names = [
- "cgit.${config.networking.hostName}"
- "cgit.${config.networking.hostName}.retiolum"
- ];
- locations = [
- (nameValuePair "/" ''
- include ${pkgs.nginx}/conf/fastcgi_params;
- fastcgi_param SCRIPT_FILENAME ${pkgs.cgit}/cgit/cgit.cgi;
- fastcgi_param PATH_INFO $uri;
- fastcgi_param QUERY_STRING $args;
- fastcgi_param HTTP_HOST $server_name;
- fastcgi_pass unix:${config.services.fcgiwrap.socketAddress};
- '')
- (nameValuePair "/static/" ''
- root ${pkgs.cgit}/cgit;
- rewrite ^/static(/.*)$ $1 break;
- '')
- ];
- };
- };
- };
-
- fcgitwrap-user = {
- name = "fcgiwrap";
- uid = 2867890860; # genid fcgiwrap
- group = "fcgiwrap";
- };
-
- fcgitwrap-group = {
- name = fcgitwrap-user.name;
- gid = fcgitwrap-user.uid;
- };
-
-
- ensureList = x:
- if typeOf x == "list" then x else [x];
-
- getName = x: x.name;
-
- isPublicRepo = getAttr "public"; # TODO this is also in ./cgit.nix
-
- makeAuthorizedKey = git-ssh-command: user@{ name, pubkey }:
- # TODO assert name
- # TODO assert pubkey
- let
- options = concatStringsSep "," [
- ''command="exec ${git-ssh-command} ${name}"''
- "no-agent-forwarding"
- "no-port-forwarding"
- "no-pty"
- "no-X11-forwarding"
- ];
- in
- "${options} ${pubkey}";
-
- # [case-pattern] -> shell-script
- # Create a shell script that succeeds (exit 0) when all its arguments
- # match the case patterns (in the given order).
- makeAuthorizeScript =
- let
- # TODO escape
- to-pattern = x: concatStringsSep "|" (ensureList x);
- go = i: ps:
- if ps == []
- then "exit 0"
- else ''
- case ''$${toString i} in ${to-pattern (head ps)})
- ${go (i + 1) (tail ps)}
- esac'';
- in
- patterns: ''
- #! /bin/sh
- set -euf
- ${concatStringsSep "\n" (map (go 1) patterns)}
- exit -1
- '';
-
- reponames = rules: sort lessThan (unique (map (x: x.repo.name) rules));
-
- # TODO makeGitHooks that uses runCommand instead of scriptFarm?
- scriptFarm =
- farm-name: scripts:
- let
- makeScript = script-name: script-string: {
- name = script-name;
- path = pkgs.writeScript "${farm-name}_${script-name}" script-string;
- };
- in
- pkgs.linkFarm farm-name (mapAttrsToList makeScript scripts);
-
-
- git-ssh-command = pkgs.writeScript "git-ssh-command" ''
- #! /bin/sh
- set -euf
-
- PATH=${makeSearchPath "bin" (with pkgs; [
- coreutils
- git
- gnugrep
- gnused
- systemd
- ])}
-
- abort() {
- echo "error: $1" >&2
- systemd-cat -p err -t git echo "error: $1"
- exit -1
- }
-
- GIT_SSH_USER=$1
-
- systemd-cat -p info -t git echo \
- "authorizing $GIT_SSH_USER $SSH_CONNECTION $SSH_ORIGINAL_COMMAND"
-
- # References: The Base Definitions volume of
- # POSIX.1‐2013, Section 3.278, Portable Filename Character Set
- portable_filename_bre="^[A-Za-z0-9._-]\\+$"
-
- command=$(echo "$SSH_ORIGINAL_COMMAND" \
- | sed -n 's/^\([^ ]*\) '"'"'\(.*\)'"'"'/\1/p' \
- | grep "$portable_filename_bre" \
- || abort 'cannot read command')
-
- GIT_SSH_REPO=$(echo "$SSH_ORIGINAL_COMMAND" \
- | sed -n 's/^\([^ ]*\) '"'"'\(.*\)'"'"'/\2/p' \
- | grep "$portable_filename_bre" \
- || abort 'cannot read reponame')
-
- ${cfg.etcDir}/authorize-command \
- "$GIT_SSH_USER" "$GIT_SSH_REPO" "$command" \
- || abort 'access denied'
-
- repodir=${escapeShellArg cfg.dataDir}/$GIT_SSH_REPO
-
- systemd-cat -p info -t git \
- echo "authorized exec $command $repodir"
-
- export GIT_SSH_USER
- export GIT_SSH_REPO
- exec "$command" "$repodir"
- '';
-
- init-script = pkgs.writeScript "git-init" ''
- #! /bin/sh
- set -euf
-
- PATH=${makeSearchPath "bin" (with pkgs; [
- coreutils
- findutils
- gawk
- git
- gnugrep
- gnused
- ])}
-
- dataDir=${escapeShellArg cfg.dataDir}
- mkdir -p "$dataDir"
-
- # Notice how the presence of hooks symlinks determine whether
- # we manage a repositry or not.
-
- # Make sure that no existing repository has hooks. We can delete
- # symlinks because we assume we created them.
- find "$dataDir" -mindepth 2 -maxdepth 2 -name hooks -type l -delete
- bad_hooks=$(find "$dataDir" -mindepth 2 -maxdepth 2 -name hooks)
- if echo "$bad_hooks" | grep -q .; then
- printf 'error: unknown hooks:\n%s\n' \
- "$(echo "$bad_hooks" | sed 's/^/ /')" \
- >&2
- exit -1
- fi
-
- # Initialize repositories.
- ${concatMapStringsSep "\n" (repo:
- let
- hooks = scriptFarm "git-hooks" (makeHooks repo);
- in
- ''
- reponame=${escapeShellArg repo.name}
- repodir=$dataDir/$reponame
- mode=${toString (if isPublicRepo repo then 0711 else 0700)}
- if ! test -d "$repodir"; then
- mkdir -m "$mode" "$repodir"
- git init --bare --template=/var/empty "$repodir"
- chown -R git:nogroup "$repodir"
- fi
- ln -s ${hooks} "$repodir/hooks"
- ''
- ) (attrValues cfg.repos)}
-
- # Warn about repositories that exist but aren't mentioned in the
- # current configuration (and thus didn't receive a hooks symlink).
- unknown_repos=$(find "$dataDir" -mindepth 1 -maxdepth 1 \
- -type d \! -exec test -e '{}/hooks' \; -print)
- if echo "$unknown_repos" | grep -q .; then
- printf 'warning: stale repositories:\n%s\n' \
- "$(echo "$unknown_repos" | sed 's/^/ /')" \
- >&2
- fi
- '';
-
- makeHooks = repo: removeAttrs repo.hooks [ "pre-receive" ] // {
- pre-receive = ''
- #! /bin/sh
- set -euf
-
- PATH=${makeSearchPath "bin" (with pkgs; [
- coreutils # env
- git
- systemd
- ])}
-
- accept() {
- #systemd-cat -p info -t git echo "authorized $1"
- accept_string="''${accept_string+$accept_string
- }authorized $1"
- }
- reject() {
- #systemd-cat -p err -t git echo "denied $1"
- #echo 'access denied' >&2
- #exit_code=-1
- reject_string="''${reject_string+$reject_string
- }access denied: $1"
- }
-
- empty=0000000000000000000000000000000000000000
-
- accept_string=
- reject_string=
- while read oldrev newrev ref; do
-
- if [ $oldrev = $empty ]; then
- receive_mode=create
- elif [ $newrev = $empty ]; then
- receive_mode=delete
- elif [ "$(git merge-base $oldrev $newrev)" = $oldrev ]; then
- receive_mode=fast-forward
- else
- receive_mode=non-fast-forward
- fi
-
- if ${cfg.etcDir}/authorize-push \
- "$GIT_SSH_USER" "$GIT_SSH_REPO" "$ref" "$receive_mode"; then
- accept "$receive_mode $ref"
- else
- reject "$receive_mode $ref"
- fi
- done
-
- if [ -n "$reject_string" ]; then
- systemd-cat -p err -t git echo "$reject_string"
- exit -1
- fi
-
- systemd-cat -p info -t git echo "$accept_string"
-
- ${optionalString (hasAttr "post-receive" repo.hooks) ''
- # custom post-receive hook
- ${repo.hooks.post-receive}''}
- '';
- };
-
- etc-base =
- assert (hasPrefix "/etc/" cfg.etcDir);
- removePrefix "/etc/" cfg.etcDir;
-
-in
-out
diff --git a/3modules/tv/github-hosts-sync.nix b/3modules/tv/github-hosts-sync.nix
deleted file mode 100644
index f50bf2b1..00000000
--- a/3modules/tv/github-hosts-sync.nix
+++ /dev/null
@@ -1,83 +0,0 @@
-{ config, lib, pkgs, ... }:
-
-with builtins;
-with lib;
-let
- cfg = config.tv.github-hosts-sync;
-
- out = {
- options.tv.github-hosts-sync = api;
- config = mkIf cfg.enable imp;
- };
-
- api = {
- enable = mkEnableOption "tv.github-hosts-sync";
- port = mkOption {
- type = types.int; # TODO port type
- default = 1028;
- };
- dataDir = mkOption {
- type = types.str; # TODO path (but not just into store)
- default = "/var/lib/github-hosts-sync";
- };
- ssh-identity-file = mkOption {
- type = types.str; # TODO must be named *.ssh.{id_rsa,id_ed25519}
- default = "/root/src/secrets/github-hosts-sync.ssh.id_rsa";
- };
- };
-
- imp = {
- systemd.services.github-hosts-sync = {
- after = [ "network.target" ];
- wantedBy = [ "multi-user.target" ];
- environment = {
- port = toString cfg.port;
- };
- serviceConfig = {
- PermissionsStartOnly = "true";
- SyslogIdentifier = "github-hosts-sync";
- User = user.name;
- Restart = "always";
- ExecStartPre = pkgs.writeScript "github-hosts-sync-init" ''
- #! /bin/sh
- set -euf
-
- ssh_identity_file_target=$(
- case ${cfg.ssh-identity-file} in
- *.ssh.id_rsa|*.ssh.id_ed25519) echo ${cfg.dataDir}/.ssh/id_rsa;;
- *.ssh.id_ed25519) echo ${cfg.dataDir}/.ssh/id_ed25519;;
- *)
- echo "bad identity file name: ${cfg.ssh-identity-file}" >&2
- exit 1
- esac
- )
-
- mkdir -p ${cfg.dataDir}
- chown ${user.name}: ${cfg.dataDir}
-
- install \
- -o ${user.name} \
- -m 0400 \
- ${cfg.ssh-identity-file} \
- "$ssh_identity_file_target"
-
- ln -snf ${Zpkgs.github-known_hosts} ${cfg.dataDir}/.ssh/known_hosts
- '';
- ExecStart = "${Zpkgs.github-hosts-sync}/bin/github-hosts-sync";
- };
- };
-
- users.extraUsers = singleton {
- inherit (user) name uid;
- home = cfg.dataDir;
- };
- };
-
- user = {
- name = "github-hosts-sync";
- uid = 3220554646; # genid github-hosts-sync
- };
-
- Zpkgs = import ../../Zpkgs/tv { inherit pkgs; };
-in
-out
diff --git a/3modules/tv/identity.nix b/3modules/tv/identity.nix
deleted file mode 100644
index 9a83908a..00000000
--- a/3modules/tv/identity.nix
+++ /dev/null
@@ -1,88 +0,0 @@
-{ config, lib, pkgs, ... }:
-
-with import ../../4lib/tv { inherit lib pkgs; };
-let
- cfg = config.tv.identity;
-
- out = {
- options.tv.identity = api;
- config = mkIf cfg.enable imp;
- };
-
- api = {
- enable = mkEnableOption "tv.identity";
-
- self = mkOption {
- type = types.host;
- };
-
- #others = mkOption {
- # type = types.host;
- # default = filterAttrs (name: _host: name != cfg.self.name) cfg.hosts;
- #};
-
- hosts = mkOption {
- type = with types; attrsOf host;
- apply = mapAttrs (name: value: value // { inherit name; });
- };
-
- search = mkOption {
- type = types.hostname;
- };
- };
-
- imp = {
- networking.extraHosts =
- concatStringsSep "\n" (flatten (
- # TODO deepMap ["hosts" "nets"] (hostname: host: netname: net:
- mapAttrsToList (hostname: host:
- mapAttrsToList (netname: net:
- let
- aliases = toString (unique (longs ++ shorts));
- longs = (splitByProvider net.aliases).hosts;
- shorts = map (removeSuffix ".${cfg.search}") longs;
- in
- map (addr: "${addr} ${aliases}") net.addrs
- ) host.nets
- ) cfg.hosts
- ));
- };
-
- # TODO move domain name providers to a dedicated module
- # providers : tree label providername
- providers = {
- internet = "hosts";
- retiolum = "hosts";
- de.viljetic = "regfish";
- de.krebsco = "ovh";
- de.habsys = "hosts";
- de.pixelpocket = "hosts";
- de.karlaskop = "hosts";
- de.ubikmedia = "hosts";
- de.apanowicz = "hosts";
- de.aidsballs = "hosts";
- };
-
- # splitByProvider : [alias] -> set providername [alias]
- splitByProvider = foldl (acc: alias: insert (providerOf alias) alias acc) {};
-
- # providerOf : alias -> providername
- providerOf = alias:
- tree-get (splitString "." alias) providers;
-
- # insert : k -> v -> set k [v] -> set k [v]
- insert = name: value: set:
- set // { ${name} = set.${name} or [] ++ [value]; };
-
- # tree k v = set k (either v (tree k v))
-
- # tree-get : [k] -> tree k v -> v
- tree-get = path: x:
- let
- y = x.${last path};
- in
- if typeOf y != "set"
- then y
- else tree-get (init path) y;
-in
-out
diff --git a/3modules/tv/nginx.nix b/3modules/tv/nginx.nix
deleted file mode 100644
index a58c4952..00000000
--- a/3modules/tv/nginx.nix
+++ /dev/null
@@ -1,71 +0,0 @@
-{ config, pkgs, lib, ... }:
-
-with builtins;
-with lib;
-let
- cfg = config.tv.nginx;
-
- out = {
- options.tv.nginx = api;
- config = mkIf cfg.enable imp;
- };
-
- api = {
- enable = mkEnableOption "tv.nginx";
-
- servers = mkOption {
- type = with types; attrsOf optionSet;
- options = singleton {
- server-names = mkOption {
- type = with types; listOf str;
- default = [
- "${config.networking.hostName}"
- "${config.networking.hostName}.retiolum"
- ];
- };
- locations = mkOption {
- type = with types; listOf (attrsOf str);
- };
- };
- default = {};
- };
- };
-
- imp = {
- services.nginx = {
- enable = true;
- httpConfig = ''
- include ${pkgs.nginx}/conf/mime.types;
- default_type application/octet-stream;
- sendfile on;
- keepalive_timeout 65;
- gzip on;
- server {
- listen 80 default_server;
- server_name _;
- return 404;
- }
- ${concatStrings (mapAttrsToList (_: to-server) cfg.servers)}
- '';
- };
- };
-
-
- indent = replaceChars ["\n"] ["\n "];
-
- to-location = { name, value }: ''
- location ${name} {
- ${indent value}
- }
- '';
-
- to-server = { server-names, locations, ... }: ''
- server {
- listen 80;
- server_name ${toString server-names};
- ${indent (concatStrings (map to-location locations))}
- }
- '';
-
-in
-out
diff --git a/3modules/tv/retiolum.nix b/3modules/tv/retiolum.nix
deleted file mode 100644
index ca1418c3..00000000
--- a/3modules/tv/retiolum.nix
+++ /dev/null
@@ -1,222 +0,0 @@
-{ config, pkgs, lib, ... }:
-
-with builtins;
-with lib;
-let
- cfg = config.tv.retiolum;
-
- out = {
- options.tv.retiolum = api;
- config = mkIf cfg.enable imp;
- };
-
- api = {
- enable = mkEnableOption "tv.retiolum";
-
- name = mkOption {
- type = types.str;
- default = config.networking.hostName;
- # Description stolen from tinc.conf(5).
- description = ''
- This is the name which identifies this tinc daemon. It must
- be unique for the virtual private network this daemon will
- connect to. The Name may only consist of alphanumeric and
- underscore characters. If Name starts with a $, then the
- contents of the environment variable that follows will be
- used. In that case, invalid characters will be converted to
- underscores. If Name is $HOST, but no such environment
- variable exist, the hostname will be read using the
- gethostnname() system call This is the name which identifies
- the this tinc daemon.
- '';
- };
-
- generateEtcHosts = mkOption {
- type = types.str;
- default = "both";
- description = ''
- If set to <literal>short</literal>, <literal>long</literal>, or <literal>both</literal>,
- then generate entries in <filename>/etc/hosts</filename> from subnets.
- '';
- };
-
- network = mkOption {
- type = types.str;
- default = "retiolum";
- description = ''
- The tinc network name.
- It is used to generate long host entries,
- and name the TUN device.
- '';
- };
-
- tincPackage = mkOption {
- type = types.package;
- default = pkgs.tinc;
- description = "Tincd package to use.";
- };
-
- hosts = mkOption {
- default = null;
- description = ''
- Hosts package or path to use.
- If a path is given, then it will be used to generate an ad-hoc package.
- '';
- };
-
- iproutePackage = mkOption {
- type = types.package;
- default = pkgs.iproute;
- description = "Iproute2 package to use.";
- };
-
-
- privateKeyFile = mkOption {
- # TODO if it's types.path then it gets copied to /nix/store with
- # bad unsafe permissions...
- type = types.str;
- default = "/root/src/secrets/retiolum.rsa_key.priv";
- description = "Generate file with <literal>tincd -K</literal>.";
- };
-
- connectTo = mkOption {
- type = types.listOf types.str;
- default = [ "fastpoke" "pigstarter" "kheurop" ];
- description = "TODO describe me";
- };
-
- };
-
- imp = {
- environment.systemPackages = [ tinc hosts iproute ];
-
- networking.extraHosts = retiolumExtraHosts;
-
- systemd.services.retiolum = {
- description = "Tinc daemon for Retiolum";
- after = [ "network.target" ];
- wantedBy = [ "multi-user.target" ];
- path = [ tinc iproute ];
- serviceConfig = {
- PermissionsStartOnly = "true";
- PrivateTmp = "true";
- Restart = "always";
- # TODO we cannot chroot (-R) b/c we use symlinks to hosts
- # and the private key.
- ExecStartPre = pkgs.writeScript "retiolum-init" ''
- #! /bin/sh
- install -o ${user.name} -m 0400 ${cfg.privateKeyFile} /tmp/retiolum-rsa_key.priv
- '';
- ExecStart = "${tinc}/sbin/tincd -c ${confDir} -d 0 -U ${user.name} -D";
- SyslogIdentifier = "retiolum";
- };
- };
-
- users.extraUsers = singleton {
- inherit (user) name uid;
- };
- };
-
- user = {
- name = "retiolum";
- uid = 301281149; # genid retiolum
- };
-
- tinc = cfg.tincPackage;
- hostsType = builtins.typeOf cfg.hosts;
- hosts =
- if hostsType == "package" then
- # use package as is
- cfg.hosts
- else if hostsType == "path" then
- # use path to generate a package
- pkgs.stdenv.mkDerivation {
- name = "custom-retiolum-hosts";
- src = cfg.hosts;
- installPhase = ''
- mkdir $out
- find . -name .git -prune -o -type f -print0 | xargs -0 cp --target-directory $out
- '';
- }
- else
- abort "The option `services.retiolum.hosts' must be set to a package or a path"
- ;
- iproute = cfg.iproutePackage;
-
- retiolumExtraHosts = import (pkgs.runCommand "retiolum-etc-hosts"
- { }
- ''
- generate() {
- (cd ${hosts}
- printf \'\'
- for i in `ls`; do
- names=$(hostnames $i)
- for j in `sed -En 's|^ *Aliases *= *(.+)|\1|p' $i`; do
- names="$names $(hostnames $j)"
- done
- sed -En '
- s|^ *Subnet *= *([^ /]*)(/[0-9]*)? *$|\1 '"$names"'|p
- ' $i
- done | sort
- printf \'\'
- )
- }
-
- case ${cfg.generateEtcHosts} in
- short)
- hostnames() { echo "$1"; }
- generate
- ;;
- long)
- hostnames() { echo "$1.${cfg.network}"; }
- generate
- ;;
- both)
- hostnames() { echo "$1.${cfg.network} $1"; }
- generate
- ;;
- *)
- echo '""'
- ;;
- esac > $out
- '');
-
-
- confDir = pkgs.runCommand "retiolum" {
- # TODO text
- executable = true;
- preferLocalBuild = true;
- } ''
- set -euf
-
- mkdir -p $out
-
- ln -s ${hosts} $out/hosts
-
- cat > $out/tinc.conf <<EOF
- Name = ${cfg.name}
- Device = /dev/net/tun
- Interface = ${cfg.network}
- ${concatStrings (map (c : "ConnectTo = " + c + "\n") cfg.connectTo)}
- PrivateKeyFile = /tmp/retiolum-rsa_key.priv
- EOF
-
- # source: krebscode/painload/retiolum/scripts/tinc_setup/tinc-up
- cat > $out/tinc-up <<EOF
- host=$out/hosts/${cfg.name}
- ${iproute}/sbin/ip link set \$INTERFACE up
-
- addr4=\$(sed -n 's|^ *Subnet *= *\(10[.][^ ]*\) *$|\1|p' \$host)
- if [ -n "\$addr4" ];then
- ${iproute}/sbin/ip -4 addr add \$addr4 dev \$INTERFACE
- ${iproute}/sbin/ip -4 route add 10.243.0.0/16 dev \$INTERFACE
- fi
- addr6=\$(sed -n 's|^ *Subnet *= *\(42[:][^ ]*\) *$|\1|p' \$host)
- ${iproute}/sbin/ip -6 addr add \$addr6 dev \$INTERFACE
- ${iproute}/sbin/ip -6 route add 42::/16 dev \$INTERFACE
- EOF
-
- chmod +x $out/tinc-up
- '';
-in
-out
diff --git a/3modules/tv/urlwatch.nix b/3modules/tv/urlwatch.nix
deleted file mode 100644
index a659fc74..00000000
--- a/3modules/tv/urlwatch.nix
+++ /dev/null
@@ -1,136 +0,0 @@
-{ config, lib, pkgs, ... }:
-
-# TODO multiple users
-# TODO inform about unused caches
-# cache = url: "${cfg.dataDir}/.urlwatch/cache/${hashString "sha1" url}"
-# TODO hooks.py
-
-with builtins;
-with lib;
-let
- cfg = config.tv.urlwatch;
-
- # TODO assert sendmail's existence
- out = {
- options.tv.urlwatch = api;
- config = mkIf cfg.enable imp;
- };
-
- api = {
- enable = mkEnableOption "tv.urlwatch";
-
- dataDir = mkOption {
- type = types.str;
- default = "/var/lib/urlwatch";
- description = ''
- Directory where the urlwatch service should store its state.
- '';
- };
- from = mkOption {
- type = types.str;
- default = "${user.name}@${config.networking.hostName}.retiolum";
- description = ''
- Content of the From: header of the generated mails.
- '';
- };
- mailto = mkOption {
- type = types.str;
- description = ''
- Content of the To: header of the generated mails. [AKA recipient :)]
- '';
- };
- onCalendar = mkOption {
- type = types.str;
- description = ''
- Run urlwatch at this interval.
- The format is described in systemd.time(7), CALENDAR EVENTS.
- '';
- example = "04:23";
- };
- urls = mkOption {
- type = with types; listOf str;
- description = "URL to watch.";
- example = [
- https://nixos.org/channels/nixos-unstable/git-revision
- ];
- };
- };
-
- urlsFile = toFile "urls" (concatStringsSep "\n" cfg.urls);
-
- imp = {
- systemd.timers.urlwatch = {
- wantedBy = [ "timers.target" ];
- timerConfig = {
- OnCalendar = cfg.onCalendar;
- Persistent = "true";
- };
- };
- systemd.services.urlwatch = {
- path = with pkgs; [
- coreutils
- gnused
- urlwatch
- ];
- environment = {
- HOME = cfg.dataDir;
- LC_ALL = "en_US.UTF-8";
- LOCALE_ARCHIVE = "${pkgs.glibcLocales}/lib/locale/locale-archive";
- SSL_CERT_FILE = "${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt";
- };
- serviceConfig = {
- User = user.name;
- PermissionsStartOnly = "true";
- PrivateTmp = "true";
- Type = "oneshot";
- ExecStartPre =
- pkgs.writeScript "urlwatch-prestart" ''
- #! /bin/sh
- set -euf
-
- dataDir=$HOME
-
- if ! test -e "$dataDir"; then
- mkdir -m 0700 -p "$dataDir"
- chown ${user.name}: "$dataDir"
- fi
- '';
- ExecStart = pkgs.writeScript "urlwatch" ''
- #! /bin/sh
- set -euf
-
- from=${escapeShellArg cfg.from}
- mailto=${escapeShellArg cfg.mailto}
- urlsFile=${escapeShellArg urlsFile}
-
- cd /tmp
-
- urlwatch -e --urls="$urlsFile" > changes 2>&1 || :
-
- if test -s changes; then
- date=$(date -R)
- subject=$(sed -n 's/^\(CHANGED\|ERROR\|NEW\): //p' changes \
- | tr \\n \ )
- {
- echo "Dat