citadel

My dotfiles, scripts and nix configs
git clone git://jb55.com/citadel
Log | Files | Refs | README | LICENSE

commit 50e4b2040727974c3905968e41910fa0ab9ea641
parent 11e4ada074a4971339deb90a0b358879ab777c9b
Author: William Casarin <jb55@jb55.com>
Date:   Tue, 15 Sep 2020 21:06:38 -0700

add nix configs

Diffstat:
Anix-config/.gitignore | 2++
Anix-config/certs/default.nix | 7+++++++
Anix-config/certs/flynn-dev.cer | 20++++++++++++++++++++
Anix-config/certs/flynn-prod.cer | 20++++++++++++++++++++
Anix-config/configuration.nix | 110+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Anix-config/environment/default.nix | 85+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Anix-config/environment/desktop/default.nix | 98+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Anix-config/fonts/default.nix | 108+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Anix-config/hardware-configuration.nix | 11+++++++++++
Anix-config/hardware/desktop/default.nix | 112+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Anix-config/machines/archer/backups/default.nix | 45+++++++++++++++++++++++++++++++++++++++++++++
Anix-config/machines/archer/backups/git.nix | 45+++++++++++++++++++++++++++++++++++++++++++++
Anix-config/machines/archer/backups/wiki.nix | 42++++++++++++++++++++++++++++++++++++++++++
Anix-config/machines/archer/bandcamp-sales-bot/default.nix | 22++++++++++++++++++++++
Anix-config/machines/archer/beatport-sales-bot/default.nix | 25+++++++++++++++++++++++++
Anix-config/machines/archer/cogs-bot/default.nix | 23+++++++++++++++++++++++
Anix-config/machines/archer/config/default.nix | 5+++++
Anix-config/machines/archer/default.nix | 146+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Anix-config/machines/archer/fail-notifier/default.nix | 29+++++++++++++++++++++++++++++
Anix-config/machines/archer/hardware/default.nix | 36++++++++++++++++++++++++++++++++++++
Anix-config/machines/archer/itunes-bots/default.nix | 40++++++++++++++++++++++++++++++++++++++++
Anix-config/machines/archer/nginx/default.nix | 95+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Anix-config/machines/archer/nginx/git.nix | 70++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Anix-config/machines/archer/nginx/hoogle.nix | 17+++++++++++++++++
Anix-config/machines/archer/nginx/nix-serve.nix | 7+++++++
Anix-config/machines/archer/nginx/sites/local | 18++++++++++++++++++
Anix-config/machines/archer/payments-runner/default.nix | 9+++++++++
Anix-config/machines/archer/payments-server/default.nix | 57+++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Anix-config/machines/archer/shopify-sales-bot/default.nix | 22++++++++++++++++++++++
Anix-config/machines/archer/transaction-bot/default.nix | 21+++++++++++++++++++++
Anix-config/machines/archer/trendbot/default.nix | 21+++++++++++++++++++++
Anix-config/machines/archer/tunecore-sales-bot/default.nix | 24++++++++++++++++++++++++
Anix-config/machines/archer/youtube-pub-sales-bot/default.nix | 23+++++++++++++++++++++++
Anix-config/machines/archer/youtube-sales-bot/default.nix | 20++++++++++++++++++++
Anix-config/machines/charon/config/default.nix | 1+
Anix-config/machines/charon/default.nix | 453+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Anix-config/machines/charon/dovecot/filters.sieve | 191+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Anix-config/machines/charon/hardware/default.nix | 24++++++++++++++++++++++++
Anix-config/machines/charon/networking/default.nix | 22++++++++++++++++++++++
Anix-config/machines/charon/nginx/default.nix | 75+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Anix-config/machines/charon/nginx/pokemap.nix | 28++++++++++++++++++++++++++++
Anix-config/machines/charon/nginx/sites/coretto.io | 0
Anix-config/machines/charon/nginx/sites/hearpress.com | 43+++++++++++++++++++++++++++++++++++++++++++
Anix-config/machines/charon/nginx/sites/jb55.com | 0
Anix-config/machines/charon/nginx/sites/npmrepo.com | 14++++++++++++++
Anix-config/machines/charon/nginx/sites/wineparty.xyz | 33+++++++++++++++++++++++++++++++++
Anix-config/machines/charon/sheetzen/default.nix | 79+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Anix-config/machines/charon/vidstats/default.nix | 40++++++++++++++++++++++++++++++++++++++++
Anix-config/machines/monad/bitcoin/dca.nix | 36++++++++++++++++++++++++++++++++++++
Anix-config/machines/monad/bitcoin/default.nix | 74++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Anix-config/machines/monad/bitcoin/walletemail.nix | 57+++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Anix-config/machines/monad/config/default.nix | 12++++++++++++
Anix-config/machines/monad/contracts/commit/default.nix | 20++++++++++++++++++++
Anix-config/machines/monad/contracts/plastiq/default.nix | 12++++++++++++
Anix-config/machines/monad/default.nix | 320+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Anix-config/machines/monad/hardware/default.nix | 64++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Anix-config/machines/monad/networking/default.nix | 175+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Anix-config/machines/monad/nginx/default.nix | 99+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Anix-config/machines/quiver/config/default.nix | 4++++
Anix-config/machines/quiver/default.nix | 187+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Anix-config/machines/quiver/hardware-configuration.nix | 46++++++++++++++++++++++++++++++++++++++++++++++
Anix-config/machines/quiver/networking/default.nix | 111+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Anix-config/machines/quiver/timers/archer-cookies/default.nix | 57+++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Anix-config/machines/quiver/timers/default.nix | 6++++++
Anix-config/misc/dnsmasq-adblock.nix | 20++++++++++++++++++++
Anix-config/misc/git-server.nix | 60++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Anix-config/misc/imap-notifier/default.nix | 114+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Anix-config/misc/msmtp/default.nix | 12++++++++++++
Anix-config/misc/util.nix | 7+++++++
Anix-config/networking/default.nix | 7+++++++
Anix-config/nixpkgs/config.nix | 510+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Anix-config/nixpkgs/dotfiles.nix | 43+++++++++++++++++++++++++++++++++++++++++++
Anix-config/nixpkgs/haskell-overrides/default.nix | 5+++++
Anix-config/nixpkgs/haskell-overrides/massager-service.nix | 24++++++++++++++++++++++++
Anix-config/nixpkgs/haskell-overrides/monstercat-backend.nix | 89+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Anix-config/nixpkgs/haskell-overrides/payment.nix | 104+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Anix-config/nixpkgs/scripts/ds4ctl/default.nix | 24++++++++++++++++++++++++
Anix-config/nixpkgs/scripts/footswitch/default.nix | 26++++++++++++++++++++++++++
Anix-config/nixpkgs/scripts/footswitch/patch.diff | 37+++++++++++++++++++++++++++++++++++++
Anix-config/nixpkgs/scripts/ical2org/default.nix | 36++++++++++++++++++++++++++++++++++++
Anix-config/services/default.nix | 28++++++++++++++++++++++++++++
Anix-config/services/desktop/default.nix | 264+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Anix-config/services/desktop/networking/default.nix | 204+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Anix-config/services/fail-notifier/default.nix | 56++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Anix-config/services/footswitch/default.nix | 72++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Anix-config/services/hoogle/default.nix | 66++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Anix-config/services/mailz/default.nix | 331+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Anix-config/services/mailz/opensmtpd.diff | 21+++++++++++++++++++++
Anix-config/services/mailz/opensmtpd.nix | 48++++++++++++++++++++++++++++++++++++++++++++++++
Anix-config/services/mailz/proc_path.diff | 76++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Anix-config/services/pokemongo-map/default.nix | 53+++++++++++++++++++++++++++++++++++++++++++++++++++++
Anix-config/services/pokemongo-map/requirements.nix | 42++++++++++++++++++++++++++++++++++++++++++
Anix-config/services/pokemongo-map/requirements_generated.nix | 974+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Anix-config/services/pokemongo-map/requirements_override.nix | 5+++++
Anix-config/timers/sync-ical2org.nix | 47+++++++++++++++++++++++++++++++++++++++++++++++
Anix-config/wayland/default.nix | 28++++++++++++++++++++++++++++
96 files changed, 7151 insertions(+), 0 deletions(-)

diff --git a/nix-config/.gitignore b/nix-config/.gitignore @@ -0,0 +1,2 @@ +private.nix +/machines/monad/commit/commit.ovpn diff --git a/nix-config/certs/default.nix b/nix-config/certs/default.nix @@ -0,0 +1,7 @@ +{ config, lib, pkgs, ... }: +let certs = [ ./flynn-dev.cer + ./flynn-prod.cer + ]; +in { + security.pki.certificates = map builtins.readFile certs; +} diff --git a/nix-config/certs/flynn-dev.cer b/nix-config/certs/flynn-dev.cer @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDAzCCAe2gAwIBAgIQRt44w0Dtmo6Kc0rZK/yGtzALBgkqhkiG9w0BAQswLTEO +MAwGA1UEChMFRmx5bm4xGzAZBgNVBAsTEkZseW5uIEVwaGVtZXJhbCBDQTAeFw0x +NjAxMTEyMzU4MTRaFw0yMTAxMDkyMzU4MTRaMC0xDjAMBgNVBAoTBUZseW5uMRsw +GQYDVQQLExJGbHlubiBFcGhlbWVyYWwgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IB +DwAwggEKAoIBAQC1vDwqPoUmwRepdUV1rs67c/vnDn8GaFoKyLY4OBrmsxMA/E9J +yeTK5cfTmFK7YnMjBOg93PxYkQIL3viJhL04gKqZdVF3VTMdP0RNYLIT28qyoWbt +bDfc/OMLDh8pNXtOovCuIIWkKkVJWPk+SA5a1Cj6755WU8faRJ58unUFK3AeurFs +5g7F+FZahzrGqYAZt6uN/er3OQlYWOueklMBkQBo26EPN9GX6wSJJyh+tlXXnIU7 +aGs+Y3za8Sf9aitEdZJ1++S7nunzfv6DHmT+qGLgKkeykWJp3pt01l2KfM99n4cu +dTMY1sdI8xjc5bKb1N80xf39GZfCw5btzZctAgMBAAGjIzAhMA4GA1UdDwEB/wQE +AwIABjAPBgNVHRMBAf8EBTADAQH/MAsGCSqGSIb3DQEBCwOCAQEAOy5O7cME57bR +BemhUY9tQrcxJOIu/Wzo6ccHxDzWMJ2aCPuFZGcCvflGKdYorVFDGq4qWAAISrRT +3j5gtfPgDxGlck17RdptM1PB6IM//1WwoZoKO6h6tRyXGjCQr7PvhBB9rWepZfyZ +8CxH6XZY3To0IdVfikXnSgWpFncpmlfl465fBERKkDRN0+5q51wlxPNsykQOzgjo +giJySbYUD345vGDsVwAffwMnnE9xwGB9Xdoyd7AvAaXFmsYONGCb0+kaN4CZQYtR +P1zau8J1jy5KAahfvMIWvih2aWqeqQpNQ9PfSsz5F2C76XvkxnkOicga9tuoJYgo +luF0apj1Qg== +-----END CERTIFICATE-----+ \ No newline at end of file diff --git a/nix-config/certs/flynn-prod.cer b/nix-config/certs/flynn-prod.cer @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDAzCCAe2gAwIBAgIQWmzx7lHQxRCWh1Nm8gse2zALBgkqhkiG9w0BAQswLTEO +MAwGA1UEChMFRmx5bm4xGzAZBgNVBAsTEkZseW5uIEVwaGVtZXJhbCBDQTAeFw0x +NjAxMTIwMDI0MjdaFw0yMTAxMTAwMDI0MjdaMC0xDjAMBgNVBAoTBUZseW5uMRsw +GQYDVQQLExJGbHlubiBFcGhlbWVyYWwgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IB +DwAwggEKAoIBAQCn5f5K0iqK5ZtE2wjFnxD5hoMa3k9oyvkSflOO7tDyMi+zLyt3 +chvbccKcJLiYEWB5+RTu/JzmTNMejxh1toAglrrKTxqQ76t8oHDh0pD661rUELDQ +I4a83Lh3A4JBY2IjFMSWHqSJjEK50HIUoPbkkIkRlBVpZP6n/c4Tgl43VTLiShFz +RndX3PF3+Zxdilo4sIbFGKzw2Gq15qKuSV5P8FRpQMBC5uMAFaC2coxgdHZ0SclV +m/te3f5L3Dg71dLXePqotlCBW89peoOBu3+n8v0IzMB0R4tMm5kT7kGVYWNN//Gf +d4syJ7Q5mg2fWOdfOGiTOgZWw3OI/odn1TnPAgMBAAGjIzAhMA4GA1UdDwEB/wQE +AwIABjAPBgNVHRMBAf8EBTADAQH/MAsGCSqGSIb3DQEBCwOCAQEAAfEDAS/VW7q0 +xaWqjtr341h+VKAjLPjgMrrOIli52oco1q5UvYWa5EVSoVtU2NZwzstDOIrnD/2T ++RG1gOdMA+FyRIeC6qmQ7An4Tim2O08TG18jGRHDMzoIi2s4ZSek989OT4ZvLMmX +yIh4M1mNt3v2aSOVEYiUrZ0yibo1i6QgRJSgIJ/QSCCyR1suyKIcQIlYGSgIeA0s +cPUbGhjj2T28oAZDVDPx7QdXRwLz07FAvrblL4mm4LnI/tjZ9Zy5xYqRdEl/Q0uu +PLmE19PrMCXE3r2kS3z+EY2KKbaZyaoP5nkSdx5YI1re6jPp6snZsjyCW7uOpY2Z +VjkJuS7sCQ== +-----END CERTIFICATE-----+ \ No newline at end of file diff --git a/nix-config/configuration.nix b/nix-config/configuration.nix @@ -0,0 +1,110 @@ +# Edit this configuration file to define what should be installed on +# your system. Help is available in the configuration.nix(5) man page +# and in the NixOS manual (accessible by running ‘nixos-help’). + +{ config, pkgs, ... }: + +let machine = "quiver"; + isDesktop = true; + machinePath = p: let m = "/" + machine; + in ./machines + m + p; + machineConfig = import (machinePath "/config") pkgs; + userConfig = pkgs.callPackage ./nixpkgs/dotfiles.nix { + machineSessionCommands = machineConfig.sessionCommands; + }; + extra = { + is-minimal = false; + git-server = import ./misc/git-server.nix; + util = import ./misc/util.nix { inherit pkgs; }; + private = import ./private.nix; + machine = machineConfig; + }; + util = extra.util; + caches = [ "https://cache.nixos.org" ]; + zsh = "${pkgs.zsh}/bin/zsh"; + composeKey = if machine == "quiver" then "ralt" else "rwin"; + home = "/home/jb55"; + isDark = false; + theme = if isDark then { + package = pkgs.theme-vertex; + name = "Vertex-Dark"; + } + else { + package = pkgs.arc-theme; + name = "Arc"; + }; + icon-theme = { + package = pkgs.numix-icon-theme; + name = "Numix"; + }; + user = { + name = "jb55"; + group = "users"; + uid = 1000; + extraGroups = [ "wheel" "dialout" ]; + createHome = true; + openssh.authorizedKeys.keys = [ + "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDAvMdnEEAd/ZQM+pYp6ZYG/1NPE/HSwIKoec0/QgGy4UlO0EvpWWhxPaV0HlNUFfwiHE0I2TwHc+KOKcG9jcbLAjCk5rvqU7K8UeZ0v/J83bQh78dr4le09WLyhczamJN0EkNddpCyUqIbH0q3ISGPmTiW4oQniejtkdJPn2bBwb3Za8jLzlh2UZ/ZJXhKvcGjQ/M1+fBmFUwCp5Lpvg0XYXrmp9mxAaO+fxY32EGItXcjYM41xr/gAcpmzL5rNQ9a9YBYFn2VzlpL+H7319tgdZa4L57S49FPQ748paTPDDqUzHtQD5FEZXe7DZZPZViRsPc370km/5yIgsEhMPKr jb55" + ]; + home = home; + shell = zsh; + }; +in { + imports = + [ # Include the results of the hardware scan. + ./hardware-configuration.nix + ./certs + (import ./services extra) + (import ./environment extra) + (import ./networking machine) + (import (machinePath "") extra) + ] ++ (if isDesktop then [ + (import ./hardware/desktop extra) + # ./wayland + (import ./fonts extra) + (import ./environment/desktop { inherit userConfig theme icon-theme extra; }) + (import ./services/desktop { inherit extra util composeKey userConfig theme icon-theme; }) + ] else []); + + # Use the GRUB 2 boot loader. + boot.loader.grub.enable = true; + environment.ld-linux = true; + systemd.extraConfig = '' + DefaultTimeoutStopSec=10s + DefaultTimeoutStartSec=20s + ''; + + documentation.nixos.enable = false; + + programs.ssh.startAgent = true; + + time.timeZone = "America/Vancouver"; + + nixpkgs.config = import ./nixpkgs/config.nix; + + nix.useSandbox = machine != "charon"; + nix.trustedUsers = [ "root" "jb55" ]; + + users.extraUsers.jb55 = user; + users.extraGroups.docker.members = [ "jb55" ]; + + users.defaultUserShell = zsh; + users.mutableUsers = true; + + i18n.consoleUseXkbConfig = true; + + programs.zsh.enable = true; + + boot.kernelPackages = pkgs.linuxPackages_latest; + + # boot.kernelPatches = [{ + # name = "nintendo-hid"; + # patch = (pkgs.fetchurl { + # url = "https://jb55.com/s/2020-03-24-HID-nintendo-add-nintendo-switch-controller-driver.patch"; + # sha256 = "660302c88b797df6a89e5e715388ab22144dedfc0174597221a03a987a496a2e"; + # }); + # extraConfig = '' + # NINTENDO_FF y + # ''; + # }]; +} diff --git a/nix-config/environment/default.nix b/nix-config/environment/default.nix @@ -0,0 +1,85 @@ +extra: +{ config, lib, pkgs, ... }: +let jb55pkgs = import <jb55pkgs> { inherit pkgs; }; + kindle-send = pkgs.callPackage (pkgs.fetchFromGitHub { + owner = "jb55"; + repo = "kindle-send"; + rev = "0.2.1"; + sha256 = "0xd86s2smjvlc7rlb6rkgx2hj3c3sbcz3gs8rf93x69jqdvwb6rr"; + }) {}; + nixify = pkgs.nur.repos.kampka.nixify; + myPackages = with jb55pkgs; [ + bcalc + csv-delim + csv-scripts + dbopen + extname + kindle-send + mandown + samp + sharefile + snap + btcs + ]; + myHaskellPackages = with pkgs.haskellPackages; [ + #skeletons + ]; + + minimal-pkgs = with pkgs; [ + git-tools + neovim + fzf + ripgrep + ]; + + mypkgs = with pkgs; myHaskellPackages ++ myPackages ++ [ + aspell + aspellDicts.en + aspellDicts.en-computers + aspellDicts.en-science + bat + bc + binutils + dateutils + direnv + du-dust + file + fzf + git-tools + gnupg + groff + haskellPackages.una + htop + imagemagick + jq + libbitcoin-explorer + libqalculate + linuxPackages.bpftrace + lsof + manpages + minisign + neovim + network-tools + nixify + nodejs + opentimestamps-client + par + parallel + patchelf + pv + python + ranger + ripgrep + rsync + screen + shellcheck + unixtools.xxd + unzip + weechat + wget + zip + zstd + ]; +in { + environment.systemPackages = if extra.is-minimal then minimal-pkgs else mypkgs; +} diff --git a/nix-config/environment/desktop/default.nix b/nix-config/environment/desktop/default.nix @@ -0,0 +1,98 @@ +{ userConfig, theme, icon-theme, extra }: +{ config, lib, pkgs, ... }: +let gtk2rc = pkgs.writeText "gtk2rc" '' + gtk-icon-theme-name = "${icon-theme.name}" + gtk-theme-name = "${theme.name}" + + binding "gtk-binding-menu" { + bind "j" { "move-current" (next) } + bind "k" { "move-current" (prev) } + bind "h" { "move-current" (parent) } + bind "l" { "move-current" (child) } + } + class "GtkMenuShell" binding "gtk-binding-menu" + ''; + + mypkgs = with pkgs; [ + aerc + clipmenu + colorpicker + dmenu2 + dragon-drop + dunst + dynamic-colors + emacs + feh + getmail # for getmail-gmail-xoauth-tokens + gnome3.gnome-calculator + gtk-engine-murrine + lastpass-cli + libnotify + msmtp + muchsync + notmuch + oathToolkit + pandoc + pavucontrol + pinentry + postgresql # psql + python37Packages.trezor + qalculate-gtk + qutebrowser + rxvt_unicode-with-plugins + signal-desktop + simplescreenrecorder + slock + spotify + sxiv + texlive.combined.scheme-basic + userConfig + vlc + w3m + wine + wmctrl + xautolock + xbindkeys + xclip + xdotool + xlibs.xev + xlibs.xmodmap + xlibs.xset + zathura + zoom-us + ]; +in { + + # latest emacs overlay + #nixpkgs.overlays = [ + # (import (builtins.fetchTarball { + # url = https://github.com/nix-community/emacs-overlay/archive/773a9f17db9296b45e6b7864d8cee741c8d0d7c7.tar.gz; + # sha256 = "157klv69myjmdgqvxv0avv32yfra3i21h5bxjhksvaii1xf3w1gp"; + # })) + #]; + + environment.variables = lib.mkIf (!extra.is-minimal) { + LC_TIME="en_DK.UTF-8"; + GDK_PIXBUF_MODULE_FILE = "${pkgs.librsvg.out}/lib/gdk-pixbuf-2.0/2.10.0/loaders.cache"; + GTK2_RC_FILES = "${gtk2rc}:${theme.package}/share/themes/${theme.name}/gtk-2.0/gtkrc:$GTK2_RC_FILES"; + GTK_DATA_PREFIX = "${theme.package}"; + GTK_EXEC_PREFIX = "${theme.package}"; + GTK_IM_MODULE = "xim"; + GTK_PATH = "${theme.package}:${pkgs.gtk3.out}"; + GTK_THEME = "${theme.name}"; + QT_STYLE_OVERRIDE = "GTK+"; + VK_ICD_FILENAMES = "/run/opengl-driver/share/vulkan/icd.d/radeon_icd.x86_64.json"; # radv + }; + + environment.systemPackages = if extra.is-minimal then (with pkgs; [ + steam + steam-run + wine + lastpass-cli + rxvt_unicode-with-plugins + ]) else mypkgs; + + security.wrappers = { + slock.source = "${pkgs.slock}/bin/slock"; + }; +} diff --git a/nix-config/fonts/default.nix b/nix-config/fonts/default.nix @@ -0,0 +1,108 @@ +extra: +{ config, lib, pkgs, ... }: +let mkfont = n: lesrc: + pkgs.stdenv.mkDerivation rec { + name = "${n}-${version}"; + src = pkgs.fetchurl lesrc; + version = "1.0"; + phases = ["installPhase"]; + + installPhase = '' + mkdir -p $out/share/fonts/${n} + cp -v ${src} $out/share/fonts/${n} + ''; + }; + aldrich = + mkfont "aldrich" { + url = "https://jb55.com/s/bef303d9e370f941.ttf"; + sha256 = "ecc2fbf1117eed2d0b1bf32ee8624077577d568f1c785699353416b67b519227"; + }; + VarelaRound-Regular = + mkfont "VarelaRound-Regular" { + url = "https://jb55.com/s/c8bbd8415dea995f.ttf"; + sha256 = "c4327a38270780eb03d305de3514de62534262c73f9e7235eea6ce26904c2dc5"; + }; + Bookerly-Regular = + mkfont "Bookerly-Regular" { + url = "https://jb55.com/s/Bookerly-Regular.ttf"; + sha256 = "1db94d4ab763f812b3fe505c02cdeb0927251c118cc65322be23eb93a70eafd7"; + }; + Bookerly-RegularItalic = + mkfont "Bookerly-RegularItalic" { + url = "https://jb55.com/s/Bookerly-RegularItalic.ttf"; + sha256 = "6e364837e08fa89c0fed287a13c7149567ab5657847f666e45e523ecc9c7820b"; + }; + Bookerly-Bold = + mkfont "Bookerly-Bold" { + url = "https://jb55.com/s/Bookerly-Bold.ttf"; + sha256 = "367a28ceb9b2c79dbe5956624f023a54219d89f31d6d2e81e467e202273d40da"; + }; + Bookerly-BoldItalic = + mkfont "Bookerly-BoldItalic" { + url = "https://jb55.com/s/Bookerly-BoldItalic.ttf"; + sha256 = "d975e3260e26f1b33fc50b00540caece84a0800e9bc900922cf200645e79693f"; + }; + Questrial = + mkfont "Questrial" { + url = "https://jb55.com/s/1ccac9ff5cb42fd7.ttf"; + sha256 = "294729bb4bf3595490d2e3e89928e1754a7bfa91ce91e1e44ecd18c974a6dbbc"; + }; + Comfortaa-Regular = + mkfont "Comfortaa-Regular" { + url = "https://jb55.com/s/a266c50144cbad1a.ttf"; + sha256 = "db5133b6a09c8eba78b29dc05019d8f361f350483d679fd8c668e1c657a303fc"; + }; + + ohsnap = + pkgs.stdenv.mkDerivation rec { + name = "ohsnap-${version}"; + version = "1.7.9"; + + src = pkgs.fetchzip { + url = "https://sourceforge.net/projects/osnapfont/files/${name}.tar.gz"; + sha256 = "0jvgii1sdv3gzmx8k68bd3fp2rmfsdigg67spbi2c83krb1x445v"; + }; + + phases = ["unpackPhase" "installPhase"]; + + installPhase = '' + mkdir -p $out/share/fonts/ohsnap + cp ${src}/* $out/share/fonts/ohsnap + ''; + }; + + myfonts = [ aldrich VarelaRound-Regular Questrial Comfortaa-Regular + Bookerly-Regular Bookerly-RegularItalic Bookerly-Bold Bookerly-BoldItalic ohsnap ]; +in +{ + fonts = { + enableFontDir = true; + enableGhostscriptFonts = true; + fontconfig.defaultFonts.serif = [ "Bookerly" ]; + fontconfig.defaultFonts.monospace = [ "Inconsolata" ]; + fontconfig.defaultFonts.sansSerif = [ "Noto Sans" ]; + enableDefaultFonts = if extra.is-minimal then false else true; + fonts = if extra.is-minimal then [pkgs.terminus_font] else (with pkgs; [ + aldrich + corefonts + # emojione + fira-code + fira-mono + inconsolata + ipafont + kochi-substitute + libertinus + ibm-plex + noto-fonts + noto-fonts-emoji + opensans-ttf + raleway + profont + terminus_font + paratype-pt-mono + source-code-pro + ubuntu_font_family + proggyfonts + ] ++ myfonts); + }; +} diff --git a/nix-config/hardware-configuration.nix b/nix-config/hardware-configuration.nix @@ -0,0 +1,11 @@ +# Do not modify this file! It was generated by ‘nixos-generate-config’ +# and may be overwritten by future invocations. Please make changes +# to /etc/nixos/configuration.nix instead. +{ config, lib, pkgs, ... }: + +{ + imports = [ ]; + + boot.loader.grub.version = 2; + nix.maxJobs = 8; +} diff --git a/nix-config/hardware/desktop/default.nix b/nix-config/hardware/desktop/default.nix @@ -0,0 +1,112 @@ +extra: +{ config, lib, pkgs, ... }: +let + kindle-opts = ["noatime" "user" "gid=100" "uid=1000" "utf8" "x-systemd.automount"]; +in +{ + boot.supportedFilesystems = ["ntfs" "exfat"]; + + services.udev.extraRules = '' + # coldcard + KERNEL=="hidraw*", ATTRS{idVendor}=="d13e", ATTRS{idProduct}=="cc10", GROUP="plugdev", MODE="0666", SYMLINK+="coldcard + + # yubikey neo + KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1050", ATTRS{idProduct}=="0116", MODE="0666" + + # yubikey4 + KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1050", ATTRS{idProduct}=="0407", MODE="0666" + + # kindle + ATTRS{idVendor}=="1949", ATTRS{idProduct}=="0004", SYMLINK+="kindle" + ATTRS{idVendor}=="1949", ATTRS{idProduct}=="0003", SYMLINK+="kindledx" + + # HTC Vive HID Sensor naming and permissioning + # vive hmd + KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="0bb4", ATTRS{idProduct}=="2c87", TAG+="uaccess" + + # vive controller + KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="28de", ATTRS{idProduct}=="2101", TAG+="uaccess" + + # vive lighthouse + KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="28de", ATTRS{idProduct}=="2000", TAG+="uaccess" + KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="28de", ATTRS{idProduct}=="1043", TAG+="uaccess" + KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="28de", ATTRS{idProduct}=="2050", TAG+="uaccess" + KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="28de", ATTRS{idProduct}=="2011", TAG+="uaccess" + KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="28de", ATTRS{idProduct}=="2012", TAG+="uaccess" + + # vive audio + KERNEL=="hidraw*", ATTRS{idVendor}=="0d8c", ATTRS{idProduct}=="0012", MODE="0666" + + SUBSYSTEM=="usb", ATTRS{idVendor}=="0bb4", ATTRS{idProduct}=="2c87", TAG+="uaccess" + + # HTC Camera USB Node + SUBSYSTEM=="usb", ATTRS{idVendor}=="114d", ATTRS{idProduct}=="8328", TAG+="uaccess" + + # HTC Mass Storage Node + SUBSYSTEM=="usb", ATTRS{idVendor}=="114d", ATTRS{idProduct}=="8200", TAG+="uaccess" + + # ds4 + KERNEL=="uinput", MODE="0666" + KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="054c", ATTRS{idProduct}=="05c4", MODE="0666" + KERNEL=="hidraw*", SUBSYSTEM=="hidraw", KERNELS=="0005:054C:05C4.*", MODE="0666" + + # Nintendo Switch Pro Controller over USB hidraw + KERNEL=="hidraw*", ATTRS{idVendor}=="057e", ATTRS{idProduct}=="2009", MODE="0666" + + # Nintendo Switch Pro Controller over bluetooth hidraw + KERNEL=="hidraw*", KERNELS=="*057E:2009*", MODE="0666" + + # rtl-sdr + SUBSYSTEM=="usb", ATTRS{idVendor}=="0bda", ATTRS{idProduct}=="2832", MODE="0666", SYMLINK+="rtl_sdr" + SUBSYSTEM=="usb", ATTRS{idVendor}=="0bda", ATTRS{idProduct}=="2838", MODE="0666", SYMLINK+="rtl_sdr_dvb" + + # arduino + SUBSYSTEM=="usb", ATTRS{idVendor}=="2341", ATTRS{idProduct}=="0043", MODE="0666", SYMLINK+="arduino" + ''; + + services.xserver.config = '' + Section "InputClass" + Identifier "Logitech M705" + MatchIsPointer "yes" + Option "AccelerationProfile" "-1" + Option "ConstantDeceleration" "5" + Option "AccelerationScheme" "none" + Option "AccelSpeed" "-1" + EndSection + + Section "InputClass" + Identifier "Razer Razer DeathAdder 2013" + MatchIsPointer "yes" + Option "AccelerationProfile" "-1" + Option "ConstantDeceleration" "5" + Option "AccelerationScheme" "none" + Option "AccelSpeed" "-1" + EndSection + ''; + + services.printing.drivers = [ pkgs.samsung-unified-linux-driver_4_01_17 ]; + + boot.blacklistedKernelModules = ["dvb_usb_rtl28xxu"]; + fileSystems."/media/kindle" = + { device = "/dev/kindle"; + fsType = "vfat"; + options = kindle-opts; + }; + + fileSystems."/media/kindledx" = + { device = "/dev/kindledx"; + fsType = "vfat"; + options = kindle-opts; + }; + + hardware = { + bluetooth.enable = true; + pulseaudio = { + package = if extra.is-minimal then pkgs.pulseaudio else pkgs.pulseaudioFull; + enable = true; + support32Bit = true; + }; + opengl.driSupport32Bit = true; + opengl.driSupport = true; + }; +} diff --git a/nix-config/machines/archer/backups/default.nix b/nix-config/machines/archer/backups/default.nix @@ -0,0 +1,45 @@ +extra: +{ config, lib, pkgs, ... }: +let pubkey = pkgs.fetchurl { + url = "https://jb55.com/pgp.txt"; + sha256 = "012910961fb58b886fc44a8ebedba394240be4e17604703f3b094eef86d5aca5"; + }; +in +{ + systemd.services.postgresql-backup = { + description = "PostgreSQL backups"; + + environment = { + AWS_ACCESS_KEY_ID = extra.private.aws_access_key; + AWS_SECRET_ACCESS_KEY = extra.private.aws_secret_key; + }; + + unitConfig.OnFailure = "notify-failed@%n.service"; + # Saturday morning? should be fine + startAt = "Sat *-*-* 08:10:00"; + serviceConfig.ExecStart = let script = pkgs.writeScript "postgresql-backup" '' + #!${pkgs.bash}/bin/bash + set -euo pipefail + + filename="Monstercat-pgdev-$(date +%F-%H%M%z).sql.xz.gpg" + + ${pkgs.gnupg}/bin/gpg2 --import ${pubkey} || echo "already have key!" + + ${pkgs.postgresql}/bin/pg_dump Monstercat \ + | ${pkgs.pxz}/bin/pxz -T24 \ + | ${pkgs.gnupg}/bin/gpg2 \ + -e \ + --compress-level 0 \ + --yes \ + --no-tty \ + --output - \ + -r 0x6D3E2004415AF4A3 \ + | ${pkgs.awscli}/bin/aws s3 \ + cp - \ + "s3://data.monstercat.com/backups/pg-dev/$filename" + + ''; + in "${script}"; + }; + +} diff --git a/nix-config/machines/archer/backups/git.nix b/nix-config/machines/archer/backups/git.nix @@ -0,0 +1,45 @@ +extra: +{ config, lib, pkgs, ... }: +let pubkey = pkgs.fetchurl { + url = "https://jb55.com/pgp.txt"; + sha256 = "012910961fb58b886fc44a8ebedba394240be4e17604703f3b094eef86d5aca5"; + }; +in +{ + systemd.services.gitzero-backup = { + description = "Git repo backups"; + + environment = { + AWS_ACCESS_KEY_ID = extra.private.aws_access_key; + AWS_SECRET_ACCESS_KEY = extra.private.aws_secret_key; + }; + + unitConfig.OnFailure = "notify-failed@%n.service"; + # Saturday morning? should be fine + startAt = "*-*-* 03:57:00"; + serviceConfig.ExecStart = let script = pkgs.writeScript "gitzero-backup" '' + #!${pkgs.bash}/bin/bash + set -euo pipefail + + filename="Monstercat-gitzero-$(date +%F-%H%M%z).tar.xz.gpg" + + ${pkgs.gnupg}/bin/gpg2 --import ${pubkey} || echo "already have key!" + + ${pkgs.gnutar}/bin/tar --exclude=/var/git/db-backup -cf - /var/git \ + | ${pkgs.pxz}/bin/pxz -T24 \ + | ${pkgs.gnupg}/bin/gpg2 \ + -e \ + --compress-level 0 \ + --yes \ + --no-tty \ + --output - \ + -r 0x6D3E2004415AF4A3 \ + | ${pkgs.awscli}/bin/aws s3 \ + cp - \ + "s3://data.monstercat.com/backups/gitzero/$filename" + + ''; + in "${script}"; + }; + +} diff --git a/nix-config/machines/archer/backups/wiki.nix b/nix-config/machines/archer/backups/wiki.nix @@ -0,0 +1,42 @@ +extra: +{ config, lib, pkgs, ... }: +let pubkey = pkgs.fetchurl { + url = "https://jb55.com/pgp.txt"; + sha256 = "012910961fb58b886fc44a8ebedba394240be4e17604703f3b094eef86d5aca5"; + }; +in +{ + systemd.services.wiki-backup = { + description = "Wiki backups"; + + environment = { + AWS_ACCESS_KEY_ID = extra.private.aws_access_key; + AWS_SECRET_ACCESS_KEY = extra.private.aws_secret_key; + }; + + unitConfig.OnFailure = "notify-failed@%n.service"; + startAt = "Sat *-*-* 02:57:00"; + serviceConfig.ExecStart = extra.util.writeBash "wiki-backup" '' + set -euo pipefail + + filename="Monstercat-wiki-$(date +%F-%H%M%z).tar.xz.gpg" + + ${pkgs.gnupg}/bin/gpg2 --import ${pubkey} || echo "already have key!" + + ${pkgs.gnutar}/bin/tar -cf - /var/lib/gitit \ + | ${pkgs.pxz}/bin/pxz -T24 \ + | ${pkgs.gnupg}/bin/gpg2 \ + -e \ + --compress-level 0 \ + --yes \ + --no-tty \ + --output - \ + -r 0x6D3E2004415AF4A3 \ + | ${pkgs.awscli}/bin/aws s3 \ + cp - \ + "s3://data.monstercat.com/backups/wiki/$filename" + + ''; + }; + +} diff --git a/nix-config/machines/archer/bandcamp-sales-bot/default.nix b/nix-config/machines/archer/bandcamp-sales-bot/default.nix @@ -0,0 +1,22 @@ +extra: +{ config, lib, pkgs, ... }: +let cfg = extra.private; +in +{ + systemd.services.bandcamp-sales-bot = { + description = "bandcamp sales bot"; + + environment = { + BANDCAMP_USER = cfg.bandcamp-user; + BANDCAMP_PASS = cfg.bandcamp-pass; + AWS_ACCESS_KEY_ID = cfg.aws_access_key; + AWS_SECRET_ACCESS_KEY = cfg.aws_secret_key; + }; + + serviceConfig.ExecStart = "${extra.import-scripts}/bin/bandcamp-sales-bot"; + unitConfig.OnFailure = "notify-failed@%n.service"; + + # 3rd day of each month + startAt = "*-*-03 8:30:00"; + }; +} diff --git a/nix-config/machines/archer/beatport-sales-bot/default.nix b/nix-config/machines/archer/beatport-sales-bot/default.nix @@ -0,0 +1,25 @@ +extra: +{ config, lib, pkgs, ... }: +let cfg = extra.private; + util = extra.util; + import-scripts = extra.import-scripts; +in +{ + systemd.user.services.shopify-sales-bot = { + description = "beatport sales bot"; + + wantedBy = [ "default.target" ]; + after = [ "default.target" ]; + + environment = { + SHOPIFY_USER = extra.private.beatport-user; + SHOPIFY_PASS = extra.private.beatport-pass; + }; + + serviceConfig.ExecStart = "${import-scripts}/bin/beaport-sales-bot"; + unitConfig.OnFailure = "notify-failed-user@%n.service"; + + # 20th is always before the earliest possible last wednesday (22nd) + startAt = "*-*-20 7:30:00"; + }; +} diff --git a/nix-config/machines/archer/cogs-bot/default.nix b/nix-config/machines/archer/cogs-bot/default.nix @@ -0,0 +1,23 @@ +extra: +{ config, lib, pkgs, ... }: +let cfg = extra.private; + util = extra.util; + import-scripts = extra.import-scripts; +in +{ + systemd.user.services.cogs-bot = { + description = "cogs bot"; + + wantedBy = [ "default.target" ]; + after = [ "default.target" ]; + + environment = { + COGS_SHEET_ID="1lIluimJqBlGK1yRTmsekwUmk0_Wk0wD9VErUE8z6_dY"; + }; + + serviceConfig.ExecStart = "${import-scripts}/bin/cogs-bot daily-check"; + unitConfig.OnFailure = "notify-failed-user@%n.service"; + + startAt = "*-*-* 5:30:00"; + }; +} diff --git a/nix-config/machines/archer/config/default.nix b/nix-config/machines/archer/config/default.nix @@ -0,0 +1,5 @@ +pkgs: { + sessionCommands = '' + ${pkgs.xlibs.xset}/bin/xset m 0 0 + ''; +} diff --git a/nix-config/machines/archer/default.nix b/nix-config/machines/archer/default.nix @@ -0,0 +1,146 @@ +extra: +{ config, lib, pkgs, ... }: +let util = extra.util; + private = extra.private; + extras = (rec { ztip = "10.144.14.20"; + nix-serve = { + port = 10845; + bindAddress = ztip; + }; + import-scripts = (import <monstercatpkgs> { }).import-scripts; + }) // extra; +in { + imports = [ + ./hardware + (import ./backups extras) + (import ./backups/git.nix extras) + (import ./backups/wiki.nix extras) + (import ./nginx extras) + (import ./trendbot extras) + (import ./transaction-bot extras) + (import ./tunecore-sales-bot extras) + (import ./bandcamp-sales-bot extras) + (import ./youtube-sales-bot extras) + (import ./youtube-pub-sales-bot extras) + (import ./shopify-sales-bot extras) + (import ./itunes-bots extras) + (import ./cogs-bot extras) + (import <nixpkgs/nixos/modules/services/misc/gitit.nix>) + ]; + + services.printing.drivers = [ pkgs.samsung-unified-linux-driver_4_01_17 ]; + services.mongodb.enable = true; + services.redis = { + enable = true; + bind = extras.ztip; + }; + + services.gitit = rec { + enable = true; + wikiTitle = "Monstercat Wiki"; + requireAuthentication = "none"; + sessionTimeout = 43800; + math = "mathml"; + mathJaxScript = "MathJax/MathJax.js"; + plugins = []; + mailCommand = "/run/current-system/sw/bin/sendmail %s"; + accessQuestion = "Enter 'monstercat' here"; + accessQuestionAnswers = "monstercat"; + staticDir = "/var/lib/gitit-static"; + useFeed = true; + resetPasswordMessage = '' + + > From: gitit@monstercat.com + > To: $useremail$ + > Subject: ${wikiTitle} password reset + > + > Hello $username$, + > + > To reset your password, please follow the link below: + > http://wiki.monstercat.com$resetlink$ + > + > Regards + ''; + }; + + users.extraGroups.gitit.members = [ "jb55" ]; + + services.nginx.httpConfig = '' + server { + listen 80; + server_name pkgs.monster.cat; + + location = / { + return 301 https://github.com/monstercat/monstercatpkgs/archive/master.tar.gz; + } + } + + server { + listen 80; + server_name nixcache.monstercat.com; + + location / { + proxy_pass http://${extras.nix-serve.bindAddress}:${toString extras.nix-serve.port}; + proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504; + proxy_redirect off; + proxy_buffering off; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + } + } + + server { + listen 80; + server_name wiki.monstercat.com wiki.monster.cat; + + location / { + proxy_pass http://localhost:${toString config.services.gitit.port}; + proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504; + proxy_redirect off; + proxy_buffering off; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + } + } + ''; + + services.nix-serve.enable = true; + services.nix-serve.bindAddress = extras.nix-serve.bindAddress; + services.nix-serve.port = extras.nix-serve.port; + + networking.firewall.trustedInterfaces = ["zt0" "zt2"]; + networking.firewall.allowedTCPPorts = [ 22 143 80 ]; + + networking.defaultMailServer = { + directDelivery = private.gmail-user != null || private.gmail-pass != null; + hostName = "smtp.gmail.com:587"; + root = "bill@monstercat.com"; + domain = "monstercat.com"; + useTLS = true; + useSTARTTLS = true; + authUser = private.gmail-user; + authPass = private.gmail-pass; + }; + + services.fcgiwrap.enable = true; + + systemd.services.postgresql.after = [ "zerotierone.service" ]; + + services.postgresql = { + dataDir = "/var/db/postgresql/9.5/"; + enable = true; + # extraPlugins = with pkgs; [ pgmp ]; + authentication = pkgs.lib.mkForce '' + # type db user address method + local all all trust + host all all 10.144.0.0/16 trust + host all all 192.168.1.0/16 trust + + ''; + extraConfig = '' + listen_addresses = '10.144.14.20,192.168.1.49' + ''; + }; +} diff --git a/nix-config/machines/archer/fail-notifier/default.nix b/nix-config/machines/archer/fail-notifier/default.nix @@ -0,0 +1,29 @@ +{ config, lib, pkgs, ... }: +{ + systemd.services."notify-failed@" = { + description = "Job failure notifier"; + + serviceConfig.ExecStart = let script = pkgs.writeScript "failure-notifier" '' + #!${pkgs.bash}/bin/bash + + UNIT=$1 + + /var/setuid-wrappers/sendmail -t <<ERRMAIL + To: bill@monstercat.com + From: systemd <root@$HOSTNAME> + Subject: $UNIT Failed + Content-Transfer-Encoding: 8bit + Content-Type: text/plain; charset=UTF-8 + + $2 + $3 + $4 + + $(systemctl status $UNIT) + ERRMAIL + ''; + in "${script} %I 'Hostname: %H' 'Machine ID: %m' 'Boot ID: %b'"; + + }; + +} diff --git a/nix-config/machines/archer/hardware/default.nix b/nix-config/machines/archer/hardware/default.nix @@ -0,0 +1,36 @@ +# Do not modify this file! It was generated by ‘nixos-generate-config’ +# and may be overwritten by future invocations. Please make changes +# to /etc/nixos/configuration.nix instead. +{ config, lib, pkgs, ... }: + +{ + imports = + [ <nixpkgs/nixos/modules/installer/scan/not-detected.nix> + ]; + + boot.initrd.availableKernelModules = [ "ehci_pci" "ahci" "xhci_hcd" "firewire_ohci" "usb_storage" "usbhid" ]; + boot.kernelModules = [ "kvm-intel" ]; + boot.extraModulePackages = [ ]; + boot.loader.grub.device = "/dev/sda"; + + fileSystems."/" = { + device = "/dev/disk/by-uuid/4b076497-f2f8-4e3a-bd27-2874a4a0e361"; + fsType = "ext4"; + options = ["noatime" "nodiratime" "discard"]; + }; + + fileSystems."/shares/turtlerock" = { + device = "//192.168.1.66/Confidential\\040Share"; + fsType = "cifs"; + options = ["x-systemd.automount" "x-systemd.idle-timeout=1min" "username=bill" "password=connect123" "uid=1000" "gid=1000" "workgroup=WORKGROUP" "rw"]; + }; + + fileSystems."/dropbox" = { + device = "/dev/disk/by-label/vertex"; + fsType = "ext4"; + options = ["noatime" "nodiratime" "discard"]; + }; + + # swapDevices = + # [ { device = "/dev/disk/by-uuid/d4e4ae51-9179-439d-925b-8df42dd1bfc5"; } ] ; +} diff --git a/nix-config/machines/archer/itunes-bots/default.nix b/nix-config/machines/archer/itunes-bots/default.nix @@ -0,0 +1,40 @@ +extra: +{ config, lib, pkgs, ... }: +let util = extra.util; + import-scripts = extra.import-scripts; + countries = pkgs.fetchurl { + url = "https://jb55.com/s/8536f14537bbb417.csv"; + sha256 = "9c31690e31f5a26b12bc5a16d3a1508a06ac1d842e4a129868bc7aaf33358ab5"; + }; +in +{ + systemd.user.services.itunes-sales-bot = { + description = "itunes sales bot"; + + wantedBy = [ "default.target" ]; + after = [ "default.target" ]; + + environment = { + ISO_3166_COUNTRIES = countries; + }; + + serviceConfig.ExecStart = "${import-scripts}/bin/itunes-sales-bot"; + unitConfig.OnFailure = "notify-failed-user@%n.service"; + + # First tuesday of every month @ 1600 + startAt = "Tue *-*-1..7 11:30:00"; + }; + + systemd.user.services.itunes-transaction-bot = { + description = "itunes transaction bot"; + + wantedBy = [ "default.target" ]; + after = [ "default.target" ]; + + serviceConfig.ExecStart = "${import-scripts}/bin/itunes-transaction-bot"; + unitConfig.OnFailure = "notify-failed-user@%n.service"; + + # First tuesday of every month @11 + startAt = "Tue *-*-1..7 11:00:00"; + }; +} diff --git a/nix-config/machines/archer/nginx/default.nix b/nix-config/machines/archer/nginx/default.nix @@ -0,0 +1,95 @@ +extra: +{ config, lib, pkgs, ... }: +let sites = [ ]; + logDir = "/var/log/nginx"; + gitExtra = { + git = { + projectroot = "/var/git"; + }; + }; + gitCfg = import ./git.nix { inherit config pkgs; extra = extra // gitExtra; }; + hoogle = import ./hoogle.nix extra.ztip; + nixserve = import ./nix-serve.nix extra; +in { + services.logrotate.config = '' + ${logDir}/*.log { + daily + missingok + rotate 52 + compress + delaycompress + notifempty + # 20MB + minsize 20971520 + create 640 root adm + sharedscripts + postrotate + ${pkgs.procps}/bin/pkill -USR1 nginx + endscript + } + ''; + + services.nginx = { + enable = true; + + httpConfig = '' + port_in_redirect off; + ssl_protocols TLSv1 TLSv1.1 TLSv1.2; + ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:ECDHE-RSA-DES-CBC3-SHA:ECDHE-ECDSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA'; + ssl_prefer_server_ciphers on; + + # HSTS (ngx_http_headers_module is required) (15768000 seconds = 6 months) + add_header Strict-Transport-Security max-age=15768000; + + sendfile on; + tcp_nopush on; + tcp_nodelay on; + keepalive_timeout 65; + types_hash_max_size 2048; + client_max_body_size 6G; + + # server_tokens off; + proxy_buffering off; + proxy_read_timeout 300s; + expires off; + default_type application/octet-stream; + + access_log ${logDir}/access.log; + error_log ${logDir}/error.log; + + gzip on; + gzip_disable "msie6"; + + server { + listen 80; + server_name archer.zero.monster.cat; + + root /www/public; + index index.html index.htm; + + location / { + try_files $uri $uri/ =404; + } + } + + server { + listen 80; + server_name siren.zero.monster.cat; + + location / { + include ${pkgs.nginx}/conf/fastcgi_params; + gzip off; + + fastcgi_param SCRIPT_FILENAME /home/jb55/src/c/libsirenofshame/siren-rest.fcgi; + fastcgi_param PATH_INFO $uri; + fastcgi_pass unix:${config.services.fcgiwrap.socketAddress}; + } + } + + ${lib.concatStringsSep "\n\n" (map builtins.readFile sites)} + + ${gitCfg} + ${hoogle} + ''; + }; +} diff --git a/nix-config/machines/archer/nginx/git.nix b/nix-config/machines/archer/nginx/git.nix @@ -0,0 +1,70 @@ + +{ extra, config, pkgs }: +let gitwebConf = pkgs.writeText "gitweb.conf" '' + # path to git projects (<project>.git) + $projectroot = "${extra.git.projectroot}"; + ''; + gitweb-wrapper = pkgs.writeScript "gitweb.cgi" '' + #!${pkgs.bash}/bin/bash + export PERL5LIB=$PERL5LIB:${with pkgs.perlPackages; pkgs.lib.makePerlPath [ CGI HTMLParser ]} + ${pkgs.perl}/bin/perl ${pkgs.git}/share/gitweb/gitweb.cgi + ''; + gitweb-theme = pkgs.fetchFromGitHub { + owner = "kogakure"; + repo = "gitweb-theme"; + rev = "4305b3551551c470339c24a6567b1ac9e642ae54"; + sha256 = "0gagy0jvqb3mc587b6yy8l9g5j5wqr2xlz128v6f01364cb7whmv"; + }; + giturl = "git.monster.cat"; +in +if config.services.fcgiwrap.enable then '' + server { + listen 80; + server_name ${giturl}; + + location = / { + return 301 http://${giturl}/repos/; + } + + location = /repos { + return 301 http://${giturl}/repos/; + } + + location / { + # fcgiwrap is set up to listen on this host:port + fastcgi_pass unix:${config.services.fcgiwrap.socketAddress}; + include ${pkgs.nginx}/conf/fastcgi_params; + fastcgi_param SCRIPT_FILENAME ${pkgs.git}/bin/git-http-backend; + + client_max_body_size 0; + + # export all repositories under GIT_PROJECT_ROOT + + fastcgi_param GIT_HTTP_EXPORT_ALL ""; + fastcgi_param GIT_PROJECT_ROOT ${extra.git.projectroot}; + fastcgi_param PATH_INFO $uri; + } + + location /repos/static { + alias ${gitweb-theme}; + } + + location /add-repo { + include ${pkgs.nginx}/conf/fastcgi_params; + gzip off; + + fastcgi_param SCRIPT_FILENAME /var/git/mkrepod; + fastcgi_pass unix:${config.services.fcgiwrap.socketAddress}; + } + + location /repos { + include ${pkgs.nginx}/conf/fastcgi_params; + gzip off; + + fastcgi_param GITWEB_CONFIG ${gitwebConf}; + fastcgi_param SCRIPT_FILENAME ${gitweb-wrapper}; + fastcgi_pass unix:${config.services.fcgiwrap.socketAddress}; + } + + } +'' else "" diff --git a/nix-config/machines/archer/nginx/hoogle.nix b/nix-config/machines/archer/nginx/hoogle.nix @@ -0,0 +1,16 @@ +ztip: '' + server { + listen 80; + server_name hoogle.zero.monster.cat; + + location / { + proxy_pass http://localhost:8080; + proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504; + proxy_redirect off; + proxy_buffering off; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + } + } +''+ \ No newline at end of file diff --git a/nix-config/machines/archer/nginx/nix-serve.nix b/nix-config/machines/archer/nginx/nix-serve.nix @@ -0,0 +1,7 @@ +config: +let + port = config.nix-serve.port; + bind = config.ztip; + localbind = config.nix-serve.bindAddress; +in '' +'' diff --git a/nix-config/machines/archer/nginx/sites/local b/nix-config/machines/archer/nginx/sites/local @@ -0,0 +1,17 @@ + +server { + listen 80; + server_name archer.; + root /www/jb55/public; + index index.html index.htm; + + location / { + try_files $uri $uri/ =404; + } +} + +server { + listen 80; + server_name www.archer.; + return 301 https://archer.$request_uri; +}+ \ No newline at end of file diff --git a/nix-config/machines/archer/payments-runner/default.nix b/nix-config/machines/archer/payments-runner/default.nix @@ -0,0 +1,9 @@ +extra: +{ config, lib, pkgs, ... }: +let + monstercatpkgs = import <monstercatpkgs> {}; + payments-processor = monstercatpkgs.payments-processor; + payment-scripts = monstercatpkgs.payment-scripts; +in +{ +} diff --git a/nix-config/machines/archer/payments-server/default.nix b/nix-config/machines/archer/payments-server/default.nix @@ -0,0 +1,57 @@ +extra: +{ config, lib, pkgs, ... }: +let + port = "8989"; + monstercatpkgs = import <monstercatpkgs> {}; + payments-server = monstercatpkgs.payments-server; + payments-client = monstercatpkgs.payments-client; +in +{ + services.nginx.httpConfig = lib.mkIf config.services.nginx.enable '' + server { + listen 80; + server_name payments.zero.monster.cat; + root ${payments-client}/share; + index index.html; + + location ^~ /api/ { + proxy_pass http://localhost:${port}/; + proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504; + proxy_redirect off; + proxy_buffering off; + proxy_intercept_errors on; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + } + + location / { + try_files $uri $uri /index.html; + } + } + ''; + + systemd.services.payments-server = { + description = "Monstercat Payments Server"; + + wantedBy = [ "multi-user.target" ]; + after = [ "network.target" "redis.service" "postgresql.service" ]; + + environment = with extra.private; { + POSTGRES_USER = "jb55"; + POSTGRES_PASSWORD = ""; + POSTGRES_HOST = "db.zero.monster.cat"; + POSTGRES_DATABASE = "Monstercat"; + REDIS_URL = "redis://redis.zero.monster.cat:6379"; + PORT = port; + AWS_ACCESS_KEY = aws_access_key; + AWS_PRIVATE_KEY = aws_secret_key; + AWS_REGION = aws_region; + AWS_BUCKET = aws_bucket; + }; + + serviceConfig.ExecStart = "${payments-server}/bin/payments-server"; + serviceConfig.Restart = "always"; + unitConfig.OnFailure = "notify-failed@%n.service"; + }; +} diff --git a/nix-config/machines/archer/shopify-sales-bot/default.nix b/nix-config/machines/archer/shopify-sales-bot/default.nix @@ -0,0 +1,22 @@ +extra: +{ config, lib, pkgs, ... }: +let cfg = extra.private; + util = extra.util; + import-scripts = extra.import-scripts; +in +{ + systemd.user.services.shopify-sales-bot = { + description = "shopify sales bot"; + + environment = { + SHOPIFY_USER = extra.private.shopify-user; + SHOPIFY_PASS = extra.private.shopify-pass; + }; + + serviceConfig.ExecStart = "${import-scripts}/bin/shopify-sales-bot"; + unitConfig.OnFailure = "notify-failed-user@%n.service"; + + # 20th is always before the earliest possible last wednesday (22nd) + startAt = "*-*-20 8:30:00"; + }; +} diff --git a/nix-config/machines/archer/transaction-bot/default.nix b/nix-config/machines/archer/transaction-bot/default.nix @@ -0,0 +1,21 @@ +extra: +{ config, lib, pkgs, ... }: +{ + systemd.user.services.transaction-bot = { + description = "tc transaction bot"; + + wantedBy = [ "default.target" ]; + after = [ "default.target" ]; + + environment = { + TUNECORE_USER = extra.private.tc-user; + TUNECORE_PASS = extra.private.tc-pass; + }; + + serviceConfig.ExecStart = "${extra.import-scripts}/bin/tunecore-transaction-bot"; + unitConfig.OnFailure = "notify-failed@%n.service"; + + startAt = "*-*-* 01:00:00"; + }; +} + diff --git a/nix-config/machines/archer/trendbot/default.nix b/nix-config/machines/archer/trendbot/default.nix @@ -0,0 +1,21 @@ +extra: +{ config, lib, pkgs, ... }: +{ + systemd.user.services.trend-bot = { + description = "tc trend bot"; + + wantedBy = [ "default.target" ]; + after = [ "default.target" ]; + + environment = { + TUNECORE_USER = extra.private.tc-user; + TUNECORE_PASS = extra.private.tc-pass; + }; + + serviceConfig.ExecStart = "${extra.import-scripts}/bin/trend-bot"; + unitConfig.OnFailure = "notify-failed@%n.service"; + + startAt = "*-*-* 23:59:00"; + }; +} + diff --git a/nix-config/machines/archer/tunecore-sales-bot/default.nix b/nix-config/machines/archer/tunecore-sales-bot/default.nix @@ -0,0 +1,24 @@ +extra: +{ config, lib, pkgs, ... }: +{ + systemd.user.services.tunecore-sales-bot = { + description = "tc sales bot"; + + wantedBy = [ "default.target" ]; + after = [ "default.target" ]; + + environment = { + TUNECORE_USER = extra.private.tc-user; + TUNECORE_PASS = extra.private.tc-pass; + AWS_ACCESS_KEY_ID = extra.private.aws_access_key; + AWS_SECRET_ACCESS_KEY = extra.private.aws_secret_key; + }; + + serviceConfig.ExecStart = "${extra.import-scripts}/bin/tunecore-sales-bot daily-check"; + unitConfig.OnFailure = "notify-failed@%n.service"; + + # monthly, first tuesday + startAt = "Tue *-*-1..7 10:30:00"; + }; +} + diff --git a/nix-config/machines/archer/youtube-pub-sales-bot/default.nix b/nix-config/machines/archer/youtube-pub-sales-bot/default.nix @@ -0,0 +1,23 @@ + +extra: +{ config, lib, pkgs, ... }: +let cfg = extra.private; +in +{ + systemd.user.services.youtube-pub-sales-bot = { + description = "youtube publishing sales bot"; + + environment = { + YOUTUBE_TYPE="publishing"; + YOUTUBE_OWNER_ID="svBi-FFZiMepj02zaNfDNQ"; + }; + + serviceConfig.ExecStart = "${extra.import-scripts}/bin/youtube-sales-bot"; + unitConfig.OnFailure = "notify-failed-user@%n.service"; + + # monthly, more than half way through the month. This is because YouTube + # updates these sheets all the way up to at most half the month (highest + # I've seen is ~15th) + startAt = "*-*-20 11:00:00"; + }; +} diff --git a/nix-config/machines/archer/youtube-sales-bot/default.nix b/nix-config/machines/archer/youtube-sales-bot/default.nix @@ -0,0 +1,20 @@ +extra: +{ config, lib, pkgs, ... }: +let cfg = extra.private; +in +{ + systemd.user.services.youtube-sales-bot = { + description = "youtube sales bot"; + + wantedBy = [ "default.target" ]; + after = [ "default.target" ]; + + serviceConfig.ExecStart = "${extra.import-scripts}/bin/youtube-sales-bot"; + unitConfig.OnFailure = "notify-failed-user@%n.service"; + + # monthly, more than half way through the month. This is because YouTube + # updates these sheets all the way up to at most half the month (highest + # I've seen is ~15th) + startAt = "*-*-20 10:24:00"; + }; +} diff --git a/nix-config/machines/charon/config/default.nix b/nix-config/machines/charon/config/default.nix @@ -0,0 +1 @@ +pkgs: {} diff --git a/nix-config/machines/charon/default.nix b/nix-config/machines/charon/default.nix @@ -0,0 +1,453 @@ +extra: +{ config, lib, pkgs, ... }: +let gitExtra = { + git = {projectroot = "/var/git";}; + host = "git.zero.jb55.com"; + }; + httpipePort = "8899"; + # httpiped = (import (pkgs.fetchgit { + # url = https://github.com/jb55/httpipe; + # rev = "376de0e37bba505ba5f23c46435277bb74603acd"; + # sha256 = "1x9d98z6zbs22x38xwxjnb6mwladbah9xajyl7kk8bm418l8wac4"; + # }) { nodejs = pkgs.nodejs; }).package; + npmrepo = (import (pkgs.fetchFromGitHub { + owner = "jb55"; + repo = "npm-repo-proxy"; + rev = "bef839a95736588ec40c917fa63d490cd736f307"; + sha256 = "1j2xclgcmz9hbf47k4ygyzmiradfg9q30m8bzr1i2x91kz1ck946"; + }) {}).package; + gitCfg = extra.git-server { inherit config pkgs; extra = extra // gitExtra; }; + hearpress = (import <jb55pkgs> { nixpkgs = pkgs; }).hearpress; + myemail = "jb55@jb55.com"; + radicale-rights = pkgs.writeText "radicale-rights" '' + [vanessa-famcal-access] + user = vanessa + collection = jb55/4bcae62e-9c8b-0d94-d8ef-977a29a24a84 + permission = rw + + # Give owners read-write access to everything else: + [owner-write] + user = .+ + collection = %(login)s(/.*)? + permission = rw + + # Everyone can read the root collection + [read] + user = .* + collection = + permission = r + ''; + jb55-activity = pkgs.writeText "jb55-custom-activity" '' + { + "@context": [ + "https://www.w3.org/ns/activitystreams" + ], + "inbox": "https://jb55/inbox", + "id": "https://jb55.com", + "type": "Person", + "preferredUsername": "jb55", + "name": "William Casarin", + "summary": "This is not a real activitypub endpoint yet! I'm still building it", + "url": "https://jb55.com", + "manuallyApprovesFollowers": false, + "icon": { + "type": "Image", + "mediaType": "image/jpeg", + "url": "https://jb55.com/me.jpg" + }, + "publicKey": { + "id": "https://jb55.com#main-key", + "owner": "https://jb55.com", + "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnJOPxwmRGBBQYm7YgHRu\nbTaYaKbMoEQiui+37nizXA73CRNeKblSXIaJnfOKfz/ttRG0GH43GzHTpghUDuZX\n+QBpyOk8UMmCW5gM0Y5c3IOv0zLezqLXrVEM8UXMUHE3hxf61r1NKl1+IG9MwhtH\nayx0Kaz6vT/V8nkotCSlb91lMT8X28bButwN86RCclZncecQXuVvgXnFeZCeBLM+\nqV2tBPnn14Ws+AqVvVnBW8xXwVfSPFHQchSLAusdWI7Kw/oWN/on2CqfRASoaVAS\nqKG+uPuJ+1f92iH0ZY1wLB2/ITl7HKTiIMKNikXTWcUudkMlKxc5Iqb7HMHuaPZ9\nIQIDAQAB\n-----END PUBLIC KEY-----" + } + } + ''; + webfinger = pkgs.writeText "webfinger-acct-jb55" '' + { + "subject": "acct:jb55@jb55.com", + "aliases": [ + "https://jb55.com" + ], + "links": [ + { + "rel": "http://webfinger.net/rel/profile-page", + "type": "text/html", + "href": "https://jb55.com" + }, + { + "rel": "self", + "type": "application/activity+json", + "href": "https://jb55.com" + } + ] + } + ''; +in +{ + imports = [ + ./networking + ./hardware + (import ./nginx extra) + (import ./sheetzen extra) + #(import ./vidstats extra) + ]; + + # systemd.services.httpiped = { + # description = "httpiped"; + # wantedBy = [ "multi-user.target" ]; + # after = [ "multi-user.target" ]; + # environment = { + # PORT = httpipePort; + # }; + # serviceConfig.Restart = "always"; + # serviceConfig.ExecStart = "${httpiped}/bin/httpiped"; + # }; + + services.xinetd.enable = true; + services.xinetd.services = + [ + { name = "gopher"; + port = 70; + server = "${pkgs.gophernicus}/bin/in.gophernicus"; + serverArgs = "-h jb55.com -nf -r /var/gopher"; + extraConfig = '' + disable = no + ''; + } + ]; + + users.extraGroups.jb55cert.members = [ "prosody" "nginx" ]; + + services.gitDaemon.basePath = "/var/git-public/repos"; + services.gitDaemon.enable = true; + + services.radicale.enable = true; + services.radicale.config = '' + [auth] + type = htpasswd + htpasswd_filename = /home/jb55/.config/radicale/users + htpasswd_encryption = plain + delay = 1 + + [storage] + filesystem_folder = /home/jb55/.config/radicale/data + + [server] + hosts = 127.0.0.1:5232 + ssl = False + max_connections = 20 + + # 1 Megabyte + max_content_length = 10000000 + + timeout = 10 + + [rights] + type = from_file + file = ${radicale-rights} + ''; + + security.acme.certs."jb55.com" = { + webroot = "/var/www/challenges"; + group = "jb55cert"; + allowKeysForGroup = true; + postRun = "systemctl restart prosody"; + email = myemail; + }; + + security.acme.certs."coretto.io" = { + webroot = "/var/www/challenges"; + email = myemail; + }; + + security.acme.certs."git.jb55.com" = { + webroot = "/var/www/challenges"; + group = "jb55cert"; + allowKeysForGroup = true; + email = myemail; + }; + + security.acme.certs."sheetzen.com" = { + webroot = "/var/www/challenges"; + email = myemail; + }; + + security.acme.certs."hearpress.com" = { + webroot = "/var/www/challenges"; + email = myemail; + }; + + services.mailz = { + enable = true; + domain = "jb55.com"; + + users = { + jb55 = { + password = "$6$KHmFLeDBaXBE1Jkg$eEN8HM3LpZ4muDK/JWC25qW9xSZq0AqsF4tlzEan7yctROJ9A/lSqz6gN1b1GtwE7efroXGHtDi2FEJ2ujDAl0"; + aliases = [ "postmaster" "bill" "will" "william" "me" "jb" ]; + }; + }; + + sieves = builtins.readFile ./dovecot/filters.sieve; + }; + + users.extraUsers.prosody.extraGroups = [ "jb55cert" ]; + services.prosody.enable = true; + services.prosody.admins = [ "jb55@jb55.com" ]; + services.prosody.allowRegistration = false; + services.prosody.extraModules = [ + # "cloud_notify" + # "smacks" + # "carbons" + # "http_upload" + ]; + services.prosody.extraConfig = '' + c2s_require_encryption = true + ''; + services.prosody.ssl = { + cert = "/var/lib/acme/jb55.com/fullchain.pem"; + key = "/var/lib/acme/jb55.com/key.pem"; + }; + services.prosody.virtualHosts.jb55 = { + enabled = true; + domain = "jb55.com"; + ssl = { + cert = "/var/lib/acme/jb55.com/fullchain.pem"; + key = "/var/lib/acme/jb55.com/key.pem"; + }; + }; + + services.postgresql = { + dataDir = "/var/db/postgresql/9.5"; + package = pkgs.postgresql95; + enable = true; + enableTCPIP = true; + authentication = '' + # type db user address method + local all all trust + host all all 172.24.0.0/16 trust + host all all 127.0.0.1/16 trust + ''; + #extraConfig = '' + # listen_addresses = '${extra.ztip}' + #''; + }; + + systemd.services.npmrepo = { + description = "npmrepo.com"; + + wantedBy = [ "multi-user.target" ]; + + serviceConfig.Type = "simple"; + serviceConfig.ExecStart = "${npmrepo}/bin/npm-repo-proxy"; + }; + + systemd.user.services.rss2email = { + description = "run rss2email"; + path = with pkgs; [ rss2email ]; + wantedBy = [ "default.target" ]; + serviceConfig.ExecStart = "${pkgs.rss2email}/bin/r2e run"; + }; + + systemd.user.services.backup-rss2email = { + description = "backup rss2email"; + wantedBy = [ "default.target" ]; + serviceConfig.ExecStart = pkgs.writeScript "backup-rss2email" '' + #!${pkgs.bash}/bin/bash + BACKUP_DIR=/home/jb55/backups/rss2email + cp /home/jb55/.config/rss2email.cfg $BACKUP_DIR + cp /home/jb55/.local/share/rss2email.json $BACKUP_DIR + cd $BACKUP_DIR + ${pkgs.git}/bin/git add -u + ${pkgs.git}/bin/git commit -m "bump" + ${pkgs.git}/bin/git push + ''; + }; + + systemd.user.timers.backup-rss2email = { + wantedBy = [ "timers.target" ]; + timerConfig.OnCalendar = "daily"; + }; + + systemd.user.timers.rss2email = { + wantedBy = [ "timers.target" ]; + timerConfig.OnCalendar = "hourly"; + }; + + # systemd.services.hearpress = { + # description = "Hearpress server"; + # wantedBy = [ "multi-user.target" ]; + # after = [ "postgresql.service" ]; + + # environment = { + # PG_CS = "postgresql://jb55@localhost/hearpress"; + # AWS_ACCESS_KEY_ID = extra.private.aws.access_key; + # AWS_SECRET_ACCESS_KEY = extra.private.aws.secret_key; + # }; + + # serviceConfig.Type = "simple"; + # serviceConfig.ExecStart = "${hearpress}/bin/hearpressd"; + # }; + + + security.setuidPrograms = [ "sendmail" ]; + + services.fcgiwrap.enable = true; + + services.nginx.httpConfig = '' + ${gitCfg} + + server { + listen 443 ssl; + server_name coretto.io; + root /home/jb55/www/coretto.io; + index index.html; + + ssl_certificate /var/lib/acme/coretto.io/fullchain.pem; + ssl_certificate_key /var/lib/acme/coretto.io/key.pem; + + location / { + try_files $uri $uri/ =404; + } + + location /email { + gzip off; + # fcgiwrap is set up to listen on this host:port + fastcgi_pass unix:${config.services.fcgiwrap.socketAddress}; + include ${pkgs.nginx}/conf/fastcgi_params; + fastcgi_param SCRIPT_FILENAME /home/jb55/www/coretto.io/email.py; + + client_max_body_size 512; + + # export all repositories under GIT_PROJECT_ROOT + + fastcgi_param PATH_INFO $uri; + } + + + } + + server { + listen 80; + server_name coretto.io www.coretto.io; + + location /.well-known/acme-challenge { + root /var/www/challenges; + } + + location / { + return 301 https://coretto.io$uri; + } + } + + server { + listen 443 ssl; + server_name www.coretto.io; + return 301 https://coretto.io$request_uri; + } + + server { + listen 80; + server_name git.jb55.com; + + location /.well-known/acme-challenge { + root /var/www/challenges; + } + + location / { + return 301 https://git.jb55.com$request_uri; + } + } + + server { + listen 443 ssl; + server_name git.jb55.com; + + root /var/git-public/stagit; + index index.html index.htm; + + ssl_certificate /var/lib/acme/git.jb55.com/fullchain.pem; + ssl_certificate_key /var/lib/acme/git.jb55.com/key.pem; + } + + server { + listen 443 ssl; + server_name jb55.com; + root /www/jb55/public; + index index.html index.htm; + + ssl_certificate /var/lib/acme/jb55.com/fullchain.pem; + ssl_certificate_key /var/lib/acme/jb55.com/key.pem; + + rewrite ^/pkgs.tar.gz$ https://github.com/jb55/jb55pkgs/archive/master.tar.gz permanent; + rewrite ^/pkgs/?$ https://github.com/jb55/jb55pkgs/archive/master.tar.gz permanent; + + location / { + error_page 418 = @jb55activity; + + if ( $http_accept ~ "application/activity\+json" ) { return 418; } + + try_files $uri $uri/ =404; + } + + location @jb55activity { + root /; + default_type application/activity+json; + try_files ${jb55-activity} =404; + } + + location = /.well-known/webfinger { + error_page 418 = @jb55webfinger; + if ( $query_string = "resource=acct:jb55@jb55.com" ) { return 418; } + return 404; + } + + location @jb55webfinger { + root /; + default_type application/jrd+json; + try_files ${webfinger} =404; + } + + location /paste/ { + proxy_max_temp_file_size 0; + client_max_body_size 0; + proxy_request_buffering off; + proxy_buffering off; + proxy_http_version 1.1; + proxy_pass http://127.0.0.1:${httpipePort}/; + + add_header X-Content-Type-Options nosniff; + } + + location /cal/ { + proxy_pass http://127.0.0.1:5232/; + proxy_set_header X-Script-Name /cal; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + } + + location ^~ /files/calls { + error_page 405 =200 $uri; + } + } + + server { + listen 80; + server_name jb55.com www.jb55.com; + + location /.well-known/acme-challenge { + root /var/www/challenges; + } + + location / { + return 301 https://jb55.com$request_uri; + } + } + server { + listen 443 ssl; + server_name www.jb55.com; + return 301 https://jb55.com$request_uri; + } + + ''; + +} diff --git a/nix-config/machines/charon/dovecot/filters.sieve b/nix-config/machines/charon/dovecot/filters.sieve @@ -0,0 +1,191 @@ + +require ["regex", "variables","envelope","mailbox","body","fileinto","imap4flags","reject"]; + +if allof (header :contains "from" "Microsoft Canada") { + addflag "\\Seen"; +} + +if header :contains "X-RSS-Feed" "reddit.com" { + fileinto "Reddit"; +} +elsif header :contains "X-RSS-Feed" "arxiv.org" { + fileinto "Arxiv"; +} +elsif header :contains "X-RSS-Feed" "youtube.com" { + fileinto "YouTube"; +} +elsif header :contains "X-RSS-Feed" "ycombinator.com" { + fileinto "HackerNews"; +} +elsif header :contains "from" "user@rss2email.invalid" { + fileinto "RSS"; +} + +if header :contains "list-id" "lobsters-izs7WbyfQp@lobste.rs" { + fileinto "Lists.lobsters"; +} + +if header :contains "from" "nixos1@discoursemail.com" { + fileinto "Lists.nix"; +} + +if header :contains "list-id" "vger.kernel.org" { + fileinto "Lists.lkml"; +} + +if header :contains "list-id" "emacs-devel.gnu.org" { + fileinto "Lists.emacs"; +} + +if header :contains "list-id" "guix-devel.gnu.org" { + fileinto "Lists.guix"; +} + +if header :contains "to" "cryptography@metzdowd.com" { + fileinto "Lists"; +} + +if header :contains "user-agent" "rss2email" { + fileinto "RSS"; +} + +if allof (header :contains "from" "post@tinyportal.net") { + discard; +} + +if allof (header :contains "from" "yahoo.com.hk") { + discard; +} + +# rule:[servers] +if allof (header :contains "from" "noreply@outbound.getsentry.com") { + fileinto "Alerts"; +} + +# rule:[Haskell Streaming] +if header :contains "list-id" + [ "streaming-haskell.googlegroups.com" + , "cabal-devel.haskell.org" + , "commercialhaskell.googlegroups.com" + , "ghc-devs.haskell.org" + , "haskell-cafe.haskell.org" + , "haskell.haskell.org" + , "libraries.haskell.org" + , "haskell-pipes.googlegroups.com" + , "shake-build-system.googlegroups.com" + ] +{ + fileinto "Lists.haskell"; +} + + + +# rule:[Alerts] +if allof (header :contains "from" "builds@circleci.com") { + fileinto "Alerts"; +} + +# rule:[bitcoin-dev] +if allof (header :contains "list-id" "bitcoin-dev.lists.linuxfoundation.org") { + fileinto "Lists.bitcoin"; +} + +# rule:[Monstercat] +if allof (header :contains "to" "bill@monstercat.com") { + fileinto "Monstercat"; +} + +# rule:[Updates] +if header :contains "from" [ "no-reply@twitch.tv" + , "notify@twitter.com" + , "info@meetup.com" + , "no-reply@mail.goodreads.com" + ] +{ + fileinto "Updates"; +} + +# rule:[WebVR] +if allof (header :contains "list-id" "web-vr-discuss.mozilla.org") { + fileinto "Lists.webvr"; +} + +# rule:[ICN] +if allof (header :contains "list-id" "ccnx.www.ccnx.org") { + fileinto "Lists.icn"; +} + +# rule:[ICN] +if allof (header :contains "list-id" "icnrg.irtf.org") { + fileinto "Lists.icn"; +} + +# rule:[ICN] +if allof (header :contains "list-id" "ccnx.ccnx.org") { + fileinto "Lists.icn"; +} + +# Elm +if header :contains "list-id" [ "elm-discuss", "elm-dev" ] { + fileinto "Lists.elm"; +} + +# GitHub +if header :contains "list-id" + [ "nix.NixOS.github.com" + , "hydra.NixOS.github.com" + , "nix-dev.lists.science.uu.nl" + , "nix-devel.googlegroups.com" + ] +{ + fileinto "Lists.nix"; +} +elsif header :contains "list-id" "spacemacs.syl20bnr.github.com" { + fileinto "Lists.spacemacs"; +} +elsif header :contains "list-id" "streaming.michaelt.github.com" { + fileinto "Lists.haskell"; +} +elsif header :contains "list-id" "nixpkgs.NixOS.github.com" { + fileinto "Lists.nixpkgs"; +} +elsif header :contains "from" "notifications@github.com" { + # file into github if it doesn't match any other github lists + fileinto "GitHub"; +} + +# rule:[Updates] +if header :contains "from" "gab.ai" { + fileinto "Updates"; +} + +if header :contains "to" "mention@noreply.github.com" { + addflag "\\Flagged"; +} + +if header :contains "list-id" "ndn-interest.lists.cs.ucla.edu" { + fileinto "Lists.icn"; +} + +# rule:[ats] +if allof (header :contains "list-id" "ats-lang-users.googlegroups.com") { + fileinto "Lists.ats"; +} + +# rule:[shen] +if allof (header :contains "list-id" "qilang.googlegroups.com") { + fileinto "Lists.shen"; +} + + +# rule:[Craigslist] +if allof (header :contains "from" "reply.craigslist.org") { + fileinto "Lists.craigslist"; +} + + +# rule:[Alerts] +if allof (header :contains "from" "noreply@md.getsentry.com") { + fileinto "Alerts"; +} + diff --git a/nix-config/machines/charon/hardware/default.nix b/nix-config/machines/charon/hardware/default.nix @@ -0,0 +1,24 @@ +{ config, lib, pkgs, ... }: +{ + imports = + [ <nixpkgs/nixos/modules/profiles/qemu-guest.nix> + ]; + boot.kernelParams = [ "console=ttyS0" ]; + boot.initrd.availableKernelModules = [ "virtio_net" "virtio_pci" "virtio_blk" "virtio_scsi" "9p" "9pnet_virtio" "ata_piix" "virtio_pci" ]; + boot.loader.grub.extraConfig = "serial; terminal_input serial; terminal_output serial"; + boot.loader.grub.device = "/dev/sda"; + + fileSystems."/" = + { device = "/dev/disk/by-uuid/98b261fa-4f9e-4e42-895b-91c17cf145b3"; + fsType = "ext4"; + }; + + fileSystems."/boot" = + { device = "/dev/disk/by-uuid/b3c7ddd8-fa2f-41ea-b77f-b9a1f434b668"; + fsType = "ext4"; + }; + + swapDevices = + [ { device = "/dev/disk/by-uuid/eb7f5cd4-6586-47f4-b4cd-c118e3521f17"; } + ]; +} diff --git a/nix-config/machines/charon/networking/default.nix b/nix-config/machines/charon/networking/default.nix @@ -0,0 +1,22 @@ +{ config, lib, pkgs, ... }: +let + openTCP = dev: port: '' + ip46tables -A nixos-fw -i ${dev} -p tcp --dport ${toString port} -j nixos-fw-accept + ''; +in +{ + networking.firewall.allowedTCPPorts = [ 22 443 80 70 12566 12788 5222 5269 ]; + networking.firewall.trustedInterfaces = ["zt0"]; + networking.domain = "jb55.com"; + networking.search = [ "jb55.com" ]; + networking.extraHosts = '' + 127.0.0.1 jb55.com + ::1 jb55.com + ''; + + networking.firewall.extraCommands = '' + ${openTCP "zt0" 993} + ${openTCP "zt0" 143} + ${openTCP "zt0" 587} + ''; +} diff --git a/nix-config/machines/charon/nginx/default.nix b/nix-config/machines/charon/nginx/default.nix @@ -0,0 +1,75 @@ +extra: +{ config, lib, pkgs, ... }: +let sites = [./sites/jb55.com + ./sites/npmrepo.com + ./sites/wineparty.xyz + ./sites/hearpress.com + ]; + logDir = "/var/log/nginx"; +in { + services.logrotate.config = '' + ${logDir}/*.log { + daily + missingok + rotate 52 + compress + delaycompress + notifempty + # 20MB + minsize 20971520 + create 640 root adm + sharedscripts + postrotate + ${pkgs.procps}/bin/pkill -USR1 nginx + endscript + } + ''; + + services.nginx = { + enable = true; + + config = '' + worker_processes 2; + + events { + worker_connections 768; + # multi_accept on; + } + ''; + + httpConfig = '' + port_in_redirect off; + ssl_protocols TLSv1 TLSv1.1 TLSv1.2; + ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:ECDHE-RSA-DES-CBC3-SHA:ECDHE-ECDSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA'; + ssl_prefer_server_ciphers on; + + # HSTS (ngx_http_headers_module is required) (15768000 seconds = 6 months) + add_header Strict-Transport-Security max-age=15768000; + + sendfile on; + tcp_nopush on; + tcp_nodelay on; + keepalive_timeout 65; + types_hash_max_size 2048; + # server_tokens off; + proxy_buffering off; + proxy_read_timeout 300s; + expires off; + default_type application/octet-stream; + + access_log ${logDir}/access.log; + error_log ${logDir}/error.log; + + gzip on; + gzip_disable "msie6"; + + server { + listen 80 default_server; + server_name ""; + return 444; + } + + ${lib.concatStringsSep "\n\n" (map builtins.readFile sites)} + ''; + }; +} diff --git a/nix-config/machines/charon/nginx/pokemap.nix b/nix-config/machines/charon/nginx/pokemap.nix @@ -0,0 +1,28 @@ +subdomain: port: '' + server { + listen 80; + server_name ${subdomain}.jb55.com; + root /www/jb55/public/maps; + + location /.well-known { + try_files $uri $uri/ =404; + } + + location / { + return 301 https://${subdomain}.jb55.com$request_uri; + } + } + + server { + listen 443; + server_name ${subdomain}.jb55.com; + + ssl_certificate /etc/letsencrypt/live/${subdomain}.jb55.com/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/${subdomain}.jb55.com/privkey.pem; + + location / { + proxy_pass http://localhost:${port}; + } + } + +'' diff --git a/nix-config/machines/charon/nginx/sites/coretto.io b/nix-config/machines/charon/nginx/sites/coretto.io diff --git a/nix-config/machines/charon/nginx/sites/hearpress.com b/nix-config/machines/charon/nginx/sites/hearpress.com @@ -0,0 +1,43 @@ +server { + listen 443 ssl; + server_name hearpress.com; + root /www/hearpress.com/public; + index index.html index.htm; + + ssl_certificate /var/lib/acme/hearpress.com/fullchain.pem; + ssl_certificate_key /var/lib/acme/hearpress.com/key.pem; + + location @hearpress { + proxy_pass http://localhost:3000$request_uri; + } + + location / { + try_files $uri $uri/ @hearpress; + error_page 405 @hearpress; + } + + location /blobs { + resolver 8.8.8.8; + proxy_pass https://hearpress.s3.amazonaws.com$request_uri; + } +} + +server { + listen 80; + server_name hearpress.com www.hearpress.com; + + location /.well-known/acme-challenge { + root /var/www/challenges; + } + + location / { + return 301 https://hearpress.com$request_uri; + } + +} + +server { + listen 443 ssl; + server_name www.hearpress.com; + return 301 https://hearpress.com$request_uri; +} diff --git a/nix-config/machines/charon/nginx/sites/jb55.com b/nix-config/machines/charon/nginx/sites/jb55.com diff --git a/nix-config/machines/charon/nginx/sites/npmrepo.com b/nix-config/machines/charon/nginx/sites/npmrepo.com @@ -0,0 +1,14 @@ +server { + listen 80; + server_name npmrepo.com www.npmrepo.com; + + location / { + proxy_pass http://localhost:9676; + proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504; + proxy_redirect off; + proxy_buffering off; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + } +} diff --git a/nix-config/machines/charon/nginx/sites/wineparty.xyz b/nix-config/machines/charon/nginx/sites/wineparty.xyz @@ -0,0 +1,33 @@ + +server { + listen 80; + server_name www.wineparty.xyz; + root /www/wineparty.xyz/public; + index index.html index.htm; + + location / { + try_files $uri $uri/ =404; + } +} + +server { + listen 80; + server_name wineparty.xyz; + return 301 http://www.wineparty.xyz$request_uri; +} + +server { + listen 80; + server_name pg-zero.wineparty.xyz; + location / { + proxy_pass http://localhost:3000; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + } +} + +server { + listen 443 ssl; + server_name wineparty.xyz www.wineparty.xyz; + return 301 http://www.wineparty.xyz$request_uri; +} diff --git a/nix-config/machines/charon/sheetzen/default.nix b/nix-config/machines/charon/sheetzen/default.nix @@ -0,0 +1,79 @@ +extra: +{ config, lib, pkgs, ... }: +let port = "1080"; + sname = "sheetzen.com"; + sheetzen = (import (pkgs.fetchzip { + url = "https://jb55.com/s/2d3e137102241acb.tgz"; + sha256 = "00rha983ym6p0bsiz0wsxv750ppgcalvpas6wx790jp9awn5zxlb"; + }) {}); +in +{ + services.nginx.httpConfig = lib.mkIf config.services.nginx.enable '' + server { + listen 80; + server_name ${sname} www.${sname}; + + location /.well-known/acme-challenge { + root /var/www/challenges; + } + + location / { + return 301 https://${sname}$request_uri; + } + } + + server { + listen 443 ssl; + server_name ${sname}; + root ${sheetzen}/share/sheetzen/frontend; + index index.html; + + ssl_certificate /var/lib/acme/${sname}/fullchain.pem; + ssl_certificate_key /var/lib/acme/${sname}/key.pem; + + location = / { + try_files index.html /index.html; + } + + location / { + try_files $uri $uri/ @proxy; + } + + location @proxy { + proxy_pass http://localhost:${port}; + proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504; + proxy_redirect off; + proxy_buffering off; + proxy_intercept_errors on; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + } + + } + ''; + + systemd.services.sheetzen = { + enable = true; + + description = "sheetzen"; + + wantedBy = [ "multi-user.target" ]; + after = [ "postgresql.target" ]; + + environment = { + PGHOST = "127.0.0.1"; + PGPORT = "5432"; + PGUSER = "jb55"; + PGPASS = ""; + PGDATABASE = "sheetzen"; + ENV = "Production"; + JWT_KEYFILE = "${sheetzen}/share/sheetzen/credentials/token-key.json"; + CREDENTIAL_PATH = "${sheetzen}/share/sheetzen/credentials/SocialTracker.json"; + PORT = "${port}"; + }; + + serviceConfig.ExecStart = "${sheetzen}/bin/sheetzend"; + unitConfig.OnFailure = "systemd-failure-emailer@%n.service"; + }; +} diff --git a/nix-config/machines/charon/vidstats/default.nix b/nix-config/machines/charon/vidstats/default.nix @@ -0,0 +1,40 @@ +extra: +{ config, lib, pkgs, ... }: +let cfg = extra.private.vidstats; + videostats = (import (pkgs.fetchgit { + url = "http://git.zero.jb55.com/edm-video-stats"; + rev = "4514bd35d111257f71235fcb121cfbbc6c11eb15"; + sha256 = "0sd26vvffk12a3ax98qlcd0kw7lgnszx9lxyqfya913qkgcyrzmb"; + }) {}).package; + client_secret = pkgs.fetchurl { + name = "client_secret.json"; + url = "http://git.zero.jb55.com/repos/?p=edm-video-stats;a=blob_plain;f=client_secret.json"; + sha256 = "0i1kwq8zy1s1w7db3yh6687hyh44m5g5xrlxc425nfnl6hzl9187"; + }; +in +{ + systemd.services.vidstats = { + enable = true; + + description = "vidstats bot"; + + wantedBy = [ "multi-user.target" ]; + after = [ "network-online.target" ]; + + environment = { + GOOGLE_SHEET_ID = cfg.sheet_id; + GOOGLE_API_KEY = cfg.api_key; + VIDEOSTATS_RANGE = cfg.range; + TOKEN_DIR = "/home/jb55/.config/edm/videostats/credentials"; + VIDEOSTATS_STATS_RANGE = cfg.stats_range; + CLIENT_SECRET = "${client_secret}"; + }; + + serviceConfig.Type = "oneshot"; + serviceConfig.ExecStart = "${videostats}/bin/video-stats"; + + unitConfig.OnFailure = "systemd-failure-emailer@%n.service"; + + startAt = "*-*-* 05:24:00"; + }; +} diff --git a/nix-config/machines/monad/bitcoin/dca.nix b/nix-config/machines/monad/bitcoin/dca.nix @@ -0,0 +1,36 @@ +{ pkgs, to, bcli, addr }: + +pkgs.writeScript "dca" +'' +#!${pkgs.bash}/bin/bash + +set -e + +keybasesock=/run/user/1000/keybase/keybased.sock +wallet=''${BTCDCA_WALLET:-cc} +user=''${BTCDCA_RPCUSER:-rpcuser} +pass=''${BTCDCA_RPCPASS:-rpcpass} +amount=''${BTCDCA_AMOUNT:-$(cat /home/jb55/var/dca-amount)} +pair=''${BTCDCA_PAIR:-XXBTZCAD} +keybaseto=''${BTCDCA_KEYBASETO:-${to}} + +price=$(${pkgs.curl}/bin/curl -sL "https://api.kraken.com/0/public/Ticker?pair=$pair" | ${pkgs.jq}/bin/jq -r ".result.$pair.a[0]") +invid=$(dd if=/dev/urandom bs=1 count=4 | ${pkgs.xxd}/bin/xxd -p | ${pkgs.libbitcoin-explorer}/bin/bx base58-encode) + +address=${addr} + +satsdec=$(${pkgs.bcalc}/bin/bcalc -n --price $price $amount fiat to sats) +sats=''${satsdec%.*} +btc=$(${pkgs.bcalc}/bin/bcalc -n $sats sats to btc) + +msg=$(printf "Please send %s BTC to %s for \$%s @ \$%s\ne-transfer password is %s\nplease ACK to confirm. e-transfer will be sent when ACKed.\n" \ + "$btc" "$address" "$amount" "$price" "$invid") + +if [ ! -e $keybasesock ]; then + ${pkgs.systemd}/bin/systemctl --user restart keybase +fi + +for user in $keybaseto; do + ${pkgs.keybase}/bin/keybase chat send "$user" "$msg" +done +'' diff --git a/nix-config/machines/monad/bitcoin/default.nix b/nix-config/machines/monad/bitcoin/default.nix @@ -0,0 +1,74 @@ +extra: +{ config, lib, pkgs, ... }: + +let + bitcoinDataDir = "/zbig/bitcoin"; + + base-bitcoin-conf = extra.private.bitcoin; + + bcli = "${pkgs.bitcoind}/bin/bitcoin-cli --datadir=${bitcoinDataDir} --conf=${base-bitcoin-conf-file} --rpcuser=${extra.private.btc-user} --rpcpassword=${extra.private.btc-pass}"; + + bitcoin-conf = '' + ${base-bitcoin-conf} + walletnotify=${walletemail} %s %w + ''; + + base-bitcoin-conf-file = pkgs.writeText "bitcoin-base.conf" base-bitcoin-conf; + bitcoin-conf-file = pkgs.writeText "bitcoin.conf" bitcoin-conf; + + dca = import ./dca.nix { + inherit pkgs bcli; + to = "jb55 ${extra.private.btc-supplier}"; + addr = extra.private.btc-supplier-addr; + }; + walletemail = import ./walletemail.nix { inherit pkgs bcli; }; +in +{ + #systemd.user.services.bitcoin-dca = { + # enable = true; + # description = "bitcoin dca"; + + # serviceConfig = { + # Type = "oneshot"; + # ExecStart = dca; + # }; + + # startAt = "Thu *-*-* 10:00:00"; + #}; + + services.bitcoind = { + mainnet = { + enable = if extra.is-minimal then false else true; + dataDir = bitcoinDataDir; + configFile = bitcoin-conf-file; + user = "jb55"; + group = "users"; + }; + }; + + services.clightning.networks = { + mainnet = { + dataDir = "/home/jb55/.lightning-bitcoin"; + + config = '' + bitcoin-rpcuser=rpcuser + bitcoin-rpcpassword=rpcpass + bitcoin-rpcconnect=127.0.0.1 + bitcoin-rpcport=8332 + fee-per-satoshi=900 + bind-addr=0.0.0.0:9735 + announce-addr=24.84.152.187:9735 + network=bitcoin + log-level=debug + alias=bitsbacker.com + rgb=ff0000 + ''; + }; + }; + + # services.electrs.enable = false; + # services.electrs.dataDir = "/zbig/electrs"; + # services.electrs.bitcoinDataDir = bitcoinDataDir; + + +} diff --git a/nix-config/machines/monad/bitcoin/walletemail.nix b/nix-config/machines/monad/bitcoin/walletemail.nix @@ -0,0 +1,57 @@ +{ pkgs, bcli }: + +pkgs.writeScript "walletemail" '' +#!${pkgs.bash}/bin/bash + +set -e + +txid="$1" +wallet="$2" + +from="Bitcoin Wallet <bitcoind@monad>" +to="William Casarin <jb55@jb55.com>" +subject="Wallet notification" +keys="-r 0x8860420C3C135662EABEADF96342E010C44A6337 -r 0x5B2B1E4F62216BC74362AC61D4FBA2FC4535A2A9 -r 0xE02D3FD4EB4585A63531C1D0E1BFCB90A1FF7A1C" + +tx="$(${bcli} -rpcwallet=$wallet gettransaction "$txid" true)" +address="$(${pkgs.jq}/bin/jq -r '.details[0].address' <<<"$tx")" +details="$(${pkgs.jq}/bin/jq -r '.details[] | [.address, .category, .amount, .label] | @csv' <<<"$tx")" +keypath="$(${bcli} -rpcwallet=$wallet getaddressinfo "$address" | ${pkgs.jq}/bin/jq -r .hdkeypath)" + +amount="$(${pkgs.jq}/bin/jq -r '.amount' <<<"$tx")" +confs="$(${pkgs.jq}/bin/jq -r '.confirmations' <<<"$tx")" + +time="$(date -d @$(${pkgs.jq}/bin/jq -r '.time' <<<"$tx"))" +received="$(date -d @$(${pkgs.jq}/bin/jq -r '.timereceived' <<<"$tx"))" + +export GNUPGHOME=/zbig/bitcoin/gpg + +msg="$(printf "txid: %s\n\naddress: %s\n\namount: %s\n\nconfirmations: %d\n\nwallet: %s\n\ntime: %s\n\nreceived: %s\n\nkeypath: %s\n\n%s\n\n\n%s" \ + "$txid" "$address" "$amount" "$confs" "$wallet" "$time" "$received" "$keypath" "$details" "$tx" )" + +enctx="$(printf "Content-Type: text/plain\n\n%s\n" "$msg" | ${pkgs.gnupg}/bin/gpg --yes --always-trust --encrypt --armor $keys)" + +{ +cat <<EOF +From: $from +To: $to +Subject: $subject +MIME-Version: 1.0 +Content-Type: multipart/encrypted; boundary="=-=-="; + protocol="application/pgp-encrypted" + +--=-=-= +Content-Type: application/pgp-encrypted + +Version: 1 + +--=-=-= +Content-Type: application/octet-stream + +$enctx +--=-=-=-- +EOF +} | /run/current-system/sw/bin/sendmail --file /zbig/bitcoin/gpg/.msmtprc -oi -t + +printf "sent walletnotify email for %s\n" "$txid" +'' diff --git a/nix-config/machines/monad/config/default.nix b/nix-config/machines/monad/config/default.nix @@ -0,0 +1,12 @@ +pkgs: rec { + hostId = "d7ee0243"; # needed for zfs + ztip = "172.24.172.111"; + nix-serve = { + port = 10845; + bindAddress = ztip; + }; + sessionCommands = '' + ${pkgs.xorg.xrandr}/bin/xrandr -r 144 + ${pkgs.xorg.xgamma}/bin/xgamma -gamma 0.8 + ''; +} diff --git a/nix-config/machines/monad/contracts/commit/default.nix b/nix-config/machines/monad/contracts/commit/default.nix @@ -0,0 +1,20 @@ +{ config, lib, pkgs, ... }: +{ + # services.kubernetes = { + # apiserver.enable = true; + # controllerManager.enable = true; + # scheduler.enable = true; + # addonManager.enable = true; + # proxy.enable = true; + # flannel.enable = true; + # masterAddress = "127.0.0.1"; + # }; + + #services.kubernetes.masterAddress = "127.0.0.1"; + #services.kubernetes.roles = [ "master" "node" ]; + + # services.openvpn.servers.commit = { + # autoStart = true; + # config = builtins.readFile ./commit.ovpn; + # }; +} diff --git a/nix-config/machines/monad/contracts/plastiq/default.nix b/nix-config/machines/monad/contracts/plastiq/default.nix @@ -0,0 +1,12 @@ +{ config, lib, pkgs, ... }: +let + user-file = pkgs.writeText "plastiq-user" '' + will.casarin + ''; +in +{ + services.openvpn.servers.plastiq = { + autoStart = false; + config = import ./plastiq.ovpn.nix user-file; + }; +} diff --git a/nix-config/machines/monad/default.nix b/nix-config/machines/monad/default.nix @@ -0,0 +1,320 @@ +extra: +{ config, lib, pkgs, ... }: +let util = extra.util; + nix-serve = extra.machine.nix-serve; + zenstates = pkgs.fetchFromGitHub { + owner = "r4m0n"; + repo = "ZenStates-Linux"; + rev = "0bc27f4740e382f2a2896dc1dabfec1d0ac96818"; + sha256 = "1h1h2n50d2cwcyw3zp4lamfvrdjy1gjghffvl3qrp6arfsfa615y"; + }; + email-notify = util.writeBash "email-notify-user" '' + export HOME=/home/jb55 + export PATH=${lib.makeBinPath (with pkgs; [ eject libnotify muchsync notmuch openssh ])}:$PATH + ( + flock -x -w 100 200 || exit 1 + + muchsync charon + + #DISPLAY=:0 notify-send --category=email "you got mail" + + ) 200>/tmp/email-notify.lock + ''; + +in +{ + imports = [ + ./hardware + # ./contracts/commit + # ./contracts/plastiq + + #(import ../../misc/dnsmasq-adblock.nix) + (import ../../misc/msmtp extra) + (import ./networking extra) + (import ../../misc/imap-notifier extra) + ] ++ (if !extra.is-minimal then [ (import ./bitcoin extra) ] else []); + + hardware.steam-hardware.enable = true; + + services.prometheus.enable = false; + # services.prometheus.dataDir = "/zbig/data/prometheus"; + services.grafana.enable = false; + services.grafana.port = 3005; + services.grafana.provision.datasources = [ + { name = "bitcoin"; + type = "prometheus"; + access = "direct"; + isDefault = true; + } + ]; + + # services.guix.enable = true; + services.synergy.server.enable = if extra.is-minimal then false else true; + services.synergy.server.autoStart = true; + services.synergy.server.screenName = "desktop"; + services.synergy.server.configFile = pkgs.writeText "synergy-cfg" '' + section: screens + desktop: + mac: + end + section: aliases + desktop: + 192.168.86.26 + mac: + 192.168.86.232 + end + section: links + desktop: + left = mac + mac: + right = desktop + end + section: options + keystroke(alt+control+h) = switchInDirection(left) + keystroke(alt+control+l) = switchInDirection(right) + end + ''; + + services.bitlbee.enable = if extra.is-minimal then false else true; + services.bitlbee.libpurple_plugins = with pkgs; [ + pidgin-skypeweb + purple-facebook + purple-hangouts + telegram-purple + purple-matrix + ]; + + # services.thelounge.enable = true; + # services.thelounge.theme = "thelounge-theme-mininapse"; + # services.thelounge.port = 9002; + + services.dnscrypt-proxy2.enable = false; + services.dnscrypt-proxy2.settings = { + + listen_addresses = [ "127.0.0.1:43" ]; + server_names = ["cs-ca2" "ev-to"]; + fallback_resolver = "1.1.1.1:53"; + sources = { + public-resolvers = { + urls = ["https://raw.githubusercontent.com/DNSCrypt/dnscrypt-resolvers/master/v2/public-resolvers.md" + "https://download.dnscrypt.info/resolvers-list/v2/public-resolvers.md" + ]; + cache_file = "public-resolvers.md"; + minisign_key = "RWQf6LRCGA9i53mlYecO4IzT51TGPpvWucNSCh1CBM0QTaLn73Y7GFO3"; + refresh_delay = 71; + }; + + relays = { + urls = ["https://raw.githubusercontent.com/DNSCrypt/dnscrypt-resolvers/master/v2/relays.md"]; + cache_file = "relays.md"; + minisign_key = "RWQf6LRCGA9i53mlYecO4IzT51TGPpvWucNSCh1CBM0QTaLn73Y7GFO3"; + refresh_delay = 71; + }; + }; + anonymized_dns.routes = [ + { server_name="cs-ca2"; via=["anon-ev-va"]; } + { server_name="ev-to"; via=["anon-cs-ca2"]; } + ]; + }; + + services.dnsmasq.enable = true; + services.dnsmasq.resolveLocalQueries = true; + #services.dnsmasq.servers = ["127.0.0.1#43"]; + # services.dnsmasq.servers = ["127.0.0.1#43" "1.1.1.1" "8.8.8.8"]; + services.dnsmasq.servers = ["1.1.1.1" "8.8.8.8"]; + services.dnsmasq.extraConfig = '' + cache-size=10000 + addn-hosts=/var/hosts + conf-file=/var/dnsmasq-hosts + conf-file=/var/distracting-hosts + ''; + + + services.bitlbee.plugins = with pkgs; [ + bitlbee-discord + bitlbee-mastodon + ]; + + # shitcoin vendor + services.keybase.enable = false; + + systemd.services.block-distracting-hosts = { + description = "Block Distracting Hosts"; + + path = with pkgs; [ systemd procps ]; + + serviceConfig.ExecStart = util.writeBash "block-distracting-hosts" '' + set -e + cp /var/undistracting-hosts /var/distracting-hosts + + # crude way to clear the cache... + systemctl restart dnsmasq + pkill qutebrowser + ''; + + startAt = "Mon..Fri *-*-* 09:00:00"; + }; + + systemd.user.services.stop-spotify-bedtime = { + enable = if extra.is-minimal then false else true; + description = "Stop spotify when Elliott goes to bed"; + wantedBy = [ "graphical-session.target" ]; + after = [ "graphical-session.target" ]; + serviceConfig.ExecStart = "${pkgs.dbus}/bin/dbus-send --print-reply --dest=org.mpris.MediaPlayer2.spotify /org/mpris/MediaPlayer2 org.mpris.MediaPlayer2.Player.Stop"; + + startAt = "*-*-* 19:30:00"; + }; + + systemd.services.unblock-distracting-hosts = { + enable = if extra.is-minimal then false else true; + + description = "Unblock Distracting Hosts"; + + path = with pkgs; [ systemd ]; + + serviceConfig.ExecStart = util.writeBash "unblock-distracting-hosts" '' + set -e + echo "" > /var/distracting-hosts + systemctl restart dnsmasq + ''; + + startAt = "Mon..Fri *-*-* 17:00:00"; + }; + + virtualisation.docker.enable = if extra.is-minimal then false else true; + virtualisation.virtualbox.host.enable = false;#if extra.is-minimal then false else true; + virtualisation.virtualbox.host.enableHardening = false; + #virtualization.virtualbox.host.enableExtensionPack = true; + users.extraUsers.jb55.extraGroups = [ "vboxusers" "bitcoin" ]; + + services.xserver.videoDrivers = [ ]; + + users.extraGroups.tor.members = [ "jb55" "nginx" ]; + users.extraGroups.bitcoin.members = [ "jb55" ]; + users.extraGroups.nginx.members = [ "jb55" ]; + users.extraGroups.transmission.members = [ "nginx" "jb55" ]; + + programs.mosh.enable = false; + programs.adb.enable = true; + + documentation.nixos.enable = false; + + # services.trezord.enable = if extra.is-minimal then false else true; + services.redis.enable = if extra.is-minimal then false else true; + + services.zeronet.enable = false; + #services.zeronet.trackers = '' + # http://tracker.nyap2p.com:8080/announce + # http://tracker3.itzmx.com:6961/announce + # http://tracker1.itzmx.com:8080/announce + # https://trakx.herokuapp.com:443/announce + # udp://ultra.zt.ua:6969/announce + #''; + + services.mongodb.enable = if extra.is-minimal then false else false; + + services.tor.enable = if extra.is-minimal then false else true; + #services.tor.controlPort = 9051; + services.tor.client.enable = true; + services.tor.extraConfig = extra.private.tor.extraConfig; + + services.fcgiwrap.enable = if extra.is-minimal then false else true; + + services.nix-serve.enable = false; + services.nix-serve.bindAddress = nix-serve.bindAddress; + services.nix-serve.port = nix-serve.port; + + services.nginx.enable = if extra.is-minimal then false else true; + services.nginx.httpConfig = '' + server { + listen 80 default_server; + server_name _; + root /www/public; + index index.html index.htm; + location / { + try_files $uri $uri/ =404; + } + } + + '' + (if config.services.nix-serve.enable then '' + server { + listen ${nix-serve.bindAddress}:80; + server_name cache.monad.jb55.com; + + location / { + proxy_pass http://${nix-serve.bindAddress}:${toString nix-serve.port}; + proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504; + proxy_redirect off; + proxy_buffering off; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + } + } + '' else "") + (if config.services.tor.enable then extra.private.tor.nginx else ""); + + # services.footswitch = { + # enable = false; + # enable-led = true; + # led = "input5::numlock"; + # }; + + systemd.services.disable-c6 = { + description = "Ryzen Disable C6 State"; + + wantedBy = [ "basic.target" ]; + after = [ "sysinit.target" "local-fs.target" ]; + + serviceConfig.Type = "oneshot"; + serviceConfig.ExecStart = util.writeBash "disable-c6-state" '' + ${pkgs.kmod}/bin/modprobe msr + ${pkgs.python2}/bin/python ${zenstates}/zenstates.py --c6-disable --list + ''; + }; + + services.mysql.enable = false; + services.mysql.package = pkgs.mariadb; + + # services.postgresql = { + # dataDir = "/var/db/postgresql/100/"; + # enable = true; + # package = pkgs.postgresql_10; + # # extraPlugins = with pkgs; [ pgmp ]; + # authentication = pkgs.lib.mkForce '' + # # type db user address method + # local all all trust + # host all all 127.0.0.1/32 trust + # host all all 192.168.86.0/24 trust + # ''; + # extraConfig = '' + # listen_addresses = '0.0.0.0' + # ''; + # }; + + # services.postgresql = { + # dataDir = "/var/db/postgresql/96/"; + # enable = true; + # package = pkgs.postgresql96; + # # extraPlugins = with pkgs; [ pgmp ]; + # authentication = pkgs.lib.mkForce '' + # # type db user address method + # local all all trust + # host all all 127.0.0.1/32 trust + # host all all 192.168.86.0/24 trust + # ''; + # extraConfig = '' + # listen_addresses = '0.0.0.0' + # ''; + # }; + + # security.pam.u2f = { + # enable = true; + # interactive = true; + # cue = true; + # control = "sufficient"; + # authfile = "${pkgs.writeText "pam-u2f-config" '' + # jb55:vMXUgYb1ytYmOVgqFDwVOxJmvVI9F3gdSJVbvsi1A1VA-3mftTUhgARo4Kmm_8SAH6IJJ8p3LSXPSbtTSXMIpQ,04d8c1542a7391ee83112a577db968b84351f0090a9abe7c75bedcd94777cf15727c68ce4ac8858ff2812ded3c86d978efc5893b25cf906032632019fe792d3ec4 + # ''}"; + # }; + +} diff --git a/nix-config/machines/monad/hardware/default.nix b/nix-config/machines/monad/hardware/default.nix @@ -0,0 +1,64 @@ +{ config, lib, pkgs, ... }: +{ + # fileSystems."/" = + # { device = "/dev/disk/by-uuid/62518649-0872-49e2-a269-34975e314c6a"; + # fsType = "ext4"; + # }; + + # fileSystems."/" = + # { device = "/dev/nvme0n1p1"; + # fsType = "zfs"; + #nixos-generate-config --root /mnt }; + + boot.initrd.availableKernelModules = [ "xhci_pci" "ahci" "nvme" "usbhid" "sd_mod" ]; + boot.kernelParams = [ "amdgpu.gpu_recovery=1" ]; + boot.kernelModules = [ "kvm-amd" ]; + boot.loader.grub.copyKernels = true; + boot.extraModulePackages = [ ]; + + fileSystems."/" = + { device = "znix/root/nixos"; + fsType = "zfs"; + }; + + fileSystems."/home" = + { device = "znix/home"; + fsType = "zfs"; + }; + + fileSystems."/zbig" = + { device = "zbig"; + fsType = "zfs"; + }; + + #fileSystems."/vr" = + # { device = "/dev/disk/by-uuid/E234A89834A87169"; + # fsType = "ntfs"; + # }; + + #fileSystems."/sand" = + # { device = "/dev/disk/by-uuid/2ee709b8-7e83-470f-91bc-d0b0ba59b945"; + # fsType = "ext4"; + # }; + + # fileSystems."/home/jb55/shares/will-vm/projects" = + # { device = "//192.168.86.199/Users/jb55/projects"; + # fsType = "cifs"; + # options = ["username=jb55" "password=notsecurepw" "gid=100" "uid=1000"]; + # }; + + #fileSystems."/home/jb55/.local/share/Steam/steamapps" = + # { device = "/sand/data/SteamAppsLinux"; + # fsType = "none"; + # options = ["bind"]; + # }; + + # swapDevices = + # [ { device = "/dev/disk/by-uuid/d4e4ae51-9179-439d-925b-8df42dd1bfc5"; } + # ]; + + hardware.enableAllFirmware = true; + + boot.loader.grub.devices = [ "/dev/nvme0n1" ]; + boot.supportedFilesystems = ["zfs"]; +} diff --git a/nix-config/machines/monad/networking/default.nix b/nix-config/machines/monad/networking/default.nix @@ -0,0 +1,175 @@ +extra: +{ config, lib, pkgs, ... }: +let + chromecastIP = "192.168.86.190"; + iptables = "iptables -A nixos-fw"; + ipr = "${pkgs.iproute}/bin/ip"; + writeBash = extra.util.writeBash; + transmission-dir = "/zbig/torrents"; + download-dir = "${transmission-dir}/Downloads"; + openCloseTCP = op: dev: port: '' + ip46tables -${op} nixos-fw -i ${dev} -p tcp --dport ${toString port} -j nixos-fw-accept ${if op == "D" then "|| true" else ""} + ''; + openTCP = dev: port: openCloseTCP "A" dev port; + closeTCP = dev: port: openCloseTCP "D" dev port; + + ports = { + synergy = 24800; + lightning = 9735; + lightningt = 9736; + dns = 53; + wireguard = 51820; + }; +in +{ + networking.hostId = extra.machine.hostId; + + #networking.firewall.trustedInterfaces = ["wg0"]; + networking.firewall.allowedTCPPorts = with ports; [ lightning lightningt synergy ]; + networking.firewall.allowedUDPPorts = [ ports.dns ports.wireguard ]; + + networking.nat.enable = true; + networking.nat.externalInterface = "eth0"; + networking.nat.internalInterfaces = [ "wg0" ]; + + networking.wireguard.interfaces = { + # "wg0" is the network interface name. You can name the interface arbitrarily. + wg0 = { + # Determines the IP address and subnet of the server's end of the tunnel interface. + ips = [ "10.100.0.1/24" ]; + + # The port that Wireguard listens to. Must be accessible by the client. + listenPort = ports.wireguard; + + postSetup = '' + ${pkgs.iptables}/bin/iptables -t nat -A POSTROUTING -s 10.100.0.0/24 -o enp30s0 -j MASQUERADE + ''; + + # This undoes the above command + postShutdown = '' + ${pkgs.iptables}/bin/iptables -t nat -D POSTROUTING -s 10.100.0.0/24 -o enp30s0 -j MASQUERADE + ''; + + + # Path to the private key file. + # + # Note: The private key can also be included inline via the privateKey option, + # but this makes the private key world-readable; thus, using privateKeyFile is + # recommended. + privateKeyFile = "/home/jb55/.wg/private"; + + peers = [ + { publicKey = "wcoun9+1GX4awQF2Yd0WbsQ6RKHE9SsOsYv3qR7mbB0="; # quiver + allowedIPs = [ "10.100.0.2/32" ]; + } + { publicKey = "vIh3IQgP92OhHaC9XBiJVDLlrs3GVcR6hlXaapjTiA0="; # phone + allowedIPs = [ "10.100.0.3/32" ]; + } + { publicKey = "Dp8Df75X8Kh9gd33e+CWyyhOvT4mT0X9ToPwBUEBU1k="; # macos + allowedIPs = [ "10.100.0.4/32" ]; + } + ]; + }; + }; + + + services.transmission = { + enable = true; + home = transmission-dir; + settings = { + incomplete-dir-enable = true; + rpc-whitelist = "127.0.0.1"; + }; + + port = 14325; + }; + + services.plex = { + enable = false; + group = "transmission"; + openFirewall = true; + }; + + services.xinetd.enable = true; + services.xinetd.services = + [ + { name = "gopher"; + port = 70; + server = "${pkgs.gophernicus}/bin/in.gophernicus"; + serverArgs = "-nf -r /var/gopher"; + extraConfig = '' + disable = no + env = PATH=${pkgs.coreutils}/bin:${pkgs.curl}/bin + passenv = PATH + ''; + } + ]; + + services.nginx.httpConfig = lib.mkIf config.services.transmission.enable '' + server { + listen 80; + listen ${extra.machine.ztip}:80; + listen 192.168.86.26; + + # server names for this server. + # any requests that come in that match any these names will use the proxy. + server_name plex.jb55.com plez.jb55.com media.home plex.home; + + # this is where everything cool happens (you probably don't need to change anything here): + location / { + # if a request to / comes in, 301 redirect to the main plex page. + # but only if it doesn't contain the X-Plex-Device-Name header + # this fixes a bug where you get permission issues when accessing the web dashboard + + if ($http_x_plex_device_name = \'\') { + rewrite ^/$ http://$http_host/web/index.html; + } + + # set some headers and proxy stuff. + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_redirect off; + + # include Host header + proxy_set_header Host $host; + + # proxy request to plex server + proxy_pass http://127.0.0.1:32400; + } + } + + server { + listen 80; + listen ${extra.machine.ztip}:80; + listen 192.168.86.26; + server_name torrents.jb55.com torrentz.jb55.com torrents.home torrent.home; + + location = /download { + return 301 " /download/"; + } + + location /download/ { + alias ${download-dir}/; + autoindex on; + } + + location / { + proxy_read_timeout 300; + proxy_pass_header X-Transmission-Session-Id; + proxy_set_header X-Forwarded-Host $host; + proxy_set_header X-Forwarded-Server $host; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_pass http://127.0.0.1:${toString config.services.transmission.port}/transmission/web/; + } + + location /rpc { + proxy_pass http://127.0.0.1:${toString config.services.transmission.port}/transmission/rpc; + } + + location /upload { + proxy_pass http://127.0.0.1:${toString config.services.transmission.port}/transmission/upload; + } + } + ''; + +} diff --git a/nix-config/machines/monad/nginx/default.nix b/nix-config/machines/monad/nginx/default.nix @@ -0,0 +1,99 @@ +extra: +{ config, lib, pkgs, ... }: +let sites = [ ]; + logDir = "/var/log/nginx"; + gitExtra = { + ztip = "172.24.172.226"; + git = { + projectroot = "/var/git"; + }; + host = "git.zero.jb55.com"; + }; + razornetExtra = { + ztip = "172.29.172.226"; + git = { + projectroot = "/var/razorgit"; + }; + host = "git.razor.jb55.com"; + }; + gitCfg = extra.git-server { inherit config pkgs; extra = extra // gitExtra; }; + razornetGit = extra.git-server { inherit config pkgs; extra = extra // razornetExtra; }; +in { + services.logrotate.config = '' + ${logDir}/*.log { + daily + missingok + rotate 52 + compress + delaycompress + notifempty + # 20MB + minsize 20971520 + create 640 root adm + sharedscripts + postrotate + ${pkgs.procps}/bin/pkill -USR1 nginx + endscript + } + ''; + + services.nginx = { + enable = true; + + package = pkgs.nginx.override { + modules = with pkgs.nginxModules; [ lua ]; + }; + + user = "jb55"; + + config = '' + worker_processes 2; + + events { + worker_connections 768; + # multi_accept on; + } + ''; + + httpConfig = '' + port_in_redirect off; + ssl_protocols TLSv1 TLSv1.1 TLSv1.2; + ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:ECDHE-RSA-DES-CBC3-SHA:ECDHE-ECDSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA'; + ssl_prefer_server_ciphers on; + + # HSTS (ngx_http_headers_module is required) (15768000 seconds = 6 months) + add_header Strict-Transport-Security max-age=15768000; + + sendfile on; + tcp_nopush on; + tcp_nodelay on; + keepalive_timeout 65; + types_hash_max_size 2048; + # server_tokens off; + proxy_buffering off; + proxy_read_timeout 300s; + expires off; + default_type application/octet-stream; + + access_log ${logDir}/access.log; + error_log ${logDir}/error.log; + + gzip on; + gzip_disable "msie6"; + + server { + listen 80 default_server; + server_name _; + root /www/public; + index index.html index.htm; + location / { + try_files $uri $uri/ =404; + } + } + + ${gitCfg} + + ${razornetGit} + ''; + }; +} diff --git a/nix-config/machines/quiver/config/default.nix b/nix-config/machines/quiver/config/default.nix @@ -0,0 +1,4 @@ + +pkgs: { + sessionCommands = ""; +} diff --git a/nix-config/machines/quiver/default.nix b/nix-config/machines/quiver/default.nix @@ -0,0 +1,187 @@ +extra: +{ config, lib, pkgs, ... }: +{ + imports = [ + ./hardware-configuration.nix + (import ../../misc/msmtp extra) + (import ./networking extra) + (import ../../misc/imap-notifier extra) + (import ./timers extra) + ]; + + environment.systemPackages = with pkgs; [ acpi xorg.xbacklight ]; + + virtualisation.docker.enable = true; + virtualisation.virtualbox.host.enable = false; + users.extraGroups.vboxusers.members = [ "jb55" ]; + + documentation.nixos.enable = false; + + boot.extraModprobeConfig = '' + options thinkpad_acpi enabled=0 + ''; + + + # telepathy is a garbage fire + services.telepathy.enable = false; + services.zerotierone.enable = false; + services.mongodb.enable = true; + services.redis.enable = true; + services.keybase.enable = true; + services.mysql.enable = true; + services.mysql.package = pkgs.mariadb; + + services.xinetd.enable = true; + services.xinetd.services = [ + { name = "gopher"; + port = 70; + server = "/var/gopher/in.gophernicus"; + serverArgs = "-nf -r /var/gopher"; + extraConfig = '' + disable = no + ''; + } + ]; + + services.xserver.libinput.enable = true; + services.xserver.config = '' + Section "InputClass" + Identifier "Enable libinput for TrackPoint" + MatchProduct "TPPS/2 Elan TrackPoint" + Driver "libinput" + Option "AccelSpeed" "1" + Option "AccelProfile" "flat" + EndSection + + Section "InputClass" + Identifier "Disable TouchPad" + MatchIsTouchpad "on" + Driver "libinput" + Option "Ignore" "true" + EndSection + ''; + + + services.plex = { + enable = false; + openFirewall = true; + }; + + services.nginx.enable = true; + services.nginx.group = "www-data"; + + services.nginx.httpConfig = '' + server { + listen 80; + + root /var/www/share; + + location / { + autoindex on; + } + } + ''; + + systemd.user.services.clightning-rpc-tunnel = { + description = "clightning mainnet rpc tunnel"; + wantedBy = [ "default.target" ]; + after = [ "default.target" ]; + + serviceConfig.ExecStart = extra.util.writeBash "lightning-tunnel" '' + socket=/home/jb55/.lightning-bitcoin-rpc + rm -f $socket + ${pkgs.socat}/bin/socat -d -d UNIX-LISTEN:$socket,reuseaddr,fork TCP:10.147.20.220:7878 + ''; + }; + + systemd.user.services.clightning-testnet-rpc-tunnel = { + description = "clightning testnet rpc tunnel"; + wantedBy = [ "default.target" ]; + after = [ "default.target" ]; + + serviceConfig.ExecStart = extra.util.writeBash "lightning-testnet-tunnel" '' + socket=/home/jb55/.lightning-testnet-rpc + rm -f $socket + ${pkgs.socat}/bin/socat -d -d UNIX-LISTEN:$socket,reuseaddr,fork TCP:10.147.20.220:7879 + ''; + }; + + systemd.services.blink-led-battery-low = { + description = "blink power led when battery is low"; + wantedBy = [ "default.target" ]; + after = [ "default.target" ]; + + path = with pkgs; [ gnused acpi ]; + + serviceConfig.ExecStart = extra.util.writeBash "battery-power" '' + set -e + + LED=/sys/class/leds/tpacpi::power + LED2=/sys/class/leds/tpacpi::kbd_backlight + + # led will start blinking below this battery % + limit=10 + + state="" + + while true + do + percent=$(acpi -b | sed -E -n 's/.* ([0-9]+)%.*/\1/p') + + if [ $percent -lt $limit ] && [ "$state" != "heartbeat" ] + then + printf "battery %d%% < %d%%, setting heartbeat trigger\n" "$percent" "$limit" >&2 + echo heartbeat > "$LED"/trigger + echo heartbeat > "$LED2"/trigger + state="heartbeat" + elif [ $percent -ge $limit ] && [ "$state" = "heartbeat" ] + then + printf "battery %d%% >= %d%%, resetting led trigger\n" "$percent" "$limit" >&2 + echo none > "$LED"/trigger + echo none > "$LED2"/trigger + cat "$LED"/max_brightness > "$LED"/brightness + state="" + fi + sleep 10 + done + ''; + }; + + services.hydra.enable = false; + services.hydra.dbi = "dbi:Pg:dbname=hydra;host=localhost;user=postgres;"; + services.hydra.hydraURL = "localhost"; + services.hydra.notificationSender = "hydra@quiver"; + services.hydra.buildMachinesFiles = []; + services.hydra.useSubstitutes = true; + + users.extraGroups.hydra.members = [ "jb55" ]; + users.extraGroups.www-data.members = [ "jb55" ]; + + # https://github.com/nmikhailov/Validity90 # driver not done yet + services.fprintd.enable = false; + + services.tor.enable = false; + services.tor.controlPort = 9051; + + services.autorandr.enable = true; + services.acpid.enable = false; + powerManagement.enable = false; + + networking.wireless.enable = true; + + services.postgresql = { + dataDir = "/var/db/postgresql/10/"; + enable = true; + package = pkgs.postgresql_10; + # extraPlugins = with pkgs; [ pgmp ]; + authentication = pkgs.lib.mkForce '' + # type db user address method + local all all trust + host all all localhost trust + ''; + # extraConfig = '' + # listen_addresses = '172.24.172.226,127.0.0.1' + # ''; + }; + +} diff --git a/nix-config/machines/quiver/hardware-configuration.nix b/nix-config/machines/quiver/hardware-configuration.nix @@ -0,0 +1,46 @@ +# Do not modify this file! It was generated by ‘nixos-generate-config’ +# and may be overwritten by future invocations. Please make changes +# to /etc/nixos/configuration.nix instead. +{ config, lib, pkgs, ... }: + +{ + imports = + [ <nixpkgs/nixos/modules/installer/scan/not-detected.nix> + ]; + + boot.initrd.availableKernelModules = [ "xhci_pci" "nvme" "usb_storage" "sd_mod" "rtsx_pci_sdmmc" ]; + boot.kernelModules = [ "kvm-intel" "ledtrig_heartbeat" ]; + #boot.kernelParams = [ "intel_pstate=nohwp" ]; + boot.extraModulePackages = [ ]; + + boot.loader.grub.enable = true; + boot.loader.grub.device = "nodev"; + boot.loader.grub.efiSupport = true; + boot.loader.efi.canTouchEfiVariables = true; + + boot.initrd.luks.devices = [ + { name = "root"; + device = "/dev/disk/by-uuid/ddb70a55-f123-461d-a4c1-a42a393b61fa"; + preLVM = false; + allowDiscards = true; + } + ]; + + fileSystems."/" = + { device = "/dev/disk/by-uuid/a6670d72-9bdf-4c62-b397-d35c8c1356ef"; + fsType = "ext4"; + options = [ "noatime" "nodiratime" "discard" ]; + }; + + fileSystems."/boot" = + { device = "/dev/disk/by-uuid/4F4E-282E"; + fsType = "vfat"; + }; + + swapDevices = + [ { device = "/dev/disk/by-uuid/699fec01-9969-4279-bc7c-8f64252e40b0"; } + ]; + + nix.maxJobs = lib.mkDefault 4; + powerManagement.cpuFreqGovernor = "powersave"; +} diff --git a/nix-config/machines/quiver/networking/default.nix b/nix-config/machines/quiver/networking/default.nix @@ -0,0 +1,111 @@ +extra: +{ config, lib, pkgs, ... }: +let + chromecastIPs = [ "192.168.86.190" ]; + iptables = "iptables -A nixos-fw"; + openChromecast = ip: '' + ${iptables} -p udp -s ${ip} -j nixos-fw-accept + ${iptables} -p tcp -s ${ip} -j nixos-fw-accept + ''; + ipr = "${pkgs.iproute}/bin/ip"; + writeBash = extra.util.writeBash; + openTCP = dev: port: '' + ip46tables -A nixos-fw -i ${dev} -p tcp --dport ${toString port} -j nixos-fw-accept + ''; + +in +{ + networking.extraHosts = '' + 10.0.9.1 secure.datavalet.io. + 172.24.242.111 securitycam.home. + 24.244.54.234 wifisignon.shaw.ca. + ''; + + networking.wireguard.interfaces = { + # "wg0" is the network interface name. You can name the interface arbitrarily. + wg0 = { + # Determines the IP address and subnet of the client's end of the tunnel interface. + ips = [ "10.100.0.2/28" ]; + + # Path to the private key file. + # + # Note: The private key can also be included inline via the privateKey option, + # but this makes the private key world-readable; thus, using privateKeyFile is + # recommended. + privateKeyFile = "/home/jb55/.wg/private"; + + peers = [ + # For a client configuration, one peer entry for the server will suffice. + { + # Public key of the server (not a file path). + publicKey = "TbGgpOqD6teLon0ksZKS8zvvjHtkOGKNWPpHZxhVFWA="; + + allowedIPs = [ "10.100.0.1/32" ]; + + # Set this to the server IP and port. + endpoint = "24.84.152.187:53"; + + # Send keepalives every 25 seconds. Important to keep NAT tables alive. + persistentKeepalive = 25; + } + { + publicKey = "vIh3IQgP92OhHaC9XBiJVDLlrs3GVcR6hlXaapjTiA0="; + + allowedIPs = [ "10.100.0.3/32" ]; + + # Send keepalives every 25 seconds. Important to keep NAT tables alive. + persistentKeepalive = 25; + } + { + publicKey = "Dp8Df75X8Kh9gd33e+CWyyhOvT4mT0X9ToPwBUEBU1k="; # macos + allowedIPs = [ "10.100.0.4/32" ]; + + # Send keepalives every 25 seconds. Important to keep NAT tables alive. + persistentKeepalive = 25; + } + ]; + }; + }; + + + networking.wireless.userControlled.enable = true; + + networking.firewall.enable = true; + networking.firewall.extraCommands = '' + ${lib.concatStringsSep "\n\n" (map openChromecast chromecastIPs)} + + # home network nginx + iptables -A nixos-fw -p tcp -s 192.168.86.0/24 -d 192.168.86.0/24 --dport 80 -j nixos-fw-accept + + # mark tor-related packets + iptables -t mangle -A OUTPUT -m cgroup --cgroup 12 -j MARK --set-mark 12 + + # all tor traffic should never try to route outside our wireguard tunnel to our tor node + iptables -t nat -A POSTROUTING -m cgroup --cgroup 12 -o wg0 -j MASQUERADE + + # create separate routing table + ${ipr} rule add fwmark 12 table 12 + + # add fallback route that blocks traffic, should the VPN go down + ${ipr} route add blackhole default metric 2 table 12 + ''; + + networking.firewall.extraStopCommands = '' + iptables -D nixos-fw -p tcp -s 192.168.86.0/24 -d 192.168.86.0/24 --dport 80 -j nixos-fw-accept || true + + # mark tor-related packets + iptables -t mangle -D OUTPUT -m cgroup --cgroup 12 -j MARK --set-mark 12 || true + + # all tor traffic should never try to route outside our wireguard tunnel to our tor node + iptables -t nat -D POSTROUTING -m cgroup --cgroup 12 -o wg0 -j MASQUERADE || true + + # create separate routing table + ${ipr} rule del fwmark 12 table 12 + + # add fallback route that blocks traffic, should the VPN go down + ${ipr} route del blackhole default metric 2 table 12 + ''; + + + #networking.firewall.allowedTCPPorts = [ 8333 ]; +} diff --git a/nix-config/machines/quiver/timers/archer-cookies/default.nix b/nix-config/machines/quiver/timers/archer-cookies/default.nix @@ -0,0 +1,57 @@ +extra: +{ config, lib, pkgs, ... }: +let + util = extra.util; +in +{ + + systemd.user.services.cookie-bot = { + description = "copy cookies to archer"; + + wantedBy = [ "default.target" ]; + after = [ "default.target" ]; + + path = with pkgs; [ openssh rsync ]; + + serviceConfig.ExecStart = util.writeBash "cp-cookies" '' + export HOME=/home/jb55 + PTH=".config/chromium/Default/Cookies" + rsync -av $HOME/$PTH archer:$PTH + ''; + unitConfig.OnFailure = "notify-failed-user@%n.service"; + + startAt = [ + "*-*-20 09:24:00" # youtube bot is run on the 20th at 10:24:00 + "Tue *-*-1..7 15:00:00" # cookies for itunes bot on the first tuesday + ]; + }; + + systemd.user.services.cookie-bot-reminder = { + description = "reminder to login"; + + wantedBy = [ "default.target" ]; + after = [ "default.target" ]; + + serviceConfig.ExecStart = util.writeBash "cookie-reminder" '' + /run/wrappers/bin/sendmail -f bill@monstercat.com <<EOF + To: bill@monstercat.com + Cc: jb55@jb55.com + From: THE COOKIE MONSTER <cookiemonster@quiver> + Subject: Reminder to log into YouTube cms + + I'll be doing an rsync from quiver tomorrow at 10:24 + + Here's a link for your convenience: + + https://cms.youtube.com + + Cheers, + THE COOKIE MONSTER + EOF + ''; + unitConfig.OnFailure = "notify-failed-user@%n.service"; + + startAt = "*-*-19 10:24:00"; + }; + +} diff --git a/nix-config/machines/quiver/timers/default.nix b/nix-config/machines/quiver/timers/default.nix @@ -0,0 +1,6 @@ +extra: +{ config, lib, pkgs, ... }: +{ + imports = [ + ]; +} diff --git a/nix-config/misc/dnsmasq-adblock.nix b/nix-config/misc/dnsmasq-adblock.nix @@ -0,0 +1,20 @@ +{ config, lib, pkgs, ... }: +let + adblock-hosts = pkgs.fetchurl { + url = "https://jb55.com/s/ad-sources.txt"; + sha256 = "d9e6ae17ecc41eb7021c0552548a1c8da97efbb61e3a750fb023674d01d81134"; + }; + dnsmasq-adblock = pkgs.fetchurl { + url = "https://jb55.com/s/dnsmasq-ad-sources.txt"; + sha256 = "3b34e565fb240c4ac1d261cb223bdc2d992fa755b5f6e981144e5b18f96f260d"; + }; +in +{ + services.dnsmasq.enable = true; + services.dnsmasq.resolveLocalQueries = false; + services.dnsmasq.servers = ["1.1.1.1" "8.8.8.8"]; + services.dnsmasq.extraConfig = '' + addn-hosts=${adblock-hosts} + conf-file=${dnsmasq-adblock} + ''; +} diff --git a/nix-config/misc/git-server.nix b/nix-config/misc/git-server.nix @@ -0,0 +1,60 @@ +{ extra, config, pkgs }: +let gitwebConf = pkgs.writeText "gitweb.conf" '' + # path to git projects (<project>.git) + $projectroot = "${extra.git.projectroot}"; + ''; + gitweb-wrapper = pkgs.writeScript "gitweb.cgi" '' + #!${pkgs.bash}/bin/bash + export PERL5LIB=$PERL5LIB:${with pkgs.perlPackages; makePerlPath [ CGI HTMLParser ]} + ${pkgs.perl}/bin/perl ${pkgs.git}/share/gitweb/gitweb.cgi + ''; + gitweb-theme = pkgs.fetchFromGitHub { + owner = "kogakure"; + repo = "gitweb-theme"; + rev = "4305b3551551c470339c24a6567b1ac9e642ae54"; + sha256 = "0gagy0jvqb3mc587b6yy8l9g5j5wqr2xlz128v6f01364cb7whmv"; + }; +in +if config.services.fcgiwrap.enable then '' + server { + listen 80; + server_name ${extra.host}; + + location = / { + return 301 http://${extra.host}/repos/; + } + + location = /repos { + return 301 http://${extra.host}/repos/; + } + + location / { + # fcgiwrap is set up to listen on this host:port + fastcgi_pass unix:${config.services.fcgiwrap.socketAddress}; + include ${pkgs.nginx}/conf/fastcgi_params; + fastcgi_param SCRIPT_FILENAME ${pkgs.git}/bin/git-http-backend; + + client_max_body_size 0; + + # export all repositories under GIT_PROJECT_ROOT + + fastcgi_param GIT_HTTP_EXPORT_ALL ""; + fastcgi_param GIT_PROJECT_ROOT ${extra.git.projectroot}; + fastcgi_param PATH_INFO $uri; + } + + location /repos/static { + alias ${gitweb-theme}; + } + + location /repos { + include ${pkgs.nginx}/conf/fastcgi_params; + gzip off; + + fastcgi_param GITWEB_CONFIG ${gitwebConf}; + fastcgi_param SCRIPT_FILENAME ${gitweb-wrapper}; + fastcgi_pass unix:${config.services.fcgiwrap.socketAddress}; + } + + } +'' else throw "fcgiwrap must be enabled to run git-server" diff --git a/nix-config/misc/imap-notifier/default.nix b/nix-config/misc/imap-notifier/default.nix @@ -0,0 +1,114 @@ +extra: +{ config, lib, pkgs, ... }: +let notify = pkgs.callPackage (pkgs.fetchFromGitHub { + owner = "jb55"; + repo = "imap-notify"; + rev = "c0936c0bb4b7e283bbfeccdbac77f4cb50f71b3b"; + sha256 = "19vadvnkg6bjp1607nlawdx1x07xnbbx7bgk66rbwrs4vhkvarkg"; + }) {}; + penv = pkgs.python2.withPackages (ps: with ps; [ dbus-python pygobject2 ]); + awake-from-sleep-fetcher = pkgs.writeScript "awake-from-sleep-fetcher" '' + #!${penv}/bin/python2 -u + + import dbus + import datetime + import gobject + import os + from dbus.mainloop.glib import DBusGMainLoop + + def start_home(): + print("starting email fetcher") + os.system("systemctl restart --user email-fetcher") + + def handle_sleep_callback(sleeping): + if not sleeping: + # awoke from sleep + start_home() + + DBusGMainLoop(set_as_default=True) # integrate into main loob + bus = dbus.SystemBus() # connect to dbus system wide + bus.add_signal_receiver( # defince the signal to listen to + handle_sleep_callback, # name of callback function + 'PrepareForSleep', # signal name + 'org.freedesktop.login1.Manager', # interface + 'org.freedesktop.login1' # bus name + ) + + loop = gobject.MainLoop() # define mainloop + loop.run() + ''; + + notifier = user: pass: cmd: host: extra.util.writeBash "notifier" '' + set -e + + arg="${host}" + + # wait for connectivity + until ${pkgs.libressl.nc}/bin/nc -w 1 -vz jb55.com 12566 &>/dev/null; do sleep 1; done + + # run it once first in case we missed any from lost connectivity + ${cmd} || : + export IMAP_NOTIFY_USER=${user} + export IMAP_NOTIFY_PASS=${pass} + export IMAP_NOTIFY_CMD=${cmd} + export IMAP_NOTIFY_HOST=${host} + exec ${notify}/bin/imap-notify + ''; +in +with extra; { + systemd.user.services.email-fetcher = { + enable = if extra.is-minimal then false else true; + description = "email fetcher"; + + environment = { + IMAP_ALLOW_UNAUTHORIZED = "0"; + IMAP_NOTIFY_PORT = "12788"; + }; + + path = with pkgs; [ eject utillinux muchsync notmuch bash openssh ]; + + serviceConfig.Type = "simple"; + serviceConfig.Restart = "always"; + serviceConfig.ExecStart = + let cmd = util.writeBash "email-fetcher" '' + set -e + export HOME=/home/jb55 + export DATABASEDIR=$HOME/mail/personal + + notify() { + local c=$(notmuch --config /home/jb55/.notmuch-config-personal count 'tag:inbox and not tag:filed and not tag:noise') + local lc=$c + if [ -f /tmp/last-email-count ]; then + lc=$(</tmp/last-email-count) + fi + echo "$c" > /tmp/last-email-count + if [ -f ~/var/notify/home ] && [ $c -ne $lc ]; then + ${pkgs.libnotify}/bin/notify-send -i email-new "You Got Mail (inbox $c)" + fi + } + + ( + flock -x -w 100 200 || exit 1 + if [ -f ~/var/notify/home ]; then + ${pkgs.libnotify}/bin/notify-send -i email-new "Fetching new mail..." + fi + muchsync -C ~/.notmuch-config-personal notmuch + notify + ) 200>/tmp/email-notify.lock + ''; + in notifier "jb55@jb55.com" private.personal-email-pass cmd "jb55.com"; + }; + + systemd.user.services.awake-from-sleep-fetcher = { + enable = if extra.is-minimal then false else true; + description = ""; + + path = with pkgs; [ systemd ]; + + wantedBy = [ "default.target" ]; + after = [ "default.target" ]; + + serviceConfig.ExecStart = "${awake-from-sleep-fetcher}"; + }; + +} diff --git a/nix-config/misc/msmtp/default.nix b/nix-config/misc/msmtp/default.nix @@ -0,0 +1,12 @@ +extra: +{ config, lib, pkgs, ... }: +{ + # services.mail.sendmailSetuidWrapper = { + # program = "sendmail"; + # source = lib.mkForce (extra.util.writeBash "sendmail" '' + # ${pkgs.msmtp}/bin/msmtp --read-envelope-from -C /home/jb55/.msmtprc -t "$@" + # ''); + # setuid = false; + # setgid = false; + # }; +} diff --git a/nix-config/misc/util.nix b/nix-config/misc/util.nix @@ -0,0 +1,7 @@ +{ pkgs }: +{ + writeBash = fname: body: pkgs.writeScript fname '' + #! ${pkgs.bash}/bin/bash + ${body} + ''; +} diff --git a/nix-config/networking/default.nix b/nix-config/networking/default.nix @@ -0,0 +1,7 @@ +machine: +{ config, lib, pkgs, ... }: +{ + networking.hostName = machine; + + networking.firewall.allowPing = true; +} diff --git a/nix-config/nixpkgs/config.nix b/nix-config/nixpkgs/config.nix @@ -0,0 +1,510 @@ +{ pkgs }: +let #monstercatPkgs = import <monstercatpkgs> { inherit pkgs; }; + #haskellOverrides = import ./haskell-overrides { inherit monstercatPkgs; }; + jb55pkgs = import <jb55pkgs> { inherit pkgs; }; + callPackage = pkgs.callPackage; + doJailbreak = pkgs.haskell.lib.doJailbreak; + dontCheck = pkgs.haskell.lib.dontCheck; + regularFiles = builtins.filterSource (f: type: type == "symlink" + || type == "directory" + || type == "regular"); +in { + allowUnfree = true; + allowUnfreeRedistributable = true; + allowBroken = false; + zathura.useMupdf = true; + + #firefox = #{ + # enableGoogleTalkPlugin = false; + # enableAdobeFlash = false; + # }; + + packageOverrides = super: rec { + + # /run/current-system/sw/bin/ls $HOME/.emacs.d/elpa | sed 's/-[[:digit:]].*//g;s/\+$/-plus/g' | sort -u + #emacs = super.emacsHead; + nur = import (builtins.fetchTarball { + url = "https://github.com/nix-community/NUR/archive/cff4dfbe6d6f4ab14560234fcf2d73332ee3ecc1.tar.gz"; + sha256 = "01yxz6w820vryirrwkmsnxkmvp35dncjp1n8fdfsq4n0r28nw31a"; + }) { + inherit pkgs; + }; + + + msmtp = pkgs.lib.overrideDerivation super.msmtp (attrs: { + patches = [ /home/jb55/dev/msmtp-1.8.3/msmtpq-custom-conn-test.patch ]; + }); + + weechat = super.weechat.override {configure = {availablePlugins, ...}: { + scripts = with super.weechatScripts; [ wee-slack ]; + }; + }; + + dunst = pkgs.lib.overrideDerivation super.dunst (attrs: { + src = pkgs.fetchFromGitHub { + owner = "jb55"; + repo = "dunst"; + rev = "138edff170e4e4a2bf6891bd634c4ec215d4b7ef"; + sha256 = "1pf3v4mrcd0cfhvm9fk9nwvgj5dy6qlbs0mhlcyx26cbqxd62brp"; + }; + }); + + lastpass-cli = super.lastpass-cli.override { guiSupport = true; }; + + wine = super.wineWowPackages.staging; + + dasht = super.lib.overrideDerivation super.dasht (attrs: { + src = pkgs.fetchFromGitHub { + owner = "sunaku"; + repo = "dasht"; + sha256 = "1i4gc68aypa0fk94ssy2gzakcn2qlmp9qf427km6fxbjx15qsbjn"; + rev = "issue-45"; + }; + }); + + phonectl = super.python3Packages.callPackage (import (super.fetchFromGitHub { + owner = "jb55"; + repo = "phonectl"; + sha256 = "0wqpwg32qa1rzpw7881r6q2zklxlq1y4qgyyy742pihfh99rkcmj"; + rev = "de0f37a20d16a32a73f9267860302357b2df0c20"; + })) {}; + + notmuch = pkgs.lib.overrideDerivation super.notmuch (attrs: { + src = pkgs.fetchFromGitHub { + owner = "jb55"; + repo = "notmuch"; + rev = "adcc427b8356cca865479b433d4be362b1f50e38"; + sha256 = "14l95hld7gs42p890a9r8dfw4m945iy2sf9bdyajs2yqjwmarwn7"; + }; + + doCheck = false; + }); + + # wirelesstools = + # let + # patch = super.fetchurl { + # url = "https://jb55.com/s/iwlist-print-scanning-info-allocation-failed.patch"; + # sha256 = "31c97c6abf3f0073666f9f94f233fae2fcb8990aae5e7af1030af980745a8efc"; + # }; + # in + # pkgs.lib.overrideDerivation super.wirelesstools (attrs: { + # prePatch = '' + # patch -p0 < ${patch} + # ''; + # }); + + dmenu2 = pkgs.lib.overrideDerivation super.dmenu2 (attrs: { + patches = + [ (super.fetchurl + { url = "https://jb55.com/s/404ad3952cc5ccf3.patch"; + sha1 = "404ad3952cc5ccf3aa0674f31a70ef0e446a8d49"; + }) + ]; + }); + + #htop = pkgs.lib.overrideDerivation super.htop (attrs: { + # patches = + # [ (super.fetchurl + # { url = "https://jb55.com/s/htop-vim.patch"; + # sha256 = "3d72aa07d28d7988e91e8e4bc68d66804a4faeb40b93c7a695c97f7d04a55195"; + # }) + + # (super.fetchurl + # { url = "https://jb55.com/s/0001-Improving-Command-display-sort.patch"; + # sha256 = "2207dccce7f9de0c3c6f56d846d7e547c96f63c8a4659ef46ef90c3bd9a013d1"; + # }) + # ]; + #}); + + #ical2org = super.callPackage ./scripts/ical2org { }; + + #footswitch = super.callPackage ./scripts/footswitch { }; + + ds4ctl = super.callPackage ./scripts/ds4ctl { }; + + haskellEnvHoogle = haskellEnvFun { + name = "haskellEnvHoogle"; + #compiler = "ghc821"; + withHoogle = true; + }; + + haskellEnv = haskellEnvFun { + name = "haskellEnv"; + #compiler = "ghc821"; + withHoogle = false; + }; + + haskell-tools = super.buildEnv { + name = "haskell-tools"; + paths = haskellTools super.haskellPackages; + }; + + jb55-tools-env = pkgs.buildEnv { + name = "jb55-tools"; + paths = with jb55pkgs; [ + csv-delim + csv-scripts + dbopen + extname + mandown + snap + sharefile + samp + ]; + }; + + jvm-tools-env = pkgs.buildEnv { + name = "jvm-tools"; + paths = with pkgs; [ + gradle + maven + oraclejdk + ]; + }; + + # mk-rust-env = name: rustVer: pkgs.buildEnv { + # name = "rust-dev-${name}"; + # paths = with pkgs; with rustVer; [ + # clang + # rustracer + # rustracerd + # rust + # #cargo-edit + # #rustfmt + # rust-bindgen + # ]; + # }; + + #rust-dev-env-nightly = mk-rust-env "nightly" pkgs.rustChannels.nightly; + #rust-dev-env-beta = mk-rust-env "beta" pkgs.rustChannels.beta; + + gaming-env = pkgs.buildEnv { + name = "gaming"; + paths = with pkgs; [ + steam + ]; + }; + + file-tools = pkgs.buildEnv { + name = "file-tools"; + paths = with pkgs; [ + ripgrep + ranger + ]; + }; + + network-tools = pkgs.buildEnv { + name = "network-tools"; + paths = with pkgs; with xorg; [ + nmap + dnsutils + whois + nethogs + ]; + }; + + system-tools = pkgs.buildEnv { + name = "system-tools"; + paths = with pkgs; with xorg; [ + xbacklight + acpi + psmisc + ]; + }; + + desktop-tools = pkgs.buildEnv { + name = "desktop-tools"; + paths = with pkgs; with xorg; [ + twmn + libnotify + ]; + }; + + syntax-tools = pkgs.buildEnv { + name = "syntax-tools"; + paths = with pkgs; [ + shellcheck + ]; + }; + + mail-tools = pkgs.buildEnv { + name = "mail-tools"; + paths = with pkgs; [ + notmuch + msmtp + muchsync + isync + ]; + }; + + photo-env = pkgs.buildEnv { + name = "photo-tools"; + paths = with pkgs; [ + gimp + darktable + rawtherapee + ufraw + dcraw + ]; + }; + + git-tools = pkgs.buildEnv { + name = "git-tools"; + paths = with pkgs; [ + diffstat + diffutils + gist + git-series + gitAndTools.git-extras + gitAndTools.git-absorb + gitAndTools.delta + gitAndTools.gitFull + github-release + patch + patchutils + ]; + }; + + haskellEnvFun = { withHoogle ? false, compiler ? null, name }: + let hp = if compiler != null + then super.haskell.packages.${compiler} + else super.haskellPackages; + + ghcWith = if withHoogle + then hp.ghcWithHoogle + else hp.ghcWithPackages; + + in super.buildEnv { + name = name; + paths = [(ghcWith myHaskellPackages)]; + }; + + haskellTools = hp: with hp; [ + alex + cabal-install + cabal2nix + #stack2nix + hpack + ghc-core + happy + (dontCheck hasktags) + hindent + hlint + structured-haskell-mode + haskell-ci + ]; + + myHaskellPackages = hp: with hp; [ + #(doJailbreak pandoc-lens) + (dontCheck (doJailbreak serialise)) + Boolean + Decimal + HTTP + HUnit + MissingH + QuickCheck + SafeSemaphore + aeson + aeson-qq + async + attoparsec + # base32-bytestring + base32string + base58-bytestring + bifunctors + # bitcoin-api + # bitcoin-api-extra + unliftio + # bitcoin-block + # bitcoin-script + # bitcoin-tx + blaze-builder + blaze-builder-conduit + blaze-html + blaze-markup + blaze-textual + # bson-lens + #bytestring-show + cased + cassava + cereal + clientsession + clientsession + colour + comonad + comonad-transformers + #compact-string-fix + #cryptohash + directory + dlist + dlist-instances + doctest + either + elm-export + elm-export-persistent + exceptions + filepath + fingertree + foldl + formatting + free + generics-sop + hamlet + hashable + hashids + here + heroku + hedgehog + hspec + hspec-expectations + html + http-client + http-date + http-types + inline-c + io-memoize + io-storage + keys + language-c + language-javascript + lens + lens-action + lens-aeson + lens-datetime + lens-family + lens-family-core + lifted-async + lifted-base + linear + list-extras + # list-t + logict + mbox + mime-mail + mime-types + miso + mmorph + monad-control + monad-coroutine + monad-loops + monad-par + monad-par-extras + monad-stm + monadloc + # mongoDB + monoid-extras + neat-interpolation + network + newtype + numbers + options + optparse-applicative + optparse-generic + pandoc + parsec + megaparsec + parsers + pcg-random + persistent + persistent-postgresql + persistent-template + posix-paths + #postgresql-binary + postgresql-simple + pretty-show + probability + profunctors + pwstore-fast + quickcheck-instances + random + reducers + reflection + regex-applicative + regex-base + regex-compat + regex-posix + relational-record + resourcet + retry + rex + s3-signer + safe + #sbv + scotty + sqlite-simple + lucid + semigroupoids + semigroups + #servant + #servant-cassava + #servant-client + #servant-docs + #servant-lucid + #servant-server + shake + shakespeare + #shelly + shqq + simple-reflect + #speculation + split + spoon + stache + stm + stm-chans + #stm-stats + store + stache + streaming + smtp-mail + streaming-bytestring + streaming-wai + strict + stringsearch + strptime + syb + system-fileio + system-filepath + tagged + taggy + taggy-lens + tar + tardis + tasty + tasty-hspec + tasty-hunit + tasty-quickcheck + tasty-smallcheck + temporary + test-framework + test-framework-hunit + text + # text-format + text-regex-replace + thyme + time + time-units + #tinytemplate + transformers + transformers-base + turtle + unagi-chan + uniplate + unix-compat + unordered-containers + uuid + vector + void + wai + wai-middleware-static + wai-extra + warp + wreq + xhtml + xml-lens + yaml + zippers + zlib + ]; + }; +} diff --git a/nix-config/nixpkgs/dotfiles.nix b/nix-config/nixpkgs/dotfiles.nix @@ -0,0 +1,43 @@ +{ pkgs +, fetchFromGitHub +, fetchurl +, stdenv +, writeScript +, machineSessionCommands ? "" +}: +let + #dotfiles = pkgs.jb55-dotfiles; + bgimg = fetchurl { + url = "https://jb55.com/s/red-low-poly.png"; + sha256 = "e45cc45eb084d615babfae1aae703757c814d544e056f0627d175a6ab18b35ab"; + }; + impureSessionCommands = '' + #!${pkgs.bash}/bin/bash + '' + "\n" + machineSessionCommands; + sessionCommands = '' + #!${pkgs.bash}/bin/bash + ${pkgs.feh}/bin/feh --bg-fill ${bgimg} + ${pkgs.xlibs.xsetroot}/bin/xsetroot -cursor_name left_ptr + + gpg-connect-agent /bye + GPG_TTY=$(tty) + export GPG_TTY + unset SSH_AGENT_PID + export SSH_AUTH_SOCK="/run/user/1000/gnupg/S.gpg-agent.ssh" + '' + "\n" + impureSessionCommands; + xinitrc = writeScript "xinitrc" sessionCommands; + xinitrc-refresh = writeScript "xinitrc-refresh" impureSessionCommands; +in stdenv.mkDerivation rec { + name = "jb55-config-${version}"; + version = "git-2015-01-13"; + + phases = "installPhase"; + + installPhase = '' + mkdir -p $out/bin + echo "user config at '$out'" + cp "${xinitrc}" $out/bin/xinitrc + cp "${xinitrc-refresh}" $out/bin/xinitrc-refresh + ln -s $out/bin/xinitrc $out/.xinitrc + ''; +} diff --git a/nix-config/nixpkgs/haskell-overrides/default.nix b/nix-config/nixpkgs/haskell-overrides/default.nix @@ -0,0 +1,5 @@ +{ monstercatPkgs }: +pkgs: self: super: +let overrideCabal = pkgs.haskell.lib.overrideCabal; +in { +} diff --git a/nix-config/nixpkgs/haskell-overrides/massager-service.nix b/nix-config/nixpkgs/haskell-overrides/massager-service.nix @@ -0,0 +1,24 @@ +{ mkDerivation, base, bytestring, cassava, flexible-instances +, http-types, payment, data-default, pipes, pipes-csv, stdenv, streaming +, streaming-wai, text, unordered-containers, vector, wai, warp +, word8 +}: +with stdenv.lib; +mkDerivation { + pname = "massager-service"; + version = "0.1.0"; + src = /dropbox/projects/monstercat/haskell/massager-service; + isLibrary = false; + isExecutable = true; + executableHaskellDepends = [ + base bytestring data-default cassava flexible-instances http-types payment + pipes pipes-csv streaming streaming-wai text unordered-containers + vector wai warp word8 + ]; + postInstall = '' + cp -r parsers $out/bin + ''; + homepage = "https://phabricator.monstercat.com/diffusion/MASRV"; + description = "Match csvs with Connect users and tracks"; + license = stdenv.lib.licenses.mit; +} diff --git a/nix-config/nixpkgs/haskell-overrides/monstercat-backend.nix b/nix-config/nixpkgs/haskell-overrides/monstercat-backend.nix @@ -0,0 +1,89 @@ +{ Decimal +, MissingH +, aeson +, async +, attoparsec +, base +, bson +, bytestring +, conduit +, data-default +, failure +, fetchgitPrivate +, flexible +, flexible-instances +, ghc-prim +, hashable +, hashable-generics +, lens +, mkDerivation +, mongoDB +, mtl +, persistent +, persistent-mongoDB +, persistent-template +, pwstore-fast +, safe +, stdenv +, template-haskell +, text +, time +, transformers +, unordered-containers +, uuid +, vector +, word8 +}: + +with stdenv.lib; +mkDerivation rec { + pname = "monstercat-backend"; + version = "1.1.0"; + + # todo: get fetchgitPrivate working + + src = fetchgitPrivate { + url = "ssh://git@phabricator.monstercat.com/diffusion/HBACK/haskell-backend"; + rev = "3e5ba112ca708e3ef036a26d03c632ee7507140e"; + sha256 = "306c7a985135011066cfcf6611bc5c7e7386e7900f218209f534083beaaff4ba"; + }; + + # src = /dropbox/projects/monstercat/haskell/monstercat-backend; + + buildDepends = [ + Decimal + MissingH + aeson + async + attoparsec + base + bson + bytestring + conduit + data-default + failure + flexible + flexible-instances + ghc-prim + hashable + lens + mongoDB + mtl + persistent + persistent-mongoDB + persistent-template + pwstore-fast + safe + template-haskell + text + time + transformers + unordered-containers + uuid + vector + word8 + ]; + + description = "Monstercat backend database"; + license = stdenv.lib.licenses.unfree; +} diff --git a/nix-config/nixpkgs/haskell-overrides/payment.nix b/nix-config/nixpkgs/haskell-overrides/payment.nix @@ -0,0 +1,104 @@ +{ mkDerivation +, Decimal +, MissingH +, QuickCheck +, aeson +, aeson-pretty +, ansi-wl-pprint +, async +, attoparsec +, base +, bytestring +, cased +, cassava +, data-default +, directory +, errors +, envy +, fetchFromGitHub +, fetchgitPrivate +, filepath +, flexible +, flexible-instances +, foldl +, formatting +, hashable +, haskellPackages +, keys +, lens +, lens-aeson +, lifted-base +, money +, monstercat-backend +, mtl +, options +, parsec +, pipes +, pipes-bytestring +, pipes-csv +, pipes-safe +, random +, safe +, stdenv +, syb +, split +, text +, time +, transformers +, unordered-containers +, uuid +, yaml +}: +mkDerivation { + pname = "payment"; + version = "0.1.2"; + src = /dropbox/projects/monstercat/haskell/massager; + buildDepends = [ + Decimal + MissingH + QuickCheck + aeson + aeson-pretty + ansi-wl-pprint + async + attoparsec + base + bytestring + cased + cassava + data-default + directory + errors + envy + filepath + formatting + split + flexible + flexible-instances + foldl + hashable + keys + lens + lens-aeson + lifted-base + money + monstercat-backend + mtl + options + parsec + pipes + pipes-bytestring + pipes-csv + pipes-safe + random + safe + syb + text + time + transformers + unordered-containers + uuid + yaml + ]; + license = stdenv.lib.licenses.bsd3; +} diff --git a/nix-config/nixpkgs/scripts/ds4ctl/default.nix b/nix-config/nixpkgs/scripts/ds4ctl/default.nix @@ -0,0 +1,24 @@ +{ stdenv, fetchFromGitHub }: + +stdenv.mkDerivation rec { + name = "ds4ctl-${version}"; + version = "0.6.4"; + + src = fetchFromGitHub { + owner = "jb55"; + repo = "ds4ctl"; + rev = version; + sha256 = "1zv905bhqxb1ksd96i6pwqq5ai1zkn3xf3xc3ky57cxgvb8p5c2a"; + }; + + makeFlags = "PREFIX=$(out)"; + + buildInputs = [ ]; + + meta = with stdenv.lib; { + description = "ds4ctl"; + homepage = "https://github.com/jb55/ds4ctl"; + maintainers = with maintainers; [ jb55 ]; + license = licenses.mit; + }; +} diff --git a/nix-config/nixpkgs/scripts/footswitch/default.nix b/nix-config/nixpkgs/scripts/footswitch/default.nix @@ -0,0 +1,26 @@ +{ stdenv, hidapi, fetchFromGitHub }: + +stdenv.mkDerivation rec { + name = "footswitch-${version}"; + version = "git-2015-06-23"; + + src = fetchFromGitHub { + repo = "footswitch"; + owner = "rgerganov"; + rev = "cbb9091277a34adf236ee90e0f3895e35359051c"; + sha256 = "0b5s8wccvk5825kplac6nzfqjzjfyml6qvk0qpf6md9dq0f9fy16"; + }; + + makeFlags = "PREFIX=$(out)"; + + patches = [ ./patch.diff ]; + + buildInputs = [ hidapi ]; + + meta = with stdenv.lib; { + description = "footswitch usb driver"; + homepage = "https://github.com/rgerganov/footswitch"; + maintainers = with maintainers; [ jb55 ]; + license = licenses.mit; + }; +} diff --git a/nix-config/nixpkgs/scripts/footswitch/patch.diff b/nix-config/nixpkgs/scripts/footswitch/patch.diff @@ -0,0 +1,37 @@ +diff --git a/Makefile b/Makefile +index e3e4814..6605e65 100644 +--- a/Makefile ++++ b/Makefile +@@ -1,5 +1,5 @@ +-INSTALL = /usr/bin/install -c +-INSTALLDATA = /usr/bin/install -c -m 644 ++INSTALL = install -D ++INSTALLDATA = install -D -m 644 + PROGNAME = footswitch + CFLAGS = -Wall + UNAME := $(shell uname) +@@ -7,11 +7,7 @@ ifeq ($(UNAME), Darwin) + CFLAGS += -DOSX + LDFLAGS = -lhidapi + else +- ifeq ($(UNAME), Linux) +- LDFLAGS = `pkg-config hidapi-libusb --libs` +- else +- LDFLAGS = -lhidapi +- endif ++LDFLAGS = -lhidapi-hidraw + endif + + all: $(PROGNAME) +@@ -20,9 +16,9 @@ $(PROGNAME): $(PROGNAME).c common.h common.c debug.h debug.c + $(CC) $(PROGNAME).c common.c debug.c -o $(PROGNAME) $(CFLAGS) $(LDFLAGS) + + install: all +- $(INSTALL) $(PROGNAME) /usr/bin ++ $(INSTALL) $(PROGNAME) $(PREFIX)/bin/$(PROGNAME) + ifeq ($(UNAME), Linux) +- $(INSTALLDATA) 19-footswitch.rules /etc/udev/rules.d ++ $(INSTALLDATA) 19-footswitch.rules $(PREFIX)/etc/udev/rules.d + endif + + clean: diff --git a/nix-config/nixpkgs/scripts/ical2org/default.nix b/nix-config/nixpkgs/scripts/ical2org/default.nix @@ -0,0 +1,36 @@ +{ stdenv, gawk, fetchurl }: +stdenv.mkDerivation rec { + name = "ical2org-${version}"; + version = "15r1rq9xpjypij0bb89zrscm1wc5czljfyv47z68vmkhimr579az"; + + src = fetchurl { + url = http://orgmode.org/worg/code/awk/ical2org.awk; + sha256 = version; + }; + + phases = [ "installPhase" ]; + + buildInputs = [ gawk ]; + + installPhase = '' + mkdir -p $out/bin + cp $src $out/bin/ical2org + chmod +x $out/bin/ical2org + substituteInPlace $out/bin/ical2org \ + --replace "/usr/bin/awk" "${gawk}/bin/gawk" \ + --replace "max_age = 7" "max_age = -1" \ + --replace "condense = 0" "condense = 1" \ + --replace "original = 1" "original = 0" \ + --replace "preamble = 1" "preamble = 0" \ + --replace 'author = "Eric S Fraga"' 'author = "William Casarin"' \ + --replace 'emailaddress = "e.fraga@ucl.ac.uk"' 'emailaddress = "bill@casarin.me"' + ''; + + meta = with stdenv.lib; { + description = "Convert ical to org"; + homepage = "http://orgmode.org/worg/org-tutorials/org-google-sync.html"; + license = licenses.free; + platforms = with platforms; linux ++ darwin ; + maintainers = with maintainers; [ jb55 ]; + }; +} diff --git a/nix-config/services/default.nix b/nix-config/services/default.nix @@ -0,0 +1,28 @@ +extra: +{ config, lib, pkgs, ... }: +{ + imports = [ + # ./footswitch + # ./fail-notifier + ]; + + #services.mongodb.enable = true; + #services.redis.enable = true; + + services.openssh.enable = true; + services.openssh.passwordAuthentication = false; + services.openssh.permitRootLogin = "no"; + + services.atd.enable = true; + + services.logrotate = { + enable = true; + config = '' + dateext + dateformat %Y-%m-%d. + compresscmd ${pkgs.xz.bin}/bin/xz + uncompresscmd ${pkgs.xz.bin}/bin/unxz + compressext .xz + ''; + }; +} diff --git a/nix-config/services/desktop/default.nix b/nix-config/services/desktop/default.nix @@ -0,0 +1,264 @@ +{ composeKey, util, userConfig, theme, icon-theme, extra }: +{ config, lib, pkgs, ... }: +let + clippings-pl-file = pkgs.fetchurl { + url = "https://raw.githubusercontent.com/jb55/kindle-clippings/master/clippings.pl"; + sha256 = "13bn5lvm4p85369yj88jr62h3zalmmyrzmjc332qwlqgqhyf3dls"; + }; + clippings-pl = util.writeBash "clippings.pl" '' + ${lib.getBin pkgs.perl}/bin/perl ${clippings-pl-file} + ''; + + secrets = extra.private; +in +{ + imports = [ + (import ./networking extra) + ]; + + services.hoogle = { + enable = false; + packages = pkgs.myHaskellPackages; + haskellPackages = pkgs.haskellPackages; + }; + + services.gnome3.gnome-keyring.enable = if extra.is-minimal then false else true; + + services.trezord.enable = if extra.is-minimal then false else true; + + services.avahi.enable = true; + services.spotifyd.enable = if extra.is-minimal then false else false; + services.spotifyd.config = '' + [global] + username = bcasarin + password = ${secrets.spotify.password} + backend = pulseaudio + bitrate = 160 + device_name = spotifyd + no_audio_cache = true + volume_normalisation = true + normalisation_pregain = -10 + ''; + + programs.gnupg.agent.enable = true; + programs.gnupg.agent.pinentryFlavor = "gtk2"; + + # programs.gnupg.trezor-agent = { + # enable = if extra.is-minimal then false else true; + # configPath = "/home/jb55/.gnupg"; + # }; + + services.emacs.enable = if extra.is-minimal then false else true; + services.emacs.install = if extra.is-minimal then false else true; + + systemd.user.services.emacs.path = with pkgs; [ bash nix ]; + systemd.user.services.emacs.serviceConfig.ExecStart = + let + cfg = config.services.emacs; + in + lib.mkIf (!extra.is-minimal) ( + lib.mkForce ( + pkgs.writeScript "start-emacs" '' + #!/usr/bin/env bash + source ${config.system.build.setEnvironment} + + # hacky af + export NIX_PATH=dotfiles=/home/jb55/dotfiles:jb55pkgs=/home/jb55/etc/jb55pkgs:monstercatpkgs=/home/jb55/etc/monstercatpkgs:nixos-config=/home/jb55/etc/nix-files:nixpkgs=/home/jb55/nixpkgs:/home/jb55/.nix-defexpr/channels:nixpkgs=/nix/var/nix/profiles/per-user/root/channels/nixos:nixos-config=/etc/nixos/configuration.nix:/nix/var/nix/profiles/per-user/root/channels + export NIXPKGS=/home/jb55/nixpkgs + + exec ${cfg.package}/bin/emacs --daemon + '' + )); + + services.redshift = { + enable = if extra.is-minimal then false else true; + temperature.day = 5500; + temperature.night = 4300; + + brightness = { + day = "1.0"; + night = "0.8"; + }; + }; + + location.latitude = 49.270186; + location.longitude = -123.109353; + + systemd.user.services.udiskie = { + enable = if extra.is-minimal then false else true; + description = "userspace removable drive automounter"; + after = [ "multi-user.target" ]; + wants = [ "multi-user.target" ]; + wantedBy = [ "multi-user.target" ]; + serviceConfig = { + Type = "simple"; + ExecStart = "${lib.getBin pkgs.udiskie}/bin/udiskie"; + }; + }; + + systemd.user.services.kindle-sync3 = { + enable = false; + description = "sync kindle"; + after = [ "media-kindle.mount" ]; + requires = [ "media-kindle.mount" ]; + wantedBy = [ "media-kindle.mount" ]; + serviceConfig = { + ExecStart = util.writeBash "kindle-sync" '' + export PATH=${lib.makeBinPath (with pkgs; [ coreutils eject perl dos2unix git ])}:$PATH + NOTES=/home/jb55/doc/notes/kindle + mkdir -p $NOTES + </media/kindle/documents/My\ Clippings.txt dos2unix | \ + ${clippings-pl} > $NOTES/clippings.yml + cd $NOTES + if [ ! -d ".git" ]; then + git init . + git remote add origin gh:jb55/my-clippings + fi + git add clippings.yml + git commit -m "update" + git push -u origin master + ''; + }; + }; + + services.mpd = { + enable = false; + dataDir = "/home/jb55/mpd"; + user = "jb55"; + group = "users"; + extraConfig = '' + audio_output { + type "pulse" + name "Local MPD" + server "127.0.0.1" + } + ''; + }; + + services.xserver = { + enable = true; + layout = "us"; + + # xset r rate 200 50 + autoRepeatDelay = 200; + autoRepeatInterval = 50; + + xkbOptions = "terminate:ctrl_alt_bksp, ctrl:nocaps, keypad:hex, altwin:swap_alt_win, lv3:ralt_switch, compose:${composeKey}"; + + wacom.enable = false; + + displayManager = { + defaultSession = "none+xmonad"; + sessionCommands = "${userConfig}/bin/xinitrc"; + lightdm = { + enable = true; + background = "${pkgs.fetchurl { + url = "https://jb55.com/s/red-low-poly.png"; + sha256 = "e45cc45eb084d615babfae1aae703757c814d544e056f0627d175a6ab18b35ab"; + }}"; + }; + }; + + windowManager = { + xmonad = { + enable = true; + enableContribAndExtras = true; + }; + }; + + desktopManager = { + xterm.enable = false; + }; + + screenSection = '' + Option "metamodes" "1920x1080 +0+0" + Option "dpi" "96 x 96" + ''; + }; + + # Enable the OpenSSH daemon. + # Enable CUPS to print documents. + services.printing = { + enable = if extra.is-minimal then false else true; + drivers = [ pkgs.gutenprint ] ; + }; + + systemd.user.services.standup = { + enable = if extra.is-minimal then false else true; + description = "Standup notification"; + wantedBy = [ "graphical-session.target" ]; + after = [ "graphical-session.target" ]; + serviceConfig.ExecStart = "${pkgs.libnotify}/bin/notify-send -u critical standup"; + startAt = "Mon..Fri *-*-* 9:28:00"; + }; + + systemd.user.services.urxvtd = { + enable = true; + description = "RXVT-Unicode Daemon"; + wantedBy = [ "graphical-session.target" ]; + after = [ "graphical-session.target" ]; + path = [ pkgs.rxvt_unicode-with-plugins ]; + serviceConfig = { + Restart = "always"; + ExecStart = "${pkgs.rxvt_unicode-with-plugins}/bin/urxvtd -q -o"; + }; + }; + + systemd.user.services.xautolock = { + enable = true; + description = "X auto screen locker"; + wantedBy = [ "graphical-session.target" ]; + after = [ "graphical-session.target" ]; + serviceConfig.ExecStart = "${pkgs.xautolock}/bin/xautolock -time 10 -locker ${pkgs.slock}/bin/slock"; + }; + + services.clipmenu.enable = true; + + environment.systemPackages = [pkgs.phonectl]; + systemd.user.services.phonectl = { + enable = if extra.is-minimal then false else true; + description = "phonectl"; + wantedBy = [ "graphical-session.target" ]; + after = [ "graphical-session.target" ]; + + serviceConfig.ExecStart = "${pkgs.phonectl}/bin/phonectld"; + + environment = with secrets.phonectl; { + PHONECTLUSER=user; + PHONECTLPASS=pass; + PHONECTLPHONE=phone; + }; + }; + + # TODO: maybe doesn't have my package env + # systemd.user.services.xbindkeys = { + # enable = true; + # description = "X key bind helper"; + # wantedBy = [ "graphical-session.target" ]; + # after = [ "graphical-session.target" ]; + # serviceConfig.ExecStart = "${pkgs.xbindkeys}/bin/xbindkeys -n -f ${pkgs.jb55-dotfiles}/.xbindkeysrc"; + # }; + + systemd.user.services.dunst = { + enable = if extra.is-minimal then false else true; + + description = "dunst notifier"; + wantedBy = [ "graphical-session.target" ]; + after = [ "graphical-session.target" ]; + serviceConfig.ExecStart = "${pkgs.dunst}/bin/dunst"; + }; + + systemd.user.services.xinitrc = { + enable = true; + description = "X session init commands"; + wantedBy = [ "graphical-session.target" ]; + after = [ "graphical-session.target" ]; + + serviceConfig = { + Type = "oneshot"; + RemainAfterExit = true; + ExecStart = "${userConfig}/bin/xinitrc"; + }; + }; + +} diff --git a/nix-config/services/desktop/networking/default.nix b/nix-config/services/desktop/networking/default.nix @@ -0,0 +1,204 @@ +extra: +{ config, lib, pkgs, ... }: +let + chromecastIP = "192.168.86.190"; + iptables = "iptables -A nixos-fw"; + ipr = "${pkgs.iproute}/bin/ip"; + writeBash = extra.util.writeBash; + vpn = { + name = "pia"; + table = "300"; + credfile = pkgs.writeText "vpncreds" '' + ${extra.private.vpncred.user} + ${extra.private.vpncred.pass} + ''; + routeup = writeBash "openvpn-pia-routeup" '' + ${pkgs.iproute}/bin/ip route add default via $route_vpn_gateway dev $dev metric 1 table ${vpn.table} + exit 0 + ''; +# up = writeBash "openvpn-pia-preup" config.services.openvpn.servers.pia.up; +# down = writeBash "openvpn-pia-stop" config.services.openvpn.servers.pia.down; + }; + +in +{ + #networking.nameservers = [ "1.1.1.1" "8.8.8.8" ]; + + networking.firewall.extraCommands = + # openvpn stuff, we only want to do this once + if builtins.hasAttr "services" config.services.openvpn && config.services.openvpn.services.pia != null then '' + # mangle packets in cgroup with a mark + iptables -t mangle -A OUTPUT -m cgroup --cgroup 11 -j MARK --set-mark 11 + + # NAT packets in cgroup through VPN tun interface + iptables -t nat -A POSTROUTING -m cgroup --cgroup 11 -o tun0 -j MASQUERADE + + # create separate routing table + ${ipr} rule add fwmark 11 table ${vpn.table} + + # add fallback route that blocks traffic, should the VPN go down + ${ipr} route add blackhole default metric 2 table ${vpn.table} + '' else ""; + + networking.firewall.extraStopCommands = + if builtins.hasAttr "services" config.services.openvpn && config.services.openvpn.services.pia != null then '' + # mangle packets in cgroup with a mark + iptables -t mangle -D OUTPUT -m cgroup --cgroup 11 -j MARK --set-mark 11 || true + + # NAT packets in cgroup through VPN tun interface + iptables -t nat -D POSTROUTING -m cgroup --cgroup 11 -o tun0 -j MASQUERADE || true + + # remove separate routing table + ${ipr} rule del fwmark 11 table ${vpn.table} || true + ${ipr} route del blackhole default metric 2 table ${vpn.table} || true + '' else ""; + + users.extraGroups.vpn-pia.members = [ "jb55" "transmission" ]; + users.extraGroups.tor.members = [ "jb55" ]; + + systemd.services.openvpn-pia.path = [ pkgs.libcgroup ]; + services.openvpn.servers = { + pia = { + autoStart = false; + + config = '' + client + dev tun + proto udp + remote 66.115.146.27 1194 + resolv-retry infinite + remote-random + nobind + tun-mtu 1500 + tun-mtu-extra 32 + mssfix 1450 + persist-key + persist-tun + ping 15 + ping-restart 0 + ping-timer-rem + reneg-sec 0 + comp-lzo no + + remote-cert-tls server + + auth-user-pass ${vpn.credfile} + fast-io + cipher AES-256-CBC + auth SHA512 + + route-noexec + route-up ${vpn.routeup} + + <ca> + -----BEGIN CERTIFICATE----- + MIIFCjCCAvKgAwIBAgIBATANBgkqhkiG9w0BAQ0FADA5MQswCQYDVQQGEwJQQTEQ + MA4GA1UEChMHTm9yZFZQTjEYMBYGA1UEAxMPTm9yZFZQTiBSb290IENBMB4XDTE2 + MDEwMTAwMDAwMFoXDTM1MTIzMTIzNTk1OVowOTELMAkGA1UEBhMCUEExEDAOBgNV + BAoTB05vcmRWUE4xGDAWBgNVBAMTD05vcmRWUE4gUm9vdCBDQTCCAiIwDQYJKoZI + hvcNAQEBBQADggIPADCCAgoCggIBAMkr/BYhyo0F2upsIMXwC6QvkZps3NN2/eQF + kfQIS1gql0aejsKsEnmY0Kaon8uZCTXPsRH1gQNgg5D2gixdd1mJUvV3dE3y9FJr + XMoDkXdCGBodvKJyU6lcfEVF6/UxHcbBguZK9UtRHS9eJYm3rpL/5huQMCppX7kU + eQ8dpCwd3iKITqwd1ZudDqsWaU0vqzC2H55IyaZ/5/TnCk31Q1UP6BksbbuRcwOV + skEDsm6YoWDnn/IIzGOYnFJRzQH5jTz3j1QBvRIuQuBuvUkfhx1FEwhwZigrcxXu + MP+QgM54kezgziJUaZcOM2zF3lvrwMvXDMfNeIoJABv9ljw969xQ8czQCU5lMVmA + 37ltv5Ec9U5hZuwk/9QO1Z+d/r6Jx0mlurS8gnCAKJgwa3kyZw6e4FZ8mYL4vpRR + hPdvRTWCMJkeB4yBHyhxUmTRgJHm6YR3D6hcFAc9cQcTEl/I60tMdz33G6m0O42s + Qt/+AR3YCY/RusWVBJB/qNS94EtNtj8iaebCQW1jHAhvGmFILVR9lzD0EzWKHkvy + WEjmUVRgCDd6Ne3eFRNS73gdv/C3l5boYySeu4exkEYVxVRn8DhCxs0MnkMHWFK6 + MyzXCCn+JnWFDYPfDKHvpff/kLDobtPBf+Lbch5wQy9quY27xaj0XwLyjOltpiST + LWae/Q4vAgMBAAGjHTAbMAwGA1UdEwQFMAMBAf8wCwYDVR0PBAQDAgEGMA0GCSqG + SIb3DQEBDQUAA4ICAQC9fUL2sZPxIN2mD32VeNySTgZlCEdVmlq471o/bDMP4B8g + nQesFRtXY2ZCjs50Jm73B2LViL9qlREmI6vE5IC8IsRBJSV4ce1WYxyXro5rmVg/ + k6a10rlsbK/eg//GHoJxDdXDOokLUSnxt7gk3QKpX6eCdh67p0PuWm/7WUJQxH2S + DxsT9vB/iZriTIEe/ILoOQF0Aqp7AgNCcLcLAmbxXQkXYCCSB35Vp06u+eTWjG0/ + pyS5V14stGtw+fA0DJp5ZJV4eqJ5LqxMlYvEZ/qKTEdoCeaXv2QEmN6dVqjDoTAo + k0t5u4YRXzEVCfXAC3ocplNdtCA72wjFJcSbfif4BSC8bDACTXtnPC7nD0VndZLp + +RiNLeiENhk0oTC+UVdSc+n2nJOzkCK0vYu0Ads4JGIB7g8IB3z2t9ICmsWrgnhd + NdcOe15BincrGA8avQ1cWXsfIKEjbrnEuEk9b5jel6NfHtPKoHc9mDpRdNPISeVa + wDBM1mJChneHt59Nh8Gah74+TM1jBsw4fhJPvoc7Atcg740JErb904mZfkIEmojC + VPhBHVQ9LHBAdM8qFI2kRK0IynOmAZhexlP/aT/kpEsEPyaZQlnBn3An1CRz8h0S + PApL8PytggYKeQmRhl499+6jLxcZ2IegLfqq41dzIjwHwTMplg+1pKIOVojpWA== + -----END CERTIFICATE----- + </ca> + key-direction 1 + <tls-auth> + # + # 2048 bit OpenVPN static key + # + -----BEGIN OpenVPN Static key V1----- + e685bdaf659a25a200e2b9e39e51ff03 + 0fc72cf1ce07232bd8b2be5e6c670143 + f51e937e670eee09d4f2ea5a6e4e6996 + 5db852c275351b86fc4ca892d78ae002 + d6f70d029bd79c4d1c26cf14e9588033 + cf639f8a74809f29f72b9d58f9b8f5fe + fc7938eade40e9fed6cb92184abb2cc1 + 0eb1a296df243b251df0643d53724cdb + 5a92a1d6cb817804c4a9319b57d53be5 + 80815bcfcb2df55018cc83fc43bc7ff8 + 2d51f9b88364776ee9d12fc85cc7ea5b + 9741c4f598c485316db066d52db4540e + 212e1518a9bd4828219e24b20d88f598 + a196c9de96012090e333519ae18d3509 + 9427e7b372d348d352dc4c85e18cd4b9 + 3f8a56ddb2e64eb67adfc9b337157ff4 + -----END OpenVPN Static key V1----- + </tls-auth> + ''; + + up = '' + # enable ip forwarding + echo 1 > /proc/sys/net/ipv4/ip_forward + + # create cgroup for 3rd party VPN (can change 'vpn' to your name of choice) + mkdir -p /sys/fs/cgroup/net_cls/${vpn.name} + + # give it an arbitrary id + echo 11 > /sys/fs/cgroup/net_cls/${vpn.name}/net_cls.classid + + # grant a non-root user access + cgcreate -t jb55:vpn-pia -a jb55:vpn-pia -g net_cls:${vpn.name} + + # disable reverse path filtering for all interfaces + for i in /proc/sys/net/ipv4/conf\/*/rp_filter; do echo 0 > $i; done + ''; + + down = '' + echo 0 > /proc/sys/net/ipv4/ip_forward + + cgdelete -g net_cls:${vpn.name} + + # not sure if cgdelete does this... + rm -rf /sys/fs/cgroup/net_cls/${vpn.name} + ''; + }; + }; + + networking.firewall.checkReversePath = false; + networking.firewall.logReversePathDrops = true; + + #systemd.services.tor.requires = [ "openvpn-pia.service" ]; + #systemd.services.tor.after = [ "openvpn-pia.service" ]; + #systemd.services.tor.serviceConfig.ExecStart = lib.mkForce ( + # writeBash "start-tor-under-vpn" '' + # exec ${pkgs.libcgroup}/bin/cgexec --sticky -g net_cls:pia \ + # ${pkgs.tor}/bin/tor -f ${config.services.tor.rcFile} + # '' + #); + + systemd.services.transmission.requires = [ "openvpn-pia.service" ]; + systemd.services.transmission.after = [ "openvpn-pia.service" ]; + systemd.services.transmission.serviceConfig.User = lib.mkForce "root"; + systemd.services.transmission.serviceConfig.ExecStart = lib.mkForce ( + writeBash "start-transmission-under-vpn" '' + exec ${pkgs.libcgroup}/bin/cgexec --sticky -g net_cls:pia \ + ${pkgs.sudo}/bin/sudo -u transmission \ + ${pkgs.transmission}/bin/transmission-daemon \ + -f \ + --port ${toString config.services.transmission.port}; + '' + ); + + +} diff --git a/nix-config/services/fail-notifier/default.nix b/nix-config/services/fail-notifier/default.nix @@ -0,0 +1,56 @@ +{ config, lib, pkgs, ... }: +{ + systemd.services."notify-failed@" = { + description = "Job failure notifier"; + + serviceConfig.ExecStart = let script = pkgs.writeScript "failure-notifier" '' + #!${pkgs.bash}/bin/bash + + UNIT=$1 + + /run/wrappers/bin/sendmail -f bill@monstercat.com -t <<ERRMAIL + To: bill@monstercat.com + From: systemd <root@$HOSTNAME> + Subject: $UNIT Failed + Content-Transfer-Encoding: 8bit + Content-Type: text/plain; charset=UTF-8 + + $2 + $3 + $4 + + $(systemctl status $UNIT) + ERRMAIL + ''; + in "${script} %I 'Hostname: %H' 'Machine ID: %m' 'Boot ID: %b'"; + + }; + + # todo: abstract + systemd.user.services."notify-failed-user@" = { + description = "Job failure notifier"; + + serviceConfig.ExecStart = let script = pkgs.writeScript "failure-notifier" '' + #!${pkgs.bash}/bin/bash + + UNIT=$1 + + /run/wrappers/bin/sendmail -f bill@monstercat.com -t <<ERRMAIL + To: bill@monstercat.com + From: systemd <root@$HOSTNAME> + Subject: user $UNIT Failed + Content-Transfer-Encoding: 8bit + Content-Type: text/plain; charset=UTF-8 + + $2 + $3 + $4 + + $(systemctl --user status $UNIT) + ERRMAIL + ''; + in "${script} %I 'Hostname: %H' 'Machine ID: %m' 'Boot ID: %b'"; + + }; + +} diff --git a/nix-config/services/footswitch/default.nix b/nix-config/services/footswitch/default.nix @@ -0,0 +1,72 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + + cfg = config.services.footswitch; + +in { + + options.services.footswitch = { + enable = mkOption { + type = types.bool; + default = false; + example = true; + description = "Enable foot switch"; + }; + + enable-led = mkOption { + type = types.bool; + default = false; + example = true; + description = "Enable foot switch led"; + }; + + led = mkOption { + type = types.string; + default = "input2::scrolllock"; + example = "input2::scrolllock"; + description = "/sys/class/leds/<led> to turn on when foot switch is pressed"; + }; + + args = mkOption { + type = types.string; + default = "-m alt"; + example = "-m ctrl"; + description = "footswitch arguments"; + }; + + }; + + config = mkIf cfg.enable { + systemd.services.footswitch = { + description = "Footswitch Setup"; + + wantedBy = [ "multi-user.target" ]; + + serviceConfig.Type = "oneshot"; + serviceConfig.RemainAfterExit = "yes"; + serviceConfig.ExecStart = "${pkgs.footswitch}/bin/footswitch ${cfg.args}"; + }; + + + systemd.services.footswitch-led = mkIf cfg.enable-led { + description = "Footswitch LED"; + + wantedBy = [ "multi-user.target" ]; + + serviceConfig.Type = "simple"; + serviceConfig.ExecStart = pkgs.writeScript "footswitch-led" '' + #!${pkgs.bash}/bin/bash + ${pkgs.evtest}/bin/evtest /dev/input/by-id/usb-RDing_FootSwitch1F1.-event-kbd | \ + stdbuf -oL grep KEY_ | \ + stdbuf -oL sed 's/.*value \(.\)$/\1/' | \ + stdbuf -oL tr '2' '1' | \ + while read x; do echo $x > /sys/class/leds/${cfg.led}/brightness; done + ''; + }; + }; + + +} diff --git a/nix-config/services/hoogle/default.nix b/nix-config/services/hoogle/default.nix @@ -0,0 +1,66 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + + cfg = config.services.hoogle; + ghcWithHoogle = pkgs.haskellPackages.ghcWithHoogle; + +in { + + options.services.hoogle = { + enable = mkOption { + type = types.bool; + default = false; + example = true; + description = '' + Enable Hoogle to run a documentation server for a list of haskell packages + ''; + }; + + port = mkOption { + type = types.int; + default = 8080; + description = '' + Number of the port Hoogle will be listening to. + ''; + }; + + packages = mkOption { + default = hp: []; + example = "hp: with hp; [ text lens ]"; + description = '' + A function that takes a haskell package set and returns a list of + packages from it. + ''; + }; + + haskellPackages = mkOption { + description = "Which haskell package set to use."; + example = "pkgs.haskell.packages.ghc704"; + default = pkgs.haskellPackages; + type = types.attrs; + }; + }; + + config = mkIf cfg.enable { + systemd.services.hoogle = { + description = "Hoogle Haskell documentation search"; + wantedBy = [ "multi-user.target" ]; + serviceConfig = { + Restart = "always"; + ExecStart = + let env = cfg.haskellPackages.ghcWithHoogle cfg.packages; + hoogleEnv = pkgs.buildEnv { + name = "hoogleServiceEnv"; + paths = [env]; + }; + in '' + ${hoogleEnv}/bin/hoogle server --local -p ${toString cfg.port} + ''; + }; + }; + }; + +} diff --git a/nix-config/services/mailz/default.nix b/nix-config/services/mailz/default.nix @@ -0,0 +1,331 @@ + +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.services.mailz; + mailbox = name: '' + mailbox ${name} { + auto = subscribe + } + ''; + + # Convert: + # + # { + # a = { aliases = [ "x", "y" ]; }; + # b = { aliases = [ "x" ]; }; + # } + # + # To: + # + # { + # x = [ "a" "b" ]; + # y = [ "a" ]; + # } + aliases = foldAttrs (user: users: [user] ++ users) [ ] + (flatten (flip mapAttrsToList cfg.users + (user: options: flip map options.aliases + (alias: { ${alias} = user; })))); + + files = { + credentials = pkgs.writeText "credentials" + (concatStringsSep "\n" + (flip mapAttrsToList cfg.users + (user: options: "${user}@${cfg.domain} ${options.password}"))); + + users = pkgs.writeText "users" + (concatStringsSep "\n" + (flip mapAttrsToList cfg.users + (user: options: "${user}:${options.password}:::::"))); + + recipients = pkgs.writeText "recipients" + (concatStringsSep "\n" + (map (user: "${user}@${cfg.domain}") + (attrNames cfg.users ++ flatten ((flip mapAttrsToList) cfg.users + (user: options: options.aliases))))); + + aliases = pkgs.writeText "aliases" + (concatStringsSep "\n" + (flip mapAttrsToList aliases + (alias: users: "${alias} ${concatStringsSep "," users}"))); + + spamassassinSieve = pkgs.writeText "spamassassin.sieve" '' + require "fileinto"; + if header :contains "X-Spam-Flag" "YES" { + fileinto "Spam"; + } + ''; + + # From <https://github.com/OpenSMTPD/OpenSMTPD-extras/blob/master/extras/wip/filters/filter-regex/filter-regex.conf> + regex = pkgs.writeText "filter-regex.conf" '' + helo ! ^\[ + helo ^\. + helo \.$ + helo ^[^\.]*$ + ''; + }; + +in + +{ + options = { + services.mailz = { + domain = mkOption { + default = cfg.networking.hostName; + type = types.str; + description = "Domain for this mail server."; + }; + + enable = mkEnableOption "enable mailz: self-hosted email"; + + user = mkOption { + default = "vmail"; + type = types.str; + }; + + sieves = mkOption { + default = ""; + type = types.str; + }; + + group = mkOption { + default = "vmail"; + type = types.str; + }; + + uid = mkOption { + default = 2000; + type = types.int; + }; + + gid = mkOption { + default = 2000; + type = types.int; + }; + + dkimDirectory = mkOption { + default = "/var/lib/dkim"; + type = types.str; + description = "Where to store DKIM keys."; + }; + + dkimBits = mkOption { + type = types.int; + default = 2048; + description = "Size of the generated DKIM key."; + }; + + users = mkOption { + default = { }; + type = types.loaOf types.optionSet; + description = '' + Attribute set of users. + ''; + + options = { + password = mkOption { + type = types.str; + description = '' + The user password, generated with + <literal>smtpctl encrypt</literal>. + ''; + }; + + aliases = mkOption { + type = types.listOf types.str; + default = [ ]; + example = [ "postmaster" ]; + description = "A list of aliases for this user."; + }; + }; + + example = { + "foo" = { + password = "encrypted"; + aliases = [ "postmaster" ]; + }; + "bar" = { + password = "encrypted"; + }; + }; + }; + }; + }; + + config = mkIf (cfg.enable && cfg.users != { }) { + nixpkgs.config.packageOverrides = pkgs: { + opensmtpd = pkgs.callPackage ./opensmtpd.nix { }; + opensmtpd-extras = pkgs.opensmtpd-extras.override { + # Needed to have PRNG working in chroot (for dkim-signer) + openssl = pkgs.libressl; + }; + }; + + system.activationScripts.mailz = '' + # Make sure SpamAssassin database is present + if ! [ -d /etc/spamassassin ]; then + cp -r ${pkgs.spamassassin}/share/spamassassin /etc + fi + + # Make sure a DKIM private key exist + if ! [ -d ${cfg.dkimDirectory}/${cfg.domain} ]; then + mkdir -p ${cfg.dkimDirectory}/${cfg.domain} + chmod 700 ${cfg.dkimDirectory}/${cfg.domain} + ${pkgs.opendkim}/bin/opendkim-genkey --bits ${toString cfg.dkimBits} --domain ${cfg.domain} --directory ${cfg.dkimDirectory}/${cfg.domain} + fi + ''; + + services.spamassassin.enable = true; + + services.opensmtpd = { + enable = true; + serverConfiguration = '' + filter smtp connect check-rdns reject "550 you need a reverse DNS" + filter smtp ehlo check-rdns reject "550 your HELO hostname and rDNS mismatch" + + filter filter-pause pause + filter filter-regex regex "${files.regex}" + filter filter-spamassassin spamassassin "-s accept" + filter filter-dkim-signer dkim-signer "-d ${cfg.domain}" "-p${cfg.dkimDirectory}/${cfg.domain}/default.private" + + pki ${cfg.domain} certificate "/var/lib/acme/${cfg.domain}/fullchain.pem" + pki ${cfg.domain} key "/var/lib/acme/${cfg.domain}/key.pem" + + table credentials file:${files.credentials} + table recipients file:${files.recipients} + table aliases file:${files.aliases} + + listen on 0.0.0.0 port 25 hostname ${cfg.domain} filter in tls pki ${cfg.domain} + listen on 0.0.0.0 port 12566 hostname ${cfg.domain} filter out tls-require pki ${cfg.domain} auth <credentials> + + accept from any for domain "${cfg.domain}" recipient <recipients> alias <aliases> deliver to lmtp localhost:24 + accept from local for any relay + ''; + procPackages = [ pkgs.opensmtpd-extras ]; + }; + + services.dovecot2 = { + enable = true; + enablePop3 = false; + enableLmtp = true; + mailLocation = "maildir:/var/spool/mail/%n"; + mailUser = cfg.user; + mailGroup = cfg.group; + modules = [ pkgs.dovecot_pigeonhole ]; + sslServerCert = "/var/lib/acme/${cfg.domain}/fullchain.pem"; + sslServerKey = "/var/lib/acme/${cfg.domain}/key.pem"; + enablePAM = false; + sieveScripts = { + before = files.spamassassinSieve; + before2 = pkgs.writeText "sieves" cfg.sieves; + }; + extraConfig = '' + postmaster_address = postmaster@${cfg.domain} + mail_attribute_dict = file:/var/spool/mail/%n/dovecot-attributes + + service lmtp { + inet_listener lmtp { + address = 127.0.0.1 ::1 + port = 24 + } + } + + service imap-login { + inet_listener imaps { + port = 12788 + ssl = yes + } + } + + userdb { + driver = passwd-file + args = username_format=%n ${files.users} + default_fields = uid=${cfg.user} gid=${cfg.user} home=/var/spool/mail/%n + } + + passdb { + driver = passwd-file + args = username_format=%n ${files.users} + } + + namespace inbox { + inbox = yes + + mailbox Sent { + auto = subscribe + special_use = \Sent + } + + mailbox Drafts { + auto = subscribe + special_use = \Drafts + } + + mailbox Spam { + auto = subscribe + special_use = \Junk + } + + mailbox Trash { + auto = subscribe + special_use = \Trash + } + + mailbox Archives { + auto = subscribe + special_use = \Archive + } + + ${mailbox "Alerts"} + ${mailbox "RSS"} + ${mailbox "GitHub"} + ${mailbox "Lists"} + ${mailbox "YouTube"} + ${mailbox "Lists.ats"} + ${mailbox "Arxiv"} + ${mailbox "Reddit"} + ${mailbox "Lists.lobsters"} + ${mailbox "Lists.icn"} + ${mailbox "HackerNews"} + ${mailbox "Lists.craigslist"} + ${mailbox "Lists.bitcoin"} + ${mailbox "Lists.elm"} + ${mailbox "Lists.emacs"} + ${mailbox "Lists.guix"} + ${mailbox "Lists.haskell"} + ${mailbox "Lists.lkml"} + ${mailbox "Lists.nix"} + ${mailbox "Lists.nixpkgs"} + ${mailbox "Lists.shen"} + ${mailbox "Lists.spacemacs"} + ${mailbox "Monstercat"} + ${mailbox "Updates"} + + } + + protocol lmtp { + mail_plugins = $mail_plugins sieve notify push_notification + } + + protocol imap { + imap_metadata = yes + } + ''; + }; + + # users.extraUsers = optional (cfg.user == "vmail") { + # name = "vmail"; + # uid = cfg.uid; + # group = cfg.group; + # }; + + # users.extraGroups = optional (cfg.group == "vmail") { + # name = "vmail"; + # gid = cfg.gid; + # }; + + networking.firewall.allowedTCPPorts = [ 25 ]; + }; +} diff --git a/nix-config/services/mailz/opensmtpd.diff b/nix-config/services/mailz/opensmtpd.diff @@ -0,0 +1,21 @@ +diff --git a/smtpd/smtp.c b/smtpd/smtp.c +index 5f817be..a318b16 100644 +--- a/smtpd/smtp.c ++++ b/smtpd/smtp.c +@@ -161,6 +161,15 @@ smtp_setup_listeners(void) + sizeof(opt)) < 0) + fatal("smtpd: setsockopt"); + #endif ++#ifdef IPV6_V6ONLY ++ /* If using IPv6, bind only to IPv6 if possible. This avoids ++ ambiguities with IPv4-mapped IPv6 addresses. */ ++ if (l->ss.ss_family == AF_INET6) { ++ if (setsockopt(l->fd, IPPROTO_IPV6, IPV6_V6ONLY, &opt, ++ sizeof(opt)) < 0) ++ fatal("smtpd: setsockopt"); ++ } ++#endif + if (bind(l->fd, (struct sockaddr *)&l->ss, SS_LEN(&l->ss)) == -1) + fatal("smtpd: bind"); + } + diff --git a/nix-config/services/mailz/opensmtpd.nix b/nix-config/services/mailz/opensmtpd.nix @@ -0,0 +1,48 @@ +{ stdenv, fetchurl, autoconf, automake, libtool, bison +, libasr, libevent, zlib, openssl, db, pam, cacert +}: + +stdenv.mkDerivation rec { + name = "opensmtpd-${version}"; + version = "5.7.3p2"; + + nativeBuildInputs = [ autoconf automake libtool bison ]; + buildInputs = [ libasr libevent zlib openssl db pam ]; + + src = fetchurl { + url = "http://www.opensmtpd.org/archives/${name}.tar.gz"; + sha256 = "0d2973008d0f66bebb84bed516be6c32617735241cc54dd26643529281a8e52b"; + }; + + patches = [ ./proc_path.diff ]; + + configureFlags = [ + "--sysconfdir=/etc" + "--localstatedir=/var" + "--with-mantype=doc" + "--with-pam" + "--without-bsd-auth" + "--with-sock-dir=/run" + "--with-privsep-user=smtpd" + "--with-queue-user=smtpq" + "--with-ca-file=/etc/ssl/certs/ca-certificates.crt" + "--with-libevent-dir=${libevent}" + "--enable-table-db" + ]; + + installFlags = [ + "sysconfdir=\${out}/etc" + "localstatedir=\${TMPDIR}" + ]; + + meta = { + homepage = https://www.opensmtpd.org/; + description = '' + A free implementation of the server-side SMTP protocol as defined by + RFC 5321, with some additional standard extensions + ''; + license = stdenv.lib.licenses.isc; + platforms = stdenv.lib.platforms.linux; + maintainers = [ stdenv.lib.maintainers.rickynils ]; + }; +} diff --git a/nix-config/services/mailz/proc_path.diff b/nix-config/services/mailz/proc_path.diff @@ -0,0 +1,76 @@ +diff -Naur opensmtpd-5.7.1p1/smtpd/parse.y opensmtpd-5.7.1p1.patched/smtpd/parse.y +--- opensmtpd-5.7.1p1/smtpd/parse.y 2015-06-30 10:13:34.000000000 +0200 ++++ opensmtpd-5.7.1p1.patched/smtpd/parse.y 2015-09-26 08:41:17.012472516 +0200 +@@ -2519,13 +2519,19 @@ + { + struct filter_conf *f; + char *path; ++ const char *proc_path; + + if (dict_get(&conf->sc_filters, name)) { + yyerror("filter \"%s\" already defined", name); + return (NULL); + } + +- if (asprintf(&path, "%s/filter-%s", PATH_LIBEXEC, prog) == -1) { ++ proc_path = getenv("OPENSMTPD_PROC_PATH"); ++ if (proc_path == NULL) { ++ proc_path = PATH_LIBEXEC; ++ } ++ ++ if (asprintf(&path, "%s/filter-%s", proc_path, prog) == -1) { + yyerror("filter \"%s\" asprintf failed", name); + return (0); + } +diff -Naur opensmtpd-5.7.1p1/smtpd/smtpd.c opensmtpd-5.7.1p1.patched/smtpd/smtpd.c +--- opensmtpd-5.7.1p1/smtpd/smtpd.c 2015-06-30 10:13:34.000000000 +0200 ++++ opensmtpd-5.7.1p1.patched/smtpd/smtpd.c 2015-09-26 08:41:16.998472557 +0200 +@@ -854,6 +854,7 @@ + char path[PATH_MAX]; + char name[PATH_MAX]; + char *arg; ++ char *proc_path; + + if (strlcpy(name, conf, sizeof(name)) >= sizeof(name)) { + log_warnx("warn: %s-proc: conf too long", key); +@@ -864,7 +865,12 @@ + if (arg) + *arg++ = '\0'; + +- if (snprintf(path, sizeof(path), PATH_LIBEXEC "/%s-%s", key, name) >= ++ proc_path = getenv("OPENSMTPD_PROC_PATH"); ++ if (proc_path == NULL) { ++ proc_path = PATH_LIBEXEC; ++ } ++ ++ if (snprintf(path, sizeof(path), "%s/%s-%s", proc_path, key, name) >= + (ssize_t)sizeof(path)) { + log_warn("warn: %s-proc: exec path too long", key); + return (-1); +diff -Naur opensmtpd-5.7.1p1/smtpd/table.c opensmtpd-5.7.1p1.patched/smtpd/table.c +--- opensmtpd-5.7.1p1/smtpd/table.c 2015-06-30 10:13:34.000000000 +0200 ++++ opensmtpd-5.7.1p1.patched/smtpd/table.c 2015-09-26 08:41:17.005472536 +0200 +@@ -201,6 +201,7 @@ + struct table_backend *tb; + char buf[LINE_MAX]; + char path[LINE_MAX]; ++ const char *proc_path; + size_t n; + struct stat sb; + +@@ -215,8 +216,14 @@ + if (name && table_find(name, NULL)) + fatalx("table_create: table \"%s\" already defined", name); + ++ proc_path = getenv("OPENSMTPD_PROC_PATH"); ++ if (proc_path == NULL) { ++ proc_path = PATH_LIBEXEC; ++ } ++ + if ((tb = table_backend_lookup(backend)) == NULL) { +- if ((size_t)snprintf(path, sizeof(path), PATH_LIBEXEC "/table-%s", ++ if ((size_t)snprintf(path, sizeof(path), "%s/table-%s", ++ proc_path, + backend) >= sizeof(path)) { + fatalx("table_create: path too long \"" + PATH_LIBEXEC "/table-%s\"", backend); diff --git a/nix-config/services/pokemongo-map/default.nix b/nix-config/services/pokemongo-map/default.nix @@ -0,0 +1,53 @@ +extra: +{ config, lib, pkgs, ... }: +with lib; +let private = extra.private; + foldAttr = lib.lists.fold (a: b: a // b) {}; + foldMap = fn: foldAttr (map fn private.pokemaps); + mkName = def: "pogom-${def.subdomain}"; + mkOptions = def: { "${mkName def}" = { enable = mkEnableOption "PokemonGO-Map, ${def.subdomain}";}; }; + mkService = def: mkIf config.services."${mkName def}".enable (services def); + pythonEnv = import ./requirements.nix {}; + pokemonMap = pkgs.fetchFromGitHub { + owner = "jb55"; + repo = "PokemonGo-Map"; + rev = "a63721bfadc318b1f158f53e0cc532a4e16091ef"; + sha256 = "11m8h38glpbm2va4xxjfsvpigfmmjf531w1db2nqfccnkw872k75"; + }; + services = def: { + "${mkName def}" = { + description = "PokemonGO-Map, ${def.subdomain}"; + + wantedBy = [ "multi-user.target" ]; + + environment = { + AUTH_SERVICE = def.service; + USERNAME = def.user; + PASSWORD = def.pass; + LOCATION = def.location; + GMAPS_KEY = def.mapkey; + STEP_COUNT = "5"; + PORT = def.port; + }; + + serviceConfig.Type = "simple"; + serviceConfig.ExecStartPre = "${pkgs.coreutils}/bin/mkdir -p /var/db/pogom"; + serviceConfig.ExecStart = pkgs.writeScript "run-pogom" '' + #!${pkgs.bash}/bin/bash + ${pythonEnv.interpreter}/bin/python ${pokemonMap}/runserver.py \ + -a "$AUTH_SERVICE" \ + -u "$USERNAME" \ + -p "$PASSWORD" \ + -l "$LOCATION" \ + -st $STEP_COUNT \ + -D /var/db/pogom/pogom-${def.subdomain}.db \ + -wh "https://jb55.com/pogom" \ + -H 0.0.0.0 \ + -P $PORT \ + -k $GMAPS_KEY + ''; + }; + }; +in { options.services = foldMap mkOptions; + config.systemd.services = foldMap mkService; + } diff --git a/nix-config/services/pokemongo-map/requirements.nix b/nix-config/services/pokemongo-map/requirements.nix @@ -0,0 +1,41 @@ +# generated using pypi2nix tool (version: 1.3.0dev) +# See more at: https://github.com/garbas/pypi2nix +# +# COMMAND: +# pypi2nix -V 2.7 -r requirements.txt -E stdenv -E sqlite +# + +{ pkgs ? import <nixpkgs> {} +}: + +let + + inherit (pkgs.stdenv.lib) fix' extends inNixShell; + + pythonPackages = pkgs.python27Packages; + commonBuildInputs = with pkgs; [ sqlite ]; + commonDoCheck = false; + + buildEnv = { pkgs ? {}, modules ? {} }: + let + interpreter = pythonPackages.python.buildEnv.override { + extraLibs = (builtins.attrValues pkgs) ++ (builtins.attrValues modules); + }; + in { + mkDerivation = pythonPackages.buildPythonPackage; + interpreter = if inNixShell then interpreter.env else interpreter; + overrideDerivation = drv: f: pythonPackages.buildPythonPackage (drv.drvAttrs // f drv.drvAttrs); + pkgs_top_level = builtins.filter (x: !(builtins.hasAttr "top_level" x.passthru)) ( + builtins.attrValues (builtins.removeAttrs pkgs ["__unfix__"])); + inherit buildEnv pkgs modules; + }; + + python = buildEnv {}; + generated = import ./requirements_generated.nix { inherit pkgs python commonBuildInputs commonDoCheck; }; + overrides = import ./requirements_override.nix { inherit pkgs python; }; + + python' = buildEnv { + pkgs = fix' (extends overrides generated); + }; + +in python'+ \ No newline at end of file diff --git a/nix-config/services/pokemongo-map/requirements_generated.nix b/nix-config/services/pokemongo-map/requirements_generated.nix @@ -0,0 +1,973 @@ +# generated using pypi2nix tool (version: 1.3.0dev) +# +# COMMAND: +# pypi2nix -V 2.7 -r requirements.txt -E stdenv -E sqlite +# + +{ pkgs, python, commonBuildInputs ? [], commonDoCheck ? false }: + +self: { + + "Babel" = python.mkDerivation { + name = "Babel-2.3.4"; + src = pkgs.fetchurl { + url = "https://pypi.python.org/packages/6e/96/ba2a2462ed25ca0e651fb7b66e7080f5315f91425a07ea5b34d7c870c114/Babel-2.3.4.tar.gz"; + sha256= "c535c4403802f6eb38173cd4863e419e2274921a01a8aad8a5b497c131c62875"; + }; + doCheck = commonDoCheck; + buildInputs = commonBuildInputs; + propagatedBuildInputs = [ + self."pytz" + ]; + meta = with pkgs.stdenv.lib; { + homepage = ""; + license = licenses.bsdOriginal; + description = "Internationalization utilities"; + }; + passthru.top_level = false; + }; + + + + "CommonMark" = python.mkDerivation { + name = "CommonMark-0.5.4"; + src = pkgs.fetchurl { + url = "https://pypi.python.org/packages/4d/93/3808cbcebe94d205f55a9a32857df733a603339d32c46cd32669d808d964/CommonMark-0.5.4.tar.gz"; + sha256= "34d73ec8085923c023930dfc0bcd1c4286e28a2a82de094bb72fabcc0281cbe5"; + }; + doCheck = commonDoCheck; + buildInputs = commonBuildInputs; + propagatedBuildInputs = [ ]; + meta = with pkgs.stdenv.lib; { + homepage = ""; + license = licenses.bsdOriginal; + description = "Python parser for the CommonMark Markdown spec"; + }; + passthru.top_level = false; + }; + + + + "ConfigArgParse" = python.mkDerivation { + name = "ConfigArgParse-0.10.0"; + src = pkgs.fetchurl { + url = "https://pypi.python.org/packages/d0/b8/8f7689980caa66fc02671f5837dc761e4c7a47c6ca31b3e38b304cbc3e73/ConfigArgParse-0.10.0.tar.gz"; + sha256= "3b50a83dd58149dfcee98cb6565265d10b53e9c0a2bca7eeef7fb5f5524890a7"; + }; + doCheck = commonDoCheck; + buildInputs = commonBuildInputs; + propagatedBuildInputs = [ ]; + meta = with pkgs.stdenv.lib; { + homepage = ""; + license = licenses.mit; + description = "A drop-in replacement for argparse that allows options to also be set via config files and/or environment variables."; + }; + passthru.top_level = false; + }; + + + + "Flask" = python.mkDerivation { + name = "Flask-0.11.1"; + src = pkgs.fetchurl { + url = "https://pypi.python.org/packages/55/8a/78e165d30f0c8bb5d57c429a30ee5749825ed461ad6c959688872643ffb3/Flask-0.11.1.tar.gz"; + sha256= "b4713f2bfb9ebc2966b8a49903ae0d3984781d5c878591cf2f7b484d28756b0e"; + }; + doCheck = commonDoCheck; + buildInputs = commonBuildInputs; + propagatedBuildInputs = [ + self."Jinja2" + self."Werkzeug" + self."click" + self."itsdangerous" + ]; + meta = with pkgs.stdenv.lib; { + homepage = ""; + license = licenses.bsdOriginal; + description = "A microframework based on Werkzeug, Jinja2 and good intentions"; + }; + passthru.top_level = false; + }; + + + + "Flask-Compress" = python.mkDerivation { + name = "Flask-Compress-1.3.0"; + src = pkgs.fetchurl { + url = "https://pypi.python.org/packages/4d/ce/44564d794ff7342ba376a92c88f8bb07f604d5d30f506bcde2834311eda8/Flask-Compress-1.3.0.tar.gz"; + sha256= "e6c52f1e56b59e8702aed6eb73c6fb0bffe942e5ca188f10e54a33ec11bc5ed4"; + }; + doCheck = commonDoCheck; + buildInputs = commonBuildInputs; + propagatedBuildInputs = [ + self."Flask" + ]; + meta = with pkgs.stdenv.lib; { + homepage = ""; + license = licenses.mit; + description = "Compress responses in your Flask app with gzip."; + }; + passthru.top_level = false; + }; + + + + "Flask-Cors" = python.mkDerivation { + name = "Flask-Cors-2.1.2"; + src = pkgs.fetchurl { + url = "https://pypi.python.org/packages/99/c3/a65908bc5a031652248dfdb1fd4814391e7b8efca704a94008d764c45292/Flask-Cors-2.1.2.tar.gz"; + sha256= "f262e73adce557b2802a64054c82a0395576c88fbb944e3a9e1e2147140aa639"; + }; + doCheck = commonDoCheck; + buildInputs = commonBuildInputs; + propagatedBuildInputs = [ + self."Flask" + self."six" + ]; + meta = with pkgs.stdenv.lib; { + homepage = ""; + license = licenses.mit; + description = "A Flask extension adding a decorator for CORS support"; + }; + passthru.top_level = false; + }; + + + + "Jinja2" = python.mkDerivation { + name = "Jinja2-2.8"; + src = pkgs.fetchurl { + url = "https://pypi.python.org/packages/f2/2f/0b98b06a345a761bec91a079ccae392d282690c2d8272e708f4d10829e22/Jinja2-2.8.tar.gz"; + sha256= "bc1ff2ff88dbfacefde4ddde471d1417d3b304e8df103a7a9437d47269201bf4"; + }; + doCheck = commonDoCheck; + buildInputs = commonBuildInputs; + propagatedBuildInputs = [ + self."Babel" + self."MarkupSafe" + ]; + meta = with pkgs.stdenv.lib; { + homepage = ""; + license = licenses.bsdOriginal; + description = "A small but fast and easy to use stand-alone template engine written in pure python."; + }; + passthru.top_level = false; + }; + + + + "LatLon" = python.mkDerivation { + name = "LatLon-1.0.1"; + src = pkgs.fetchurl { + url = "https://pypi.python.org/packages/4a/2c/ae890794253ce8f87b8d8d7fb49a99a61c007776c92fc9faf8f1febe3e31/LatLon-1.0.1.tar.gz"; + sha256= "0a5b3ba8f48b3bdf2f2c8f91ab4f80b1fa83d5cb5e3c28d5b16b4e3b3857f4fd"; + }; + doCheck = commonDoCheck; + buildInputs = commonBuildInputs; + propagatedBuildInputs = [ + self."pyproj" + ]; + meta = with pkgs.stdenv.lib; { + homepage = ""; + license = ""; + description = "Methods for representing geographic coordinates"; + }; + passthru.top_level = false; + }; + + + + "MarkupSafe" = python.mkDerivation { + name = "MarkupSafe-0.23"; + src = pkgs.fetchurl { + url = "https://pypi.python.org/packages/c0/41/bae1254e0396c0cc8cf1751cb7d9afc90a602353695af5952530482c963f/MarkupSafe-0.23.tar.gz"; + sha256= "a4ec1aff59b95a14b45eb2e23761a0179e98319da5a7eb76b56ea8cdc7b871c3"; + }; + doCheck = commonDoCheck; + buildInputs = commonBuildInputs; + propagatedBuildInputs = [ ]; + meta = with pkgs.stdenv.lib; { + homepage = ""; + license = licenses.bsdOriginal; + description = "Implements a XML/HTML/XHTML Markup safe string for Python"; + }; + passthru.top_level = false; + }; + + + + "PyMySQL" = python.mkDerivation { + name = "PyMySQL-0.7.5"; + src = pkgs.fetchurl { + url = "https://pypi.python.org/packages/f3/4c/9d7611b78e88d1f8087e24239c3318ccd973a822577508a69570382c9064/PyMySQL-0.7.5.tar.gz"; + sha256= "5006c7cf25cdf56f0c01ab21b8255ae5753464678c84ea8d00444667cc7a34ef"; + }; + doCheck = commonDoCheck; + buildInputs = commonBuildInputs; + propagatedBuildInputs = [ ]; + meta = with pkgs.stdenv.lib; { + homepage = ""; + license = licenses.mit; + description = "Pure Python MySQL Driver"; + }; + passthru.top_level = false; + }; + + + + "PyYAML" = python.mkDerivation { + name = "PyYAML-3.11"; + src = pkgs.fetchurl { + url = "https://pypi.python.org/packages/75/5e/b84feba55e20f8da46ead76f14a3943c8cb722d40360702b2365b91dec00/PyYAML-3.11.tar.gz"; + sha256= "c36c938a872e5ff494938b33b14aaa156cb439ec67548fcab3535bb78b0846e8"; + }; + doCheck = commonDoCheck; + buildInputs = commonBuildInputs; + propagatedBuildInputs = [ ]; + meta = with pkgs.stdenv.lib; { + homepage = ""; + license = licenses.mit; + description = "YAML parser and emitter for Python"; + }; + passthru.top_level = false; + }; + + + + "Pygments" = python.mkDerivation { + name = "Pygments-2.1.3"; + src = pkgs.fetchurl { + url = "https://pypi.python.org/packages/b8/67/ab177979be1c81bc99c8d0592ef22d547e70bb4c6815c383286ed5dec504/Pygments-2.1.3.tar.gz"; + sha256= "88e4c8a91b2af5962bfa5ea2447ec6dd357018e86e94c7d14bd8cacbc5b55d81"; + }; + doCheck = commonDoCheck; + buildInputs = commonBuildInputs; + propagatedBuildInputs = [ ]; + meta = with pkgs.stdenv.lib; { + homepage = ""; + license = licenses.bsdOriginal; + description = "Pygments is a syntax highlighting package written in Python."; + }; + passthru.top_level = false; + }; + + + + "Sphinx" = python.mkDerivation { + name = "Sphinx-1.4.5"; + src = pkgs.fetchurl { + url = "https://pypi.python.org/packages/8b/78/eeea2b837f911cdc301f5f05163f9729a2381cadd03ccf35b25afe816c90/Sphinx-1.4.5.tar.gz"; + sha256= "c5df65d97a58365cbf4ea10212186a9a45d89c61ed2c071de6090cdf9ddb4028"; + }; + doCheck = commonDoCheck; + buildInputs = commonBuildInputs; + propagatedBuildInputs = [ + self."Babel" + self."Jinja2" + self."Pygments" + self."alabaster" + self."docutils" + self."imagesize" + self."six" + self."snowballstemmer" + ]; + meta = with pkgs.stdenv.lib; { + homepage = ""; + license = licenses.bsdOriginal; + description = "Python documentation generator"; + }; + passthru.top_level = false; + }; + + + + "Werkzeug" = python.mkDerivation { + name = "Werkzeug-0.11.10"; + src = pkgs.fetchurl { + url = "https://pypi.python.org/packages/b7/7f/44d3cfe5a12ba002b253f6985a4477edfa66da53787a2a838a40f6415263/Werkzeug-0.11.10.tar.gz"; + sha256= "cc64dafbacc716cdd42503cf6c44cb5a35576443d82f29f6829e5c49264aeeee"; + }; + doCheck = commonDoCheck; + buildInputs = commonBuildInputs; + propagatedBuildInputs = [ ]; + meta = with pkgs.stdenv.lib; { + homepage = ""; + license = licenses.bsdOriginal; + description = "The Swiss Army knife of Python web development"; + }; + passthru.top_level = false; + }; + + + + "alabaster" = python.mkDerivation { + name = "alabaster-0.7.9"; + src = pkgs.fetchurl { + url = "https://pypi.python.org/packages/71/c3/70da7d8ac18a4f4c502887bd2549e05745fa403e2cd9d06a8a9910a762bc/alabaster-0.7.9.tar.gz"; + sha256= "47afd43b08a4ecaa45e3496e139a193ce364571e7e10c6a87ca1a4c57eb7ea08"; + }; + doCheck = commonDoCheck; + buildInputs = commonBuildInputs; + propagatedBuildInputs = [ ]; + meta = with pkgs.stdenv.lib; { + homepage = ""; + license = ""; + description = "A configurable sidebar-enabled Sphinx theme"; + }; + passthru.top_level = false; + }; + + + + "argh" = python.mkDerivation { + name = "argh-0.26.2"; + src = pkgs.fetchurl { + url = "https://pypi.python.org/packages/e3/75/1183b5d1663a66aebb2c184e0398724b624cecd4f4b679cb6e25de97ed15/argh-0.26.2.tar.gz"; + sha256= "e9535b8c84dc9571a48999094fda7f33e63c3f1b74f3e5f3ac0105a58405bb65"; + }; + doCheck = commonDoCheck; + buildInputs = commonBuildInputs; + propagatedBuildInputs = [ ]; + meta = with pkgs.stdenv.lib; { + homepage = ""; + license = licenses.lgpl3; + description = "An unobtrusive argparse wrapper with natural syntax"; + }; + passthru.top_level = false; + }; + + + + "backports-abc" = python.mkDerivation { + name = "backports-abc-0.4"; + src = pkgs.fetchurl { + url = "https://pypi.python.org/packages/f5/d0/1d02695c0dd4f0cf01a35c03087c22338a4f72e24e2865791ebdb7a45eac/backports_abc-0.4.tar.gz"; + sha256= "8b3e4092ba3d541c7a2f9b7d0d9c0275b21c6a01c53a61c731eba6686939d0a5"; + }; + doCheck = commonDoCheck; + buildInputs = commonBuildInputs; + propagatedBuildInputs = [ ]; + meta = with pkgs.stdenv.lib; { + homepage = ""; + license = ""; + description = "A backport of recent additions to the 'collections.abc' module."; + }; + passthru.top_level = false; + }; + + + + "certifi" = python.mkDerivation { + name = "certifi-2016.8.2"; + src = pkgs.fetchurl { + url = "https://pypi.python.org/packages/60/d8/e4dbd7239f1dd3854135949cc2cc8344602b1545a7929b7bf652ac69fbb6/certifi-2016.8.2.tar.gz"; + sha256= "65ddc34fd9c8509851031d7075b8325393b87e6dbe5875a723959a20266d7a41"; + }; + doCheck = commonDoCheck; + buildInputs = commonBuildInputs; + propagatedBuildInputs = [ ]; + meta = with pkgs.stdenv.lib; { + homepage = ""; + license = "ISC"; + description = "Python package for providing Mozilla's CA Bundle."; + }; + passthru.top_level = false; + }; + + + + "click" = python.mkDerivation { + name = "click-6.6"; + src = pkgs.fetchurl { + url = "https://pypi.python.org/packages/7a/00/c14926d8232b36b08218067bcd5853caefb4737cda3f0a47437151344792/click-6.6.tar.gz"; + sha256= "cc6a19da8ebff6e7074f731447ef7e112bd23adf3de5c597cf9989f2fd8defe9"; + }; + doCheck = commonDoCheck; + buildInputs = commonBuildInputs; + propagatedBuildInputs = [ ]; + meta = with pkgs.stdenv.lib; { + homepage = ""; + license = ""; + description = "A simple wrapper around optparse for powerful command line utilities."; + }; + passthru.top_level = false; + }; + + + + "docutils" = python.mkDerivation { + name = "docutils-0.12"; + src = pkgs.fetchurl { + url = "https://pypi.python.org/packages/37/38/ceda70135b9144d84884ae2fc5886c6baac4edea39550f28bcd144c1234d/docutils-0.12.tar.gz"; + sha256= "c7db717810ab6965f66c8cf0398a98c9d8df982da39b4cd7f162911eb89596fa"; + }; + doCheck = commonDoCheck; + buildInputs = commonBuildInputs; + propagatedBuildInputs = [ ]; + meta = with pkgs.stdenv.lib; { + homepage = ""; + license = "public domain, Python, 2-Clause BSD, GPL 3 (see COPYING.txt)"; + description = "Docutils -- Python Documentation Utilities"; + }; + passthru.top_level = false; + }; + + + + "future" = python.mkDerivation { + name = "future-0.15.2"; + src = pkgs.fetchurl { + url = "https://pypi.python.org/packages/5a/f4/99abde815842bc6e97d5a7806ad51236630da14ca2f3b1fce94c0bb94d3d/future-0.15.2.tar.gz"; + sha256= "3d3b193f20ca62ba7d8782589922878820d0a023b885882deec830adbf639b97"; + }; + doCheck = commonDoCheck; + buildInputs = commonBuildInputs; + propagatedBuildInputs = [ ]; + meta = with pkgs.stdenv.lib; { + homepage = ""; + license = licenses.mit; + description = "Clean single-source support for Python 3 and 2"; + }; + passthru.top_level = false; + }; + + + + "geopy" = python.mkDerivation { + name = "geopy-1.11.0"; + src = pkgs.fetchurl { + url = "https://pypi.python.org/packages/19/d0/7128146692fb6facb956b07c40f73d7975b9a36bd8381a0cdb0c6a79a0b6/geopy-1.11.0.tar.gz"; + sha256= "4250e5a9e9f7abb990eddf01d1491fc112755e14f76060011c607ba759a74112"; + }; + doCheck = commonDoCheck; + buildInputs = commonBuildInputs; + propagatedBuildInputs = [ + self."pytz" + ]; + meta = with pkgs.stdenv.lib; { + homepage = ""; + license = licenses.mit; + description = "Python Geocoding Toolbox"; + }; + passthru.top_level = false; + }; + + + + "gpsoauth" = python.mkDerivation { + name = "gpsoauth-0.3.0"; + src = pkgs.fetchurl { + url = "https://pypi.python.org/packages/1a/e0/2d4eb28074c2168732251b01d833673f5cba379f8bbf12c4e53528946cc3/gpsoauth-0.3.0.tar.gz"; + sha256= "b3963375cd758a3c0ae9ceda044bebe954c25418ed76f977450a6197d38cdb7e"; + }; + doCheck = commonDoCheck; + buildInputs = commonBuildInputs; + propagatedBuildInputs = [ + self."pycryptodomex" + self."requests" + ]; + meta = with pkgs.stdenv.lib; { + homepage = ""; + license = licenses.mit; + description = "A python client library for Google Play Services OAuth."; + }; + passthru.top_level = false; + }; + + + + "imagesize" = python.mkDerivation { + name = "imagesize-0.7.1"; + src = pkgs.fetchurl { + url = "https://pypi.python.org/packages/53/72/6c6f1e787d9cab2cc733cf042f125abec07209a58308831c9f292504e826/imagesize-0.7.1.tar.gz"; + sha256= "0ab2c62b87987e3252f89d30b7cedbec12a01af9274af9ffa48108f2c13c6062"; + }; + doCheck = commonDoCheck; + buildInputs = commonBuildInputs; + propagatedBuildInputs = [ ]; + meta = with pkgs.stdenv.lib; { + homepage = ""; + license = licenses.mit; + description = "Getting image size from png/jpeg/jpeg2000/gif file"; + }; + passthru.top_level = false; + }; + + + + "itsdangerous" = python.mkDerivation { + name = "itsdangerous-0.24"; + src = pkgs.fetchurl { + url = "https://pypi.python.org/packages/dc/b4/a60bcdba945c00f6d608d8975131ab3f25b22f2bcfe1dab221165194b2d4/itsdangerous-0.24.tar.gz"; + sha256= "cbb3fcf8d3e33df861709ecaf89d9e6629cff0a217bc2848f1b41cd30d360519"; + }; + doCheck = commonDoCheck; + buildInputs = commonBuildInputs; + propagatedBuildInputs = [ ]; + meta = with pkgs.stdenv.lib; { + homepage = ""; + license = ""; + description = "Various helpers to pass trusted data to untrusted environments and back."; + }; + passthru.top_level = false; + }; + + + + "livereload" = python.mkDerivation { + name = "livereload-2.4.1"; + src = pkgs.fetchurl { + url = "https://pypi.python.org/packages/d3/fb/fa04cd6a08cc42e1ac089220b6f42d124d01aeb0c70fbe169a73713ca636/livereload-2.4.1.tar.gz"; + sha256= "887cc9976d72d7616fa57c82c4ef5bf5da27e2350dfd6f65d3f44e86efc51b92"; + }; + doCheck = commonDoCheck; + buildInputs = commonBuildInputs; + propagatedBuildInputs = [ + self."six" + self."tornado" + ]; + meta = with pkgs.stdenv.lib; { + homepage = ""; + license = licenses.bsdOriginal; + description = "Python LiveReload is an awesome tool for web developers"; + }; + passthru.top_level = false; + }; + + + + "pathtools" = python.mkDerivation { + name = "pathtools-0.1.2"; + src = pkgs.fetchurl { + url = "https://pypi.python.org/packages/e7/7f/470d6fcdf23f9f3518f6b0b76be9df16dcc8630ad409947f8be2eb0ed13a/pathtools-0.1.2.tar.gz"; + sha256= "7c35c5421a39bb82e58018febd90e3b6e5db34c5443aaaf742b3f33d4655f1c0"; + }; + doCheck = commonDoCheck; + buildInputs = commonBuildInputs; + propagatedBuildInputs = [ ]; + meta = with pkgs.stdenv.lib; { + homepage = ""; + license = licenses.mit; + description = "File system general utilities"; + }; + passthru.top_level = false; + }; + + + + "peewee" = python.mkDerivation { + name = "peewee-2.8.1"; + src = pkgs.fetchurl { + url = "https://pypi.python.org/packages/59/4a/a1b78b0e47e880c07da21d633ff2ac8d5edbf969049a414edfbdadaed869/peewee-2.8.1.tar.gz"; + sha256= "9fdb90124d95c02b470a23e06ae40751657d13a425d10ff39ae12943ecd7987d"; + }; + doCheck = commonDoCheck; + buildInputs = commonBuildInputs; + propagatedBuildInputs = [ ]; + meta = with pkgs.stdenv.lib; { + homepage = ""; + license = ""; + description = "a little orm"; + }; + passthru.top_level = false; + }; + + + + "pgoapi" = python.mkDerivation { + name = "pgoapi-1.1.6"; + src = pkgs.fetchurl { + url = "https://github.com/jb55/pgoapi/archive/master.tar.gz"; + sha256= "50974aee8acd3fb50a76ae80536ca767ab153e77e66519489f288e76b36d24d6"; + }; + doCheck = commonDoCheck; + buildInputs = commonBuildInputs; + propagatedBuildInputs = [ + self."geopy" + self."gpsoauth" + self."protobuf" + self."requests" + self."s2sphere" + self."six" + self."xxhash" + ]; + meta = with pkgs.stdenv.lib; { + homepage = ""; + license = ""; + description = "Pokemon Go API lib"; + }; + passthru.top_level = false; + }; + + + + "port-for" = python.mkDerivation { + name = "port-for-0.3.1"; + src = pkgs.fetchurl { + url = "https://pypi.python.org/packages/ec/f1/e7d7a36b5f3e77fba587ae3ea4791512ffff74bc1d065d6185e463279bc4/port-for-0.3.1.tar.gz"; + sha256= "b16a84bb29c2954db44c29be38b17c659c9c27e33918dec16b90d375cc596f1c"; + }; + doCheck = commonDoCheck; + buildInputs = commonBuildInputs; + propagatedBuildInputs = [ ]; + meta = with pkgs.stdenv.lib; { + homepage = ""; + license = "MIT license"; + description = "Utility that helps with local TCP ports managment. It can find an unused TCP localhost port and remember the association."; + }; + passthru.top_level = false; + }; + + + + "protobuf" = python.mkDerivation { + name = "protobuf-3.0.0"; + src = pkgs.fetchurl { + url = "https://pypi.python.org/packages/14/3e/56da1ecfa58f6da0053a523444dff9dfb8a18928c186ad529a24b0e82dec/protobuf-3.0.0.tar.gz"; + sha256= "ecc40bc30f1183b418fe0ec0c90bc3b53fa1707c4205ee278c6b90479e5b6ff5"; + }; + doCheck = commonDoCheck; + buildInputs = commonBuildInputs; + propagatedBuildInputs = [ + self."six" + ]; + meta = with pkgs.stdenv.lib; { + homepage = ""; + license = "New BSD License"; + description = "Protocol Buffers"; + }; + passthru.top_level = false; + }; + + + + "pycryptodomex" = python.mkDerivation { + name = "pycryptodomex-3.4.2"; + src = pkgs.fetchurl { + url = "https://pypi.python.org/packages/67/9a/a9b49b2225af75bab5328b987f5cf3fd73306188b9272bd69bcf8c57ef04/pycryptodomex-3.4.2.tar.gz"; + sha256= "66489980aa0dd97dce28171c5f42e9862d33cc354a518e52a7bad0699d9b402a"; + }; + doCheck = commonDoCheck; + buildInputs = commonBuildInputs; + propagatedBuildInputs = [ ]; + meta = with pkgs.stdenv.lib; { + homepage = ""; + license = ""; + description = "Cryptographic library for Python"; + }; + passthru.top_level = false; + }; + + + + "pyproj" = python.mkDerivation { + name = "pyproj-1.9.5.1"; + src = pkgs.fetchurl { + url = "https://pypi.python.org/packages/29/72/5c1888c4948a0c7b736d10e0f0f69966e7c0874a660222ed0a2c2c6daa9f/pyproj-1.9.5.1.tar.gz"; + sha256= "53fa54c8fa8a1dfcd6af4bf09ce1aae5d4d949da63b90570ac5ec849efaf3ea8"; + }; + doCheck = commonDoCheck; + buildInputs = commonBuildInputs; + propagatedBuildInputs = [ ]; + meta = with pkgs.stdenv.lib; { + homepage = ""; + license = "OSI Approved"; + description = "Python interface to PROJ.4 library"; + }; + passthru.top_level = false; + }; + + + + "pysqlite" = python.mkDerivation { + name = "pysqlite-2.8.2"; + src = pkgs.fetchurl { + url = "https://pypi.python.org/packages/cc/a4/023ee9dba54b3cf0c5a4d0fb2f1ad80332ef23549dd4b551a9f2cbe88786/pysqlite-2.8.2.tar.gz"; + sha256= "613d139e97ce0561dee312e29f3be4751d01fd1a085aa448dd53a003810e0008"; + }; + doCheck = commonDoCheck; + buildInputs = commonBuildInputs; + propagatedBuildInputs = [ ]; + meta = with pkgs.stdenv.lib; { + homepage = ""; + license = "zlib/libpng license"; + description = "DB-API 2.0 interface for SQLite 3.x"; + }; + passthru.top_level = false; + }; + + + + "pytz" = python.mkDerivation { + name = "pytz-2016.6.1"; + src = pkgs.fetchurl { + url = "https://pypi.python.org/packages/f7/c7/08e54702c74baf9d8f92d0bc331ecabf6d66a56f6d36370f0a672fc6a535/pytz-2016.6.1.tar.bz2"; + sha256= "b5aff44126cf828537581e534cc94299b223b945a2bb3b5434d37bf8c7f3a10c"; + }; + doCheck = commonDoCheck; + buildInputs = commonBuildInputs; + propagatedBuildInputs = [ ]; + meta = with pkgs.stdenv.lib; { + homepage = ""; + license = licenses.mit; + description = "World timezone definitions, modern and historical"; + }; + passthru.top_level = false; + }; + + + + "recommonmark" = python.mkDerivation { + name = "recommonmark-0.4.0"; + src = pkgs.fetchurl { + url = "https://pypi.python.org/packages/3d/95/aa1085573adf3dc7b164ae8569d57b1af5e98922e40345bb7efffed5ad2e/recommonmark-0.4.0.tar.gz"; + sha256= "6e29c723abcf5533842376d87c4589e62923ecb6002a8e059eb608345ddaff9d"; + }; + doCheck = commonDoCheck; + buildInputs = commonBuildInputs; + propagatedBuildInputs = [ + self."CommonMark" + self."docutils" + ]; + meta = with pkgs.stdenv.lib; { + homepage = ""; + license = ""; + description = "UNKNOWN"; + }; + passthru.top_level = false; + }; + + + + "requests" = python.mkDerivation { + name = "requests-2.10.0"; + src = pkgs.fetchurl { + url = "https://pypi.python.org/packages/49/6f/183063f01aae1e025cf0130772b55848750a2f3a89bfa11b385b35d7329d/requests-2.10.0.tar.gz"; + sha256= "63f1815788157130cee16a933b2ee184038e975f0017306d723ac326b5525b54"; + }; + doCheck = commonDoCheck; + buildInputs = commonBuildInputs; + propagatedBuildInputs = [ ]; + meta = with pkgs.stdenv.lib; { + homepage = ""; + license = licenses.asl20; + description = "Python HTTP for Humans."; + }; + passthru.top_level = false; + }; + + + + "s2sphere" = python.mkDerivation { + name = "s2sphere-0.2.4"; + src = pkgs.fetchurl { + url = "https://pypi.python.org/packages/59/49/c39a5563d6e1f244d72a384da828039d184c1c4d0b2ba3cf0ee3fb41caf1/s2sphere-0.2.4.tar.gz"; + sha256= "6e8b32b5e9c7d0c06bdd31f7c8dac39e23d81c5ff0a3c7bf1e08fed626d9f256"; + }; + doCheck = commonDoCheck; + buildInputs = commonBuildInputs; + propagatedBuildInputs = [ + self."Sphinx" + self."future" + self."sphinx-rtd-theme" + ]; + meta = with pkgs.stdenv.lib; { + homepage = ""; + license = licenses.mit; + description = "Python implementation of the S2 Geometry Library"; + }; + passthru.top_level = false; + }; + + + + "singledispatch" = python.mkDerivation { + name = "singledispatch-3.4.0.3"; + src = pkgs.fetchurl { + url = "https://pypi.python.org/packages/d9/e9/513ad8dc17210db12cb14f2d4d190d618fb87dd38814203ea71c87ba5b68/singledispatch-3.4.0.3.tar.gz"; + sha256= "5b06af87df13818d14f08a028e42f566640aef80805c3b50c5056b086e3c2b9c"; + }; + doCheck = commonDoCheck; + buildInputs = commonBuildInputs; + propagatedBuildInputs = [ + self."six" + ]; + meta = with pkgs.stdenv.lib; { + homepage = ""; + license = licenses.mit; + description = "This library brings functools.singledispatch from Python 3.4 to Python 2.6-3.3."; + }; + passthru.top_level = false; + }; + + + + "six" = python.mkDerivation { + name = "six-1.10.0"; + src = pkgs.fetchurl { + url = "https://pypi.python.org/packages/b3/b2/238e2590826bfdd113244a40d9d3eb26918bd798fc187e2360a8367068db/six-1.10.0.tar.gz"; + sha256= "105f8d68616f8248e24bf0e9372ef04d3cc10104f1980f54d57b2ce73a5ad56a"; + }; + doCheck = commonDoCheck; + buildInputs = commonBuildInputs; + propagatedBuildInputs = [ ]; + meta = with pkgs.stdenv.lib; { + homepage = ""; + license = licenses.mit; + description = "Python 2 and 3 compatibility utilities"; + }; + passthru.top_level = true; + }; + + + + "snowballstemmer" = python.mkDerivation { + name = "snowballstemmer-1.2.1"; + src = pkgs.fetchurl { + url = "https://pypi.python.org/packages/20/6b/d2a7cb176d4d664d94a6debf52cd8dbae1f7203c8e42426daa077051d59c/snowballstemmer-1.2.1.tar.gz"; + sha256= "919f26a68b2c17a7634da993d91339e288964f93c274f1343e3bbbe2096e1128"; + }; + doCheck = commonDoCheck; + buildInputs = commonBuildInputs; + propagatedBuildInputs = [ ]; + meta = with pkgs.stdenv.lib; { + homepage = ""; + license = licenses.bsdOriginal; + description = "This package provides 16 stemmer algorithms (15 + Poerter English stemmer) generated from Snowball algorithms."; + }; + passthru.top_level = false; + }; + + + + "sphinx-autobuild" = python.mkDerivation { + name = "sphinx-autobuild-0.6.0"; + src = pkgs.fetchurl { + url = "https://pypi.python.org/packages/85/cf/25b65781e6d2a4a89a431260daf1e0d53a81c52d27c98245481d46f3df2a/sphinx-autobuild-0.6.0.tar.gz"; + sha256= "2f9262d7a35f80a18c3bcb03b2bf5a83f0a5e88b75ad922b3b1cee512c7e5cd2"; + }; + doCheck = commonDoCheck; + buildInputs = commonBuildInputs; + propagatedBuildInputs = [ + self."PyYAML" + self."argh" + self."livereload" + self."pathtools" + self."port-for" + self."tornado" + self."watchdog" + ]; + meta = with pkgs.stdenv.lib; { + homepage = ""; + license = licenses.mit; + description = "Watch a Sphinx directory and rebuild the documentation when a change is detected. Also includes a livereload enabled web server."; + }; + passthru.top_level = false; + }; + + + + "sphinx-rtd-theme" = python.mkDerivation { + name = "sphinx-rtd-theme-0.1.9"; + src = pkgs.fetchurl { + url = "https://pypi.python.org/packages/99/b5/249a803a428b4fd438dd4580a37f79c0d552025fb65619d25f960369d76b/sphinx_rtd_theme-0.1.9.tar.gz"; + sha256= "273846f8aacac32bf9542365a593b495b68d8035c2e382c9ccedcac387c9a0a1"; + }; + doCheck = commonDoCheck; + buildInputs = commonBuildInputs; + propagatedBuildInputs = [ + self."Sphinx" + ]; + meta = with pkgs.stdenv.lib; { + homepage = ""; + license = licenses.mit; + description = "ReadTheDocs.org theme for Sphinx, 2013 version."; + }; + passthru.top_level = false; + }; + + + + "tornado" = python.mkDerivation { + name = "tornado-4.4.1"; + src = pkgs.fetchurl { + url = "https://pypi.python.org/packages/96/5d/ff472313e8f337d5acda5d56e6ea79a43583cc8771b34c85a1f458e197c3/tornado-4.4.1.tar.gz"; + sha256= "371d0cf3d56c47accc66116a77ad558d76eebaa8458a6b677af71ca606522146"; + }; + doCheck = commonDoCheck; + buildInputs = commonBuildInputs; + propagatedBuildInputs = [ + self."backports-abc" + self."certifi" + self."singledispatch" + ]; + meta = with pkgs.stdenv.lib; { + homepage = ""; + license = "http://www.apache.org/licenses/LICENSE-2.0"; + description = "Tornado is a Python web framework and asynchronous networking library, originally developed at FriendFeed."; + }; + passthru.top_level = false; + }; + + + + "watchdog" = python.mkDerivation { + name = "watchdog-0.8.3"; + src = pkgs.fetchurl { + url = "https://pypi.python.org/packages/54/7d/c7c0ad1e32b9f132075967fc353a244eb2b375a3d2f5b0ce612fd96e107e/watchdog-0.8.3.tar.gz"; + sha256= "7e65882adb7746039b6f3876ee174952f8eaaa34491ba34333ddf1fe35de4162"; + }; + doCheck = commonDoCheck; + buildInputs = commonBuildInputs; + propagatedBuildInputs = [ + self."PyYAML" + self."argh" + self."pathtools" + ]; + meta = with pkgs.stdenv.lib; { + homepage = ""; + license = licenses.asl20; + description = "Filesystem events monitoring"; + }; + passthru.top_level = false; + }; + + + + "wsgiref" = python.mkDerivation { + name = "wsgiref-0.1.2"; + src = pkgs.fetchurl { + url = "https://pypi.python.org/packages/41/9e/309259ce8dff8c596e8c26df86dbc4e848b9249fd36797fd60be456f03fc/wsgiref-0.1.2.zip"; + sha256= "c7e610c800957046c04c8014aab8cce8f0b9f0495c8cd349e57c1f7cabf40e79"; + }; + doCheck = commonDoCheck; + buildInputs = commonBuildInputs; + propagatedBuildInputs = [ ]; + meta = with pkgs.stdenv.lib; { + homepage = ""; + license = "PSF or ZPL"; + description = "WSGI (PEP 333) Reference Library"; + }; + passthru.top_level = false; + }; + + + + "xxhash" = python.mkDerivation { + name = "xxhash-0.6.1"; + src = pkgs.fetchurl { + url = "https://pypi.python.org/packages/08/ac/f5cf4fc624ef5a12a8c6e80143ee43d9ed8d0c8bda96e2af5772798bcfbe/xxhash-0.6.1.tar.bz2"; + sha256= "8048b482bb6aa73016e672d1ef488a89810c2b8e6831366e92c2c67a3b2b151c"; + }; + doCheck = commonDoCheck; + buildInputs = commonBuildInputs; + propagatedBuildInputs = [ ]; + meta = with pkgs.stdenv.lib; { + homepage = ""; + license = licenses.bsdOriginal; + description = "Python binding for xxHash"; + }; + passthru.top_level = false; + }; + +}+ \ No newline at end of file diff --git a/nix-config/services/pokemongo-map/requirements_override.nix b/nix-config/services/pokemongo-map/requirements_override.nix @@ -0,0 +1,5 @@ +{ pkgs, python }: + +self: super: { + +} diff --git a/nix-config/timers/sync-ical2org.nix b/nix-config/timers/sync-ical2org.nix @@ -0,0 +1,47 @@ +home: +{ config, lib, pkgs, ... }: +let calendars = (import ../private.nix).calendars; + calendarArgs = with pkgs.lib; + let xs = mapAttrsToList (n: v: "'" + n + "=" + v.category + "=" + v.link + "'") calendars; + in concatStringsSep " " xs; +in { + systemd.services.sync-ical2org = { + description = "Sync gcal calendar to calendar.org"; + serviceConfig = { + Type = "oneshot"; + ExecStart = let script = pkgs.writeScript "ical2org-auto" '' + #!${pkgs.python35}/bin/python3 + import os + import sys + from urllib.request import urlopen + import subprocess + caldir = "${home}/var/ical2org" + os.makedirs(caldir, exist_ok=True) + cat = lambda n: b"#+CATEGORY: " + bytes(n, "utf-8") + for arg in sys.argv[1:]: + [name, category, link] = arg.split("=") + ical = urlopen(link).read() + fname = os.path.join(caldir, name + ".org") + org = open(fname, "wb") + icalfd = open(os.path.join(caldir, name + ".ical"), "wb") + icalfd.write(ical) + icalfd.close() + # just download for now + #proc = subprocess.Popen("${pkgs.ical2org}/bin/ical2org", + # close_fds=True, + # stdin=subprocess.PIPE, + # stdout=subprocess.PIPE) + #out, err = proc.communicate(ical) + #org.write(out.replace(cat("google"), cat(category))) + #org.close() + ''; in "${script} ${calendarArgs}"; + + }; + preStart = '' + export SSL_CERT_FILE="${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt" + ''; + restartIfChanged = false; + startAt = "*:0/10"; + }; +} + diff --git a/nix-config/wayland/default.nix b/nix-config/wayland/default.nix @@ -0,0 +1,28 @@ +{ config, pkgs, ... }: +let + url = "https://github.com/colemickens/nixpkgs-wayland/archive/master.tar.gz"; + waylandOverlay = (import (builtins.fetchTarball url)); +in +{ + nixpkgs.overlays = [ waylandOverlay ]; + programs.sway.enable = true; + programs.sway.extraPackages = with pkgs; [ + swayidle # used for controlling idle timeouts and triggers (screen locking, etc) + swaylock # used for locking Wayland sessions + + grim # screen image capture + slurp # screen are selection tool + mako # notification daemon + oguri # animated background utility + kanshi # dynamic display configuration helper + redshift-wayland # patched to work with wayland gamma protocol + rofi + alacritty + ]; + + environment.systemPackages = with pkgs; [ + # other compositors/window-managers + wayfire # 3D wayland compositor + waybox # An openbox clone on Wayland + ]; +}