commit 54bab918d74246e845cd6a5eeacbe0d84bfac701 Author: Ingolf Wagner Date: Thu Oct 24 02:20:38 2019 +0200 init diff --git a/.channelStable.json b/.channelStable.json new file mode 100644 index 0000000..09dd3ac --- /dev/null +++ b/.channelStable.json @@ -0,0 +1,7 @@ +{ + "url": "https://github.com/NixOS/nixpkgs-channels.git", + "rev": "0e0ee084d6dfc83b5b67b6cbcefe43664114808d", + "date": "2019-10-07T15:48:50+02:00", + "sha256": "1qk0ag4ihfjh9ay28hc9zf9vnrdw096driirv62picyn30j9y0l3", + "fetchSubmodules": false +} diff --git a/.channelUnstable.json b/.channelUnstable.json new file mode 100644 index 0000000..82b8a06 --- /dev/null +++ b/.channelUnstable.json @@ -0,0 +1,7 @@ +{ + "url": "https://github.com/NixOS/nixpkgs-channels.git", + "rev": "2436c27541b2f52deea3a4c1691216a02152e729", + "date": "2019-09-25T08:02:27+02:00", + "sha256": "0p98dwy3rbvdp6np596sfqnwlra11pif3rbdh02pwdyjmdvkmbvd", + "fetchSubmodules": false +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..368cdee --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +*.swp +result +result-* +.history +TAGS + +*.tf.json diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..0ac1af0 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,6 @@ +[submodule "assets/video-browser"] + path = assets/video-browser + url = ssh://gogs@git.ingolf-wagner.de:443/palo/video-browser.git +[submodule "wetten"] + path = wetten + url = ssh://gogs@git.ingolf-wagner.de:443/palo/wetten.git diff --git a/.krops.json b/.krops.json new file mode 100644 index 0000000..03b044a --- /dev/null +++ b/.krops.json @@ -0,0 +1,7 @@ +{ + "url": "https://git.ingolf-wagner.de/krebs/krops.git", + "rev": "2e93a93ac264a480b427acc2684993476732539d", + "date": "2018-09-19T19:57:26+02:00", + "sha256": "1s6b2cs60xa270ynhr32qj1rcy3prvf9pidap0qbbvgg008iafxk", + "fetchSubmodules": false +} diff --git a/.nix-writers.json b/.nix-writers.json new file mode 100644 index 0000000..474b17a --- /dev/null +++ b/.nix-writers.json @@ -0,0 +1,7 @@ +{ + "url": "https://cgit.krebsco.de/nix-writers/", + "rev": "fc8a3802a0777a5f43a9a2fe0f5848ecaeb555a1", + "date": "2018-10-27T14:45:48+02:00", + "sha256": "1iy207rcbz9nv9bf64025ypy38x8mwzl6snbmbrq347h6vvs0ksc", + "fetchSubmodules": false +} diff --git a/.nixos-generators.json b/.nixos-generators.json new file mode 100644 index 0000000..95085c3 --- /dev/null +++ b/.nixos-generators.json @@ -0,0 +1,7 @@ +{ + "url": "https://github.com/nix-community/nixos-generators.git", + "rev": "ef1e4480cf8af45cfdeac597b2f1b1af33923e93", + "date": "2019-01-18T10:41:01+01:00", + "sha256": "0ymzp4pmpkjjjg5h8d45gv8avy4wh1dj0v238i2cz3jp3j489ik9", + "fetchSubmodules": false +} diff --git a/README.md b/README.md new file mode 100644 index 0000000..bf2a59f --- /dev/null +++ b/README.md @@ -0,0 +1,35 @@ +# My NixOS configuration + +## Folder Structure + +### configs + +This should container system specific configurations + +### system + +Holds system type information like `server` and `desktop`. + +### modules + +This should container scripts that can be copied across different sources. + +### pkgs + +My overlay is in here. + +### assets + +assets, like scripts which I dont want to write in nix-lang. + +### terranix + +some terranix scripts + +### library + +some nix-lang functions and tools I use. + +### images + +some images I use and build via nixos-generators. diff --git a/assets/jack.sh b/assets/jack.sh new file mode 100755 index 0000000..b9ca596 --- /dev/null +++ b/assets/jack.sh @@ -0,0 +1,105 @@ +set -e + +defaultDevice=PCH + +start_jack(){ + + internal_device_number=-1 + komplete_device_number=$(aplay -l | grep Vestax | cut -d":" -f1 | cut -d" " -f2) + babyface_device_number=$(aplay -l | grep Babyface | cut -d":" -f1 | cut -d" " -f2) + cmedia_device_number=$(aplay -l | grep C-Media | cut -d":" -f1 | cut -d" " -f2) + h2n_device_number=$(aplay -l | grep H2n | cut -d":" -f1 | cut -d" " -f2) + + # this should be more readable some day + if [[ $babyface_device_number == "" ]]; then + if [[ $komplete_device_number == "" ]]; then + if [[ $cmedia_device_number == "" ]]; then + if [[ $h2n_device_number == "" ]]; then + echo "use : default device" + device_number=$internal_device_number + else + echo "use : h2n" + device_number=$h2n_device_number + fi + else + echo "use : c-media" + device_number=$cmedia_device_number + fi + else + echo "use : komplete" + device_number=$komplete_device_number + fi + else + echo "use : babyface" + device_number=$babyface_device_number + fi + + # device parameter configuration + # ============================== + # + # to find configuration options do + # jack_control dp + if [[ $device_number -eq -1 ]] + then + # we use alsa in reality, but pulse opens up all the pulse + # sink and source stuff + # jack_control ds pulse # not working for some reason + jack_control ds alsa + jack_control dps device hw:$defaultDevice + else + jack_control ds alsa + jack_control dps device hw:$device_number # use usb card + fi + + jack_control dps duplex True # record and playback ports + jack_control dps hwmon False # no hardware monitoring + jack_control dps rate 48000 # use cd sample rate + + + # nperiods are the splitup of the + # sound-ring-buffer. 2 are ok for internal cards + # but for usb you should use 3 because + # you can have to write in junks to the card + # so there is one backup slice in the middle + if [[ $internal_device_number -ne -1 ]] + then + jack_control dps nperiods 3 + fi + + # engine parameter configuration + # ============================== + # + # to find configuration options do + # jack_control ep + jack_control eps sync True + + # realtime kernel + # set True for using a realtime kernel + jack_control eps realtime False + # set priority if realtime kernel is set True + # jack_control eps realtime-priority 10 + + jack_control start +} + +stop_jack(){ + jack_control exit +} + +status_jack() { + jack_control dp + jack_control ep + jack_control status +} + + +case $1 in + start) start_jack + ;; + stop) stop_jack + ;; + restart) stop_jack ; start_jack + ;; + *) status_jack + ;; +esac diff --git a/assets/shrink_exports b/assets/shrink_exports new file mode 100755 index 0000000..fc44ff7 --- /dev/null +++ b/assets/shrink_exports @@ -0,0 +1,56 @@ +#!/usr/bin/env bash + +set -e + +PROJECTS_FOLDER=~/music-projects/Rendered-Projects + +# file separator (needed to handle files with spaces) +IFS=" +" + +function info_log(){ + echo -n ">>> [ " + echo -n $@ + echo " ]" +} + +function run_ffmpeg(){ + local input=$1 + local output=$2 + + info_log "ffmpeg : ${output}" + ffmpeg \ + -i "${input}" \ + -f mp3 \ + -codec:a libmp3lame \ + -qscale:a 5 \ + -ar 44100 \ + -loglevel error \ + -af loudnorm \ + "${output}" + + +} + +function delete(){ + local input=$1 + + if [[ -e "${input}" ]] + then + info_log "delete : ${input}" + rm "${input}" + fi +} + +for file in `ls ${PROJECTS_FOLDER} | grep wav$` +do + filename=`basename ${file} .wav` + mp3="${filename}.mp3" + + info_log ${filename} + + delete "${PROJECTS_FOLDER}/${mp3}" + run_ffmpeg "${PROJECTS_FOLDER}/${file}" "${PROJECTS_FOLDER}/${mp3}" + delete "${PROJECTS_FOLDER}/${file}" + +done diff --git a/assets/sprueche-axel b/assets/sprueche-axel new file mode 100644 index 0000000..8774106 --- /dev/null +++ b/assets/sprueche-axel @@ -0,0 +1,3 @@ +"Fernsehen ist für mich der Elektro-Jude" - Dr Axel Stoll +"Der Zellkern ist gleich pures Licht" - Dr Axel Stoll +"Die Sonne ist Kalt!" - Dr Axel Stoll diff --git a/assets/sprueche-siw b/assets/sprueche-siw new file mode 100644 index 0000000..f8c4e6f --- /dev/null +++ b/assets/sprueche-siw @@ -0,0 +1,18 @@ +"Also Attracktiv oder net, ich seh hier immer noch am Besten aus" - Reiker +"Hör mal auf dich selber zu bemitleiden, sonst baft das aber echt jetzt! Dummer Lutscher" - Käpten Pika +"Komm Junge is besser du gibs dat jetzt zu, dann haste wenigsten noch ein paar Jahre wat von deinen Zähnen" - Käpten Pika +"Ich sauf doch net mit euch Pennern, echt Ey" - Käpten Pika +"Ja toll dann hab ich ja schon wieder verloren" - Deiter +"Komisch! Mein Vater heißt auch Vater, aber sieht ganz anders aus!" - Reiker +"Sag noch einmal Junge, Junge!" - Käpten Pika +"Häää? Worte, was sind Worte?" - Reiker +"Ich hau dir gleich die Zähne aus deiner fiesen Schnauze!" - Käpten Pika +"Ihr glaubt wohl ich kann keine schlauen Sachen sagen, wa? Schlaue Sachen!!" - Reiker +"Jetzt... also ich raff das jetzt echt net. Ist das so kompliziert?" - Reiker +"Dat is hier die Molekularsymplexion über trivial-komplexive Plasmakonvergenzen, wie? Wat?" - Jordi +"Äh, äh, Junge? Ey, Junge, echt jetz! Weißte?" - Käpten Pika +"Deine Dummheit unterscheidet meinen Datentransfer" - Computer +"Ähh, komisch mein Vadder sieht ganz anders aus, obwohl der auch Vadder heißt." - Reiker +"Aaaaaah, ich kann nimmer" - Reiker +"Also ich hab keine Gummipuppe. Nur Gummibärchen." - Reiker +"Richtig heisser, kochend heisser Kaffee" - Käpten Pika \ No newline at end of file diff --git a/assets/ssh/card_rsa.pub b/assets/ssh/card_rsa.pub new file mode 100644 index 0000000..f2b2a02 --- /dev/null +++ b/assets/ssh/card_rsa.pub @@ -0,0 +1 @@ +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQC6uza62+Go9sBFs3XZE2OkugBv9PJ7Yv8ebCskE5WYPcahMZIKkQw+zkGI8EGzOPJhQEv2xk+XBf2VOzj0Fto4nh8X5+Llb1nM+YxQPk1SVlwbNAlhh24L1w2vKtBtMy277MF4EP+caGceYP6gki5+DzlPUSdFSAEFFWgN1WPkiyUii15Xi3QuCMR8F18dbwVUYbT11vwNhdiAXWphrQG+yPguALBGR+21JM6fffOln3BhoDUp2poVc5Qe2EBuUbRUV3/fOU4HwWVKZ7KCFvLZBSVFutXCj5HuNWJ5T3RuuxJSmY5lYuFZx9gD+n+DAEJt30iXWcaJlmUqQB5awcB1S2d9pJ141V4vjiCMKUJHIdspFrI23rFNYD9k2ZXDA8VOnQE33BzmgF9xOVh6qr4G0oEpsNqJoKybVTUeSyl4+ifzdQANouvySgLJV/pcqaxX1srSDIUlcM2vDMWAs3ryCa0aAlmAVZIHgRhh6wa+IXW8gIYt+5biPWUuihJ4zGBEwkyVXXf2xsecMWCAGPWPDL0/fBfY9krNfC5M2sqxey2ShFIq+R/wMdaI7yVjUCF2QIUNiIdFbJL6bDrDyHnEXJJN+rAo23jUoTZZRv7Jq3DB/A5H7a73VCcblZyUmwMSlpg3wos7pdw5Ctta3zQPoxoAKGS1uZ+yTeZbPMmdbw== cardno:000611343142 diff --git a/assets/tinc/pepe_host_file b/assets/tinc/pepe_host_file new file mode 100644 index 0000000..0a9d3ed --- /dev/null +++ b/assets/tinc/pepe_host_file @@ -0,0 +1,14 @@ +Ed25519PublicKey = LnE+w6ZfNCky4Kad3TBxpFKRJ2PJshkSpW6mC3pcsPI +-----BEGIN RSA PUBLIC KEY----- +MIICCgKCAgEAmAyz71GoQq2Mn4XeUVcN9yfgxeWT57li7i6Te9lq7OVAXQ+CBtD3 +puTMrW3/LXOIS678E2iMYPmdQzMZLmADi8+ZrXOqX98uceNv5bPrTJF0z/RA9Tif +kfh78GcJCGHmZz+GGWu1ExtSa5ekBdamEtehW6vAGbrPM6Umu9B2UCn8zaSx+RGe +Y7Z81wO21+ywUorMPTbHeuPYZW+Z8L+QKHO9NdYhzZ9zMPeVMi0x/mwIZqXJ57Wz +57nx0rrPh+e+5cj3Jh+i4HC76mxPGCyCdvf+60d7W87UZxPqRiTLt2SwgltEKf56 +jBsVeOb5Fjzb6LcNGWfF8zNh0w6rAQsG4W7l93VlerTd46GtG2XW42JkGhuKb8JJ +L1olPUmbcDbxlQGGUNaI7thAzubszAzinqyat3oU8NjgDJJIueHLmo752RW+yHUY +giyRSBYtDRM9cE3s848WsToO5BtjXLkg/rC4WIWX2MNJFsAZXzfHWDmae+ajpoVy +Gl6tGYbLhjd8KtSWB9kB0OWsV56f4KmWeRxHwTgylMO30l6v+XRdnoRUAp9wj8dV +c6HJHnn5b2q4dk+qwWOYgwvpRFnSixbCCT4PoedEU9xVOzLmzxRtGmkzPsOXEOj5 +6r4Jvk0jw2LTkhEVX1CPblTrGpms9NO02SXNHkF/Akw7PGuJu+w3HZUCAwEAAQ== +-----END RSA PUBLIC KEY----- diff --git a/assets/tinc/porani_host_file b/assets/tinc/porani_host_file new file mode 100644 index 0000000..b6c8e00 --- /dev/null +++ b/assets/tinc/porani_host_file @@ -0,0 +1,14 @@ +Ed25519PublicKey = 9JI8y56NWiKMRS6g/k2H3VgTEw0q+8UEDDJdiCjOl8O +-----BEGIN RSA PUBLIC KEY----- +MIICCgKCAgEA4Ff6XRvf83XSuWUkb70Yz+cWo1/dq4LBh5ZG7SJypdIXYnWQpQJc +sLRfAS6nJZ6VixNADx7A03c8TdADVaAgl591rLd4CSzM22EgaOFstU2VO/MfMKHf +v+WUQsrTE6CQ48SW+MDbSZZ7M7FRa/A6hwqZc5qygxdG/tgTei9pmTfqW+ZdQBWl +IeCCINiNSA/fD+FjWXslZIFRZ5sQ7AYZJgL2nFAueY+cKtRZy3tcDL1v6mhDdIrE +h8JjEUiayQDGnWmBlflLqE3ODqEsEKoL6W7epqK6PcwvZQxSNwrZe/wzH3oTC43m +Yg7TQGr0v3SnSziXv3cJvcHfwr9+huo37wTbUJNmozGpI8nLszfUTEIfhbu2ODQv +R2iM7FJcE4wV48y9aybEnESKA0vsjgI23RIQfxkN0oii7L6NAZVHgl/JJBOtCMXf +V5uXAdOtkv9UvfofrrV0uahncvbz5efPTSPF8fS5EiwzWfDUW6KHrp/9+gDcnirn +H8HvmmNVeOGWA1xlrKgi8kiBHv5BxCXfurD0aD6ZIlxdLjJCvGfnLnJZ6gr//GAf +1BJJVei98uZzihNe4VbRF6Iaphns1KezsdygMsEV9gDIJw3IIqTukcUK7AcBXhb4 +IJ792j2iRwUOyiAcUYLeVYzAt3xFN6wPNcC/Opdo6TVbdMZu2uS1ZN8CAwEAAQ== +-----END RSA PUBLIC KEY----- diff --git a/assets/tinc/retiolum/host_file b/assets/tinc/retiolum/host_file new file mode 100644 index 0000000..ec35af7 --- /dev/null +++ b/assets/tinc/retiolum/host_file @@ -0,0 +1,14 @@ +Ed25519PublicKey = kc1SACqsoYjk5GimZfP+eszfJmUzZkMQhWeW42UKjfL +-----BEGIN RSA PUBLIC KEY----- +MIICCgKCAgEA2ACttoosnRZ99o+OyMrxBdUWPqsT5btzSIQ5dU1XWqGjO4nRchCE +8tO0b/4jqVgJVTRZVIUJQESZRlSmclsCAjdM8tsGj74CJrm7tBvgbBn2IObSs5+4 +oJWe57VsQaeHPuI2JZuGqv8Z3Esw+B07bQS5VTaC1ISo7vnLG/q5XLCbKHB9JZc/ +ztYbk4bEQHwbulfoPjD9FY3heLnTzqPw9Xr3ixao5gbAXfWNJM+iCluMq+Q2g1BD +ozSnyYvaGLQ6h4yksDp+xuK8YCqiRj174EkXySI8Jee1CBMuI8ciX/5Q7yzvzscQ +ZQ/MLVdx3MRW+VeT0ctaRzoA9E09ILqPe+56DjpsKzt4Ne8qeMG5HdpzO9UdNzTu +MuibsCL7CJy5Ytl38PK+LAXHQr3Os1Z4OHjeTZ38vTAZcOUJZEkl6w9nO1XjcyBL +rIaG+20Nx0ZU79MlJZFiG7ovlUiDfIEKNygng8v/yoTMaqMYLxQZ/leQwLMNLujo +sku8+oV4Jvx4SyUjuAS6jgG9CnejLCnHP/yyDGdaMQSzmlzYXacLMfnPZE3r7bj1 +EjA6yQbkPixm7xLCyMm5u2leWtqtbg1oRA6Mw3UyYkNy3hiTU+jTvztEI3SCliDH +yjGlESH4/edryKjLNjmYP77VFbM9ZSQ+QGlbMGPvjcn6XCdJGdxm3PUCAwEAAQ== +-----END RSA PUBLIC KEY----- diff --git a/assets/tinc/sputnik_host_file b/assets/tinc/sputnik_host_file new file mode 100644 index 0000000..3904379 --- /dev/null +++ b/assets/tinc/sputnik_host_file @@ -0,0 +1,14 @@ +Ed25519PublicKey = ZK9iznseTpMqjaMgDJ7MdjYaq62QlEOFquLfVxlLpFK +-----BEGIN RSA PUBLIC KEY----- +MIICCgKCAgEAzBU8x9aB7F3sPJlcg9avJiSrsAoTHsMkfk6uRKFVjUjuNJgb3rjW +gyQ7krftLAyxLkTYJzpD+4D+qWiudEgju7W+BU65/hudMIvBmbRYqXmcQlD9B9Pv +0bVAazHJ80wN8GJD060Wq6XTtkrtAJhPmQSyMt0xU4WmWw/39QBX9rWtOTy75813 +qrfuv1I11YcVQ3jegPLUIzlZqz6LeouCXiP7IRIa+WUXIwAdAYtO/RJC+tty6zyI +BXNd0Mkvpf0Qaw5joQJRXkdb1sWHOZYh75JW1QWqFMWCclkGG7/Dve4KzuO9N5XZ +ZMs/MCtDkJQpweNDT3aaiqZa8Oj29OXs4HR4FFrvYkY+qqmKCUqS70FYLo45uNx1 +sRb7GKX8/dsPyOGHfXDuFTSXsKLh9gNLMlF/kuTQ2yJMfeMKdC5jDClL145Fm0ux +akH/PWSS9DENxSu0GH1sTQnLyhc4mVzOehu1XfR9EALjYY0BNBUir7aAaiLTCbq9 +LKwMaF/D467W3j3Zp5xEAsf8xYC2CyMl1Df43zxcxLY+3K8/kUM2rkU7ocl2VT3o +7yNC+JqQz41n4SDOXBZc6cfxUXj2MqqEw9Ywgs+aXZiSCaVOulhyXj0TSE1mX1NI +woDHEzyx7q4AryQOWQsLq5JimI0v2/xN2yz+cNXoetDypjEWnws4e/ECAwEAAQ== +-----END RSA PUBLIC KEY----- diff --git a/assets/tinc/sterni_host_file b/assets/tinc/sterni_host_file new file mode 100644 index 0000000..c9e8262 --- /dev/null +++ b/assets/tinc/sterni_host_file @@ -0,0 +1,14 @@ +Ed25519PublicKey = Hm+YwSe6XiRNQD4HfJPgTB8UFVMyVi0vy+3ofMnW6jD +-----BEGIN RSA PUBLIC KEY----- +MIICCgKCAgEAu7Ajx9+mEaDK/ASZ5hoVj3X3IkWl+8MAhmj7dwnhqc4YrPrvwKE4 +cOnVcEUp4K4pyIHUG8zhsesstfpu/0owLQaz8Cekr4CyQWsjDfi7K/QiAN+v2O2m +DQOjrYzDvRyBa20A2MnO1kZU/aFHE9qcIHefZhQUZyv97j+QcsE/FDuIH/RAua6/ +p+br2tfecePGH6f0fMk8dp+YbxcjjVyhJkjyaYF2r+n+YflDl5y3ngxUFJ0UnNE0 +RfYJf2NE1wzt4rIdnYobFP3vifDIeYj6M0LGHnURPsT6zP+zStZ81MYZKrNlTJ37 +sbZhorVmO6x46xEWaDUd7UqcKJBpb7u8iSAE4S3tHLFRxBs60dPS+3UEraiTvTHr +FvWTq1Q+t/FivTxXEkVt74N5auOKbT5AAkztak21Izx6enspdx6da2aLuJD5I0OU +3F4kd8lW5PqEZubkYziDwcVoNsx88hQzHi5l2aRdzY57o82+ltWw4xXmAFR2o605 +SwVJ4AUmORHuIoDYSR+UgbtKHguxVaTLVggdfvHzlDQ1VERwEU58awMwPLU1k+jP +3QW7ehPLKRN+StB6LBlnmRD1ltkaPY5iy+NMXj17hJx0trpz3qoCuv+5TRvsGvQ7 +Je/G7c6suIGd4HbA9TvCinW6/JLbJQlDiG7MD2oCOPS1pdayUuB9Jw0CAwEAAQ== +-----END RSA PUBLIC KEY----- diff --git a/assets/tinc/workhorse_host_file b/assets/tinc/workhorse_host_file new file mode 100644 index 0000000..c74cb52 --- /dev/null +++ b/assets/tinc/workhorse_host_file @@ -0,0 +1,14 @@ +Ed25519PublicKey = sPs48jzCdtTv0Viy2Of3HlXipfxH5Y8bA+KYVkOrSiK +-----BEGIN RSA PUBLIC KEY----- +MIICCgKCAgEA01HJ49zxmnixWC9YMP0c3UFxZc4Hl5UK9nJvhMRBOuxm75kpzZsz +3v6mSy1YrVE9rrGXYjZ76wKrRhchMpvrMKKD8/DRjVqTkuFwtGgUEigzpSFoSLtC +u2Wis7Z6GW3nLgAS79NU9IUUEoeevND1zzglDb0HdERuiImiZVg3I+VXLyA31X3L +Z/B7T4QLmZGIRvFw0y1TawMjFMJZmDBtzMqfO7behkms2O1ORAciGhGxmZ9gd7yk +n/NKCpSSzeC6sJ28i33LRrWF3hRUXAEJFgq8YRxm6mjRoPLsJVsw2S98DvTcxmjN +eyVnqPVQi7JuKrOQsewQvwV2KiqI9ibEYH1zZNXwy+l05b3QSaAcyRtDpwRW7FCY +H4B3S0vjte75D4bEuYTFgT3wCzlAjdB7fPZ4jyZXdrP8G3IfbMmgsdECz5uIMwam +UaSZISlHkSJv+erA8TMJLBnqAO7ERKYI7PRIDdIun0VtX2QjRJpWIdVpxEcL4fZU +w6gzX8lOQe5NnoH/MFUfU0LyBuUH1k6WX7xdwrynUVS087vwaQN+H/VTp0QSX6PQ +oCLYPCGKS2B/St954uaPanzeG7QZQpWbvttaFVmUSkilx78xqqu3zDm9pSofFKCX +08TGlluy8JAwUqAxekQVKey2PdLmKjlMCcoUeNYbJybGplc9gv2hYhsCAwEAAQ== +-----END RSA PUBLIC KEY----- diff --git a/assets/tinc/workout_host_file b/assets/tinc/workout_host_file new file mode 100644 index 0000000..f211232 --- /dev/null +++ b/assets/tinc/workout_host_file @@ -0,0 +1,14 @@ +Ed25519PublicKey = r6mRDc814z2YtyG9ev/XXV2SgquqWR8n53V13xNXb7O +-----BEGIN RSA PUBLIC KEY----- +MIICCgKCAgEA7/bur2JIXzNrsgjQ7kfoaLUVCC9S7HNNdDrlnSdum0sWvN9urdxS +1OfzqG+kjDhQ0sS4fEeYyLMU8W3/aHkSbMjfKBiZS70bg5yHRepUEPZNqDqR3+rO +LTAGWMi/IQQQmnfcN5SjaNY/ZyXoaPd1emlpV2UXBvXo/bQTl+pmOt7AIAh7Z7M6 +X5KAwU23kUwrfn/7zFCw98euNEPcCKpdF5oD4+G+S0PGfFvBmE6Xoi2blM1rcjJ4 +39IGVCsKAlW1Vg48yj7FypSSjaFvIW+kyRcNNTEZ4V5p50Vm7DfylfW96NqAOeuz +2aSVaLhvmu8fU9z+g95MdGZOJYd57jFt76GbkwcLCF8KBCP9NhMfOQu0i1glk+AP +CcJcDa/Oj7lLQVB2+holJhw5fkHH2Yi+L+UsjIF0iLiOSTjGJp4yRT9Al9pgMCj2 +O1JUMYxQ490mSFHBomNv1fq+f5VJnytEwAkJH6AgH+RIcAC5/r+sowfLv+Gy0ga8 +jKG6t9d/x6lRNv0x5sUhYkiUD9Naq0NncaZz1GtkBAyu+hUZx2+zg3r8He4XoiXx +zWAQEgcW3X1/9VC7IBvaK9cdLG5pbeGCBaDv8S0Ue332mM0XNDlffjdC7Sg9f/TG +YV8MHpR3RwwUqdi6WFPQqVz5Hv1pE02v/Uw6tby1UgAnzskrufPh+m8CAwEAAQ== +-----END RSA PUBLIC KEY----- diff --git a/collect-network-connections.sh b/collect-network-connections.sh new file mode 100644 index 0000000..2f31707 --- /dev/null +++ b/collect-network-connections.sh @@ -0,0 +1,10 @@ +#!/usr/bin/env bash + +# collect all network configurations and save them in the store + +sudo ls /etc/NetworkManager/system-connections \ + | while read file +do + sudo cat /etc/NetworkManager/system-connections/$file \ + | pass insert -m desktop/network-manager/system-connections/$file +done diff --git a/configs/pepe/configuration.nix b/configs/pepe/configuration.nix new file mode 100644 index 0000000..2490571 --- /dev/null +++ b/configs/pepe/configuration.nix @@ -0,0 +1,64 @@ +{ config, pkgs, lib, ... }: +{ + + + imports = [ + + + ./hardware-configuration.nix + + ./encfs.nix + #./samba.nix + ./syncthing.nix + ./tinc.nix + #./wifi-access-point.nix + + ]; + + custom.samba-share.folders = { + enable = false; + public = "/home/palo/movies"; + }; + + system.custom.wifi.interfaces = ["wlp3s0"]; + + networking.hostName = "pepe"; + + security.wrappers = { + pmount.source = "${pkgs.pmount}/bin/pmount"; + pumount.source = "${pkgs.pmount}/bin/pumount"; + }; + + # keybase + services.keybase.enable = true; + services.kbfs.enable = true; + + programs.custom.steam.enable = false; + programs.custom.video.enable = false; + + services.printing.enable = true; + + # fonts + # ----- + programs.custom.urxvt.fontSize = 12; + programs.custom.xterm.fontSize = 12; + system.custom.fonts.dpi = 100; + + virtualisation = { + docker.enable = false; + + virtualbox = { + host.enable = false; + guest.x11 = false; + guest.enable = false; + }; + }; + + configuration.desktop = { + width = 1366; + height = 768; + }; + +} + + diff --git a/configs/pepe/encfs.nix b/configs/pepe/encfs.nix new file mode 100644 index 0000000..09b654d --- /dev/null +++ b/configs/pepe/encfs.nix @@ -0,0 +1,8 @@ +{ config, lib, pkgs, ... }: +{ + module.backup.services.encfs = { + "fotos".enable = true; + "desktop".enable = true; + "finance".enable = true; + }; +} diff --git a/configs/pepe/hardware-configuration.nix b/configs/pepe/hardware-configuration.nix new file mode 100644 index 0000000..63469f5 --- /dev/null +++ b/configs/pepe/hardware-configuration.nix @@ -0,0 +1,86 @@ +# 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.initrd.availableKernelModules = [ "ehci_pci" "ahci" "usb_storage" "sd_mod" "sdhci_pci" ]; + boot.kernelModules = [ "kvm-intel" ]; + boot.extraModulePackages = [ ]; + + boot.loader.grub = { + enable = true; + version = 2; + device = "/dev/sda"; + }; + + zramSwap = { + enable = true; + numDevices = 2; + swapDevices = 1; + memoryPercent = 50; + }; + + fileSystems."/share/" = { + device = "/dev/ram1"; + fsType = "tmpfs"; + }; + + fileSystems."/browsers/" = { + #device = "/dev/ram2"; + #fsType = "tmpfs"; + options = [ "noatime" "nodiratime" "discard" ]; + device = "/dev/secure_vg/browser"; + fsType = "ext4"; + }; + + nix.maxJobs = lib.mkDefault 4; + powerManagement.cpuFreqGovernor = lib.mkDefault "powersave"; + + + + # lvm volume group + # ---------------- + boot.initrd.luks.devices = [ + { + name = "secure_vg"; + device = "/dev/sda2"; + preLVM = true; + } + ]; + + # NTFS support + # ------------ + environment.systemPackages = [ + pkgs.ntfs3g + ]; + + # root + # ---- + fileSystems."/" = { + options = [ "noatime" "nodiratime" "discard" ]; + device = "/dev/secure_vg/root"; + fsType = "ext4"; + }; + + # /home/palo/private/.fotos.ct + # ---------------------------- + fileSystems."/home/palo/private/.fotos.ct" = { + options = [ "noatime" "nodiratime" "discard" ]; + device = "/dev/secure_vg/fotos"; + fsType = "ext4"; + }; + + # boot + # ---- + fileSystems."/boot" = { + device = "/dev/sda1"; + fsType = "ext4"; + }; + + +} diff --git a/configs/pepe/samba.nix b/configs/pepe/samba.nix new file mode 100644 index 0000000..bba5e4c --- /dev/null +++ b/configs/pepe/samba.nix @@ -0,0 +1,5 @@ +{ config, ... }: +{ + + +} diff --git a/configs/pepe/syncthing.nix b/configs/pepe/syncthing.nix new file mode 100644 index 0000000..65ece41 --- /dev/null +++ b/configs/pepe/syncthing.nix @@ -0,0 +1,32 @@ +{ config, pkgs, lib, ... }: +{ + + test.services.syncthing = { + enable = true; + openDefaultPorts = false; + user = "palo"; + dataDir = "/home/palo/.syncthing"; + configDir = "/home/palo/.syncthing"; + declarative = { + cert = toString ; + key = toString ; + + overrideFolders = true; + folders = { + + book.path = "/home/palo/books"; + desktop-encrypted.path = "/home/palo/.desktop.ct"; + finance-encrypted.path = "/home/palo/.finance.ct"; + fotos-encrypted.path = "/home/palo/private/.fotos.ct"; + kruck-pepe.path = "/home/palo/pepe-kruck"; + music-library.path = "/home/palo/music-library"; + music-projects.path = "/home/palo/music-projects"; + porani-pepe.path = "/home/palo/pepe-porani"; + schasch-pepe.path = "/home/palo/pepe-schasch"; + smartphone-fotos.path = "/home/palo/smartphone-fotos"; + workout-pepe.path = "/home/palo/pepe-workout"; + + }; + }; + }; +} diff --git a/configs/pepe/tinc.nix b/configs/pepe/tinc.nix new file mode 100644 index 0000000..6f8c828 --- /dev/null +++ b/configs/pepe/tinc.nix @@ -0,0 +1,18 @@ +{ config, lib, pkgs, ... }: + +with lib; + +{ + module.cluster.services.tinc = { + "private" = { + enable = true; + openPort = true; + connectTo = [ "sputnik" ]; + }; + "retiolum" = { + enable = true; + openPort = true; + }; + }; + +} diff --git a/configs/pepe/wifi-access-point.nix b/configs/pepe/wifi-access-point.nix new file mode 100644 index 0000000..4c309cb --- /dev/null +++ b/configs/pepe/wifi-access-point.nix @@ -0,0 +1,77 @@ +{lib, pkgs, ... }: + +let + wifi = "wlp0s29u1u2"; + ipAddress = "10.123.145.1"; + prefixLength = 24; + servedAddressRange = "10.123.145.2,10.123.145.150,12h"; + ssid="bumbumbum"; + wifiPassword=lib.fileContents ; +in + +{ + # todo only open needed ports + networking.firewall.trustedInterfaces = [ wifi ]; + + networking.networkmanager.unmanaged = [ wifi ]; + networking.dhcpcd.denyInterfaces = [ wifi ]; + + networking.interfaces."${wifi}".ipv4.addresses = [ { + address = ipAddress; + prefixLength = prefixLength; + }]; + + # forward traffic coming in trough the access point => provide internet and vpn network access + # todo : forward to own servers + boot.kernel.sysctl = { + "net.ipv4.conf.${wifi}.forwarding" = true; + "net.ipv6.conf.${wifi}.forwarding" = true; + }; + + systemd.services.hostapd = { + description = "hostapd wireless AP"; + path = [ pkgs.hostapd ]; + + # start manual + # wantedBy = [ "network.target" ]; + + after = [ "${wifi}-cfg.service" "nat.service" "bind.service" "dhcpd.service" "sys-subsystem-net-devices-${wifi}.device" ]; + + serviceConfig = { + ExecStart = "${pkgs.hostapd}/bin/hostapd ${pkgs.writeText "hostapd.conf" '' + interface=${wifi} + hw_mode=g + channel=10 + ieee80211d=1 + country_code=DE + ieee80211n=1 + wmm_enabled=1 + + ssid=${ssid} + auth_algs=1 + wpa=2 + wpa_key_mgmt=WPA-PSK + rsn_pairwise=CCMP + wpa_passphrase=${wifiPassword} + ''}"; + Restart = "always"; + }; + }; + + services.dnsmasq = { + enable = true; + extraConfig = '' + # Only listen to routers' LAN NIC. Doing so opens up tcp/udp port 53 to + # localhost and udp port 67 to world: + interface=${wifi} + + # Explicitly specify the address to listen on + listen-address=${ipAddress} + + # Dynamic range of IPs to make available to LAN PC and the lease time. + # Ideally set the lease time to 5m only at first to test everything works okay before you set long-lasting records. + dhcp-range=${servedAddressRange} + ''; + }; + +} diff --git a/configs/porani/configuration.nix b/configs/porani/configuration.nix new file mode 100644 index 0000000..cbf4cc7 --- /dev/null +++ b/configs/porani/configuration.nix @@ -0,0 +1,58 @@ +{ pkgs, lib, config, ... }: +{ + imports = [ + + + ./hardware-configuration.nix + + ./tinc.nix + ./syncthing.nix + #./packages.nix + #./home-assistant.nix + #./wifi-access-point.nix + #./kodi.nix + #./mpd.nix + + ]; + + networking.hostName = "porani"; + + # enable initrd ssh + configuration.init-ssh = { + enable = "enabled"; + kernelModules = [ "e1000e" ]; + authorizedKeys = config.users.users.root.openssh.authorizedKeys.keyFiles; + hostECDSAKey = ; + }; + + # programs + programs.custom.vim.enable = true; + environment.systemPackages = [ pkgs.mosh ]; + + # wifi setup + #system.custom.wifi = { + # enable = true; + # configurationFile = ; + # interfaces = [ "wlp3s0" ]; + #}; + # nix-shell -p speedtest_cli --run speedtest + #configuration.fireqos = { + # enable = true; + # interface = "wlp3s0"; + # input = 2500; + # output = 1200; + # balance = false; + #}; + + # nix-shell -p speedtest_cli --run speedtest + configuration.fireqos = { + enable = true; + interface = "eth0"; + input = 2500; + output = 1200; + balance = false; + }; + + +} + diff --git a/configs/porani/hardware-configuration.nix b/configs/porani/hardware-configuration.nix new file mode 100644 index 0000000..effeda9 --- /dev/null +++ b/configs/porani/hardware-configuration.nix @@ -0,0 +1,77 @@ +{ config, lib, pkgs, ... }: +{ + imports = + [ + ]; + + boot.initrd.availableKernelModules = [ "ehci_pci" "ahci" "usb_storage" "sd_mod" "sdhci_pci" ]; + boot.initrd.kernelModules = [ "dm-snapshot" ]; + boot.kernelModules = [ "kvm-intel" ]; + boot.extraModulePackages = [ ]; + + # grub configuration + # ------------------ + boot.loader.grub = { + device = "/dev/sda"; + enable = true; + version = 2; + }; + + # lvm volume group + # ---------------- + boot.initrd.luks.devices = [ + { + name = "vg"; + device = "/dev/sda2"; + preLVM = true; + } + ]; + + # NTFS support + # ------------ + environment.systemPackages = [ + pkgs.ntfs3g + ]; + + # root + # ---- + fileSystems."/" = { + options = [ "noatime" "nodiratime" "discard" ]; + device = "/dev/vg/root"; + fsType = "ext4"; + }; + + # boot + # ---- + fileSystems."/boot" = { + device = "/dev/sda1"; + fsType = "ext4"; + }; + + # automount + # --------- + fileSystems."/media" = { + device = "/dev/disk/by-uuid/162c2f9e-8baa-4433-99fd-bb7e7b69472f"; + fsType = "ext4"; + options = [ + "nofail" + "noauto" + #"x-systemd.device-timeout=1ms" + ]; + }; + systemd.mounts = [ + { + enable = true; + options = "nofail,noauto"; + type = "ext4"; + wantedBy = ["multi-user.target"]; + what = "/dev/disk/by-uuid/162c2f9e-8baa-4433-99fd-bb7e7b69472f"; + where = "/media"; + } + ]; + + swapDevices = [ ]; + + nix.maxJobs = lib.mkDefault 4; + powerManagement.cpuFreqGovernor = lib.mkDefault "powersave"; +} diff --git a/configs/porani/home-assistant.nix b/configs/porani/home-assistant.nix new file mode 100644 index 0000000..b466290 --- /dev/null +++ b/configs/porani/home-assistant.nix @@ -0,0 +1,228 @@ +{ pkgs, config, lib, ... }: +let + unstablePkgs = import {}; +in { + + imports = [ + ./home-assistant/chaospott.nix + ./home-assistant/holiday.nix + ./home-assistant/mpd.nix + ./home-assistant/sonoff.nix + ./home-assistant/mqtt.nix + ./home-assistant/dayOfWeek.nix + ./home-assistant/timer.nix + ./home-assistant/kodi.nix + ./home-assistant/zigbee2mqtt.nix + ]; + + + services.homeAssistantConfig = { + + # turn on to edit GUI + # lovelace = {}; + + homeassistant = { + latitude = 51.444847; + longitude = 6.967006; + elevation = 116; + + + auth_providers = [ + { + type = "trusted_networks"; + trusted_networks = [ + config.module.cluster.services.tinc."private".networkSubnet + ]; + } + ]; + }; + + prometheus.namespace = "hass"; + + automation = [ + + # todo when ich weis ich bin zuhause + #{ + # alias = "Licht and wenn Dunkel"; + # trigger = { + # platform = "state"; + # entity_id = [ "binary_sensor.night" ]; + # from = "off"; + # to = "on"; + # }; + # action = [ + # { + # service = "switch.turn_on"; + # entity_id = "group.kitchen"; + # } + # { + # service = "switch.turn_on"; + # entity_id = "group.living_room"; + # } + # ]; + #} + + #{ + # alias = "Küchen Sensor An"; + # trigger = { + # platform = "state"; + # entity_id = [ "binary_sensor.motion_1" ]; + # to = "on"; + # }; + # action = { + # service = "switch.turn_on"; + # entity_id = "group.kitchen"; + # }; + #} + + #{ + # alias = "Küchen Sensor aus"; + # trigger = { + # platform = "state"; + # entity_id = [ "binary_sensor.motion_1" ]; + # to = "off"; + # for = "00:00:25"; + # }; + # action = { + # service = "switch.turn_off"; + # entity_id = "group.kitchen"; + # }; + #} + ]; + + group = { + bed_room = { + name = "Schlafzimmer"; + view = false; + }; + tv = { + name = "TV"; + view = false; + }; + living_room = { + name = "Wohnzimmer"; + view = false; + }; + kitchen = { + name = "Küche"; + view = false; + }; + today = { + control = "hidden"; + name = "Today"; + view = false; + entities = [ + "sensor.weather_temperature" + "sun.sun" + ]; + }; + all_lights = { + name = "All Lights"; + view = false; + }; + unknown = { + control = "hidden"; + name = "Not Used"; + view = false; + }; + + view_rooms = { + name = "Räume"; + view = true; + entities = [ + "group.all_lights" + "group.bed_room" + "group.living_room" + "group.kitchen" + "group.tv" + ]; + }; + + view_overview = { + name = "Übersicht"; + view = true; + entities = [ "group.today" ]; + }; + + }; + + sun = {}; + + script.turn_all_off.sequence = [ ]; + + script.turn_all_on.sequence = [ ]; + + sensor = [ + # Weather prediction + { platform = "zamg"; + name = "Weather"; + } + ]; + + # todo: add holidays package to home-assiatnt + binary_sensor = [ + { + name = "before_workday"; + platform = "workday"; + country = "DE"; + province = "NW"; + workdays = [ "mon" "tue" "wed" "thu" "fri" ]; + days_offset = 1; + } + { + name = "workday"; + platform = "workday"; + country = "DE"; + province = "NW"; + workdays = [ "mon" "tue" "wed" "thu" "fri" ]; + } + ]; + + }; + + + services.home-assistant = { + enable = true; + package = unstablePkgs.home-assistant.override{ + python3 = unstablePkgs.python36; + extraPackages = python: [ + # todo : check which is still needed + python.netdisco + python.xmltodict + python.mpd2 + + # for mqtt + python.hbmqtt + python.paho-mqtt + + # needed for platform workday + (python.buildPythonPackage rec{ + + pname = "holidays"; + version = "0.9.10"; + + src = python.fetchPypi { + inherit pname version; + sha256 = "9f06d143eb708e8732230260636938f2f57114e94defd8fa2082408e0d422d6f"; + }; + + doCheck = false; + buildInputs = [ pkgs.dateutils ]; + propagatedBuildInputs = [ + python."python-dateutil" + python."six" + ]; + meta = with pkgs.stdenv.lib; { + homepage = "https://github.com/dr-prodigy/python-holidays"; + license = licenses.mit; + description = "Generate and work with holidays in Python"; + maintainers = with maintainers; [ mrVanDalo ]; + }; + + }) + ]; + }; + + }; + +} diff --git a/configs/porani/home-assistant/chaospott.nix b/configs/porani/home-assistant/chaospott.nix new file mode 100644 index 0000000..97ac37f --- /dev/null +++ b/configs/porani/home-assistant/chaospott.nix @@ -0,0 +1,85 @@ +{ config, pkgs, ... }: +let + + name = "chaospott"; + folderPath = config.services.home-assistant.configDir; + filePath = "${folderPath}/${name}.json"; + +in { + services.homeAssistantConfig = { + + sensor = [ + { + platform = "file"; + name = "${name}_aerie"; + file_path = filePath; + value_template = "{{ value_json.aerie }}"; + } + { + platform = "file"; + name = "${name}_cellar"; + file_path = filePath; + value_template = "{{ value_json.cellar }}"; + } + ]; + + homeassistant = { + whitelist_external_dirs = [ folderPath ]; + customize = { + "sensor.${name}_aerie" = { + icon = "mdi:store"; + entity_picture = "https://chaospott.de/images/logo.png"; + friendly_name = "ChaosPott Oben"; + }; + "sensor.${name}_cellar" = { + icon = "mdi:store"; + entity_picture = "https://chaospott.de/images/logo.png"; + friendly_name = "ChaosPott Unten"; + }; + }; + }; + + group = { + "${name}" = { + name = "ChaosPott (Essen)"; + control = "hidden"; + entities = [ + "sensor.${name}_aerie" + "sensor.${name}_cellar" + ]; + }; + view_overview.entities = [ "group.${name}" ]; + }; + + }; + + systemd.services."${name}" = { + enable = true; + before = [ "home-assistant.service" ]; + wantedBy = [ "home-assistant.service" ]; + serviceConfig = { + User = "hass"; + Type = "oneshot"; + }; + description = "set ${name} for homeassistant"; + script = /* sh */ '' + ${pkgs.curl}/bin/curl -Ls https://status.chaospott.de/api \ + | ${pkgs.jq}/bin/jq --compact-output \ + '.sensors.door_locked | + [.[] | { "\(.location)" : (if .value then "closed" else "open" end) }] | + reduce .[] as $item ({}; . + $item) ' \ + >> ${filePath} + ''; + }; + + systemd.timers."${name}" = { + enable = true; + wantedBy = [ "multi-user.target" ]; + timerConfig = { + OnCalendar = "hourly"; + Persistent = "true"; + }; + }; + + +} diff --git a/configs/porani/home-assistant/dayOfWeek.nix b/configs/porani/home-assistant/dayOfWeek.nix new file mode 100644 index 0000000..88b6af3 --- /dev/null +++ b/configs/porani/home-assistant/dayOfWeek.nix @@ -0,0 +1,57 @@ +{ config, ... }: +let + + folderPath = config.services.home-assistant.configDir; + filePath = "${folderPath}/dayOfWeek.json"; + +in { + services.homeAssistantConfig = { + + sensor = [ + { platform = "file"; + name = "day_of_week"; + file_path = filePath; + value_template = "{{ value_json.dayOfWeek }}"; + } + ]; + + homeassistant = { + whitelist_external_dirs = [ folderPath ]; + customize."sensor.day_of_week" = { + icon = "mdi:calendar-today"; + friendly_name = "Wochen Tag"; + }; + }; + + group = { + overview.entities = [ + "sensor.day_of_week" + ]; + }; + + }; + + systemd.services.dayOfWeek = { + enable = true; + before = [ "home-assistant.service" ]; + wantedBy = [ "home-assistant.service" ]; + serviceConfig = { + User = "hass"; + Type = "oneshot"; + }; + description = "set day of wek for homeassistant"; + script = /* sh */ '' + date +'{"dayOfWeek":"%A"}' >> ${filePath} + ''; + }; + systemd.timers.dayOfWeek = { + enable = true; + wantedBy = [ "multi-user.target" ]; + timerConfig = { + OnCalendar = "00:01:00"; + Persistent = "true"; + }; + }; + + +} diff --git a/configs/porani/home-assistant/holiday.nix b/configs/porani/home-assistant/holiday.nix new file mode 100644 index 0000000..7d2b739 --- /dev/null +++ b/configs/porani/home-assistant/holiday.nix @@ -0,0 +1,93 @@ +{ config, pkgs, ... }: +let + + state = "NW"; # NRW + # state = "BE"; # Berlin + + name = "holiday"; + folderPath = config.services.home-assistant.configDir; + filePath = "${folderPath}/${name}.json"; + +in { + services.homeAssistantConfig = { + + # todo : use the python tool + sensor = [ + { platform = "file"; + name = "${name}_date"; + file_path = filePath; + value_template = "{{ value_json.date }}"; + } + { platform = "file"; + name = "${name}_name"; + file_path = filePath; + value_template = "{{ value_json.name }}"; + } + ]; + + homeassistant = { + whitelist_external_dirs = [ folderPath ]; + customize = { + "sensor.${name}_date" = { + icon = "mdi:calendar"; + friendly_name = "Nächster Feiertag"; + }; + "sensor.${name}_name" = { + icon = "mdi:calendar"; + friendly_name = "Nächster Feiertag"; + }; + }; + }; + + group = { + + holidays = { + name = "Feiertage"; + view = false; + control = "hidden"; + entities = [ + "sensor.${name}_date" + "sensor.${name}_name" + ]; + }; + + view_overview.entities = [ "group.holidays" ]; + + }; + + }; + + systemd.services."${name}" = { + enable = true; + before = [ "home-assistant.service" ]; + wantedBy = [ "home-assistant.service" ]; + serviceConfig = { + User = "hass"; + Type = "oneshot"; + }; + description = "set ${name} for homeassistant"; + script = /* sh */ '' + ${pkgs.curl}/bin/curl \ + -Ls "https://feiertage-api.de/api/?jahr=$( date +%Y )&nur_land=${state}" \ + | ${pkgs.jq}/bin/jq --compact-output ' + map_values( .datum ) | + to_entries | + map( { date: .value, name : .key } ) | + sort_by( .date ) | + map(select ( .date >= "'`date +%Y-%m-%d`'" )) | + .[0]' \ + >> ${filePath} + ''; + }; + + systemd.timers."${name}" = { + enable = true; + wantedBy = [ "multi-user.target" ]; + timerConfig = { + OnCalendar = "daily"; + Persistent = "true"; + }; + }; + + +} diff --git a/configs/porani/home-assistant/kodi.nix b/configs/porani/home-assistant/kodi.nix new file mode 100644 index 0000000..3998815 --- /dev/null +++ b/configs/porani/home-assistant/kodi.nix @@ -0,0 +1,85 @@ +{ pkgs, config, lib, ... }: +{ + + services.homeAssistantConfig = { + + group.view_overview.entities = [ + "media_player.kodi" + ]; + + media_player = [ + { + platform = "kodi"; + host = "127.0.0.1"; + turn_on_action.service = "script.watch_tv"; + turn_off_action.service = "script.stop_watch_tv"; + } + ]; + + shell_command = { + start_display = "sudo ${pkgs.systemd}/bin/systemctl start display-manager"; + stop_display = "sudo ${pkgs.systemd}/bin/systemctl stop display-manager"; + }; + + script = { + + turn_all_off.sequence = [ + # todo : use the shell_command here + { + alias = "turn off tv"; + service = "switch.turn_off"; + data.entity_id = "group.tv"; + } + { + alias = "stop kodi"; + service = "shell_command.stop_display"; + } + ]; + + test_display.sequence = [ + { service = "shell_command.start_display"; } + { delay.seconds = 20; } + { service = "shell_command.stop_display"; } + ]; + + watch_tv = { + alias = "Watch TV"; + sequence = [ + { + alias = "turn on tv"; + service = "switch.turn_on"; + data.entity_id = "group.tv"; + } + { delay.minutes = 1;} + { + alias = "start kodi"; + service = "shell_command.start_display"; + } + ]; + }; + + stop_watch_tv = { + alias = "Stop TV"; + sequence = [ + { + alias = "turn off tv"; + service = "switch.turn_off"; + data.entity_id = "group.tv"; + } + { + alias = "stop kodi"; + service = "shell_command.stop_display"; + } + ]; + }; + }; + + group.tv.entities = [ "script.watch_tv" "script.stop_watch_tv" ]; + + }; + + security.sudo.extraConfig = '' + hass ALL= (root) NOPASSWD: ${pkgs.systemd}/bin/systemctl start display-manager + hass ALL= (root) NOPASSWD: ${pkgs.systemd}/bin/systemctl stop display-manager + ''; +} diff --git a/configs/porani/home-assistant/mpd.nix b/configs/porani/home-assistant/mpd.nix new file mode 100644 index 0000000..8400bb8 --- /dev/null +++ b/configs/porani/home-assistant/mpd.nix @@ -0,0 +1,43 @@ +{ lib, ... }: + +{ + services.homeAssistantConfig = { + + group.view_overview.entities = [ + "media_player.mpd" + ]; + + media_player = [ + { + platform = "mpd"; + host = "localhost"; + } + ]; + + script.turn_all_off.sequence = [ + { + alias = "turn mpd off"; + service = "media_player.turn_off"; + data.entity_id = "media_player.mpd"; + } + ]; + + script.turn_all_on.sequence = [ + { + alias = "turn mpd on"; + service = "media_player.turn_on"; + data.entity_id = "media_player.mpd"; + } + { + alias = "Adjust volume"; + service = "media_player.volume_set"; + data = { + entity_id = "media_player.mpd"; + volume_level = "0.90"; + }; + } + ]; + + }; + +} diff --git a/configs/porani/home-assistant/mqtt.nix b/configs/porani/home-assistant/mqtt.nix new file mode 100644 index 0000000..f3a4e92 --- /dev/null +++ b/configs/porani/home-assistant/mqtt.nix @@ -0,0 +1,27 @@ +{ + services.homeAssistantConfig.mqtt = { + # discovery = false; + + # for mosquitto + broker = "127.0.0.1"; + username = fileContents ; + password = fileContents ; + + }; + + services.mosquitto = { + enable = true; + host = "0.0.0.0"; + users = { + homeassistant = { + password = lib.fileContents ; + acl = [ "topic readwrite #" ]; + }; + zigbee = { + password = lib.fileContents ; + acl = [ "topic readwrite #" ]; + }; + }; + }; + +} diff --git a/configs/porani/home-assistant/sonoff.nix b/configs/porani/home-assistant/sonoff.nix new file mode 100644 index 0000000..38ebba8 --- /dev/null +++ b/configs/porani/home-assistant/sonoff.nix @@ -0,0 +1,118 @@ +{ pkgs, config, lib, ... }: + +let + unstablePkgs = import {}; +in { + + services.homeAssistantConfig = + let + + sonoffSwitches = { + "pal01" = { label = "Bett"; icon = "mdi:lightbulb-on"; }; + "pal02" = { label = "Lampe"; icon = "mdi:lightbulb-on"; }; + "pal03" = { label = "Couche"; icon = "mdi:lightbulb-on"; }; + "pal06" = { label = "Küche"; icon = "mdi:lightbulb-on"; }; + "pal05" = { label = "TV"; icon = "mdi:television"; }; + + "pal04" = { label = "Nummer 4"; icon = "mdi:power-plug-off"; }; + "pal07" = { label = "Nummer 7"; icon = "mdi:power-plug-off"; }; + "pal08" = { label = "Nummer 8"; icon = "mdi:power-plug-off"; }; + }; + + toSwitch = name: "switch.${name}"; + + in { + + homeassistant = { + customize = lib.mapAttrs' ( + entity: value: + { + name = toSwitch entity; + value = { + friendly_name = value.label; + icon = value.icon; + }; + } + ) sonoffSwitches; + }; + + script.turn_all_off.sequence = [ + { + alias = "turn off sonoff"; + service = "switch.turn_off"; + data.entity_id = "group.all_lights"; + } + { + alias = "turn off sonoff"; + service = "switch.turn_off"; + data.entity_id = "group.tv"; + } + ]; + + script.turn_all_on.sequence = [ + { + alias = "turn on all lights"; + service = "switch.turn_on"; + data.entity_id = "group.all_lights"; + } + ]; + + group = { + bed_room = { + entities = builtins.map toSwitch [ "pal01" ]; + }; + living_room = { + entities = builtins.map toSwitch [ "pal03" "pal02" ]; + }; + tv = { + entities = builtins.map toSwitch [ "pal05" ]; + }; + kitchen = { + entities = builtins.map toSwitch [ "pal06" ]; + }; + unknown = { + entities = builtins.map toSwitch [ "pal04" "pal07" "pal08" ]; + }; + all_lights = { + entities = builtins.map toSwitch [ "pal01" "pal02" "pal03" "pal06" ]; + }; + }; + + switch = + let + sonoffConfigurations = builtins.map (name: + { + name = name; + platform = "mqtt"; + command_topic = "cmnd/${lib.toUpper name}/POWER"; + state_topic = "stat/${lib.toUpper name}/POWER"; + payload_on = "ON"; + payload_off = "OFF"; + state_on = "ON"; + state_off = "OFF"; + }) (builtins.attrNames sonoffSwitches) ; + in + sonoffConfigurations; + + # discover state on init + automation = [ + { + alias = "Sonoff initial Power state"; + trigger = { + platform = "homeassistant"; + event = "start"; + }; + action = builtins.map ( name: + { + service = "mqtt.publish"; + data = { + topic = "cmnd/${lib.toUpper name}/power"; + payload = ""; + }; + }) + (builtins.attrNames sonoffSwitches); + } + ]; + }; + +} diff --git a/configs/porani/home-assistant/timer.nix b/configs/porani/home-assistant/timer.nix new file mode 100644 index 0000000..ad9bc07 --- /dev/null +++ b/configs/porani/home-assistant/timer.nix @@ -0,0 +1,274 @@ +{ config, ... }: +{ + + imports = [ ./mpd.nix ]; + + services.homeAssistantConfig = { + + sensor = [ + { + platform = "time_date"; + display_options = [ + "time" + "date" + ]; + } + ]; + + input_datetime = { + wakeup = { + name = "Arbeitswecker"; + has_time = true; + has_date = false; + icon = "mdi:alarm"; + }; + leave = { + name = "Turn off Time"; + has_time = true; + has_date = false; + icon = "mdi:alarm"; + }; + return = { + name = "Return home"; + has_time = true; + has_date = false; + icon = "mdi:alarm"; + }; + sleep = { + name = "Turn off Time"; + has_time = true; + has_date = false; + icon = "mdi:alarm"; + }; + }; + + input_boolean = { + wakeup = { + name = "enable"; + icon = "mdi:toggle-switch"; + }; + leave = { + name = "enable"; + icon = "mdi:toggle-switch"; + }; + return = { + name = "enable"; + icon = "mdi:toggle-switch"; + }; + sleep = { + name = "enable"; + icon = "mdi:toggle-switch"; + }; + }; + + input_select = { + wakeup = { + name = "Playlist"; + icon = "mdi:library-music"; + options = [ "wakeup" "wakeup1" "wakeup2" ]; + }; + }; + + binary_sensor = [ + { + platform = "tod"; + name = "night"; + after = "sunset"; + before = "sunrise"; + } + { + platform = "tod"; + name = "daytime"; + after = "sunrise"; + before = "sunset"; + } + ]; + + group = { + + timer_wakeup = { + view = false; + name = "Arbeits Aufwachen"; + control = "hidden"; + entities = [ + "input_boolean.wakeup" + "input_datetime.wakeup" + "input_select.wakeup" + ]; + }; + + timer_leave = { + view = false; + name = "Leave Time"; + control = "hidden"; + entities = [ + "input_boolean.leave" + "input_datetime.leave" + ]; + }; + + timer_return = { + view = false; + name = "Nach Hause kommen"; + control = "hidden"; + entities = [ + "input_boolean.return" + "input_datetime.return" + ]; + }; + + timer_sleep = { + view = false; + name = "Einschlafen"; + control = "hidden"; + entities = [ + "input_boolean.sleep" + "input_datetime.sleep" + ]; + }; + + timers.entities = [ + "group.timer_wakeup" + "group.timer_leave" + "group.timer_return" + "group.timer_sleep" + "binary_sensor.night" + "binary_sensor.daytime" + ]; + + today.entities = [ + "sensor.date" + "sensor.time" + ]; + + view_overview.entities = [ + "group.timer_wakeup" + "group.timer_leave" + "group.timer_return" + "group.timer_sleep" + ]; + }; + + automation = [ + { + alias = "Wecker Arbeiten"; + trigger = { + platform = "template"; + value_template = + "{{ states('sensor.time') == (states.input_datetime.wakeup.attributes.timestamp | int | timestamp_custom('%H:%M', False)) }}"; + }; + condition = { + condition = "and"; + conditions = [ + { + condition = "state"; + entity_id = "input_boolean.wakeup"; + state = "on"; + } + { + condition = "state"; + entity_id = "binary_sensor.workday"; + state = "on"; + } + ]; + }; + action = [ + { + alias = "Play wakeup list"; + service = "media_player.play_media"; + data_template = { + entity_id = "media_player.mpd"; + media_content_type = "playlist"; + media_content_id = "{{ states('input_select.wakeup') }}"; + }; + } + { + alias = "turn all on"; + service = "script.turn_on"; + entity_id = "script.turn_all_on"; + } + ]; + } + + { + alias = "Leave Turn all off Timer"; + trigger = { + platform = "template"; + value_template = + "{{ states('sensor.time') == (states.input_datetime.leave.attributes.timestamp | int | timestamp_custom('%H:%M', False)) }}"; + }; + condition = { + condition = "and"; + conditions = [ + { + condition = "state"; + entity_id = "input_boolean.leave"; + state = "on"; + } + ]; + }; + action = [ + { + alias = "turn all off"; + service = "script.turn_on"; + entity_id = "script.turn_all_off"; + } + ]; + } + + { + alias = "Return to Home"; + trigger = { + platform = "template"; + value_template = + "{{ states('sensor.time') == (states.input_datetime.return.attributes.timestamp | int | timestamp_custom('%H:%M', False)) }}"; + }; + condition = { + condition = "and"; + conditions = [ + { + condition = "state"; + entity_id = "input_boolean.return"; + state = "on"; + } + ]; + }; + action = [ + { + alias = "turn all on"; + service = "script.turn_on"; + entity_id = "script.turn_all_on"; + } + ]; + } + + { + alias = "Sleep Turn all off Timer"; + trigger = { + platform = "template"; + value_template = + "{{ states('sensor.time') == (states.input_datetime.sleep.attributes.timestamp | int | timestamp_custom('%H:%M', False)) }}"; + }; + condition = { + condition = "and"; + conditions = [ + { + condition = "state"; + entity_id = "input_boolean.sleep"; + state = "on"; + } + ]; + }; + action = [ + { + alias = "turn all off"; + service = "script.turn_on"; + entity_id = "script.turn_all_off"; + } + ]; + } + + ]; + }; + +} diff --git a/configs/porani/home-assistant/zigbee2mqtt.nix b/configs/porani/home-assistant/zigbee2mqtt.nix new file mode 100644 index 0000000..fdc6006 --- /dev/null +++ b/configs/porani/home-assistant/zigbee2mqtt.nix @@ -0,0 +1,304 @@ +{ pkgs, lib, config , ... }: +let + + # allow new devices to join + enablePairing = true; + + device = "/dev/ttyACM0"; + dataFolder = "/srv/zigbee/data"; + + sensors = { + buttons = { + "button_1".id = "0x00158d0002b04f65"; + "button_2".id = "0x00158d0002b04f09"; + "button_3".id = "0x00158d0002b00e04"; + }; + temperature = { + "temperature_sensor_1".id = "0x00158d0002d79220"; + "temperature_sensor_2".id = "0x00158d0002d7913d"; + }; + motion = { + "motion_sensor_1".id = "0x00158d0002fbd451"; + }; + }; + + # todo : rename with allSensors + allSensors = with sensors; buttons // temperature // motion; + + zigBee2MqttConfig = { + + # Home Assistant integration (MQTT discovery) + homeassistant = false; + # homeassistant = true; + + # allow new devices to join + permit_join = enablePairing; + + # MQTT settings + mqtt = { + # MQTT base topic for zigbee2mqtt MQTT messages + base_topic = "zigbee2mqtt"; + # MQTT server URL + server = "mqtt://127.0.0.1:1883"; + # MQTT server authentication, uncomment if required: + user = "zigbee"; + password = lib.fileContents ; + }; + + # Serial settings + serial = { + port = "/dev/ttyACM0"; + # Optional: disable LED of CC2531 USB sniffer + disable_led = true; + }; + + devices = lib.mapAttrs' ( + name: { id , ... }: + { + name = id; + value = { + retain = false; + friendly_name = name; + }; + } + ) allSensors; + }; + + configurationYaml = pkgs.writeText "configuration.yml" (builtins.toJSON zigBee2MqttConfig); +in +{ + imports = [ ./mqtt.nix ]; + + services.homeAssistantConfig = { + + # group.unknown.entities = [ "sensor.button_1" ]; + + sensor = let + buttons = with lib; mapAttrsToList ( + name: {...}: + { + platform = "mqtt"; + name = name; + icon = "mdi:toggle-switch"; + state_topic = "zigbee2mqtt/${name}"; + availability_topic = "zigbee2mqtt/bridge/state"; + value_template = "{{ value_json.click }}"; + } + ) sensors.buttons; + + + temperature = with lib; mapAttrsToList ( + name: {...}: + [ + { + platform = "mqtt"; + name = name; + state_topic = "zigbee2mqtt/${name}"; + availability_topic = "zigbee2mqtt/bridge/state"; + unit_of_measurement = "°C"; + device_class = "temperature"; + value_template = "{{ value_json.temperature }}"; + } + { + platform = "mqtt"; + name = "humidity_${name}"; + state_topic = "zigbee2mqtt/${name}"; + availability_topic = "zigbee2mqtt/bridge/state"; + unit_of_measurement = "%"; + device_class = "humidity"; + value_template = "{{ value_json.humidity }}"; + } + { + platform = "mqtt"; + name = "pressure_${name}"; + state_topic = "zigbee2mqtt/${name}"; + availability_topic = "zigbee2mqtt/bridge/state"; + unit_of_measurement = "hPa"; + device_class = "pressure"; + value_template = "{{ value_json.pressure }}"; + } + ] + ) sensors.temperature; + + informations = lib.mapAttrsToList ( + name: {...}: + [ + { + platform = "mqtt"; + name = "battery_${name}"; + state_topic = "zigbee2mqtt/${name}"; + availability_topic = "zigbee2mqtt/bridge/state"; + unit_of_measurement = "%"; + device_class = "battery"; + value_template = "{{ value_json.battery }}"; + } + { + name = "link_${name}"; + platform = "mqtt"; + state_topic = "zigbee2mqtt/${name}"; + availability_topic = "zigbee2mqtt/bridge/state"; + unit_of_measurement = "-"; + value_template = "{{ value_json.linkquality }}"; + } + ] + ) allSensors; + + in + lib.flatten ( buttons ++ temperature ++ informations ); + + binary_sensor = let + + motion = lib.mapAttrsToList ( + name: { ... }: + { + name = name; + platform = "mqtt"; + device_class = "motion"; + #icon = "mdi:motion-sensor"; + state_topic = "zigbee2mqtt/${name}"; + availability_topic = "zigbee2mqtt/bridge/state"; + payload_on = true; + payload_off = false; + value_template = "{{ value_json.occupancy }}"; + } + ) sensors.motion; + in + lib.flatten ( motion ); + + + + group = let + + information = name: [ "sensor.battery_${name}" "sensor.link_${name}" ]; + + sensor = lib.mapAttrs' ( + name: {...}: + { + name = name; + value = { + control = "hidden"; + entities = ["sensor.${name}"] ++ (information name); + }; + } + ) (sensors.buttons); + + sensorTemperature = lib.mapAttrs' ( + name: { ... }: + { + name = name; + value = { + control = "hidden"; + entities = [ + "sensor.${name}" + "sensor.humidity_${name}" + "sensor.pressure_${name}" + ] ++ (information name); + }; + } + ) (sensors.temperature); + + binarySensor = lib.mapAttrs' ( + name: { ... }: + { + name = name; + value = { + control = "hidden"; + entities = [ "binary_sensor.${name}" ] ++ (information name); + }; + } + ) (sensors.motion); + + views = { + view_sensors = { + name = "Sensoren"; + control = "hidden"; + view = true; + entities = lib.mapAttrsToList (name: { ... }: "group.${name}") allSensors; + }; + }; + + in + views // sensor // binarySensor // sensorTemperature ; + + automation = + let + lights = map (button: + { + alias = "Toggle all lights, on click"; + trigger = { + platform = "mqtt"; + topic = "zigbee2mqtt/${button}"; + }; + condition = { + condition = "template"; + value_template = ''{{ "single" == trigger.payload_json.click }}''; + }; + action = { + service = "switch.toggle"; + entity_id = "group.all_lights"; + }; + }) ["button_1" "button_2" "button_3"]; + mpd = map (button: + { + alias = "Toggle mpd, on double click"; + trigger = { + platform = "mqtt"; + topic = "zigbee2mqtt/${button}"; + }; + condition = { + condition = "template"; + value_template = ''{{ "double" == trigger.payload_json.click }}''; + }; + action = { + service = "media_player.toggle"; + # todo use a group here + entity_id = "media_player.mpd"; + }; + }) ["button_1" "button_2" "button_3"]; + in + lights ++ mpd; + + # click = double => music an aus + + # click = hold => film an aus + + }; + + virtualisation.docker.enable = true; + + # todo : einen eigenen container bauen mit dockerTool : https://nixos.wiki/wiki/Docker + + systemd.services."zigbee2mqtt" = { + enable = true; + description = "Allows you to use your Zigbee devices without the vendors bridge/gateway."; + after = [ "docker.service" ]; + requires = [ "docker.service" ]; + # todo : udev rule erstellen, die diesen service erst startet, dieses wanted by ist labil + wantedBy = [ "home-assistant.service" ]; + + preStart = '' + if [ -f ${dataFolder}/configuration.yaml ] + then + rm ${dataFolder}/configuration.yaml + fi + mkdir -p ${dataFolder} + cat ${configurationYaml} | ${pkgs.yq}/bin/yq --yaml-output '.' > ${dataFolder}/configuration.yaml + ''; + + restartTriggers = [ configurationYaml ]; + + script = '' + # delete old instance to ensure update + ${pkgs.docker}/bin/docker stop zigbee2mqtt || true && ${pkgs.docker}/bin/docker rm -f zigbee2mqtt || true + # start instance + ${pkgs.docker}/bin/docker run \ + --network="host" \ + --name zigbee2mqtt \ + -v ${dataFolder}:/app/data \ + --device=${device} \ + koenkk/zigbee2mqtt + ''; + }; + + +} diff --git a/configs/porani/kodi.nix b/configs/porani/kodi.nix new file mode 100644 index 0000000..27dc32b --- /dev/null +++ b/configs/porani/kodi.nix @@ -0,0 +1,30 @@ +{ config, lib, pkgs, ... }: +{ + + + services.xserver = { + enable = true; + autorun = false; + desktopManager = { + kodi.enable = true; + default = "kodi"; + xterm.enable = false; + }; + displayManager.lightdm = { + enable = true; + autoLogin.enable = true; + autoLogin.user = config.users.users.kodi.name; + }; + }; + + users = { + # mutableUsers = true; + users.kodi= { + isNormalUser = true; + name = "kodi"; + uid = 1338; + initialPassword = lib.fileContents ; + }; + }; + +} diff --git a/configs/porani/mpd.nix b/configs/porani/mpd.nix new file mode 100644 index 0000000..2f1b861 --- /dev/null +++ b/configs/porani/mpd.nix @@ -0,0 +1,12 @@ +{ config, lib, ... }: +{ + + sound.enable = true; + + services.mpd = { + enable = true; + network.listenAddress = "any"; + musicDirectory = "/media/music-library"; + }; + +} diff --git a/configs/porani/packages.nix b/configs/porani/packages.nix new file mode 100644 index 0000000..4456ca7 --- /dev/null +++ b/configs/porani/packages.nix @@ -0,0 +1,7 @@ +{ pkgs, ... }: +{ + + environment.systemPackages = [ + ]; + +} diff --git a/configs/porani/syncthing.nix b/configs/porani/syncthing.nix new file mode 100644 index 0000000..fa47ac4 --- /dev/null +++ b/configs/porani/syncthing.nix @@ -0,0 +1,38 @@ +{ config, pkgs, lib, ... }: +{ + + test.services.syncthing = { + enable = true; + openDefaultPorts = true; + declarative = { + cert = toString ; + key = toString ; + overrideFolders = true; + folders = { + movies.path = "/media/movies"; + music-library.path = "/media/music-library"; + podcasts.path = "/media/podcasts"; + series.path = "/media/series"; + }; + }; + }; + + systemd.services."permown._media" = { + bindsTo = [ "media.mount" ]; + after = [ "media.mount" ]; + }; + system.permown."/media" = { + owner = "syncthing"; + group = "syncthing"; + umask = "0007"; + }; + systemd.services."syncthing" = { + bindsTo = [ "media.mount" ]; + after = [ "media.mount" ]; + }; + + users.groups."syncthing".members = [ "mpd" "syncthing" "kodi" "palo" ]; + + + +} diff --git a/configs/porani/tinc.nix b/configs/porani/tinc.nix new file mode 100644 index 0000000..6c15e0b --- /dev/null +++ b/configs/porani/tinc.nix @@ -0,0 +1,12 @@ +{ config, lib, pkgs, ... }: +{ + + module.cluster.services.tinc = { + "private" = { + enable = true; + openPort = true; + connectTo = [ "sputnik" ]; + }; + }; + +} diff --git a/configs/porani/wifi-access-point.nix b/configs/porani/wifi-access-point.nix new file mode 100644 index 0000000..6b17801 --- /dev/null +++ b/configs/porani/wifi-access-point.nix @@ -0,0 +1,67 @@ +{lib, pkgs, ... }: + +let + wifi = "wlp0s29u1u2"; + ipAddress = "10.23.45.1"; + prefixLength = 24; + servedAddressRange = "10.23.45.2,10.23.45.150,12h"; + ssid="palosiot"; + wifiPassword=lib.fileContents ; +in + +{ + # todo only open needed ports + networking.firewall.trustedInterfaces = [ wifi ]; + + networking.networkmanager.unmanaged = [ wifi ]; + networking.dhcpcd.denyInterfaces = [ wifi ]; + + networking.interfaces."${wifi}".ipv4.addresses = [ { + address = ipAddress; prefixLength = prefixLength; + }]; + + systemd.services.hostapd = { + description = "hostapd wireless AP"; + path = [ pkgs.hostapd ]; + wantedBy = [ "network.target" ]; + + after = [ "${wifi}-cfg.service" "nat.service" "bind.service" "dhcpd.service" "sys-subsystem-net-devices-${wifi}.device" ]; + + serviceConfig = { + ExecStart = "${pkgs.hostapd}/bin/hostapd ${pkgs.writeText "hostapd.conf" '' + interface=${wifi} + hw_mode=g + channel=10 + ieee80211d=1 + country_code=DE + ieee80211n=1 + wmm_enabled=1 + + ssid=${ssid} + auth_algs=1 + wpa=2 + wpa_key_mgmt=WPA-PSK + rsn_pairwise=CCMP + wpa_passphrase=${wifiPassword} + ''}"; + Restart = "always"; + }; + }; + + services.dnsmasq = { + enable = true; + extraConfig = '' + # Only listen to routers' LAN NIC. Doing so opens up tcp/udp port 53 to + # localhost and udp port 67 to world: + interface=${wifi} + + # Explicitly specify the address to listen on + listen-address=${ipAddress} + + # Dynamic range of IPs to make available to LAN PC and the lease time. + # Ideally set the lease time to 5m only at first to test everything works okay before you set long-lasting records. + dhcp-range=${servedAddressRange} + ''; + }; + +} diff --git a/configs/porani/wifi-networking.nix b/configs/porani/wifi-networking.nix new file mode 100644 index 0000000..18d0b32 --- /dev/null +++ b/configs/porani/wifi-networking.nix @@ -0,0 +1,4 @@ +{ config, lib, ... }: +{ + +} diff --git a/configs/sputnik/configuration.nix b/configs/sputnik/configuration.nix new file mode 100644 index 0000000..7eb4b20 --- /dev/null +++ b/configs/sputnik/configuration.nix @@ -0,0 +1,41 @@ +{ config, pkgs, lib, ... }: +{ + imports = [ + + + ./hardware-configuration.nix + + ./nginx.nix + ./tinc.nix + + ]; + + networking.hostName = "sputnik"; + networking.useDHCP = true; + + boot.kernelParams = [ "net.ifnames=0" ]; + boot.loader.grub = { + enable = true; + version = 2; + device = "/dev/sda"; + }; + + # nix-shell -p speedtest_cli --run speedtest + configuration.fireqos = { + enable = true; + interface = "eth0"; + input = 55000; + output = 4000; + balance = false; + }; + + services.custom.ssh.sshd.rootKeyFiles = [ (toString ) ]; + + # make sure ssh is only available trough the tinc + networking.firewall.extraCommands = '' + iptables -t nat -A PREROUTING ! -i tinc.private -p tcp -m tcp --dport 22 -j REDIRECT --to-ports 0 + ''; + +} + + diff --git a/configs/sputnik/hardware-configuration.nix b/configs/sputnik/hardware-configuration.nix new file mode 100644 index 0000000..1ce8aaa --- /dev/null +++ b/configs/sputnik/hardware-configuration.nix @@ -0,0 +1,23 @@ +# 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.initrd.availableKernelModules = [ "ata_piix" "uhci_hcd" "virtio_pci" "sd_mod" "sr_mod" ]; + boot.kernelModules = [ ]; + boot.extraModulePackages = [ ]; + + fileSystems."/" = + { device = "/dev/disk/by-uuid/8f2986a3-d2b0-4735-be98-9ec081b87984"; + fsType = "ext4"; + }; + + swapDevices = [ ]; + + nix.maxJobs = lib.mkDefault 1; +} diff --git a/configs/sputnik/nginx.nix b/configs/sputnik/nginx.nix new file mode 100644 index 0000000..f5447e3 --- /dev/null +++ b/configs/sputnik/nginx.nix @@ -0,0 +1,146 @@ +{ config, lib, pkgs, ... }: +{ + + networking.firewall.allowedTCPPorts = [ 80 443 ]; + + services.nginx = { + enable = true; + virtualHosts = { + + "git.ingolf-wagner.de" = { + listen = [ + { addr = "0.0.0.0"; port = 4443; ssl = true; } + { addr = "0.0.0.0"; port = 80; ssl = false; } + ]; + forceSSL = true; + enableACME = true; + locations."/" = { + proxyPass = "http://workhorse.private:3000"; + }; + }; + + "paste.ingolf-wagner.de" = { + listen = [ + { addr = "0.0.0.0"; port = 4443; ssl = true; } + { addr = "0.0.0.0"; port = 80; ssl = false; } + ]; + forceSSL = true; + enableACME = true; + locations."/" = { + proxyPass = "http://workhorse.private:8000"; + }; + }; + + #"landing.ingolf-wagner.de" = { + # default = true; + # listen = [ + # { addr = "0.0.0.0"; port = 4443; ssl = true; } + # { addr = "0.0.0.0"; port = 80; ssl = false; } + # ]; + # forceSSL = true; + # enableACME = true; + # locations."/" = { + # root = "/srv/www/ingolf-wagner.de"; + # }; + #}; + + "tech.ingolf-wagner.de" = { + listen = [ + { addr = "0.0.0.0"; port = 4443; ssl = true; } + { addr = "0.0.0.0"; port = 80; ssl = false; } + ]; + forceSSL = true; + enableACME = true; + locations."/" = { + root = "/srv/www/tech"; + extraConfig = '' + if (-d $request_filename) { + rewrite [^/]$ $scheme://$http_host$uri/ permanent; + } + ''; + }; + }; + + "terranix.org" = { + listen = [ + { addr = "0.0.0.0"; port = 4443; ssl = true; } + { addr = "0.0.0.0"; port = 80; ssl = false; } + ]; + forceSSL = true; + enableACME = true; + locations."/" = { + root = "/srv/www/terranix"; + extraConfig = '' + if (-d $request_filename) { + rewrite [^/]$ $scheme://$http_host$uri/ permanent; + } + ''; + }; + }; + + + "seafile.gaykraft.com" = { + listen = [ + { addr = "0.0.0.0"; port = 4443; ssl = true; } + { addr = "0.0.0.0"; port = 80; ssl = false; } + ]; + forceSSL = true; + enableACME = true; + locations."/" = { + proxyPass = "http://workhorse.private:3030"; + extraConfig = '' + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Host $server_name; + proxy_set_header X-Forwarded-Proto https; + + sub_filter "http://seafile.gaykraft.com" "https://seafile.gaykraft.com"; + + # used for view/edit office file via Office Online Server + client_max_body_size 0; + ''; + }; + }; + + "gaykraft.com" = { + listen = [ + { addr = "0.0.0.0"; port = 4443; ssl = true; } + { addr = "0.0.0.0"; port = 80; ssl = false; } + ]; + forceSSL = true; + enableACME = true; + locations."/" = { + root = "/srv/www/gaykraft"; + }; + }; + + }; + }; + + services.sslh = { + enable = true; + listenAddress = "0.0.0.0"; + port = 443; + verbose = false; + transparent = true; + appendConfig = /* json */ '' + protocols: + ( + { name: "ssh"; service: "ssh"; host: "localhost"; port: "2222"; probe: "builtin"; }, + { name: "ssl"; host: "localhost"; port: "4443"; probe: "builtin"; }, + { name: "tinc"; host: "localhost"; port: "655"; probe: "builtin"; } + ); + ''; + }; + + systemd.services."socat-proxy" = { + wantedBy = [ "sslh.service" "multi-user.target" ]; + after = [ "sslh.service" ]; + script = '' + ${pkgs.socat}/bin/socat TCP-LISTEN:2222,fork TCP:workhorse.private:2222 + ''; + #serviceConfig.User = "sslh"; + }; + +} diff --git a/configs/sputnik/tinc.nix b/configs/sputnik/tinc.nix new file mode 100644 index 0000000..14b49e5 --- /dev/null +++ b/configs/sputnik/tinc.nix @@ -0,0 +1,10 @@ +{ config, lib, pkgs, ... }: +{ + module.cluster.services.tinc = { + "private" = { + enable = true; + openPort = true; + }; + }; + +} diff --git a/configs/sterni/configuration.nix b/configs/sterni/configuration.nix new file mode 100644 index 0000000..f0ca833 --- /dev/null +++ b/configs/sterni/configuration.nix @@ -0,0 +1,65 @@ +{ config, pkgs, lib, ... }: +{ + + + imports = [ + + + ./hardware-configuration.nix + + ./encfs.nix + ./packages.nix + ./syncthing.nix + ./tinc.nix + + #./wifi-access-point.nix + + ]; + + networking.hostName = "sterni"; + + system.custom.wifi.interfaces = ["wlp3s0"]; + + security.wrappers = { + pmount.source = "${pkgs.pmount}/bin/pmount"; + pumount.source = "${pkgs.pmount}/bin/pumount"; + }; + + # keybase + services.keybase.enable = true; + services.kbfs.enable = true; + + programs.custom.steam.enable = false; + programs.custom.video.enable = false; + + services.printing.enable = true; + + # fonts + # ----- + programs.custom.urxvt.fontSize = 12; + programs.custom.xterm.fontSize = 12; + system.custom.fonts.dpi = 100; + + virtualisation = { + docker.enable = false; + + virtualbox = { + host.enable = false; + guest.x11 = false; + guest.enable = false; + }; + }; + + configuration.desktop = { + width = 1366; + height = 768; + }; + + custom.samba-share.folders = { + enable = false; + public = "/home/palo/movies"; + }; + +} + + diff --git a/configs/sterni/encfs.nix b/configs/sterni/encfs.nix new file mode 100644 index 0000000..09b654d --- /dev/null +++ b/configs/sterni/encfs.nix @@ -0,0 +1,8 @@ +{ config, lib, pkgs, ... }: +{ + module.backup.services.encfs = { + "fotos".enable = true; + "desktop".enable = true; + "finance".enable = true; + }; +} diff --git a/configs/sterni/hardware-configuration.nix b/configs/sterni/hardware-configuration.nix new file mode 100644 index 0000000..f4d4058 --- /dev/null +++ b/configs/sterni/hardware-configuration.nix @@ -0,0 +1,92 @@ +# 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.initrd.availableKernelModules = [ "ehci_pci" "ahci" "xhci_pci" "usb_storage" "sd_mod" "sdhci_pci" ]; + boot.initrd.kernelModules = [ "dm-snapshot" ]; + boot.kernelModules = [ "kvm-intel" ]; + boot.extraModulePackages = [ ]; + + # Use the systemd-boot EFI boot loader. + boot.loader.systemd-boot.enable = true; + boot.loader.efi.canTouchEfiVariables = true; + + zramSwap = { + enable = true; + numDevices = 2; + swapDevices = 1; + memoryPercent = 50; + }; + + fileSystems."/share/" = { + device = "/dev/ram1"; + fsType = "tmpfs"; + }; + + fileSystems."/browsers/" = { + #device = "/dev/ram2"; + #fsType = "tmpfs"; + options = [ "noatime" "nodiratime" "discard" ]; + device = "/dev/vg/browser"; + fsType = "ext4"; + }; + + nix.maxJobs = lib.mkDefault 4; + powerManagement.cpuFreqGovernor = lib.mkDefault "powersave"; + + # lvm volume group + # ---------------- + boot.initrd.luks.devices = [ + { + name = "vg"; + device = "/dev/sda2"; + preLVM = true; + } + ]; + + # NTFS support + # ------------ + environment.systemPackages = [ + pkgs.ntfs3g + ]; + + # root + # ---- + fileSystems."/" = { + options = [ "noatime" "nodiratime" "discard" ]; + device = "/dev/vg/root"; + fsType = "ext4"; + }; + + # home + # ---- + fileSystems."/home" = { + options = [ "noatime" "nodiratime" "discard" ]; + device = "/dev/vg/home"; + fsType = "ext4"; + }; + + # /home/palo/private/.fotos.ct + # -------------------- + #fileSystems."/home/palo/private/.fotos.ct" = { + # options = [ "noatime" "nodiratime" "discard" ]; + # device = "/dev/vg/fotos"; + # fsType = "ext4"; + #}; + + # boot + # ---- + fileSystems."/boot" = { + device = "/dev/sda1"; + fsType = "vfat"; + }; + + +} diff --git a/configs/sterni/packages.nix b/configs/sterni/packages.nix new file mode 100644 index 0000000..367d331 --- /dev/null +++ b/configs/sterni/packages.nix @@ -0,0 +1,8 @@ +{ config, lib, pkgs, ... }: +{ + + environment.systemPackages = with pkgs ; [ + bitwig-studio + ]; + +} diff --git a/configs/sterni/syncthing.nix b/configs/sterni/syncthing.nix new file mode 100644 index 0000000..72be451 --- /dev/null +++ b/configs/sterni/syncthing.nix @@ -0,0 +1,27 @@ +{ config, pkgs, lib, ... }: +{ + + test.services.syncthing = { + enable = true; + openDefaultPorts = false; + user = "palo"; + dataDir = "/home/palo/.syncthing"; + configDir = "/home/palo/.syncthing"; + declarative = { + cert = toString ; + key = toString ; + + overrideFolders = true; + folders = { + + book.path = "/home/palo/books"; + desktop-encrypted.path = "/home/palo/.desktop.ct"; + finance-encrypted.path = "/home/palo/.finance.ct"; + fotos-encrypted.path = "/home/palo/private/.fotos.ct"; + music-library.path = "/home/palo/music-library"; + music-projects.path = "/home/palo/music-projects"; + + }; + }; + }; +} diff --git a/configs/sterni/tinc.nix b/configs/sterni/tinc.nix new file mode 100644 index 0000000..6f8c828 --- /dev/null +++ b/configs/sterni/tinc.nix @@ -0,0 +1,18 @@ +{ config, lib, pkgs, ... }: + +with lib; + +{ + module.cluster.services.tinc = { + "private" = { + enable = true; + openPort = true; + connectTo = [ "sputnik" ]; + }; + "retiolum" = { + enable = true; + openPort = true; + }; + }; + +} diff --git a/configs/sterni/wifi-access-point.nix b/configs/sterni/wifi-access-point.nix new file mode 100644 index 0000000..4c309cb --- /dev/null +++ b/configs/sterni/wifi-access-point.nix @@ -0,0 +1,77 @@ +{lib, pkgs, ... }: + +let + wifi = "wlp0s29u1u2"; + ipAddress = "10.123.145.1"; + prefixLength = 24; + servedAddressRange = "10.123.145.2,10.123.145.150,12h"; + ssid="bumbumbum"; + wifiPassword=lib.fileContents ; +in + +{ + # todo only open needed ports + networking.firewall.trustedInterfaces = [ wifi ]; + + networking.networkmanager.unmanaged = [ wifi ]; + networking.dhcpcd.denyInterfaces = [ wifi ]; + + networking.interfaces."${wifi}".ipv4.addresses = [ { + address = ipAddress; + prefixLength = prefixLength; + }]; + + # forward traffic coming in trough the access point => provide internet and vpn network access + # todo : forward to own servers + boot.kernel.sysctl = { + "net.ipv4.conf.${wifi}.forwarding" = true; + "net.ipv6.conf.${wifi}.forwarding" = true; + }; + + systemd.services.hostapd = { + description = "hostapd wireless AP"; + path = [ pkgs.hostapd ]; + + # start manual + # wantedBy = [ "network.target" ]; + + after = [ "${wifi}-cfg.service" "nat.service" "bind.service" "dhcpd.service" "sys-subsystem-net-devices-${wifi}.device" ]; + + serviceConfig = { + ExecStart = "${pkgs.hostapd}/bin/hostapd ${pkgs.writeText "hostapd.conf" '' + interface=${wifi} + hw_mode=g + channel=10 + ieee80211d=1 + country_code=DE + ieee80211n=1 + wmm_enabled=1 + + ssid=${ssid} + auth_algs=1 + wpa=2 + wpa_key_mgmt=WPA-PSK + rsn_pairwise=CCMP + wpa_passphrase=${wifiPassword} + ''}"; + Restart = "always"; + }; + }; + + services.dnsmasq = { + enable = true; + extraConfig = '' + # Only listen to routers' LAN NIC. Doing so opens up tcp/udp port 53 to + # localhost and udp port 67 to world: + interface=${wifi} + + # Explicitly specify the address to listen on + listen-address=${ipAddress} + + # Dynamic range of IPs to make available to LAN PC and the lease time. + # Ideally set the lease time to 5m only at first to test everything works okay before you set long-lasting records. + dhcp-range=${servedAddressRange} + ''; + }; + +} diff --git a/configs/workhorse/bepasty.nix b/configs/workhorse/bepasty.nix new file mode 100644 index 0000000..f544e03 --- /dev/null +++ b/configs/workhorse/bepasty.nix @@ -0,0 +1,56 @@ +{ config, pkgs, lib, ... }: + +with lib; +let + port = 8000; +in { + + # configure nginx + services.nginx = { + enable = true; + virtualHosts = { + "paste.workhorse.private" = { + locations."/" = { + proxyPass = "http://localhost:${toString port}"; + extraConfig = '' + proxy_set_header Host $host:$server_port; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_read_timeout 90; + proxy_redirect http://localhost:${toString port} https://paste.workhorse.private/; + ''; + }; + }; + }; + }; + + krops.userKeys."bepasty" = { + user = "bepasty"; + source = toString ; + requiredBy = [ "bepasty-server-ingolf-wagner.de-gunicorn.service" ]; + }; + + services.bepasty = { + enable = true; + servers."ingolf-wagner.de" = { + bind = "0.0.0.0:${toString port}"; + secretKeyFile = config.krops.userKeys."bepasty".target; + extraConfig = '' + PERMISSIONS = { + '${lib.fileContents }': 'admin,list,create,read,delete', + } + ''; + }; + }; + + /* fix bepasty service */ + nixpkgs.overlays = let + overlay = self: super: + { + bepasty = super.bepasty.override { python3Packages = pkgs.python27Packages; }; + }; + in + [ overlay ]; + +} diff --git a/configs/workhorse/castget.nix b/configs/workhorse/castget.nix new file mode 100644 index 0000000..79c962e --- /dev/null +++ b/configs/workhorse/castget.nix @@ -0,0 +1,25 @@ +{ config, lib, ... }: +let + + home = "/home/syncthing/podcasts"; + +in { + custom.services.castget = { + enable = true; + user = "root"; + feeds = { + Alternativlos = { + url = "https://alternativlos.org/alternativlos.rss"; + spool = "${home}/alternativlos"; + }; + LORA_radio = { + url = "https://www.freie-radios.net/portal/podcast.php?radio=19&rss"; + spool = "${home}/lora_radio"; + }; + gegenstandpunkt = { + url = "https://pc.argudiss.de/"; + spool = "${home}/GegenStandpunkt"; + }; + }; + }; +} diff --git a/configs/workhorse/configuration.nix b/configs/workhorse/configuration.nix new file mode 100644 index 0000000..7c92f75 --- /dev/null +++ b/configs/workhorse/configuration.nix @@ -0,0 +1,80 @@ +{ lib, config, pkgs, ... }: +{ + imports = [ + + + ./hardware-configuration.nix + + ./bepasty.nix + ./castget.nix + ./gogs.nix + ./grafana.nix + ./graylog.nix + ./jenkins.nix + ./kibana.nix + ./lektor-gaykraft.nix + ./lektor-techblog.nix + ./lektor-terranix.nix + ./mail-fetcher.nix + ./packages.nix + ./prometheus.nix + ./restic.nix + ./seafile.nix + ./syncthing.nix + ./taskserver.nix + ./tinc.nix + ./transmission.nix + ./weechat.nix + ./wetten.nix + + ]; + + networking.hostName = "workhorse"; + + # enable initrd ssh + configuration.init-ssh = { + enable = "enabled"; + kernelModules = [ "r8169" ]; + authorizedKeys = config.users.users.root.openssh.authorizedKeys.keyFiles; + hostECDSAKey = ; + }; + + # nix-shell -p speedtest_cli --run speedtest + configuration.fireqos = { + enable = true; + interface = "eth0"; + input = 30000; + output = 2000; + balance = false; + }; + + security.wrappers = { + pmount.source = "${pkgs.pmount}/bin/pmount"; + pumount.source = "${pkgs.pmount}/bin/pumount"; + }; + + services.logind.lidSwitch = lib.mkForce "ignore"; + system.custom.x11.enable = lib.mkForce false; + programs.custom.steam.enable = false; + programs.custom.video.enable = false; + + # font + # ---- + programs.custom.urxvt.fontSize = 17; + programs.custom.xterm.fontSize = 17; + system.custom.fonts.dpi = 140; + + services.printing.enable = true; + nix.useSandbox = true; + + virtualisation = { + docker.enable = true; + virtualbox = { + host.enable = true; + guest.x11 = true; + guest.enable = true; + }; + }; + +} + diff --git a/configs/workhorse/encfs.nix b/configs/workhorse/encfs.nix new file mode 100644 index 0000000..09b654d --- /dev/null +++ b/configs/workhorse/encfs.nix @@ -0,0 +1,8 @@ +{ config, lib, pkgs, ... }: +{ + module.backup.services.encfs = { + "fotos".enable = true; + "desktop".enable = true; + "finance".enable = true; + }; +} diff --git a/configs/workhorse/gogs.nix b/configs/workhorse/gogs.nix new file mode 100644 index 0000000..1790a66 --- /dev/null +++ b/configs/workhorse/gogs.nix @@ -0,0 +1,39 @@ +{ config, lib, ... }: +{ + + services.nginx = { + enable = true; + statusPage = true; + virtualHosts = { + "gogs.${config.networking.hostName}.private" = { + serverAliases = ["git.${config.networking.hostName}.private"]; + locations."/" = { + proxyPass = "http://${config.networking.hostName}.private:${toString config.services.gogs.httpPort}"; + }; + }; + }; + }; + + services.gogs = { + enable = true; + appName = "Kruck GoGs"; + domain = "git.ingolf-wagner.de"; + httpPort = 3000; + repositoryRoot = "/home/gogs/repositories"; + stateDir = "/home/gogs"; + rootUrl = "https://git.ingolf-wagner.de/"; + extraConfig = '' + [service] + DISABLE_REGISTRATION = true + SHOW_REGISTRATION_BUTTON = false + [server] + SSH_DOMAIN = "git.ingolf-wagner.de" + SSH_PORT = 443 + START_SSH_SERVER = true + SSH_LISTEN_PORT = 2222 + ''; + }; + + backup.all.restic.dirs = [ config.services.gogs.repositoryRoot ]; + +} diff --git a/configs/workhorse/grafana.nix b/configs/workhorse/grafana.nix new file mode 100644 index 0000000..22ed645 --- /dev/null +++ b/configs/workhorse/grafana.nix @@ -0,0 +1,38 @@ +{ config, ... }: +{ + services.nginx = { + enable = true; + statusPage = true; + virtualHosts = { + "grafana.${config.networking.hostName}.private" = { + serverAliases = []; + locations."/" = { + proxyPass = "http://${config.networking.hostName}.private:${toString config.services.grafana.port}"; + }; + }; + }; + }; + + services.grafana = { + enable = true; + port = 5656; + addr = config.module.cluster.services.tinc."private".hosts."${config.networking.hostName}".tincIp; + auth.anonymous = { + enable = true; + org_role = "Editor"; + org_name = "AWESOME"; + }; + provision = { + enable = true; + datasources = [ + { + type = "prometheus"; + isDefault = true; + name = "Prometheus Workhorse"; + url = "http://workhorse.private:9090"; + } + ]; + }; + }; + +} diff --git a/configs/workhorse/graylog.nix b/configs/workhorse/graylog.nix new file mode 100644 index 0000000..3c9faf5 --- /dev/null +++ b/configs/workhorse/graylog.nix @@ -0,0 +1,100 @@ +{ config, lib, pkgs, ... }: +let + port = 9000; +in +{ + # configure nginx + services.nginx = { + enable = true; + virtualHosts = { + "graylog.workhorse.private" = { + locations."/" = { + proxyPass = "http://localhost:${toString port}"; + extraConfig = '' + proxy_set_header Host $host:$server_port; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_read_timeout 90; + proxy_redirect http://localhost:${toString port} https://graylog.workhorse.private/; + ''; + }; + }; + }; + }; + + services.elasticsearch.enable = true; + services.mongodb.enable = true; + + services.graylog.enable = true; + services.graylog.elasticsearchHosts = [ "http://${config.services.elasticsearch.listenAddress}:9200" ]; + + # https://docs.graylog.org/en/3.0/pages/configuration/server.conf.html + services.graylog.extraConfig = '' + http_bind_address = 0.0.0.0:${toString port} + http_publish_uri = http://workhorse.private:${toString port}/ + ''; + + # other wise this does not work + services.graylog.nodeIdFile = "/var/lib/graylog/node-id"; + + # pwgen -N 1 -s 96 + services.graylog.passwordSecret = lib.fileContents ; + + # echo -n yourpassword | shasum -a 256 + services.graylog.rootPasswordSha2 = lib.fileContents ; + + environment.etc."graylog/server/GeoLite2-City.mmdb" = { + enable = true; + source = "${pkgs.geodatabase}/GeoLite2-City.mmdb"; + }; + + # https://wiki.splunk.com/Http_status.csv + environment.etc."graylog/server/httpCodes.csv" = { + enable = true; + text = '' + status,status_description,status_type + 100,Continue,Informational + 101,Switching Protocols,Informational + 200,OK,Successful + 201,Created,Successful + 202,Accepted,Successful + 203,Non-Authoritative Information,Successful + 204,No Content,Successful + 205,Reset Content,Successful + 206,Partial Content,Successful + 300,Multiple Choices,Redirection + 301,Moved Permanently,Redirection + 302,Found,Redirection + 303,See Other,Redirection + 304,Not Modified,Redirection + 305,Use Proxy,Redirection + 307,Temporary Redirect,Redirection + 400,Bad Request,Client Error + 401,Unauthorized,Client Error + 402,Payment Required,Client Error + 403,Forbidden,Client Error + 404,Not Found,Client Error + 405,Method Not Allowed,Client Error + 406,Not Acceptable,Client Error + 407,Proxy Authentication Required,Client Error + 408,Request Timeout,Client Error + 409,Conflict,Client Error + 410,Gone,Client Error + 411,Length Required,Client Error + 412,Precondition Failed,Client Error + 413,Request Entity Too Large,Client Error + 414,Request-URI Too Long,Client Error + 415,Unsupported Media Type,Client Error + 416,Requested Range Not Satisfiable,Client Error + 417,Expectation Failed,Client Error + 500,Internal Server Error,Server Error + 501,Not Implemented,Server Error + 502,Bad Gateway,Server Error + 503,Service Unavailable,Server Error + 504,Gateway Timeout,Server Error + 505,HTTP Version Not Supported,Server Error + ''; + }; + +} diff --git a/configs/workhorse/hardware-configuration.nix b/configs/workhorse/hardware-configuration.nix new file mode 100644 index 0000000..c968587 --- /dev/null +++ b/configs/workhorse/hardware-configuration.nix @@ -0,0 +1,98 @@ +{ config, lib, pkgs, ... }: + +let + mainUserHome = "/home/palo"; +in +{ + + # grub configuration + # ------------------ + boot.loader.grub = { + device = "/dev/sda"; + enable = true; + version = 2; + }; + + # lvm volume group + # ---------------- + boot.initrd.luks.devices = [ + { + name = "vg"; + device = "/dev/sda2"; + preLVM = true; + } + ]; + + # NTFS support + # ------------ + environment.systemPackages = [ + pkgs.ntfs3g + ]; + + # root + # ---- + fileSystems."/" = { + options = [ "noatime" "nodiratime" "discard" ]; + device = "/dev/vg/root"; + fsType = "ext4"; + }; + + # boot + # ---- + fileSystems."/boot" = { + device = "/dev/sda1"; + fsType = "ext4"; + }; + + # home + # ---- + fileSystems."/home" = { + options = [ "noatime" "nodiratime" ]; + device = "/dev/mapper/decrypted_home"; + fsType = "ext4"; + encrypted = { + enable = true; + keyFile = "/mnt-root/root/keys/home.key"; + label = "decrypted_home"; + blkDev = "/dev/mapper/store-home"; + }; + }; + + # var/lib/docker + # -------------- + fileSystems."/var/lib/docker" = { + options = [ "noatime" "nodiratime" ]; + device = "/dev/mapper/decrypted_docker"; + fsType = "ext4"; + encrypted = { + enable = true; + keyFile = "/mnt-root/root/keys/docker.key"; + label = "decrypted_docker"; + blkDev = "/dev/mapper/store-docker"; + }; + }; + + # automount + # --------- + fileSystems."/media" = { + device = "/dev/disk/by-uuid/f7fa1c0e-ac9f-4955-b4bd-644c1ddb0d89"; + fsType = "ext4"; + options = [ + "nofail" + "noauto" + #"x-systemd.device-timeout=1ms" + ]; + }; + systemd.mounts = [ + { + enable = true; + options = "nofail,noauto"; + type = "ext4"; + wantedBy = ["multi-user.target"]; + what = "/dev/disk/by-uuid/f7fa1c0e-ac9f-4955-b4bd-644c1ddb0d89"; + where = "/media"; + } + ]; + +} + diff --git a/configs/workhorse/jenkins.nix b/configs/workhorse/jenkins.nix new file mode 100644 index 0000000..f22e36e --- /dev/null +++ b/configs/workhorse/jenkins.nix @@ -0,0 +1,239 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + + library = import { inherit pkgs lib; }; + + sync-repo = library.jenkins.syncJob; + job = library.jenkins.job; + +in { + + environment.systemPackages = [ pkgs.cabal-install ]; + + services.nginx = { + enable = true; + virtualHosts = { + "jenkins.${config.networking.hostName}.private" = { + locations."/" = { + proxyPass = "http://localhost:${toString config.services.jenkins.port}"; + extraConfig = '' + proxy_set_header Host $host:$server_port; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + + proxy_read_timeout 90; + proxy_redirect http://localhost:${toString config.services.jenkins.port} https://jenkins.${config.networking.hostName}.private/; + ''; + }; + }; + }; + }; + + krops.userKeys."accessToken" = { + user = "jenkins"; + source = toString ; + requiredBy = [ "jenkins-job-builder.service" ]; + }; + + services.jenkins = { + enable = true; + home = "/home/jenkins"; + port = 10420; + + # Plugins to Install: + # - all the plugins recommended at the setup + # - Build pipeline + # - SSH Agent + jobBuilder = { + enable = true; + + # create an access token in the admin users panel + accessTokenFile = config.krops.userKeys."accessToken".target; + accessUser = "admin"; + + # https://docs.openstack.org/infra/jenkins-job-builder/definition.html#modules + nixJobs = + let + # ssh username + key + gogs-id = "bc584c99-0fb7-43fb-af75-4076d64c51b2"; + # ssh username + key + github-id = "bc584c99-0fb7-43fb-af75-4076d64c51b2"; + # ssh username + key + sshSputnik = "d91eb57c-5bff-434c-b317-68aad46848d7"; + + sync-to-github = + name: source: target: + sync-repo name + { + url = source; + credentialsId = gogs-id; + } + { + url = target; + credentialsId = github-id; + }; + + in [ + + + (job "deploy-gaykraft" + { url = "ssh://gogs@workhorse.private:2222/palo/gaykraft.git"; + credentialsId = gogs-id; } + [ + { "build" = [ + "nix-shell --run build" + ]; + } + { "publish" = [ + { + script = "nix-shell --run publish"; + credentialsId = sshSputnik; + } + ]; + } + ] + ) + + (job "deploy-techblock" + { url = "ssh://gogs@workhorse.private:2222/palo/tech.ingolf-wagner.de.git"; + credentialsId = gogs-id; } + [ + { "build" = ["nix-shell --run build"];} + { "publish" = [ + { + script = "nix-shell --run publish"; + credentialsId = sshSputnik; + } + ];} + ]) + + (job "deploy-terranix" + { url = "ssh://gogs@workhorse.private:2222/terranix/terranix.org.git"; + credentialsId = gogs-id; } + [ + { "build" = ["nix-shell --run build"];} + { "publish" = [ + { + script = "nix-shell --run publish"; + credentialsId = sshSputnik; + } + ];} + ]) + + (job "sync-retiolum" + { url = "git@github.com:krebs/retiolum.git"; + credentialsId = github-id; + triggers = [ { timed = "H/30 * * * *"; } ];} + [ + { "Download Files" = [ + ''chmod 755 hosts'' + ''chmod 755 -R hosts'' + ''nix-shell -p curl -p gnutar -p bzip2 --run "curl https://lassul.us/retiolum-hosts.tar.bz2 | tar xvjf - || true"'' + ''chmod 755 -R etc.hosts'' + ''nix-shell -p curl --run "curl https://lassul.us/retiolum.hosts > etc.hosts || true"'' + ];} + { "update repo" = [ + ''nix-shell -p git --run "git add ."'' + ''nix-shell -p git --run "git -c user.name=\'Ingolf Wagner\' -c user.email=\'contact@ingolf-wagner.de\' commit -m update-`date +%Y-%m-%dT%H:%M:%S` || exit 0"'' + ];} + { Push = [ + { script = ''nix-shell -p git --run "git push origin master"''; + credentialsId = github-id; } + ];} + ]) + + (job "test-terranix" + { url = "ssh://gogs@workhorse.private:2222/terranix/terranix.git"; + credentialsId = github-id; + branch = "develop";} + [ + { "run Tests" = [ + ''nix-shell tests/shell.nix --run "test-terranix"'' + ];} + ]) + + (job "test-taskninja" + { url = "ssh://gogs@workhorse.private:2222/palo/taskninja.git"; + credentialsId = gogs-id; } + [ + { "Create Shell" = [ + ''nix-shell -p cabal2nix --run "cabal2nix --shell file://. > jenkins.nix"'' + ];} + { Update = [ + ''nix-shell ./jenkins.nix --run "cabal update"'' + ];} + { Configure = [ + ''nix-shell ./jenkins.nix --run "cabal configure --enable-tests"'' + ''nix-shell ./jenkins.nix --run "cabal install --only-dependencies"'' + ];} + { Build = [ + ''nix-shell ./jenkins.nix --run "cabal build"'' + ];} + { Test = [ + ''nix-shell ./jenkins.nix --run "cabal test"'' + ];} + ]) + + + # sync to me + # ---------- + (sync-to-github "sync-nixwriters" + "https://cgit.krebsco.de/nix-writers/" + "ssh://gogs@workhorse.private:2222/krebs/nix-writers.git") + + (sync-to-github "sync-krops" + "https://cgit.krebsco.de/krops/" + "ssh://gogs@workhorse.private:2222/krebs/krops.git") + + + # sync to github + # -------------- + (sync-to-github "sync-radiodj" + "ssh://gogs@workhorse.private:2222/crashburn_radio/radio_dj.git" + "git@github.com:crashburn-radio/radio-dj.git") + + (sync-to-github "sync-krops-module" + "ssh://gogs@workhorse.private:2222/nix-modules/krops.git" + "git@github.com:mrVanDalo/module.krops.git") + + (sync-to-github "sync-cluster-module" + "ssh://gogs@workhorse.private:2222/nix-modules/cluster.git" + "git@github.com:mrVanDalo/module.cluster.git") + + (sync-to-github "sync-backup-module" + "ssh://gogs@workhorse.private:2222/nix-modules/backup.git" + "git@github.com:mrVanDalo/module.backup.git") + + (sync-to-github "sync-module-tinc" + "ssh://gogs@workhorse.private:2222/palo/nixos-tinc.git" + "git@github.com:mrVanDalo/nixos-tinc.git") + + (sync-to-github "sync-memo" + "ssh://gogs@workhorse.private:2222/palo/memo.git" + "git@github.com:mrVanDalo/memo.git") + + (sync-to-github "sync-diagrams-template" + "ssh://gogs@workhorse.private:2222/palo/diagrams-template.git" + "git@github.com:mrVanDalo/diagrams.git") + + (sync-to-github "sync-terranix" + "ssh://gogs@workhorse.private:2222/terranix/terranix.git" + "git@github.com:mrVanDalo/terranix.git") + + (sync-to-github "sync-plops" + "ssh://gogs@workhorse.private:2222/palo/plops.git" + "git@github.com:mrVanDalo/plops.git") + + (sync-to-github "sync-image-generator" + "ssh://gogs@workhorse.private:2222/palo/image-generator.git" + "git@github.com:mrVanDalo/image-generator.git") + + ]; + }; + }; + +} diff --git a/configs/workhorse/kibana.nix b/configs/workhorse/kibana.nix new file mode 100644 index 0000000..4c4433c --- /dev/null +++ b/configs/workhorse/kibana.nix @@ -0,0 +1,24 @@ +{ config, ... }: +{ + services.nginx = { + enable = true; + statusPage = true; + virtualHosts = { + "kibana.${config.networking.hostName}.private" = { + serverAliases = []; + locations."/" = { + proxyPass = "http://${config.networking.hostName}.private:${toString config.services.kibana.port}"; + }; + }; + }; + }; + + services.elasticsearch.enable = true; + services.elasticsearch.listenAddress = "workhorse.private"; + + services.kibana.enable = true; + services.kibana.elasticsearch.hosts = [ "http://workhorse.private:9200" ]; + services.kibana.listenAddress = "workhorse.private"; + services.kibana.port = 5601; + +} diff --git a/configs/workhorse/lektor-gaykraft.nix b/configs/workhorse/lektor-gaykraft.nix new file mode 100644 index 0000000..6acfe7a --- /dev/null +++ b/configs/workhorse/lektor-gaykraft.nix @@ -0,0 +1,54 @@ +{ config, pkgs, lib, ... }: + +let + + containerName = "gaykraft"; + port = 5001; + repository = "ssh://gogs@git.ingolf-wagner.de:443/palo/gaykraft.git"; + sshKey = toString ; + +in { + + services.nginx = { + enable = true; + statusPage = true; + virtualHosts = { + "${containerName}.${config.networking.hostName}.private" = { + serverAliases = []; + locations."/" = { + proxyPass = "http://${config.networking.hostName}.private:${toString port}"; + }; + }; + }; + }; + + containers.${containerName} = { + + bindMounts = { + "/var/src" = { + hostPath = toString "/var/src/"; + isReadOnly = true; + }; + }; + + autoStart = true; + config = + { config, pkgs, ... }: + { + imports = [ ]; + services.lektor = { + enable = true; + host = "git.ingolf-wagner.de"; + sshKey = sshKey; + repository = repository; + port = port; + additionalScript = pkgs.writeScript "build" "${pkgs.nix}/bin/nix-shell --run build"; + }; + }; + + }; + + # it might take some time will this thing is up + systemd.services."container@${containerName}".serviceConfig.TimeoutStartSec = lib.mkForce "infinity"; + +} diff --git a/configs/workhorse/lektor-techblog.nix b/configs/workhorse/lektor-techblog.nix new file mode 100644 index 0000000..e900485 --- /dev/null +++ b/configs/workhorse/lektor-techblog.nix @@ -0,0 +1,54 @@ +{ config, pkgs, lib, ... }: + +let + + containerName = "techblog"; + port = 5002; + repository = "ssh://gogs@git.ingolf-wagner.de:443/palo/tech.ingolf-wagner.de.git"; + sshKey = toString ; + +in { + + services.nginx = { + enable = true; + statusPage = true; + virtualHosts = { + "${containerName}.${config.networking.hostName}.private" = { + serverAliases = []; + locations."/" = { + proxyPass = "http://${config.networking.hostName}.private:${toString port}"; + }; + }; + }; + }; + + containers.${containerName} = { + + bindMounts = { + "/var/src" = { + hostPath = toString "/var/src/"; + isReadOnly = true; + }; + }; + + autoStart = true; + config = + { config, pkgs, ... }: + { + imports = [ ]; + services.lektor = { + enable = true; + host = "git.ingolf-wagner.de"; + sshKey = sshKey; + repository = repository; + port = port; + additionalScript = pkgs.writeScript "build" "${pkgs.nix}/bin/nix-shell --run build"; + }; + }; + + }; + + # it might take some time will this thing is up + systemd.services."container@${containerName}".serviceConfig.TimeoutStartSec = lib.mkForce "infinity"; + +} diff --git a/configs/workhorse/lektor-terranix.nix b/configs/workhorse/lektor-terranix.nix new file mode 100644 index 0000000..81185f2 --- /dev/null +++ b/configs/workhorse/lektor-terranix.nix @@ -0,0 +1,54 @@ +{ config, pkgs, lib, ... }: + +let + + containerName = "terranix"; + port = 5003; + repository = "ssh://gogs@git.ingolf-wagner.de:443/terranix/terranix.org.git"; + sshKey = toString ; + +in { + + services.nginx = { + enable = true; + statusPage = true; + virtualHosts = { + "${containerName}.${config.networking.hostName}.private" = { + serverAliases = []; + locations."/" = { + proxyPass = "http://${config.networking.hostName}.private:${toString port}"; + }; + }; + }; + }; + + containers.${containerName} = { + + bindMounts = { + "/var/src" = { + hostPath = toString "/var/src/"; + isReadOnly = true; + }; + }; + + autoStart = true; + config = + { config, pkgs, ... }: + { + imports = [ ]; + services.lektor = { + enable = true; + host = "git.ingolf-wagner.de"; + sshKey = sshKey; + repository = repository; + port = port; + additionalScript = pkgs.writeScript "build" "${pkgs.nix}/bin/nix-shell --run build"; + }; + }; + + }; + + # it might take some time will this thing is up + systemd.services."container@${containerName}".serviceConfig.TimeoutStartSec = lib.mkForce "infinity"; + +} diff --git a/configs/workhorse/mail-fetcher.nix b/configs/workhorse/mail-fetcher.nix new file mode 100644 index 0000000..c366bcf --- /dev/null +++ b/configs/workhorse/mail-fetcher.nix @@ -0,0 +1,292 @@ +# fetches mails for me +{ lib, pkgs, config, ... }: +{ + users.users.mailUser = { + isNormalUser = true; + description = "collects mails for me"; + hashedPassword = "!"; + name = "mailfetcher"; + openssh.authorizedKeys.keyFiles = config.users.users.root.openssh.authorizedKeys.keyFiles; + }; + + + # configure passwords + krops.userKeys = { + "gmail.palipalo9" = { + user = config.users.users.mailUser.name; + source = toString ; + requiredBy = ["fetchmail.service"]; + }; + "gmx.palo_van_dalo" = { + user = config.users.users.mailUser.name; + source = toString ; + requiredBy = ["fetchmail.service"]; + }; + "gmx.ingolf_wagner" = { + user = config.users.users.mailUser.name; + source = toString ; + requiredBy = ["fetchmail.service"]; + }; + "web.pali_palo" = { + user = config.users.users.mailUser.name; + source = toString ; + requiredBy = ["fetchmail.service"]; + }; + "siteground.contact" = { + user = config.users.users.mailUser.name; + source = toString ; + requiredBy = ["fetchmail.service"]; + }; + }; + + environment.systemPackages = [ pkgs.muchsync ]; + + # configure accounts + home-manager.users.mailUser.accounts.email = { + accounts = { + palo_van_dalo-gmx = { + primary = false; + address = "palo_van_dalo@gmx.de"; + aliases = [ ]; + realName = "Ingolf Wagner"; + userName = "palo_van_dalo@gmx.de"; + passwordCommand = "cat ${toString config.krops.userKeys."gmx.palo_van_dalo".target}"; + imap = { + host = "imap.gmx.net"; + port = 993; + }; + mbsync = { + enable = true; + create = "both"; + }; + notmuch.enable = true; + }; + ingolf-wagner-gmx = { + primary = false; + address = "ingolf.wagner@gmx.de"; + aliases = [ ]; + realName = "Ingolf Wagner"; + userName = "ingolf.wagner@gmx.de"; + passwordCommand = "cat ${toString config.krops.userKeys."gmx.ingolf_wagner".target}"; + + imap = { + host = "imap.gmx.net"; + port = 993; + }; + mbsync = { + enable = true; + create = "both"; + }; + notmuch.enable = true; + }; + pali_palo = { + primary = false; + address = "pali_palo@web.de"; + aliases = [ ]; + realName = "Ingolf Wagner"; + userName = "pali_palo@web.de"; + passwordCommand = "cat ${toString config.krops.userKeys."web.pali_palo".target}"; + imap = { + host = "imap.web.de"; + port = 993; + }; + mbsync = { + enable = true; + create = "both"; + }; + notmuch.enable = true; + }; + gmail = { + # for google accounts you have to allow 'less secure apps' in accounts.google.com + primary = true; + address = "palipalo9@googlemail.com"; + aliases = [ ]; + realName = "Ingolf Wagner"; + userName = "palipalo9@googlemail.com"; + passwordCommand = "cat ${toString config.krops.userKeys."gmail.palipalo9".target}"; + imap = { + host = "imap.gmail.com"; + port = 993; + }; + mbsync = { + enable = true; + create = "both"; + }; + notmuch.enable = true; + }; + ingolf-wagner = { + primary = false; + address = "contact@ingolf-wagner.de"; + aliases = [ ]; + realName = "Ingolf Wagner"; + userName = "contact@ingolf-wagner.de"; + passwordCommand = "cat ${toString config.krops.userKeys."siteground.contact".target}"; + imap = { + host = "securees5.sgcpanel.com"; + port = 143; + tls.useStartTls = true; + }; + mbsync = { + enable = true; + create = "both"; + }; + notmuch.enable = true; + }; + }; + }; + + + # configure mbsync + home-manager.users.mailUser.programs.mbsync.enable = true; + systemd.services.fetchmail = { + enable = true; + serviceConfig = { + User = config.users.users.mailUser.name; + }; + environment.NOTMUCH_CONFIG = "${config.users.users.mailUser.home}/.config/notmuch/notmuchrc"; + script = '' + echo "run mbsync" + ${pkgs.isync}/bin/mbsync \ + --verbose \ + --all + echo "run notmuch" + ${pkgs.notmuch}/bin/notmuch new + echo "run afew" + ${pkgs.afew}/bin/afew --new --tag -v + ''; + }; + systemd.timers.fetchmail = { + enable = true; + # timerConfig.OnCalendar = " *-*-* *:00:00"; + timerConfig.OnCalendar = "*:0/10"; + wantedBy = ["multi-user.target"]; + }; + + # configure notmuch + home-manager.users.mailUser.programs.notmuch = { + enable = true; + new.tags = [ "unread" "inbox" "new" ]; + }; + home-manager.users.mailUser.home.file."notmuch" = { + source = "${config.users.users.mailUser.home}/.config/notmuch/notmuchrc"; + target = ".notmuch-config"; + }; + + # a few config + home-manager.users.mailUser.programs.afew = { + enable = true; + extraConfig = with lib; let + + template = index: { tags, query, message ? "generic", ... }: '' + [Filter.${toString index}] + query = ${query} + tags = ${concatStringsSep ";" tags} + message = ${message} + ''; + + filters = [ + + {query = "from:no-reply@backtrace.io"; tags = ["+sononym" "-inbox" "-unread"];} + {query = "from:linkedin.com"; tags = [ "+linked" "+jobs" "-inbox" ];} + {query = "from:computerfutures.com OR from:computerfutures.de"; tags = [ "+jobs" "-inbox" ];} + {query = "from:xing.com"; tags = [ "+jobs" "-inbox" ];} + {query = "from:ebay.com OR from:ebay.de OR from:ebay.net"; tags = [ "+ebay" "+shop" "+billing"];} + {query = "from:seek.com.au"; tags = [ "+jobs" "-inbox" ];} + {query = "from:bahn.de"; tags = [ "+billing" "+bahn" ];} + {query = "from:fysitech.atlassian.net OR to:engiadina-pwa@noreply.github.com"; tags = [ "+mia" "+work" "-unread" "-inbox"];} + {query = "from:circleci.com OR (from:noreply@github.com AND to:audio-overlay@googlegroups.com)"; tags = [ "-inbox" "-unread" "+junk" ];} + {query = "from:getdigital.de"; tags = [ "-inbox" "-unread" "+junk" ];} + {query = "from:digitalo.de"; tags = [ "-inbox" "-unread" "+junk" ];} + {query = "from:puppet.com"; tags = [ "-inbox" "-unread" "+junk" ];} + {query = "from:mixcloudmail.com AND subject:Weekly Update"; tags = [ "-inbox" "-unread" "+junk" ];} + {query = "from:facebook.com OR from:facebookmail.com"; tags = [ "-inbox" "-unread" "+junk" ];} + {query = "from:getpocket.com"; tags = [ "-inbox" "-unread" "+junk" ];} + {query = "from:oknotify2.com"; tags = [ "+okcupid" ];} + {query = "from:oknotify2.com AND NOT subject:New message"; tags = [ "-inbox" "-unread" "+junk" ];} + {query = "from:paulaschoice.com"; tags = [ "-inbox" "-unread" "+junk" ];} + {query = "from:samplemagic.com OR from:wavealchemy.co.uk OR from:creators.gumroad.com"; tags = [ "-inbox" "-unread" "+junk" ];} + {query = "from:immobilienscout24.de"; tags = [ "-inbox" "-unread" "+junk" ];} + {query = "from:magix.net"; tags = [ "-inbox" "-unread" "+junk" ];} + {query = "from:booking.com"; tags = [ "-inbox" "-unread" "+junk" ];} + {query = "from:hackster.io"; tags = [ "-inbox" "-unread" "+junk" ];} + {query = "from:trade4less.de"; tags = [ "-inbox" "-unread" "+junk" ];} + {query = "from:taxback.de OR to:taxback.de"; tags = ["+steuer"] ;} + {query = "from:campact.de"; tags = ["+campact" "+politics"] ;} + {query = "from:menospese.com"; tags = ["+junk" "-unread" "-inbox"] ;} + {query = "from:aliexpress.com"; tags = ["+shop" "+aliexpress"] ;} + {query = "from:congstar.de"; tags = ["+billing" "+congstar" "-inbox" "-unread"] ;} + {query = "from:congstarnews.de"; tags = ["+congstar" "-inbox" "-unread" "+junk"] ;} + {query = "from:fitnessfirst.de"; tags = ["-inbox" "-unread" "+junk"] ;} + {query = "from:steampowered.com AND NOT ( subject:purchase OR subject:received )"; tags = ["-inbox" "-unread" ] ;} + {query = "from:steampowered.com AND ( subject:purchase OR subject:received )"; tags = ["+billing" "+steam" ] ;} + {query = "from:gog.com AND NOT subject:Bestellung"; tags = ["-inbox" "-unread" ] ;} + {query = "from:gog.com AND subject:Bestellung"; tags = ["+billing" "+gog" ] ;} + {query = "from:drive-now.com"; tags = ["+billing" "+drivenow" "-inbox" "-unread"] ;} + {query = "from:mindfactory.de"; tags = ["+shop" "+billing"] ;} + {query = "from:zalando.de"; tags = ["+shop" "+billing" "+zalando"] ;} + {query = "from:ing.de"; tags = ["+bank" "+ingdiba"] ;} + {query = "from:nab.com.au"; tags = ["+bank" "+nab" "-inbox" "-unread"] ;} + {query = "from:dkb.de"; tags = ["+bank" "+dkb"] ;} + {query = "from:o2online.de"; tags = ["+billing" "+o2"] ;} + {query = "from:betfair.com"; tags = ["+work" "+betfair"] ;} + {query = "from:ghostinspector.com"; tags = ["-unread" "-inbox" "+junk"] ;} + {query = "from:travis-ci.org AND subject:csv-to-qif"; tags = ["+development" "+csv-to-qif"] ;} + {query = "to:proaudio@lists.tuxfamily.org"; tags = ["-inbox" "-unread"] ;} + {query = "tag:lists AND from:nixos1@discoursemail.com"; tags = ["+nixos" "+discourse"] ;} + {query = "from:limebike.com AND (subject:Funds OR subject:Receipt)" ; tags = ["-inbox" "-unread" "+billing" "+limebike"] ;} + {query = "from:hetzner.com OR from:hetzner.de" ; tags = ["+hetzner"] ;} + {query = "from:freemusicarchive.org" ; tags = ["+FMA"] ;} + {query = "from:namecheap.com" ; tags = ["+namecheap" "+billing"] ;} + {query = "from:nintendo.com" ; tags = ["+nintendo" "+billing"] ;} + {query = "from:oculus.com AND subject:receipt" ; tags = ["+oculus" "+billing"] ;} + {query = "from:vstbuzz.com" ; tags = ["+junk" "-inbox" ] ;} + {query = "from:runtastic.com" ; tags = ["+junk" "-inbox" ] ;} + {query = "from:letterboxd.com" ; tags = ["+junk" "-inbox" ] ;} + {query = "from::microsoftstoreemail.com" ; tags = ["+junk" "-inbox" ] ;} + {query = "from:car2go.com" ; tags = ["-inbox" "-unread" ] ;} + {query = "from:sixt.de" ; tags = ["-inbox" "-unread" ] ;} + {query = "from:meetup.com" ; tags = ["-inbox" "-unread" "+meetup"] ;} + {query = "from:slack.com" ; tags = ["+slack"] ;} + {query = "from:keybase.io" ; tags = ["+keybase"] ;} + {query = "from:tumblr.com" ; tags = ["+junk" "-inbox" "-unread"];} + {query = "from:jobs2web.com" ; tags = ["+newzealand" "+jobs" "-inbox" ];} + {query = "from:mailings.gmx.net" ; tags = ["+junk" "-inbox" "-unread"];} + {query = "from:paypal.de AND subject:Bestätigung"; tags = ["-unread" "+paypal" "+billing"] ;} + + {query = "to:renoise@ingolf-wagner.de OR to:root@renoise.com OR from:renoise.com OR to:admin@renoise.com"; tags = ["+renoise"] ;} + {query = "from:amazon.de OR from:amazon.com AND NOT to:renoise.com"; tags = ["+shop" "+amazon" "+billing"];} + { + query = "to:renoise.com AND NOT ( from:renoise.com OR from:root OR from:hetzner.com OR from:hetzner.de OR from:amazon.com OR from:gmail.com )"; + tags = [ "-inbox" "-unread" "+junk" "+renoise" ]; + } + + # final rules to make imap sync stuff easier + # there can only be one output folder tag, and theses rules are prioritized + { query = "tag:fraud" ; tags = ["-inbox" "-archive" "-junk" "-unread" ]; message = "clean up tag fraud";} + { query = "tag:junk" ; tags = ["-inbox" "-archive" "-fraud" "-unread" ]; message = "clean up tag junk";} + { query = "tag:archive" ; tags = ["-inbox" "-junk" "-fraud" "-unread" ]; message = "clean up tag archive";} + { query = "tag:inbox" ; tags = ["-archive" "-junk" "-fraud"]; message = "clean up inbox";} + { query = "tag:killed"; tags = ["-inbox" "-unread"]; message = "clean up tag killed" ;} + + # remove new tag at the end + { query = "tag:new"; tags = ["-new"]; message = "remove new tag at the end" ;} + + ]; + + in + '' + # Tag mails which are mailing lists + [ListMailsFilter] + + # Tag mails as killed if the thread has been marked as "killed" + [KillThreadsFilter] + + ${concatStringsSep "\n" (imap0 template filters)} + + ''; + }; + + + + +} diff --git a/configs/workhorse/packages.nix b/configs/workhorse/packages.nix new file mode 100644 index 0000000..cda5056 --- /dev/null +++ b/configs/workhorse/packages.nix @@ -0,0 +1,7 @@ +{ config, pkgs, ... }: +let + unstable = import {}; +in { + environment.systemPackages = with pkgs ; [ + ]; +} diff --git a/configs/workhorse/prometheus.nix b/configs/workhorse/prometheus.nix new file mode 100644 index 0000000..5949f71 --- /dev/null +++ b/configs/workhorse/prometheus.nix @@ -0,0 +1,107 @@ +{ config, pkgs, lib, ... }: +{ + + services.nginx = { + enable = true; + statusPage = true; + virtualHosts = { + "prometheus.workhorse.private" = { + locations."/" = { + proxyPass = "http://workhorse.private:9090"; + }; + }; + }; + }; + + services.prometheus2 = { + enable = true; + scrapeConfigs = [ + { + job_name = "nginx"; + scrape_interval = "8s"; + static_configs = [ + { + targets = ["sputnik.private:9113"]; + labels = { + service = "nginx"; + server = "sputnik"; + }; + } + { + targets = ["sputnik.private:9113"]; + labels = { + service = "nginx"; + server = "sputnik"; + }; + } + { + targets = ["workhorse.private:9113"]; + labels = { + service = "nginx"; + server = "sputnik"; + }; + } + ]; + } + { + job_name = "netdata"; + metrics_path = "/api/v1/allmetrics"; + params.format = [ "prometheus" ]; + scrape_interval = "5s"; + static_configs = [ + { + targets = ["porani.private:19999"]; + labels = { + service = "netdata"; + server = "porani"; + }; + } + { + targets = ["sputnik.private:19999"]; + labels = { + service = "netdata"; + server = "sputnik"; + }; + } + { + targets = ["workhorse.private:19999"]; + labels = { + service = "netdata"; + server = "workhorse"; + }; + } + ]; + } + { + job_name = "gogs"; + metrics_path = "/-/metrics"; + params.format = [ "prometheus" ]; + scrape_interval = "10s"; + static_configs = [ + { + targets = ["workhorse.private:3000"]; + labels = { + service = "gogs"; + server = "kruck"; + }; + } + ]; + } + { + job_name = "home-assistant"; + scrape_interval = "60s"; + metrics_path = "/api/prometheus"; + static_configs = [ + { + targets = ["porani.private:8123"]; + labels = { + service = "hass"; + server = "porani"; + city = "essen"; + }; + } + ]; + } + ]; + }; +} diff --git a/configs/workhorse/restic.nix b/configs/workhorse/restic.nix new file mode 100644 index 0000000..d7af1a0 --- /dev/null +++ b/configs/workhorse/restic.nix @@ -0,0 +1,9 @@ +{config, ... }: +{ + + backup.services.restic = { + "on-porani".enable = false; + "on-workhorse".enable = true; + }; + +} diff --git a/configs/workhorse/seafile.nix b/configs/workhorse/seafile.nix new file mode 100644 index 0000000..74bddb2 --- /dev/null +++ b/configs/workhorse/seafile.nix @@ -0,0 +1,26 @@ +{ config, lib, pkgs, ... }: +{ + + services.nginx = { + enable = true; + statusPage = true; + virtualHosts = { + "seafile.${config.networking.hostName}.private" = { + serverAliases = []; + locations."/" = { + proxyPass = "http://${config.networking.hostName}.private:${toString config.custom.services.seafile.port}"; + }; + }; + }; + }; + + custom.services.seafile = { + enable = true; + hostname = "seafile.gaykraft.com"; + port = 3030; + home = "/home/seafile"; + }; + + virtualisation.docker.enable = lib.mkDefault true; + +} diff --git a/configs/workhorse/syncthing.nix b/configs/workhorse/syncthing.nix new file mode 100644 index 0000000..8dfd4e2 --- /dev/null +++ b/configs/workhorse/syncthing.nix @@ -0,0 +1,53 @@ +{ config, pkgs, lib, ... }: +{ + + test.services.syncthing = { + enable = true; + openDefaultPorts = false; + dataDir = "/home/syncthing"; + configDir = "/home/syncthing"; + declarative = { + cert = toString ; + key = toString ; + overrideFolders = true; + + folders = { + + # todo add podcast here + + # on encrypted hard drive + # ----------------------- + desktop-encrypted.path = "/home/syncthing/.desktop.ct"; + finance-encrypted.path = "/home/syncthing/.finance.ct"; + fotos-encrypted.path = "/home/syncthing/private/.fotos.ct"; + music-projects.path = "/home/syncthing/music-projects"; + video-material.path = "/home/syncthing/video-material"; + + # on media hard drive (not encrypted) + # ----------------------------------- + music-library-free.path = "/media/syncthing/music-library-free"; + samples.path = "/media/syncthing/samples"; + movies.path = "/media/syncthing/movies"; + music-library.path = "/media/syncthing/music-library"; + podcasts.path = "/media/syncthing/podcasts"; + series.path = "/media/syncthing/series"; + + }; + }; + }; + + systemd.services."permown._media_syncthing" = { + bindsTo = [ "media.mount" ]; + after = [ "media.mount" ]; + }; + system.permown."/media/syncthing" = { + owner = "syncthing"; + group = "syncthing"; + umask = "0007"; + }; + systemd.services."syncthing" = { + bindsTo = [ "media.mount" ]; + after = [ "media.mount" ]; + }; + +} diff --git a/configs/workhorse/taskserver.nix b/configs/workhorse/taskserver.nix new file mode 100644 index 0000000..841dcea --- /dev/null +++ b/configs/workhorse/taskserver.nix @@ -0,0 +1,14 @@ +{ config, lib, pkgs, ... }: +{ + + services.taskserver = { + enable = true; + fqdn = "workhorse.private"; + listenHost = "0.0.0.0"; + requestLimit = 104857600; + trust = "allow all"; + dataDir = "/var/lib/taskserver"; + organisations."orgie".users = ["palo"]; + }; + +} diff --git a/configs/workhorse/tinc.nix b/configs/workhorse/tinc.nix new file mode 100644 index 0000000..05bac3b --- /dev/null +++ b/configs/workhorse/tinc.nix @@ -0,0 +1,16 @@ +{ config, lib, pkgs, ... }: +{ + + module.cluster.services.tinc = { + "private" = { + enable = true; + openPort = true; + connectTo = [ "sputnik" ]; + }; + "retiolum" = { + enable = true; + openPort = true; + }; + }; + +} diff --git a/configs/workhorse/transmission.nix b/configs/workhorse/transmission.nix new file mode 100644 index 0000000..4450c44 --- /dev/null +++ b/configs/workhorse/transmission.nix @@ -0,0 +1,45 @@ +{ config, lib, ... }: + +with lib; + +let + + allTincNetworks = + builtins.attrNames config.module.cluster.services.tinc; + + ipAddresses = + flatten (mapAttrsToList (_: data: + mapAttrsToList (_: hostConfig: hostConfig.tincIp) data.hosts) + config.module.cluster.services.tinc); + +in { + + services.nginx = { + enable = true; + statusPage = true; + virtualHosts = { + "transmission.${config.networking.hostName}.private" = { + serverAliases = ["torrent.${config.networking.hostName}.private"]; + locations."/" = { + proxyPass = "http://${config.networking.hostName}.private:${toString config.services.transmission.port}"; + }; + }; + }; + }; + + networking.firewall = { + allowedTCPPorts = [ config.services.custom.transmission.port ]; + allowedUDPPorts = [ config.services.custom.transmission.port ]; + }; + + services.custom.transmission = { + enable = true; + home = "/home/torrent"; + store = "/home/torrent"; + hosts = concatStringsSep "," (map (name: "${config.networking.hostName}.${name}") allTincNetworks); + whitelist = concatStringsSep "," ipAddresses; + user = "palo"; + password = lib.fileContents ; + }; + +} diff --git a/configs/workhorse/weechat.nix b/configs/workhorse/weechat.nix new file mode 100644 index 0000000..53d0e23 --- /dev/null +++ b/configs/workhorse/weechat.nix @@ -0,0 +1,20 @@ +{ config, pkgs, lib, ... }: + +# how to setup a relay +# * ssh on the maching +# * sudo -u weechat screen -r +# /set relay.network.password "mypassword" +# /relay add weechat 10000 + +{ + + services.weechat = { + enable = true; + }; + + # otherwise xterm is the only thing that works + environment.systemPackages = [ pkgs.rxvt_unicode ]; + + backup.all.restic.dirs = [ config.services.weechat.root ]; + +} diff --git a/configs/workhorse/wetten.nix b/configs/workhorse/wetten.nix new file mode 100644 index 0000000..bb8d71f --- /dev/null +++ b/configs/workhorse/wetten.nix @@ -0,0 +1,40 @@ +{ config, lib, pkgs , ... }: +{ + imports = [ + + ]; + + krops.userKeys."wetten_appkey" = { + user = "wetten"; + source = toString ; + requiredBy = [ "wetten.service" ]; + }; + + krops.userKeys."wetten_key" = { + user = "wetten"; + source = ; + requiredBy = [ "wetten.service" ]; + }; + + krops.userKeys."wetten_cert" = { + user = "wetten"; + source = toString ; + requiredBy = [ "wetten.service" ]; + }; + + krops.userKeys."wetten_password" = { + user = "wetten"; + source = toString ; + requiredBy = [ "wetten.service" ]; + }; + + services.wetten = { + enable = true; + username = "palipalo9@googlemail.com"; + passwordFile = config.krops.userKeys."wetten_password".target; + appKeyFile = config.krops.userKeys."wetten_appkey".target; + clientCert = config.krops.userKeys."wetten_cert".target; + clientCertKey = config.krops.userKeys."wetten_key".target; + }; + +} diff --git a/configs/workout/configuration.nix b/configs/workout/configuration.nix new file mode 100644 index 0000000..542b94a --- /dev/null +++ b/configs/workout/configuration.nix @@ -0,0 +1,62 @@ +{ lib, config, pkgs, ... }: +{ + imports = [ + + + ./hardware-configuration.nix + + # + ./encfs.nix + ./kibana.nix + ./packages.nix + ./slack.nix + ./syncthing.nix + ./tinc.nix + + ]; + + networking.hostName = "workout"; + + services.logind.lidSwitch = lib.mkForce "ignore"; + + security.wrappers = { + pmount.source = "${pkgs.pmount}/bin/pmount"; + pumount.source = "${pkgs.pmount}/bin/pumount"; + }; + + # nix-shell -p speedtest_cli --run speedtest + configuration.fireqos = { + enable = true; + interface = "wlp1s0"; + input = 4200; + output = 1200; + balance = false; + }; + + programs.custom.steam.enable = true; + programs.custom.video.enable = true; + + # font + # ---- + programs.custom.urxvt.fontSize = 17; + programs.custom.xterm.fontSize = 17; + system.custom.fonts.dpi = 140; + + services.printing.enable = true; + + virtualisation = { + docker.enable = true; + virtualbox = { + host.enable = true; + guest.x11 = true; + guest.enable = true; + }; + }; + + configuration.desktop = { + width = 2560; + height = 1440; + }; + +} + diff --git a/configs/workout/encfs.nix b/configs/workout/encfs.nix new file mode 100644 index 0000000..09b654d --- /dev/null +++ b/configs/workout/encfs.nix @@ -0,0 +1,8 @@ +{ config, lib, pkgs, ... }: +{ + module.backup.services.encfs = { + "fotos".enable = true; + "desktop".enable = true; + "finance".enable = true; + }; +} diff --git a/configs/workout/hardware-configuration.nix b/configs/workout/hardware-configuration.nix new file mode 100644 index 0000000..b05414c --- /dev/null +++ b/configs/workout/hardware-configuration.nix @@ -0,0 +1,61 @@ +{ config, lib, pkgs, ... }: + +let + mainUserHome = "/home/palo"; +in +{ + # fix fileSystems..encrypted - false overwrite + # -------------------------------------------------- + boot.initrd.luks.cryptoModules = [ "aes" "aes_generic" "blowfish" "twofish" "serpent" "cbc" "xts" "lrw" "sha1" "sha256" "sha512" "aes_x86_64" ]; + + # todo : why should I use this here + boot.initrd.availableKernelModules = [ "xhci_pci" "ahci" "usb_storage" "sd_mod" ]; + boot.kernelModules = [ "kvm-intel" ]; + nix.maxJobs = lib.mkDefault 8; + + # lvm volume group + # ---------------- + boot.initrd.luks.devices = [ + { + name = "vg"; + device = "/dev/sda2"; + preLVM = true; + } + ]; + + # NTFS support + # ------------ + environment.systemPackages = [ + pkgs.ntfs3g + ]; + + # root + # ---- + fileSystems."/" = { + options = [ "noatime" "nodiratime" "discard" ]; + device = "/dev/vg/root"; + fsType = "ext4"; + }; + + # boot + # ---- + fileSystems."/boot" = { + device = "/dev/sda1"; + fsType = "ext4"; + }; + boot.loader.grub = { + device = "/dev/sda"; + enable = true; + version = 2; + }; + + # home + # ---- + fileSystems."/home" = { + options = [ "noatime" "nodiratime" "discard" ]; + device = "/dev/vg/home"; + fsType = "ext4"; + }; + +} + diff --git a/configs/workout/kibana.nix b/configs/workout/kibana.nix new file mode 100644 index 0000000..92634c4 --- /dev/null +++ b/configs/workout/kibana.nix @@ -0,0 +1,23 @@ +{ config, ... }: +{ + services.nginx = { + enable = true; + statusPage = true; + virtualHosts = { + "kibana.${config.networking.hostName}.private" = { + serverAliases = []; + locations."/" = { + proxyPass = "http://${config.networking.hostName}.private:${toString config.services.kibana.port}"; + }; + }; + }; + }; + services.elasticsearch.enable = true; + services.elasticsearch.listenAddress = "${config.networking.hostName}.private"; + + services.kibana.enable = true; + services.kibana.elasticsearch.hosts = [ "http://${config.networking.hostName}.private:9200" ]; + services.kibana.listenAddress = "${config.networking.hostName}.private"; + services.kibana.port = 5601; + +} diff --git a/configs/workout/packages.nix b/configs/workout/packages.nix new file mode 100644 index 0000000..0a69edc --- /dev/null +++ b/configs/workout/packages.nix @@ -0,0 +1,22 @@ +{ config, pkgs, ... }: +let + unstable = import {}; +in { + + nixpkgs.config.packageOverrides = pkgs: { + nur = import (builtins.fetchTarball "https://github.com/nix-community/NUR/archive/master.tar.gz") { + inherit pkgs; + }; + }; + + environment.systemPackages = with pkgs ; [ + bitwig-studio + #unstable.pypi2nix + #nur.repos.mic92.nixos-shell + ]; + + programs.custom.q = { + enableIntelBacklight = false; + enableBattery = false; + }; +} diff --git a/configs/workout/slack.nix b/configs/workout/slack.nix new file mode 100644 index 0000000..5810031 --- /dev/null +++ b/configs/workout/slack.nix @@ -0,0 +1,14 @@ +{ config, lib, pkgs, ... }: +{ + + programs.custom.slack = { + enable = true; + homeBackup = "~/desktop/slack"; + }; + + programs.custom.browser.configList.google-chrome = { + inherit (config.programs.custom.browser.configList.development) home homeBackup user; + sudoUsers = [ "slack" ]; + }; + +} diff --git a/configs/workout/syncthing.nix b/configs/workout/syncthing.nix new file mode 100644 index 0000000..e7905d0 --- /dev/null +++ b/configs/workout/syncthing.nix @@ -0,0 +1,40 @@ +{ config, pkgs, lib, ... }: +{ + + test.services.syncthing = { + enable = true; + openDefaultPorts = false; + user = "palo"; + dataDir = "/home/palo/.syncthing"; + configDir = "/home/palo/.syncthing"; + declarative = { + cert = toString ; + key = toString ; + + overrideFolders = true; + folders = { + + book.path = "/home/palo/books"; + desktop-encrypted.path = "/home/palo/.desktop.ct"; + finance-encrypted.path = "/home/palo/.finance.ct"; + fotos-encrypted.path = "/home/palo/private/.fotos.ct"; + kruck-workout.path = "/home/palo/workout-kruck"; + music-library-free.path = "/home/palo/music-library-free"; + music-library.path = "/home/palo/music-library"; + music-projects.path = "/home/palo/music-projects"; + porani-workout.path = "/home/palo/workout-porani"; + samples.path = "/home/palo/samples"; + schasch-workout.path = "/home/palo/workout-schasch"; + smartphone-fotos.path = "/home/palo/smartphone-fotos"; + smartphone-music.path = "/home/palo/smartphone-music"; + video-material.path = "/home/palo/video-material"; + workout-pepe.path = "/home/palo/workout-pepe"; + windows-sync.path = "/home/palo/windows-sync"; + + + }; + }; + }; + +} + diff --git a/configs/workout/tinc.nix b/configs/workout/tinc.nix new file mode 100644 index 0000000..606a6b7 --- /dev/null +++ b/configs/workout/tinc.nix @@ -0,0 +1,15 @@ +{ config, lib, pkgs, ... }: +{ + module.cluster.services.tinc = { + "private" = { + enable = true; + openPort = true; + connectTo = [ "sputnik" ]; + }; + "retiolum" = { + enable = true; + openPort = true; + }; + }; + +} diff --git a/images/remote-install/README.md b/images/remote-install/README.md new file mode 100644 index 0000000..bfb51d1 --- /dev/null +++ b/images/remote-install/README.md @@ -0,0 +1,19 @@ +# remote installation iso + +* `./config.nix` : to generate the installation image +* `./remote-service.nix` : tor configuration you have to start on your machine. + + +## Steps + +* import `./remote-service.nix` in your `/etc/nixos/configuration.nix` +* `nixos-rebuild switch` +* run `remote-install-get-hiddenReceiver` and enter the result in `./config.nix` as `hiddenReceiver` +* set the public key in `./config.nix` +* run `nixos-generate -f install-iso -c ./config.nix` +* prepare the usb stick : `sudo if= of=/dev/ bs=4096` +* boot the usb-stick at the new machine +* run `remote-install-start-service` +* after some time you will see a you can use to login to the new machine. + +Now you can do the normal installations procedure. diff --git a/images/remote-install/config.nix b/images/remote-install/config.nix new file mode 100644 index 0000000..7b93672 --- /dev/null +++ b/images/remote-install/config.nix @@ -0,0 +1,142 @@ +{ config, lib, pkgs, ... }: +let + + # cat ~/.ssh/id_rsa.pub + publicSshKey = ""; + + # remote-install-get-hiddenReceiver + hiddenReceiver = ""; + +in { + + imports = [ + { # system setup + networking.hostName = "liveos"; + + users.extraUsers = { + root = { + password = "lolhack"; + openssh.authorizedKeys.keys = [ + publicSshKey + ]; + }; + }; + + environment.extraInit = '' + EDITOR=vim + ''; + } + { # installed packages + nixpkgs.config.allowUnfree = true; + environment.systemPackages = with pkgs; [ + #style + most + rxvt_unicode.terminfo + + #monitoring tools + htop + iotop + + #network + iptables + iftop + nmap + + #stuff for dl + aria2 + + #neat utils + pciutils + psmisc + tmux + usbutils + git + + #unpack stuff + p7zip + unzip + unrar + + #data recovery + ddrescue + ntfs3g + dosfstools + ]; + } + { # bash configuration + programs.bash = { + enableCompletion = true; + interactiveShellInit = '' + HISTCONTROL='erasedups:ignorespace' + HISTSIZE=65536 + HISTFILESIZE=$HISTSIZE + + shopt -s checkhash + shopt -s histappend histreedit histverify + shopt -s no_empty_cmd_completion + complete -d cd + ''; + promptInit = '' + if test $UID = 0; then + PS1='\[\033[1;31m\]\w\[\033[0m\] ' + PROMPT_COMMAND='echo -ne "\033]0;$$ $USER@$PWD\007"' + elif test $UID = 1337; then + PS1='\[\033[1;32m\]\w\[\033[0m\] ' + PROMPT_COMMAND='echo -ne "\033]0;$$ $PWD\007"' + else + PS1='\[\033[1;33m\]\u@\w\[\033[0m\] ' + PROMPT_COMMAND='echo -ne "\033]0;$$ $USER@$PWD\007"' + fi + if test -n "$SSH_CLIENT"; then + PS1='\[\033[35m\]\h'" $PS1" + PROMPT_COMMAND='echo -ne "\033]0;$$ $HOSTNAME $USER@$PWD\007"' + fi + ''; + }; + } + { # ssh configuration + services.openssh.enable = true; + services.openssh.passwordAuthentication = false; + systemd.services.sshd.wantedBy = lib.mkForce [ "multi-user.target" ]; + } + { # network configuration + networking.networkmanager.enable = true; + networking.wireless.enable = lib.mkForce false; + } + { # hidden ssh announce + config = let + torDirectory = "/var/lib/tor"; + hiddenServiceDir = torDirectory + "/liveos"; + in { + services.tor = { + enable = true; + client.enable = true; + extraConfig = '' + HiddenServiceDir ${hiddenServiceDir} + HiddenServicePort 22 127.0.0.1:22 + ''; + }; + systemd.services.hidden-ssh-announce = { + description = "irc announce hidden ssh"; + after = [ "tor.service" "network-online.target" ]; + wants = [ "tor.service" ]; + wantedBy = [ "multi-user.target" ]; + serviceConfig = { + ExecStart = pkgs.writers.writeDash "irc-announce-ssh" '' + set -efu + until test -e ${hiddenServiceDir}/hostname; do + echo "still waiting for ${hiddenServiceDir}/hostname" + sleep 1 + done + until ${pkgs.tor}/bin/torify ${pkgs.netcat-openbsd}/bin/nc -z ${hiddenReceiver} 1337; do sleep 1; done && \ + echo "torify ssh root@$(cat ${hiddenServiceDir}/hostname) -i ~/.ssh/id_rsa" | ${pkgs.tor}/bin/torify ${pkgs.nmap}/bin/ncat ${hiddenReceiver} 1337 + ''; + PrivateTmp = "true"; + User = "tor"; + Type = "oneshot"; + }; + }; + }; + } + ]; +} diff --git a/images/remote-install/remote-install.nix b/images/remote-install/remote-install.nix new file mode 100644 index 0000000..8cf9a9a --- /dev/null +++ b/images/remote-install/remote-install.nix @@ -0,0 +1,20 @@ +# installs scripts and tor to provide an announcement service for nixos-remote installation. +{ + services.tor = { + enable = true; + client.enable = true; + hiddenServices.liveos.map = [ + { port = 1337; } + ]; + }; + + environment.systemPackages = [ + (pkgs.writeShellScriptBin "remote-install-start-service" '' + echo "starting announcment server to receive remote-install iso onion id" + ${pkgs.nmap}/bin/ncat -k -l -p 1337 + '') + (pkgs.writeShellScriptBin "remote-install-get-hiddenReceiver" '' + sudo cat /var/lib/tor/onion/liveos/hostname + '') + ]; +} diff --git a/images/yubikey-image.nix b/images/yubikey-image.nix new file mode 100644 index 0000000..0dd254d --- /dev/null +++ b/images/yubikey-image.nix @@ -0,0 +1,64 @@ +# NixOS livesystem to generate yubikeys in an air-gapped manner +# screenshot: https://dl.thalheim.io/wmxIqucOEo2xuLk0Ut45fQ/yubikey-live-system.png +# $ nixos-generator -f iso -c yubikey-image.nix +{ pkgs, ... }: { + environment.interactiveShellInit = '' + export GNUPGHOME=/run/user/$(id -u)/gnupghome + if [ ! -d $GNUPGHOME ]; then + mkdir $GNUPGHOME + fi + cp ${pkgs.fetchurl { + url = "https://raw.githubusercontent.com/drduh/config/662c16404eef04f506a6a208f1253fee2f4895d9/gpg.conf"; + sha256 = "118fmrsn28fz629y7wwwcx7r1wfn59h3mqz1snyhf8b5yh0sb8la"; + }} "$GNUPGHOME/gpg.conf" + echo "\$GNUPGHOME has been set up for you. Generated keys will be in $GNUPGHOME." + ''; + + environment.systemPackages = with pkgs; [ + yubikey-personalization + cryptsetup + pwgen + midori + paperkey + gnupg + haskellPackages.hopenpgp-tools + ctmg + ]; + + services.udev.packages = with pkgs; [ yubikey-personalization ]; + services.pcscd.enable = true; + users.extraUsers.root.initialHashedPassword = ""; + + # make sure we are air-gapped + networking.wireless.enable = false; + networking.dhcpcd.enable = false; + + services.mingetty.helpLine = "The 'root' account has an empty password."; + + services.xserver = { + enable = true; + displayManager.auto.enable = true; + + desktopManager = let + guide = pkgs.stdenv.mkDerivation { + name = "yubikey-guide-2019-01-21.html"; + src = pkgs.fetchFromGitHub { + owner = "drduh"; + repo = "YubiKey-Guide"; + rev = "035d98ebbed54a0218ccbf23905054d32f97508e"; + sha256 = "0rzy06a5xgfjpaklxdgrxml24d0vhk78lb577l3z4x7a2p32dbyq"; + }; + buildInputs = [ pkgs.pandoc ]; + installPhase = "pandoc --highlight-style pygments -s --toc README.md -o $out"; + }; + in { + default = "xfce"; + xterm.enable = false; + xfce.enable = true; + xfce.extraSessionCommands = '' + ${pkgs.midori}/bin/midori ${guide} & + ${pkgs.xfce.terminal}/bin/xfce4-terminal & + ''; + }; + }; +} diff --git a/library/default.nix b/library/default.nix new file mode 100644 index 0000000..44a2c74 --- /dev/null +++ b/library/default.nix @@ -0,0 +1,21 @@ +{ pkgs, lib, ... }: +{ + desktopFile = bin: { longName ? "Script", command ? "${bin}/bin/${bin.name}", ... }: + pkgs.writeTextFile { + name = "${bin.name}.desktop" ; + destination = "/share/applications/${bin.name}.desktop"; + text = '' + [Desktop Entry] + Type=Application + Exec=${bin}/bin/${command} %U + Comment=An open source web browser from Google + Terminal=false + Name=${bin.name} + GenericName=${longName} + StartupWMClass=${bin.name} + ''; + }; + + jenkins = import ./jenkins.nix { inherit lib; }; + +} diff --git a/library/jenkins.nix b/library/jenkins.nix new file mode 100644 index 0000000..6376dc6 --- /dev/null +++ b/library/jenkins.nix @@ -0,0 +1,135 @@ +{ lib, ... }: + +with builtins; + +{ + # source container url and credentialsId + job = name: { + url, + credentialsId, + branch ? "master", + # https://docs.openstack.org/infra/jenkins-job-builder/triggers.html + triggers ? [ + { pollscm = { + cron = "H/30 * * * *"; + ignore-post-commit-hooks = true; + };} + ], ... }: config: { job = { + inherit name triggers; + sandbox = true; + project-type = "pipeline"; + dsl = let + stage = elem: + let + stageName = head ( attrNames elem ); + stateScripts = map ( stage : + lib.getAttr (typeOf stage) { + string = '' + withEnv(['PATH=/run/current-system/sw/bin/','NIX_PATH=/var/src/']) { + sh '${toString stage}' + }''; + set = + let + script = '' + withEnv(['PATH=/run/current-system/sw/bin/','NIX_PATH=/var/src/']) { + sh '${toString stage.script}' + } + ''; + in + if (stage.credentialsId != null) + then '' + sshagent(['${stage.credentialsId}']) { ${script} } + '' + else script; + } + )( getAttr stageName elem ); + in '' + stage('${stageName}') { + steps { + ${concatStringsSep "\n" stateScripts} + } + } + ''; + stages = map stage config; + in '' + pipeline { + agent any + stages{ + stage('Pull') { + steps { + checkout( + [$class: 'GitSCM' + , branches: [[name: '*/${branch}']] + , doGenerateSubmoduleConfigurations: false + , extensions: [[$class: 'LocalBranch', localBranch: 'master']] + , submoduleCfg: [] + , userRemoteConfigs: + [[ credentialsId: '${credentialsId}' + , url: '${url}']] + ] + ) + } + } + ${concatStringsSep "\n" stages} + } + } + ''; + };}; + + # creates a sync job + # source and target container url and credentialsId + syncJob = name: source: target: { + job = { + name = name; + sandbox = true; + project-type = "pipeline"; + triggers = [ { + pollscm = { + cron = "H/30 * * * *"; + ignore-post-commit-hooks = true; + }; + } ]; + dsl = '' + pipeline { + agent any + stages{ + stage('Pull') { + steps { + checkout( + [$class: 'GitSCM' + , branches: [[name: '*/master']] + , doGenerateSubmoduleConfigurations: false + , extensions: [[$class: 'LocalBranch', localBranch: 'master']] + , submoduleCfg: [] + , userRemoteConfigs: + [[ credentialsId: '${source.credentialsId}' + , url: '${source.url}']] + ] + ) + } + } + stage('Push') { + steps { + sshagent(['${target.credentialsId}']) { + withEnv(['PATH=/run/current-system/sw/bin/','NIX_PATH=/var/src/']) { + sh "git push -f ${target.url}" + } + } + } + } + stage('Push Tags') { + steps { + sshagent(['${target.credentialsId}']) { + withEnv(['PATH=/run/current-system/sw/bin/']) { + sh "git push -f ${target.url} --tags" + } + } + } + } + } + } + ''; + }; + }; + +} diff --git a/modules/default.nix b/modules/default.nix new file mode 100644 index 0000000..5b11173 --- /dev/null +++ b/modules/default.nix @@ -0,0 +1,45 @@ +{ + + imports = [ + + ./later/syncthing.nix + + ./services/castget.nix + ./services/home-assistant.nix + ./services/lektor.nix + ./services/samba-share.nix + ./services/seafile.nix + ./services/sshd.nix + ./services/transmission.nix + ./services/videoencoder.nix + + ./programs/browser.nix + ./programs/citate.nix + ./programs/curl-scripts.nix + ./programs/easytag.nix + ./programs/elm.nix + ./programs/espeak.nix + ./programs/ffmpeg.nix + ./programs/git.nix + ./programs/q.nix + ./programs/shell-bash.nix + ./programs/shell-tools.nix + ./programs/shell-zsh.nix + ./programs/slack.nix + ./programs/steam.nix + ./programs/taskwarrior.nix + ./programs/urxvt.nix + ./programs/video.nix + ./programs/vim.nix + ./programs/xterm.nix + + ./system/audio.nix + ./system/bluetooth.nix + ./system/font.nix + ./system/mainUser.nix + ./system/permown.nix + ./system/wifi.nix + ./system/x11.nix + + ]; +} diff --git a/modules/later/syncthing.nix b/modules/later/syncthing.nix new file mode 100644 index 0000000..81f2feb --- /dev/null +++ b/modules/later/syncthing.nix @@ -0,0 +1,434 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.test.services.syncthing; + defaultUser = "syncthing"; + + + + devices = mapAttrsToList (name: device: { + deviceID = device.id; + inherit (device) name addresses introducer; + }) cfg.declarative.devices; + + + folders = mapAttrsToList ( _: folder: { + inherit (folder) path id label type; + devices = map (device: { deviceId = cfg.declarative.devices.${device}.id; }) folder.devices; + rescanIntervalS = folder.rescanInterval; + fsWatcherEnabled = folder.watch; + fsWatcherDelayS = folder.watchDelay; + ignorePerms = folder.ignorePerms; + }) (filterAttrs ( + _: value: + (value.path != null) && (value.devices != []) + ) cfg.declarative.folders); + + # get the api key by parsing the config.xml + getApiKey = pkgs.writers.writeDash "getAPIKey" '' + ${pkgs.libxml2}/bin/xmllint \ + --xpath 'string(configuration/gui/apikey)'\ + ${cfg.configDir}/config.xml + ''; + + updateConfig = pkgs.writers.writeDash "merge-syncthing-config" '' + set -efu + # wait for syncthing port to open + until ${pkgs.curl}/bin/curl -Ss ${cfg.guiAddress} -o /dev/null; do + sleep 1 + done + + API_KEY=$(${getApiKey}) + OLD_CFG=$(${pkgs.curl}/bin/curl -Ss \ + -H "X-API-Key: $API_KEY" \ + ${cfg.guiAddress}/rest/system/config) + + # generate the new config by merging with the nixos config options + NEW_CFG=$(echo "$OLD_CFG" | ${pkgs.jq}/bin/jq -s '.[] as $in | $in * { + "devices": (${builtins.toJSON devices}${optionalString (! cfg.declarative.overrideDevices) " + $in.devices"}), + "folders": (${builtins.toJSON folders}${optionalString (! cfg.declarative.overrideFolders) " + $in.folders"}) + }') + + # POST the new config to syncthing + echo "$NEW_CFG" | ${pkgs.curl}/bin/curl -Ss \ + -H "X-API-Key: $API_KEY" \ + ${cfg.guiAddress}/rest/system/config -d @- + + # restart syncthing after sending the new config + ${pkgs.curl}/bin/curl -Ss \ + -H "X-API-Key: $API_KEY" \ + -X POST \ + ${cfg.guiAddress}/rest/system/restart + ''; +in { + ###### interface + options = { + test.services.syncthing = { + + enable = mkEnableOption '' + Syncthing - the self-hosted open-source alternative + to Dropbox and Bittorrent Sync. Initial interface will be + available on http://127.0.0.1:8384/. + ''; + + declarative = { + cert = mkOption { + type = types.nullOr types.str; + default = null; + description = '' + Path to users cert.pem file, will be copied into the syncthing's + configDir + ''; + }; + + key = mkOption { + type = types.nullOr types.str; + default = null; + description = '' + Path to users key.pem file, will be copied into the syncthing's + configDir + ''; + }; + + overrideDevices = mkOption { + type = types.bool; + default = true; + description = '' + Whether to delete the devices which are not configured via the + declarative.devices option. + If set to false, devices added via the webinterface will + persist but will have to be deleted manually. + ''; + }; + + devices = mkOption { + default = {}; + description = '' + Peers/devices which syncthing should communicate with. + ''; + example = [ + { + name = "bigbox"; + id = "7CFNTQM-IMTJBHJ-3UWRDIU-ZGQJFR6-VCXZ3NB-XUH3KZO-N52ITXR-LAIYUAU"; + addresses = [ "tcp://192.168.0.10:51820" ]; + } + ]; + type = types.attrsOf (types.submodule ({ config, ... }: { + options = { + + name = mkOption { + type = types.str; + default = config._module.args.name; + description = '' + Name of the device + ''; + }; + + addresses = mkOption { + type = types.listOf types.str; + default = []; + description = '' + The addresses used to connect to the device. + If this is let empty, dynamic configuration is attempted + ''; + }; + + id = mkOption { + type = types.str; + description = '' + The id of the other peer, this is mandatory. It's documented at + https://docs.syncthing.net/dev/device-ids.html + ''; + }; + + introducer = mkOption { + type = types.bool; + default = false; + description = '' + If the device should act as an introducer and be allowed + to add folders on this computer. + ''; + }; + + }; + })); + }; + + overrideFolders = mkOption { + type = types.bool; + default = true; + description = '' + Whether to delete the folders which are not configured via the + declarative.folders option. + If set to false, folders added via the webinterface will persist + but will have to be deleted manually. + ''; + }; + + folders = mkOption { + default = {}; + description = '' + folders which should be shared by syncthing. + ''; + type = types.attrsOf (types.submodule ({ config, ... }: { + options = { + + path = mkOption { + type = types.nullOr types.str; + default = null; + description = '' + The path to the folder which should be shared. + ''; + }; + + id = mkOption { + type = types.str; + default = config._module.args.name; + description = '' + The id of the folder. Must be the same on all devices. + ''; + }; + + label = mkOption { + type = types.str; + default = config._module.args.name; + description = '' + The label of the folder. + ''; + }; + + devices = mkOption { + type = types.listOf types.str; + default = []; + description = '' + The devices this folder should be shared with. Must be defined + in the declarative.devices attribute. + ''; + }; + + rescanInterval = mkOption { + type = types.int; + default = 3600; + description = '' + How often the folders should be rescaned for changes. + ''; + }; + + type = mkOption { + type = types.enum [ "sendreceive" "sendonly" "receiveonly" ]; + default = "sendreceive"; + description = '' + Whether to send only changes from this folder, only receive them + or propagate both. + ''; + }; + + watch = mkOption { + type = types.bool; + default = true; + description = '' + Whether the folder should be watched for changes by inotify. + ''; + }; + + watchDelay = mkOption { + type = types.int; + default = 10; + description = '' + The delay after an inotify event is triggered. + ''; + }; + + ignorePerms = mkOption { + type = types.bool; + default = true; + description = '' + Whether to propagate permission changes. + ''; + }; + + }; + })); + }; + }; + + guiAddress = mkOption { + type = types.str; + default = "127.0.0.1:8384"; + description = '' + Address to serve the GUI. + ''; + }; + + systemService = mkOption { + type = types.bool; + default = true; + description = "Auto launch Syncthing as a system service."; + }; + + user = mkOption { + type = types.str; + default = defaultUser; + description = '' + Syncthing will be run under this user (user will be created if it doesn't exist. + This can be your user name). + ''; + }; + + group = mkOption { + type = types.str; + default = "nogroup"; + description = '' + Syncthing will be run under this group (group will not be created if it doesn't exist. + This can be your user name). + ''; + }; + + all_proxy = mkOption { + type = with types; nullOr str; + default = null; + example = "socks5://address.com:1234"; + description = '' + Overwrites all_proxy environment variable for the syncthing process to + the given value. This is normaly used to let relay client connect + through SOCKS5 proxy server. + ''; + }; + + dataDir = mkOption { + type = types.path; + default = "/var/lib/syncthing"; + description = '' + Path where synced directories will exist. + ''; + }; + + configDir = mkOption { + type = types.path; + description = '' + Path where the settings and keys will exist. + ''; + default = + let + nixos = config.system.stateVersion; + cond = versionAtLeast nixos "19.03"; + in cfg.dataDir + (optionalString cond "/.config/syncthing"); + }; + + openDefaultPorts = mkOption { + type = types.bool; + default = false; + example = literalExample "true"; + description = '' + Open the default ports in the firewall: + - TCP 22000 for transfers + - UDP 21027 for discovery + If multiple users are running syncthing on this machine, you will need to manually open a set of ports for each instance and leave this disabled. + Alternatively, if are running only a single instance on this machine using the default ports, enable this. + ''; + }; + + package = mkOption { + type = types.package; + default = pkgs.syncthing; + defaultText = "pkgs.syncthing"; + example = literalExample "pkgs.syncthing"; + description = '' + Syncthing package to use. + ''; + }; + }; + }; + + imports = [ + (mkRemovedOptionModule ["services" "syncthing" "useInotify"] '' + This option was removed because syncthing now has the inotify functionality included under the name "fswatcher". + It can be enabled on a per-folder basis through the webinterface. + '') + ]; + + ###### implementation + + config = mkIf cfg.enable { + + networking.firewall = mkIf cfg.openDefaultPorts { + allowedTCPPorts = [ 22000 ]; + allowedUDPPorts = [ 21027 ]; + }; + + systemd.packages = [ pkgs.syncthing ]; + + users = mkIf (cfg.systemService && cfg.user == defaultUser) { + users."${defaultUser}" = + { group = cfg.group; + home = cfg.dataDir; + createHome = true; + uid = config.ids.uids.syncthing; + description = "Syncthing daemon user"; + }; + + groups."${defaultUser}".gid = + config.ids.gids.syncthing; + }; + + systemd.services = { + syncthing = mkIf cfg.systemService { + description = "Syncthing service"; + after = [ "network.target" ]; + environment = { + STNORESTART = "yes"; + STNOUPGRADE = "yes"; + inherit (cfg) all_proxy; + } // config.networking.proxy.envVars; + wantedBy = [ "multi-user.target" ]; + serviceConfig = { + Restart = "on-failure"; + SuccessExitStatus = "2 3 4"; + RestartForceExitStatus="3 4"; + User = cfg.user; + Group = cfg.group; + ExecStartPre = mkIf (cfg.declarative.cert != null || cfg.declarative.key != null) + "+${pkgs.writers.writeBash "syncthing-copy-keys" '' + mkdir -p ${cfg.configDir} + chown ${cfg.user}:${cfg.group} ${cfg.configDir} + chmod 700 ${cfg.configDir} + ${optionalString (cfg.declarative.cert != null) '' + cp ${toString cfg.declarative.cert} ${cfg.configDir}/cert.pem + chown ${cfg.user}:${cfg.group} ${cfg.configDir}/cert.pem + chmod 400 ${cfg.configDir}/cert.pem + ''} + ${optionalString (cfg.declarative.key != null) '' + cp ${toString cfg.declarative.key} ${cfg.configDir}/key.pem + chown ${cfg.user}:${cfg.group} ${cfg.configDir}/key.pem + chmod 400 ${cfg.configDir}/key.pem + ''} + ''}" + ; + ExecStart = '' + ${cfg.package}/bin/syncthing \ + -no-browser \ + -gui-address=${cfg.guiAddress} \ + -home=${cfg.configDir} + ''; + }; + }; + syncthing-init = { + after = [ "syncthing.service" ]; + wantedBy = [ "multi-user.target" ]; + + serviceConfig = { + User = cfg.user; + RemainAfterExit = true; + Type = "oneshot"; + ExecStart = updateConfig; + }; + }; + + syncthing-resume = { + wantedBy = [ "suspend.target" ]; + }; + }; + }; +} diff --git a/modules/programs/browser.nix b/modules/programs/browser.nix new file mode 100644 index 0000000..6161b04 --- /dev/null +++ b/modules/programs/browser.nix @@ -0,0 +1,247 @@ +{ config, lib, pkgs, ... }: + +# todo : this needs to be cleaned up + +with lib; + +let + + cfg = config.programs.custom.browser; + library = import { inherit pkgs lib; }; + + chromiumBin = "${pkgs.chromium}/bin/chromium"; + chromeBin = "${pkgs.google-chrome}/bin/google-chrome-stable"; + firefoxBin = "${pkgs.firefox}/bin/firefox"; + tarBin = "${pkgs.gnutar}/bin/tar"; + + + # desktop file + # ------------ + # makes it possible to be used by other programs + desktopFile = bin: let + browserName = bin.name; + in pkgs.writeTextFile { + name = "${browserName}.desktop" ; + destination = "/share/applications/${browserName}.desktop"; + text = '' + [Desktop Entry] + Type=Application + Exec=${bin}/bin/${browserName} %U + Icon=chromium + Comment=An open source web browser from Google + Terminal=false + Name=${browserName} + GenericName=Web browser + MimeType=text/html;text/xml;application/xhtml+xml;x-scheme-handler/http;x-scheme-handler/https;x-scheme-handler/ftp;x-scheme-handler/webcal;x-scheme-handler/about + Categories=Network;WebBrowser + StartupWMClass=${browserName} + ''; + }; + + cleanBrowser = name: browser: home: homeBackup: + let + backupFile = "${homeBackup}.tar.lzma"; + rolloutFile = "${home}.tar.lzma"; + lockFile = "${home}-lock"; + in + pkgs.writeShellScriptBin "${name}-clean" /* sh */ '' + sudo killall -9 -u ${name} + sudo rm ${lockFile} + sudo rm -rf ${home} + ''; + + createBrowser = name: user: browser: home: homeBackup: + let + backupFile = "${homeBackup}.tar.lzma"; + rolloutFile = "${home}.tar.lzma"; + lockFile = "${home}-lock"; + in + pkgs.writeShellScriptBin "${name}" /* sh */ '' + # set -x + if [[ ! -e ${lockFile} ]] + then + # rollout backup + if [[ -e ${backupFile} ]] + then + if [[ ! -d ${home} ]] + then + # todo : use make user + sudo mkdir -p ${home} + sudo chown -R ${user}:users ${home} + fi + cp ${backupFile} ${rolloutFile} + sudo -u ${user} ${tarBin} xf ${rolloutFile} --directory ${home} + rm ${rolloutFile} + touch ${lockFile} + fi + fi + + sudo -u ${user} ${browser} + ''; + + browserExecutableList = + let + allBrowser = flip mapAttrsToList cfg.configList ( + name: config: + let + browser = if config.browserType == "chrome" + then "${chromiumBin} \"$@\"" + else if config.browserType == "google" + then "${chromeBin} \"$@\"" + else "${firefoxBin} \"$@\""; + in + createBrowser name config.user browser config.home config.homeBackup + ); + xclipBrowser = [ + (pkgs.writeShellScriptBin "copy-to-xclip" /* sh */'' + echo "$*" | ${pkgs.xclip}/bin/xclip + '') + ]; + in + allBrowser ++ xclipBrowser; + + createBackupScript = name: home: backupHome: + pkgs.writeShellScriptBin "${name}-backup" /* sh */ '' + sudo -u ${name} \ + ${tarBin} \ + --exclude=.cache \ + --exclude=Downloads \ + --create \ + --verbos \ + --lzma \ + --file ${home}.tar.lzma \ + --directory ${home} \ + . + + cp ${home}.tar.lzma ${backupHome}.tar.lzma + ''; + + allBackupScripts = + let + filteredConfigs = + filterAttrs + (name: browserConfig: browserConfig.homeBackup != null) + cfg.configList; + in + mapAttrsToList + (name: browserConfig: createBackupScript name browserConfig.home browserConfig.homeBackup) + filteredConfigs; + + allCleanScripts = + let + filteredConfigs = + filterAttrs + (name: browserConfig: browserConfig.homeBackup != null) + cfg.configList; + in + mapAttrsToList + (name: browserConfig: cleanBrowser name name browserConfig.home browserConfig.homeBackup) + filteredConfigs; + + + # browser chooser + # --------------- + browserSelect = pkgs.writeScriptBin "browser-select" '' + # select a browser using dmenu + # ---------------------------- + BROWSER=$( echo -e "${lib.concatMapStringsSep "\\n" (bin: bin.name) browserExecutableList}" \ + | ${pkgs.rofi}/bin/rofi -dmenu ) + + # start selected browser + # ---------------------- + case $BROWSER in + ${lib.concatStringsSep "\n" + (flip map browserExecutableList (bin: "${bin.name}) export BIN=${bin}/bin/${bin.name} ;;")) + } + esac + $BIN "$@" + ''; + + +in { + + options.programs.custom.browser = { + enable = mkEnableOption "enable browsers"; + configList = mkOption { + type = with types; attrsOf (submodule ({ name , ... }: { + options = { + browserType = mkOption { + type = with types; enum ["firefox" "chrome" "google"]; + default = "chrome"; + description = '' + the type of browser which is simulated + ''; + }; + home = mkOption { + type = with types; str; + description = '' + Home of the browser. + ''; + }; + user = mkOption { + default = name; + type = with types; str; + description = '' + user to run the browser as + ''; + }; + sudoUsers = mkOption { + default = [ config.users.users.mainUser.name ]; + type = with types; listOf str; + description = '' + user allowed to run sudo without password to start the browser + ''; + }; + homeBackup = mkOption { + type = with types; nullOr str; + default = null; + example = "~/.my-browser-backup"; + description = '' + backup of the home, which gets rolled out if the + home does not exists. usefull for homes in tmpfs. + dont use file endings! + ''; + }; + }; + })); + }; + }; + + config = mkIf cfg.enable { + + # add sudo rights + security.sudo.extraConfig = + let + extraRules = flip mapAttrsToList cfg.configList (name: values: + concatStringsSep "\n" (map (sudoUser: "${sudoUser} ALL=(${values.user}) NOPASSWD: ALL") values.sudoUsers)) ; + in + lib.concatStringsSep "\n" extraRules; + + # create users + users.users = flip mapAttrs cfg.configList (name: config: + { + home = config.home; + createHome = true; + initialPassword = "${name}-browser"; + shell = pkgs.bashInteractive; + isNormalUser = true; + group = "users"; + # enable video usage + extraGroups = [ "video" "audio" ]; + } + ); + + # add groups to mainUser + system.custom.mainUser.extraGroups = builtins.attrNames cfg.configList; + + environment.systemPackages = [ + browserSelect + ( desktopFile browserSelect ) + ] + ++ browserExecutableList + ++ (map (bin: desktopFile bin) browserExecutableList) + ++ allBackupScripts + ++ allCleanScripts; + + }; +} diff --git a/modules/programs/citate.nix b/modules/programs/citate.nix new file mode 100644 index 0000000..7679caa --- /dev/null +++ b/modules/programs/citate.nix @@ -0,0 +1,35 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + + cfg = config.programs.custom.citate; + + library = import { inherit pkgs lib; }; + + xdotool = "${pkgs.xdotool}/bin/xdotool"; + dmenu = "${pkgs.dmenu}/bin/dmenu"; + + citateScript = file: suffix: pkgs.writeShellScriptBin "citate-${suffix}" '' + ${xdotool} - <<<"type -- $( cat ${file} | ${dmenu} -l 10 -i | sed -e "s/\(.*\)/'\1'/" )" + ''; + + scriptAxel = citateScript (toString ) "axel"; + scriptSiw = citateScript (toString ) "siw"; + +in { + + options.programs.custom.citate = { + enable = mkEnableOption "enable programs.custom.citate"; + }; + + config = mkIf cfg.enable { + environment.systemPackages = [ + scriptAxel + (library.desktopFile scriptAxel { longName = "Citate Axel"; command = "citate-axel"; }) + scriptSiw + (library.desktopFile scriptSiw { longName = "Citate Sinnlos im Weltall"; command = "citate-siw"; }) + ]; + }; +} diff --git a/modules/programs/curl-scripts.nix b/modules/programs/curl-scripts.nix new file mode 100644 index 0000000..67243fb --- /dev/null +++ b/modules/programs/curl-scripts.nix @@ -0,0 +1,34 @@ +{ config, pkgs, lib, ... }: + +with lib; + +let + + weatherScript = pkgs.writeShellScriptBin "weather" '' + ${pkgs.curl}/bin/curl wttr.in/Berlin + ''; + + qrCodeScript = pkgs.writeShellScriptBin "qrCode" '' + ${pkgs.curl}/bin/curl "qrenco.de/$1" + ''; + + cheatSheetScript = pkgs.writeShellScriptBin "cheatsheet" '' + ${pkgs.curl}/bin/curl "cheat.sh/$1" + ''; + + cfg = config.programs.custom.curlScripts; + +in { + + options.programs.custom.curlScripts.enable = mkEnableOption "enable curl scripts"; + + config = mkIf cfg.enable { + environment.systemPackages = [ + weatherScript + qrCodeScript + cheatSheetScript + ]; + }; +} + + diff --git a/modules/programs/easytag.nix b/modules/programs/easytag.nix new file mode 100644 index 0000000..92ca44d --- /dev/null +++ b/modules/programs/easytag.nix @@ -0,0 +1,20 @@ +{ config, pkgs, lib, ... }: + +with lib; + +let + + cfg = config.programs.custom.easytag; + +in { + + options.programs.custom.easytag.enable = mkEnableOption "install easytag with dependencies"; + + config = mkIf cfg.enable { + environment.systemPackages = with pkgs; [ + easytag + gnome3.dconf + ]; + }; +} + diff --git a/modules/programs/elm.nix b/modules/programs/elm.nix new file mode 100644 index 0000000..17ae6b5 --- /dev/null +++ b/modules/programs/elm.nix @@ -0,0 +1,24 @@ +{ config, pkgs, lib, ... }: + +with lib; + +let + + cfg = config.programs.custom.elm; + +in { + + options.programs.custom.elm.enable = mkEnableOption "enable elm stack"; + + config = mkIf cfg.enable { + environment.systemPackages = with pkgs ; [ + elmPackages.elm + elmPackages.elm-compiler + elmPackages.elm-format + elmPackages.elm-make + elmPackages.elm-reactor + elm-github-install + ]; + }; +} + diff --git a/modules/programs/espeak.nix b/modules/programs/espeak.nix new file mode 100644 index 0000000..55545cc --- /dev/null +++ b/modules/programs/espeak.nix @@ -0,0 +1,54 @@ +{ config, pkgs, lib, ... }: + +with lib; + +let + + # can't use bash aliases because programms will not pic it up + en_espeak = pkgs.writeShellScriptBin "en-speak" '' + exec ${pkgs.espeak}/bin/espeak \ + -v en\ + -s 145 \ + -p 23 \ + $@ + ''; + + # read from copyq + en_read = pkgs.writeShellScriptBin "en-read" '' + exec ${pkgs.copyq}/bin/copyq read 0 | ${en_espeak}/bin/en-speak + ''; + + # can't use bash aliases because programms will not pic it up + de_espeak = pkgs.writeShellScriptBin "de-speak" '' + exec ${pkgs.espeak}/bin/espeak \ + -v de\ + -s 143 \ + -p 20 \ + $@ + ''; + + # read from copyq + de_read = pkgs.writeShellScriptBin "de-read" '' + exec ${pkgs.copyq}/bin/copyq read 0 | ${de_espeak}/bin/de-speak + ''; + + cfg = config.programs.custom.espeak; + +in { + + options.programs.custom.espeak.enable = mkEnableOption "enable espeak scripts"; + + config = mkIf cfg.enable { + + environment.systemPackages = with pkgs ; [ + espeak + en_espeak + en_read + de_espeak + de_read + ]; + + }; +} + + diff --git a/modules/programs/ffmpeg.nix b/modules/programs/ffmpeg.nix new file mode 100644 index 0000000..be30608 --- /dev/null +++ b/modules/programs/ffmpeg.nix @@ -0,0 +1,120 @@ +{ config, lib, pkgs, ... }: +with lib; +let + + cfg = config.programs.custom.ffmpeg; + + ffmpegTemplate = name: { profile, preset, tune ? null}: + pkgs.writeShellScriptBin "ffmpeg-${name}" '' + + if [ $# -eq 0 ] + then + cat <---720p + + profiles = + "baseline" - Primarily for low-cost applications that require additional data loss robustness + "main" - This profile is used for standard-definition digital TV broadcasts that use the MPEG-4 format as defined in the DVB standard. + "high" - The primary profile for broadcast and disc storage applications, particularly for high-definition television applications + + presets = + "ultrafast" + "superfast" + "veryfast" + "faster" + "fast" + "medium" + "slow" + "slower" + "veryslow" + + tunes = (optional) + "film" - use for high quality movie content; lowers deblockin + "animation" - good for cartoons; uses higher deblocking and more reference frames + "grain" - preserves the grain structure in old, grainy film material + "stillimage" - good for slideshow-like content + "fastdecode" - allows faster decoding by disabling certain filters + + EOF + exit 0 + fi + + if [ $# -ne 2 ] + then + echo "ffmpeg-${name} " + exit 1 + fi + + input=$1 + output=$2 + + if [ ! -f "$input" ] + then + echo "input does not exist $input" + exit 1 + fi + + exec ${pkgs.ffmpeg}/bin/ffmpeg \ + -i "$input" \ + -filter:v scale=h='min(720\,ih)':w='min(1280\,iw)' \ + -vcodec libx264 \ + -preset ${preset} \ + -profile:v ${profile} \ + ${optionalString (tune != null) "-tune ${tune}"} \ + -acodec aac \ + "$output" \ + -hide_banner + ''; + + ffmpegDescriptive = profile: preset: + ffmpegTemplate "${profile}-${preset}-720p" { inherit profile preset ; }; + + ffmpegDescriptiveTune = profile: preset: tune: + ffmpegTemplate "${profile}-${preset}-${tune}-720p" { inherit profile preset tune; }; + + # https://en.wikipedia.org/wiki/H.264/MPEG-4_AVC#Profiles + profiles = [ + "baseline" + "main" + "high" + #"high10" + #"high422" + #"high44" + ]; + presets = [ + #"ultrafast" + #"superfast" + #"veryfast" + #"faster" + "fast" + "medium" + "slow" + #"slower" + "veryslow" + ]; + tunes = [ + "film" + "animation" + "grain" + "stillimage" + "fastdecode" + ]; + + ffmpegs = lib.crossLists + ffmpegDescriptive + [ profiles presets ]; + + ffmpegsTune = lib.crossLists + ffmpegDescriptiveTune + [ profiles presets tunes ]; + +in { + + options.programs.custom.ffmpeg = { + enable = mkEnableOption "enable programs.custom.ffmpeg"; + }; + + config = mkIf cfg.enable { + environment.systemPackages = ffmpegs ++ ffmpegsTune; + }; +} diff --git a/modules/programs/git.nix b/modules/programs/git.nix new file mode 100644 index 0000000..c119cf4 --- /dev/null +++ b/modules/programs/git.nix @@ -0,0 +1,32 @@ +{ config, pkgs, lib, ... }: + +with lib; + +let + + cfg = config.programs.custom.git; + +in { + + options.programs.custom.git.enable = mkEnableOption "install git and all its tools"; + + config = mkIf cfg.enable { + + environment.systemPackages = with pkgs ; [ + git + tig + git-crypt + gitAndTools.gitflow + gitAndTools.gitSVN + gitAndTools.git2cl + + # merge tools + meld + + # activate using : + # git config --global core.pager "diff-so-fancy | less --tabs=4 -RFX" + gitAndTools.diff-so-fancy + ]; + }; +} + diff --git a/modules/programs/q.nix b/modules/programs/q.nix new file mode 100644 index 0000000..5b9aef2 --- /dev/null +++ b/modules/programs/q.nix @@ -0,0 +1,37 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + + cfg = config.programs.custom.q; + +in { + + options.programs.custom.q = { + enable = mkEnableOption "custom.programs.q"; + timeZones = mkOption { + default = [ "Europe/Berlin" ]; + type = with types; listOf str; + example = [ "Europe/Berlin" "Asia/Kolkata" "Asia/Singapore" ]; + }; + enableIntelBacklight = mkOption { + default = true; + type = with types; bool; + }; + enableBattery = mkOption { + default = true; + type = with types; bool; + }; + }; + + config = mkIf cfg.enable { + environment.systemPackages = [ + (pkgs.q.override{ + timeZones = cfg.timeZones; + enableIntelBacklight = cfg.enableIntelBacklight; + enableBattery = cfg.enableBattery; + }) + ]; + }; +} diff --git a/modules/programs/shell-bash.nix b/modules/programs/shell-bash.nix new file mode 100644 index 0000000..ce81eb8 --- /dev/null +++ b/modules/programs/shell-bash.nix @@ -0,0 +1,87 @@ +{ config, pkgs, lib, ... }: +let + cfg = config.programs.custom.bash; +in { + + options.programs.custom.bash.enable = lib.mkEnableOption "enable bash config"; + + config = lib.mkIf cfg.enable { + + programs.bash = { + + # BashCompletion + # -------------- + enableCompletion = true; + + # Configure Shell + # --------------- + interactiveShellInit = /* sh */ '' + # use vi shortcuts + # ---------------- + set -o vi + + # Configure ls-colors + # ------------------- + export LS_COLORS='rs=0:di=01;35:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=01;05;37;41:mi=01;05;37;41:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;33:*.tar=01;31:*.tgz=01;31:*.arc=01;31:*.arj=01;31:*.taz=01;31:*.lha=01;31:*.lz4=01;31:*.lzh=01;31:*.lzma=01;31:*.tlz=01;31:*.txz=01;31:*.tzo=01;31:*.t7z=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.dz=01;31:*.gz=01;31:*.lrz=01;31:*.lz=01;31:*.lzo=01;31:*.xz=01;31:*.bz2=01;31:*.bz=01;31:*.tbz=01;31:*.tbz2=01;31:*.tz=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.war=01;31:*.ear=01;31:*.sar=01;31:*.rar=01;31:*.alz=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.rz=01;31:*.cab=01;31:*.jpg=01;35:*.jpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.svg=01;35:*.svgz=01;35:*.mng=01;35:*.pcx=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.webm=01;35:*.ogm=01;35:*.mp4=01;35:*.m4v=01;35:*.mp4v=01;35:*.vob=01;35:*.qt=01;35:*.nuv=01;35:*.wmv=01;35:*.asf=01;35:*.rm=01;35:*.rmvb=01;35:*.flc=01;35:*.avi=01;35:*.fli=01;35:*.flv=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.yuv=01;35:*.cgm=01;35:*.emf=01;35:*.ogv=01;35:*.ogx=01;35::*.aac=00;36:*.au=00;36:*.flac=00;36:*.m4a=00;36:*.mid=00;36:*.midi=00;36:*.mka=00;36:*.mp3=00;36:*.mpc=00;36:*.ogg=00;36:*.ra=00;36:*.wav=00;36:*.oga=00;36:*.opus=00;36:*.spx=00;36:*.xspf=00;36:' + ''; + + # Configure Prompt + # ---------------- + promptInit = /* sh */ '' + # PS1 content functions + # --------------------- + function nonzero_return() { + RETVAL=$? + [ $RETVAL -ne 0 ] && echo "[> $RETVAL <] " + } + + # Provide a nice prompt + # --------------------- + case $TERM in + xterm*|rxvt*|Eterm) + # used : http://ezprompt.net/ + USER_COLOR="\[\e[36m\]\u\[\e[m\]\[\e[32m\]@\[\e[m\]\[\e[36m\]\h\[\e[m\]" + CURRENT_PATH="\[\e[33m\][\[\e[m\]\[\e[33m\]\w\[\e[m\]\[\e[33m\]]\[\e[m\]" + if [[ $UID -eq 0 ]] + then + USER_COLOR="\[\e[31m\]\u\[\e[m\]\[\e[32m\]@\[\e[m\]\[\e[31m\]\h\[\e[m\]" + fi + export PS1="\[\e[31m\]\`nonzero_return\`\[\e[m\]\[\e[35m\]\A\[\e[m\] $USER_COLOR $CURRENT_PATH\[\e[31m\]\\$\[\e[m\] " + ;; + screen) + export PS1="\[\e[31m\]\`nonzero_return\`\[\e[m\]\[\e[35m\]\A\[\e[m\] \[\e[36m\]\u\[\e[m\]\[\e[32m\]@\[\e[m\]\[\e[36m\]\h\[\e[m\] \[\e[33m\][\[\e[m\]\[\e[33m\]\W\[\e[m\]\[\e[33m\]]\[\e[m\]\[\e[31m\]\\$\[\e[m\] " + ;; + esac + ''; + + # Shell Aliases + # ------------- + shellAliases = { + ls = "ls --color=tty"; + l = "ls -CFh"; + la = "ls -Ah"; + ll = "ls -lh" ; + lt = "ls -lct --reverse"; + less = "less -S"; + top = "htop"; + todo = "task todo"; + active = "task active"; + version = "date '+%Y%m%d%H%M%S'"; + vclip = "xclip -selection clipboard"; + df = "df -h"; + + nix-search = "nix-env -qaP"; + nix-list = "nix-env -qaP \"*\" --description"; + nix-list-haskell = "nix-env -f \"\" -qaP -A haskellPackages"; + + nix-show-garbadge-roots = "ls -lh /nix/var/nix/gcroots/auto/"; + + }; + + }; + + }; +} + + + diff --git a/modules/programs/shell-tools.nix b/modules/programs/shell-tools.nix new file mode 100644 index 0000000..69a4dd8 --- /dev/null +++ b/modules/programs/shell-tools.nix @@ -0,0 +1,43 @@ +{ config, pkgs, lib, ... }: + +with lib; + +let + + xterm-colors = pkgs.writeShellScriptBin "256-xterm-colors" + /* sh */ '' + for i in {0..255} ; do + printf "\x1b[38;5;%sm%3d\e[0m " "$i" "$i" + if (( i == 15 )) || (( i > 15 )) && (( (i-15) % 6 == 0 )); then + printf "\n"; + fi + done + ''; + + xterm-background-colors = pkgs.writeShellScriptBin "256-xterm-colors-background" + /* sh */ '' + for i in {0..255} ; do + printf "\x1b[48;5;%sm%3d\e[0m " "$i" "$i" + if (( i == 15 )) || (( i > 15 )) && (( (i-15) % 6 == 0 )); then + printf "\n"; + fi + done + ''; + + + cfg = config.programs.custom.shellTools; + +in { + + options.programs.custom.shellTools.enable = mkEnableOption "enable shell tools"; + + config = mkIf cfg.enable { + environment.systemPackages = [ + xterm-colors + xterm-background-colors + ]; + }; + +} + + diff --git a/modules/programs/shell-zsh.nix b/modules/programs/shell-zsh.nix new file mode 100644 index 0000000..f523ab9 --- /dev/null +++ b/modules/programs/shell-zsh.nix @@ -0,0 +1,181 @@ +{ config, pkgs, lib, ... }: + +with lib; + +let + + cfg = config.programs.custom.zsh; + +in { + + options.programs.custom.zsh = { + enable = mkEnableOption "enable zsh"; + + mainUser = mkOption { + type = with types; nullOr str; + default = null; + description = '' + the main User if available + ''; + }; + + }; + + config = mkIf cfg.enable { + + programs.zsh = { + + enable = true; + enableCompletion = true; + #autosuggestions.enable = true; + syntaxHighlighting.enable = true; + + ohMyZsh = { + + custom = "/etc/zshcustom/"; + enable = true; + + # powerline themes + # ---------------- + #theme = "agnoster"; + theme = "powerlevel9k/powerlevel9k"; + + plugins = [ + "git" + "git-flow" + "git-prompt" + "gitignore" + "screen" + "sudo" + "systemd" + "tmux" + "vi-mode" + "wd" + ]; + }; + + loginShellInit = '' + export TERM="xterm-256color" + ''; + shellAliases = { + ls = "ls --color=tty"; + l = "ls -CFh"; + la = "ls -Ah"; + ll = "ls -lh" ; + lt = "ls -lct --reverse"; + less = "less -S"; + top = "htop"; + todo = "task todo"; + active = "task active"; + version = "date '+%Y%m%d%H%M%S'"; + vclip = "xclip -selection clipboard"; + df = "df -h"; + + timestamp = "date +%Y%m%d%H%M%S"; + + nix-search = "nix-env -qaP"; + nix-list = "nix-env -qaP \"*\" --description"; + nix-list-haskell = "nix-env -f \"\" -qaP -A haskellPackages"; + nix-list-node = "nix-env -f \"\" -qaP -A nodePackages"; + nix-list-beam = "nix-env -f \"\" -qaP -A beamPackages"; + # nix-find = "clear ; ${pkgs.nix-index}/bin/nix-locate -1 -w"; + + nix-show-garbadge-roots = "ls -lh /nix/var/nix/gcroots/auto/"; + + }; + }; + + #environment.systemPackages = [ + # pkgs.nix-index # make nix-index also available to users + #]; + + # only used to make quick config changes + # -------------------------------------- + environment.etc."zshcustom/mainuser.zsh".source = + pkgs.writeText "mainuser-zsh" ( + if ( cfg.mainUser != null ) + then + '' + source ${config.users.users.mainUser.home}/.zshrc + '' + else '' # programs.custom.zsh.mainUser not set '' ); + + # Theme + # ----- + # make sure powerline-fonts is set in `fonts.fonts` + + environment.etc."zshcustom/themes/powerlevel9k".source = pkgs.fetchFromGitHub { + owner = "bhilburn"; + repo = "powerlevel9k"; + rev = "v0.6.4"; + sha256 = "104wvlni3rilpw9v1dk848lnw8cm8qxl64xs70j04ly4s959dyb5"; + }; + environment.etc."zshcustom/powerlevel9kpatch.zsh".source = pkgs.writeText "powerlevel9kpatch.zsh" '' + + # this shows all the colors which are available + # --------------------------------------------- + # for code ({000..255}) print -P -- "$code: %F{$code}This is how your text would look like%f" + + # prompt elements + # --------------- + POWERLEVEL9K_LEFT_PROMPT_ELEMENTS=(vi_mode context dir vcs custom_jail background_jobs time status) + POWERLEVEL9K_RIGHT_PROMPT_ELEMENTS=() + + # vi mode + # ------- + POWERLEVEL9K_VI_MODE_INSERT_FOREGROUND="black" + POWERLEVEL9K_VI_MODE_INSERT_BACKGROUND="blue" + POWERLEVEL9K_VI_MODE_NORMAL_FOREGROUND="black" + POWERLEVEL9K_VI_MODE_NORMAL_BACKGROUND="yellow" + + # context + # ------- + POWERLEVEL9K_CONTEXT_DEFAULT_FOREGROUND="green" + POWERLEVEL9K_CONTEXT_DEFAULT_BACKGROUND="008" + POWERLEVEL9K_CONTEXT_ROOT_FOREGROUND="008" + POWERLEVEL9K_CONTEXT_ROOT_BACKGROUND="red" + POWERLEVEL9K_CONTEXT_REMOTE_FOREGROUND="008" + POWERLEVEL9K_CONTEXT_REMOTE_BACKGROUND="red" + + # dir + # --- + POWERLEVEL9K_DIR_HOME_FOREGROUND="black" + POWERLEVEL9K_DIR_HOME_BACKGROUND="yellow" + POWERLEVEL9K_DIR_HOME_SUBFOLDER_FOREGROUND="black" + POWERLEVEL9K_DIR_HOME_SUBFOLDER_BACKGROUND="yellow" + POWERLEVEL9K_DIR_DEFAULT_FOREGROUND="black" + POWERLEVEL9K_DIR_DEFAULT_BACKGROUND="green" + + # root_indicator + # -------------- + POWERLEVEL9K_ROOT_ICON="#" + POWERLEVEL9K_ROOT_INDICATOR_FOREGROUND="black" + POWERLEVEL9K_ROOT_INDICATOR_BACKGROUND="red" + + # background_jobs + # --------------- + POWERLEVEL9K_BACKGROUND_JOBS_ICON="" + + # status + # ------ + POWERLEVEL9K_STATUS_OK_BACKGROUND="008" + POWERLEVEL9K_STATUS_ERROR_BACKGROUND="008" + + # time + # ---- + POWERLEVEL9K_TIME_FOREGROUND="008" + POWERLEVEL9K_TIME_BACKGROUND="006" + + + # jail indicator + # -------------- + POWERLEVEL9K_CUSTOM_JAIL="[ -z $JAIL ] || echo $JAIL" + POWERLEVEL9K_CUSTOM_JAIL_BACKGROUND="red" + POWERLEVEL9K_CUSTOM_JAIL_FOREGROUND="black" + + + ''; + }; +} + + diff --git a/modules/programs/slack.nix b/modules/programs/slack.nix new file mode 100644 index 0000000..cd6457c --- /dev/null +++ b/modules/programs/slack.nix @@ -0,0 +1,135 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + + # name of the program + # ------------------- + program = "slack"; + + tarBin = "${pkgs.gnutar}/bin/tar"; + + # command that will be jailed + # --------------------------- + command = "${pkgs.slack}/bin/slack"; + + desktopFile = + let + name = program; + comment = "Chat Programm"; + in + pkgs.writeTextFile { + name = "${name}.desktop" ; + destination = "/share/applications/${name}.desktop"; + text = '' + [Desktop Entry] + Categories=Application;Utility; + Comment=${comment} + Encoding=UTF-8 + Exec=${bin}/bin/${name} + Icon=gnome-lockscreen + Name=${name} + Terminal=false + Type=Application + ''; + }; + + + # the script + # ---------- + bin = + let + backupFile = "${cfg.homeBackup}.tar.lzma"; + rolloutFile = "${cfg.home}.tar.lzma"; + lockFile = "${cfg.home}-lock"; + in + pkgs.writeShellScriptBin "${program}" '' + # set -x + if [[ ! -e ${lockFile} ]] + then + # rollout backup + if [[ -e ${backupFile} ]] + then + cp ${backupFile} ${rolloutFile} + sudo -u ${program} ${tarBin} xf ${rolloutFile} --directory ${cfg.home} + rm ${rolloutFile} + touch ${lockFile} + fi + fi + + sudo -u ${program} ${command} + ''; + + + + backupScript = + pkgs.writeShellScriptBin "${program}-backup" '' + sudo -u ${program} \ + ${tarBin} \ + --exclude=.cache \ + --exclude=".config/**/*Cache*" \ + --exclude-cache-all \ + --exclude=Downloads \ + --create \ + --verbos \ + --lzma \ + --file ${cfg.home}.tar.lzma \ + --directory ${cfg.home} \ + . + + cp ${cfg.home}.tar.lzma ${cfg.homeBackup}.tar.lzma + ''; + + cfg = config.programs.custom.slack; + +in { + + options.programs.custom.slack = { + enable = mkEnableOption "install slack"; + + homeBackup = mkOption { + type = with types; nullOr string; + description = '' + folder where to backup + ''; + }; + + # todo : make sure the folder /home/sudoers belongs to mainUser + home = mkOption { + type = with types; string; + default = "/home/sudoers/slack"; + description = '' + home folder of this + ''; + }; + + }; + + config = mkIf cfg.enable { + + security.sudo.extraConfig = + '' + ${config.users.users.mainUser.name} ALL=(${program}) NOPASSWD: ALL + ''; + + # create users + users.users."${program}" = { + home = cfg.home; + createHome = true; + # initialPassword = "${program}"; + shell = pkgs.bashInteractive; + isNormalUser = true; + group = "users"; + # enable video usage + extraGroups = [ "video" "audio" ]; + }; + + environment.systemPackages = [ + bin + backupScript + desktopFile + ]; + }; +} + diff --git a/modules/programs/steam.nix b/modules/programs/steam.nix new file mode 100644 index 0000000..91b3db0 --- /dev/null +++ b/modules/programs/steam.nix @@ -0,0 +1,46 @@ +{ config, lib, pkgs, ... }: + +with lib; + +# steam +# ------- +# Don't forget to run 'xhost +' with your user +# to make sure the browser user can write to X +let + + bin = pkgs.writeShellScriptBin "steam" '' + /var/run/wrappers/bin/sudo -u steam -i ${pkgs.steam}/bin/steam $@ + ''; + + cfg = config.programs.custom.steam; + +in { + + options.programs.custom.steam.enable = mkEnableOption "enable steam"; + + config = mkIf cfg.enable { + + environment.systemPackages = [ + bin + pkgs.xorg.xhost + # to use xbox controllers + pkgs.xboxdrv + ]; + + users.users.steam = { + isNormalUser = true; + home = "/home/steam"; + createHome = true; + extraGroups = [ "audio" "input" "video" ]; + }; + + # for steam + # --------- + hardware.opengl.driSupport32Bit = true; + + security.sudo.extraConfig = '' + ${config.users.extraUsers.mainUser.name} ALL=(steam) NOPASSWD: ALL + ''; + }; +} + diff --git a/modules/programs/taskwarrior.nix b/modules/programs/taskwarrior.nix new file mode 100644 index 0000000..0c76d14 --- /dev/null +++ b/modules/programs/taskwarrior.nix @@ -0,0 +1,39 @@ +{ config, pkgs, lib, ... }: + +with lib; + +let + + cfg = config.programs.custom.taskwarrior; + + taskNextWeek = pkgs.writeShellScriptBin "taskweek" /* sh */ '' + ${pkgs.taskwarrior}/bin/task \ + export \ + status:pending and \( due.before:6days \) \ + | ${pkgs.jq}/bin/jq '[.[] | { Day: .due, ID: .id, Description: .description } ] | sort_by(.Day)' \ + | ${pkgs.miller}/bin/mlr --ijson --opprint put "\$Day = strftime(strptime(\$Day,\"%Y%m%dT%H%M%SZ\")$(date +%z)00,\"%A\")" + ''; + + tsak = pkgs.writeShellScriptBin "tsak" /* sh */ '' + ${pkgs.taskwarrior}/bin/task "$@" + ''; + +in { + + options.programs.custom.taskwarrior.enable = mkEnableOption "Enable Taskwarrior services"; + + config = mkIf cfg.enable { + + environment.systemPackages = with pkgs; [ + taskwarrior + timewarrior + tasksh + taskNextWeek + tsak + + python # needed for hooks + ]; + + }; + +} diff --git a/modules/programs/urxvt.nix b/modules/programs/urxvt.nix new file mode 100644 index 0000000..54c900f --- /dev/null +++ b/modules/programs/urxvt.nix @@ -0,0 +1,169 @@ +{ config, pkgs, lib, ... }: + +with lib; + +let + + cfg = config.programs.custom.urxvt; + +in { + + options.programs.custom.urxvt = { + + enable = mkEnableOption "configure and enable urxvt"; + + fontSize = mkOption { + type = types.int; + default = 17; + description = '' + size of the terminal font + ''; + }; + + colorTheme = mkOption { + type = types.enum[ "dark" "light" ]; + default = "dark"; + description = '' + solarized color theme + ''; + }; + + }; + + config = mkIf cfg.enable { + + environment.systemPackages = [ pkgs.rxvt_unicode ]; + + environment.etc = { + + "X11/Xresource.d/urxvt".source = pkgs.writeText "Xresource-urxvt" '' + !! Perl extensions + !! --------------- + URxvt.perl-ext-common: default,matcher + + ! Urgency + URxvt.urgentOnBell: true + + !! Highlight URLs + !! -------------- + URxvt.url-launcher: /run/current-system/sw/bin/browser-select + URxvt.matcher.button: 1 + + !! History + !! ------- + URxvt.scrollStyle: rxvt + URxvt.scrollBar: false + URxvt.saveLines: 1000000 + + !! Color Configuration + !! ------------------- + + !! do not graded out unselected shells + !! ----------------------------------- + URxvt.fading: 0 + ''; + + "X11/Xresource.d/urxvt-font".source = let + fontFamily = "terminus"; + normalFont = fontSize: "-*-${fontFamily}-medium-*-*-*-${toString fontSize}-*-*-*-*-*-*-*"; + boldFont = fontSize: "-*-${fontFamily}-bold-*-*-*-${toString fontSize}-*-*-*-*-*-*-*"; + italicFont = normalFont; + itallicBoldFont = boldFont; + backupFont = fontSize: "xft:TerminessTTF Nerd Font:pixelsize=${toString fontSize}"; + + fontCommand = key: fontSize: '' + URxvt.keysym.M-${key}: command:\033]710;${normalFont fontSize},${backupFont fontSize}\007\033]711;${boldFont fontSize},${backupFont fontSize}\007 + ''; + + in pkgs.writeText "Xresource-urxvt-font" '' + + URxvt.allow_bold: true + URxvt.xftAntialias: true + + !! use xfontsel or fontmatrix to choose line + !URxvt.font: ${normalFont cfg.fontSize},${backupFont cfg.fontSize} + !URxvt.boldFont: ${boldFont cfg.fontSize},${backupFont cfg.fontSize} + !URxvt.italicFont: ${italicFont cfg.fontSize},${backupFont cfg.fontSize} + !URxvt.bolditalicFont: ${itallicBoldFont cfg.fontSize},${backupFont cfg.fontSize} + + URxvt.font: ${normalFont cfg.fontSize} + URxvt.boldFont: ${boldFont cfg.fontSize} + URxvt.italicFont: ${italicFont cfg.fontSize} + URxvt.bolditalicFont: ${itallicBoldFont cfg.fontSize} + + ${fontCommand "F1" cfg.fontSize} + ${fontCommand "F2" (cfg.fontSize + 5)} + ${fontCommand "F3" (cfg.fontSize + 10)} + ${fontCommand "F4" (cfg.fontSize + 20)} + ''; + + "X11/Xresource.d/urxvt-colors".source = + let + colorTheme = if (cfg.colorTheme == "dark") then '' + #define S_base03 #002b36 + #define S_base02 #073642 + #define S_base01 #586e75 + #define S_base00 #657b83 + #define S_base0 #839496 + #define S_base1 #93a1a1 + #define S_base2 #eee8d5 + #define S_base3 #fdf6e3 + '' else '' + #define S_base03 #fdf6e3 + #define S_base02 #eee8d5 + #define S_base01 #93a1a1 + #define S_base00 #839496 + #define S_base0 #657b83 + #define S_base1 #586e75 + #define S_base2 #073642 + #define S_base3 #002b36 + ''; + + in pkgs.writeText "Xresource-urxvt-colors" '' + + !! Common + !! ------ + #define S_yellow #b58900 + #define S_orange #cb4b16 + #define S_red #dc322f + #define S_magenta #d33682 + #define S_violet #6c71c4 + #define S_blue #268bd2 + #define S_cyan #2aa198 + #define S_green #859900 + + !! ColorTheme + !! ---------- + ${colorTheme} + + URxvt*background: S_base03 + URxvt*foreground: S_base0 + URxvt*fading: 40 + URxvt*fadeColor: S_base03 + URxvt*cursorColor: S_base1 + URxvt*pointerColorBackground: S_base01 + URxvt*pointerColorForeground: S_base1 + + URxvt*color0: S_base02 + URxvt*color1: S_red + URxvt*color2: S_green + URxvt*color3: S_yellow + URxvt*color4: S_blue + URxvt*color5: S_magenta + URxvt*color6: S_cyan + URxvt*color7: S_base2 + URxvt*color9: S_orange + URxvt*color8: S_base03 + URxvt*color10: S_base01 + URxvt*color11: S_base00 + URxvt*color12: S_base0 + URxvt*color13: S_violet + URxvt*color14: S_base1 + URxvt*color15: S_base3 + ''; + + }; + }; +} + + diff --git a/modules/programs/video.nix b/modules/programs/video.nix new file mode 100644 index 0000000..816765b --- /dev/null +++ b/modules/programs/video.nix @@ -0,0 +1,35 @@ +{ config, pkgs, lib, ... }: + +with lib; + +let + + cfg = config.programs.custom.video; + +in { + + options.programs.custom.video.enable = mkEnableOption "enable video tools"; + + config = mkIf cfg.enable { + environment.systemPackages = with pkgs; [ + youtube-dl + mplayer + mpv + + # to record your screen + # --------------------- + simplescreenrecorder + + # to transcode video material + # --------------------------- + handbrake + ffmpeg-full + + # video editing + # ------------- + openshot-qt + + ]; + }; +} + diff --git a/modules/programs/vim.nix b/modules/programs/vim.nix new file mode 100644 index 0000000..f879812 --- /dev/null +++ b/modules/programs/vim.nix @@ -0,0 +1,413 @@ +{ config, lib, pkgs, ... }: + +let + + cfg = config.programs.custom.vim; + + nix-xptemplates = pkgs.writeTextFile { + name = "nix-xptemplates"; + destination = "/ftplugin/nix/nix.xpt.vim"; + text = /* vim */ '' +XPTemplate priority=personal + +XPT option " tips +`name^ = mkOption { + type = with types; `type^; + description = ${"''"} + `cursor^ + ${"''"}; +}; + +XPT package " tips +{ config, lib, ... }: +{ + `cursor^ +} + +XPT terranix" tips +{ config, lib, pkgs, ... }: +with lib; +let + cfg = config.`name^; +in { + + options.`name^ = mkOption { + default = {}; + type = with types; attrsOf (submodule ({ name, ... }:{ + options = { + enable = mkEnableOption "`name^.name"; + }; + })); + }; + + config = + let + allConfigs = cfg + in + mkIf (cfg != {} ){ + `cursor^ + }; +} + +XPT module " tips +{ config, lib, pkgs, ... }: + +with lib; + +let + + cfg = config.`name^; + +in { + + options.`name^ = { + enable = mkEnableOption "enable `name^"; + }; + + config = mkIf cfg.enable { + `cursor^ + }; +} + +XPT shell " tips +{ pkgs ? import {} }: +pkgs.mkShell { + + # needed pkgs + # ----------- + buildInputs = with pkgs; [ + `name^ + ]; + + # run this on start + # ----------------- + shellHook = ${"''"} + + HISTFILE=${"$"}{toString ./.}/.history + + # run jailed zsh shell + # ---------------- + exec firejail \ + --env=JAIL=jail \ + --blacklist="/run/keys" \ + --blacklist="/run/keys*" \ + --private=${"$"}{toString ./.} \ + ${"$"}{pkgs.zsh}/bin/zsh + + ${"''"}; +} + +XPT fhsUser " tips +{ pkgs ? import {} }: +(pkgs.buildFHSUserEnv { +name = "fhs-user-env"; + +targetPkgs = pkgs: with pkgs; [ + # core stuff + # ---------- + vim silver-searcher curl coreutils git tig + + # common X dependencies + # --------------------- + atk cairo dbus eudev expat fontconfig freetype gdk_pixbuf glib gnome3.GConf gtk2-x11 + mesa_glu nspr nss pango xlibs.libXScrnSaver xlibs.libXcomposite xlibs.libXcursor + xlibs.libXdamage xlibs.libXfixes xlibs.libXi xlibs.libXrender xlibs.libXtst xorg.libX11 + xorg.libXext xorg.libXinerama xorg.libxcb + liblo zlib fftw minixml libcxx alsaLib glibc + + # new stuff + # --------- + `cursor^ + +]; + +# multilib packages +# ----------------- +# these are packages compiled 32bit and 64bit +multiPkgs = pkgs: with pkgs; [ +]; + +# environment variables +# --------------------- +profile = ${"''"} + export TERM="xterm" + ${"''"}; + +}).env + + ''; + }; + + vim-tv-plugin = with lib; + ((rtp: rtp // { inherit rtp; }) (pkgs.write "vim-tv" { + "/syntax/haskell.vim".text = /* vim */ '' + syn region String start=+\[[[:alnum:]]*|+ end=+|]+ + + hi link ConId Identifier + hi link VarId Identifier + hi link hsDelimiter Delimiter + ''; + "/syntax/nix.vim".text = /* vim */ '' + "" Quit when a (custom) syntax file was already loaded + "if exists("b:current_syntax") + " finish + "endif + + "setf nix + + " Ref + syn match NixID /[a-zA-Z\_][a-zA-Z0-9\_\'\-]*/ + syn match NixINT /\<[0-9]\+\>/ + syn match NixPATH /[a-zA-Z0-9\.\_\-\+]*\(\/[a-zA-Z0-9\.\_\-\+]\+\)\+/ + syn match NixHPATH /\~\(\/[a-zA-Z0-9\.\_\-\+]\+\)\+/ + syn match NixSPATH /<[a-zA-Z0-9\.\_\-\+]\+\(\/[a-zA-Z0-9\.\_\-\+]\+\)*>/ + syn match NixURI /[a-zA-Z][a-zA-Z0-9\+\-\.]*:[a-zA-Z0-9\%\/\?\:\@\&\=\+\$\,\-\_\.\!\~\*\']\+/ + syn region NixSTRING + \ matchgroup=NixSTRING + \ start='"' + \ skip='\\"' + \ end='"' + syn region NixIND_STRING + \ matchgroup=NixIND_STRING + \ start="'''" + \ skip="'''\('\|[$]\|\\[nrt]\)" + \ end="'''" + + syn match NixOther /[-!+&<>|():/;=.,?\[\]*@]/ + + syn match NixCommentMatch /\(^\|\s\)#.*/ + syn region NixCommentRegion start="/\*" end="\*/" + + hi link NixCode Statement + hi link NixData Constant + hi link NixComment Comment + + hi link NixCommentMatch NixComment + hi link NixCommentRegion NixComment + hi link NixID NixCode + hi link NixINT NixData + hi link NixPATH NixData + hi link NixHPATH NixData + hi link NixSPATH NixData + hi link NixURI NixData + hi link NixSTRING NixData + hi link NixIND_STRING NixData + + hi link NixEnter NixCode + hi link NixOther NixCode + hi link NixQuote NixData + + syn cluster nix_has_dollar_curly contains=@nix_ind_strings,@nix_strings + syn cluster nix_ind_strings contains=NixIND_STRING + syn cluster nix_strings contains=NixSTRING + + ${concatStringsSep "\n" (mapAttrsToList (name: { + extraStart ? null, + lang ? name + }: + let + startAlts = filter isString [ + ''/\* ${name} \*/'' + extraStart + ]; + sigil = ''\(${concatStringsSep ''\|'' startAlts}\)[ \t\r\n]*''; + in /* vim */ '' + syn include @nix_${lang}_syntax syntax/${lang}.vim + if exists("b:current_syntax") + unlet b:current_syntax + endif + + syn match nix_${lang}_sigil + \ X${replaceStrings ["X"] ["\\X"] sigil}\ze\('''\|"\)X + \ nextgroup=nix_${lang}_region_IND_STRING,nix_${lang}_region_STRING + \ transparent + + syn region nix_${lang}_region_STRING + \ matchgroup=NixSTRING + \ start='"' + \ skip='\\"' + \ end='"' + \ contained + \ contains=@nix_${lang}_syntax + \ transparent + + syn region nix_${lang}_region_IND_STRING + \ matchgroup=NixIND_STRING + \ start="'''" + \ skip="'''\('\|[$]\|\\[nrt]\)" + \ end="'''" + \ contained + \ contains=@nix_${lang}_syntax + \ transparent + + syn cluster nix_ind_strings + \ add=nix_${lang}_region_IND_STRING + + syn cluster nix_strings + \ add=nix_${lang}_region_STRING + + " This is required because containedin isn't transitive. + syn cluster nix_has_dollar_curly + \ add=@nix_${lang}_syntax + '') { + c = {}; + cabal = {}; + diff = {}; + haskell = {}; + python = {}; + lua = {}; + sed.extraStart = ''writeSed[^ \t\r\n]*[ \t\r\n]*"[^"]*"''; + sh.extraStart = concatStringsSep ''\|'' [ + ''write\(A\|Ba\|Da\)sh[^ \t\r\n]*[ \t\r\n]*\("[^"]*"\|[a-z]\+\)'' + ''[a-z]*Phase[ \t\r\n]*='' + ]; + yaml = {}; + vim.extraStart = + ''write[^ \t\r\n]*[ \t\r\n]*"\(\([^"]*\.\)\?vimrc\|[^"]*\.vim\)"''; + xdefaults = {}; + })} + + " Clear syntax that interferes with nixINSIDE_DOLLAR_CURLY. + syn clear shVarAssign + + syn region nixINSIDE_DOLLAR_CURLY + \ matchgroup=NixEnter + \ start="[$]{" + \ end="}" + \ contains=TOP + \ containedin=@nix_has_dollar_curly + \ transparent + + syn region nix_inside_curly + \ matchgroup=NixEnter + \ start="{" + \ end="}" + \ contains=TOP + \ containedin=nixINSIDE_DOLLAR_CURLY,nix_inside_curly + \ transparent + + syn match NixQuote /'''\(''$\|\\.\)/he=s+2 + \ containedin=@nix_ind_strings + \ contained + + syn match NixQuote /'''\('\|\\.\)/he=s+1 + \ containedin=@nix_ind_strings + \ contained + + syn match NixQuote /\\./he=s+1 + \ containedin=@nix_strings + \ contained + + syn sync fromstart + + let b:current_syntax = "nix" + + set isk=@,48-57,_,192-255,-,' + ''; + "/syntax/sed.vim".text = /* vim */ '' + syn region sedBranch + \ matchgroup=sedFunction start="T" + \ matchgroup=sedSemicolon end=";\|$" + \ contains=sedWhitespace + ''; + })); + + + # active plugins + # -------------- + extra-runtimepath = with pkgs; lib.concatMapStringsSep "," (pkg: "${pkg.rtp}") [ + vimPlugins.Syntastic + vimPlugins.ack-vim + vimPlugins.airline + vimPlugins.elm-vim + vimPlugins.rust-vim + vimPlugins.vim-elixir + vimPlugins.vim-nix + vimPlugins.xptemplate + vimPlugins.dhall-vim + vim-tv-plugin + # vimPlugins.LanguageClient-neovim + ]; + + # the vimrc + # --------- + vimrc = pkgs.writeText "vimrc" '' + + " turn on linenumbers + " to turn of :set nonumber + :set number + + " show Trailing Whitespaces + :set list listchars=tab:»·,trail:¶ + + " Map leader is the key for shortcuts + nnoremap + let mapleader = "\" + + " move blocks of text in visual mode + " does not work correctly + vmap xkP`[V`] + vmap xp`[V`] + + " search/grep case insensitive + :set ignorecase + + " tabs should always be 2 spaces + set et ts=2 sts=2 sw=2 + + " installed vim-plugins + set runtimepath=${extra-runtimepath},$VIMRUNTIME,$HOME/.vim,${nix-xptemplates} + + " syntax highlighting on + syntax on + + " xptemplates + " ----------- + " a plugin to insert snippets on demand + set nocompatible + filetype plugin on + + " enable cursor cross + " ------------------- + ":hi CursorLine cterm=NONE ctermbg=darkred ctermfg=white guibg=darkred guifg=white + ":hi CursorColumn cterm=NONE ctermbg=darkred ctermfg=white guibg=darkred guifg=white + :hi CursorLine cterm=NONE ctermbg=0 guibg=#073642 + :hi CursorColumn cterm=NONE ctermbg=0 guibg=#073642 + set cursorline + set cursorcolumn + + " save view + " --------- + augroup AutoSaveFolds + autocmd! + autocmd BufWinLeave * mkview + autocmd BufWinEnter * silent loadview + augroup END + + + ''; + +in { + + # no options + options.programs.custom.vim.enable = lib.mkEnableOption "vim"; + + config = lib.mkIf cfg.enable { + # create vimrc + # ------------ + # and load it as config for vim + environment.variables.VIMINIT = ":so /etc/vimrc"; + environment.etc.vimrc.source = vimrc; + + # set vim to the default editor + # ----------------------------- + programs.vim.defaultEditor = true; + + # install vim + # ----------- + environment.systemPackages = [ + pkgs.vim + ]; + }; + +} diff --git a/modules/programs/xterm.nix b/modules/programs/xterm.nix new file mode 100644 index 0000000..3b1bda3 --- /dev/null +++ b/modules/programs/xterm.nix @@ -0,0 +1,144 @@ +{ config, pkgs, lib, ... }: + +with lib; + +let + + cfg = config.programs.custom.xterm; + +in { + + options.programs.custom.xterm= { + enable = mkEnableOption "configure and enable urxvt"; + fontSize = mkOption { + type = types.int; + default = 17; + description = '' + size of the terminal font + ''; + }; + colorTheme = mkOption { + type = types.enum[ "dark" "light" ]; + default = "dark"; + description = '' + solarized color theme + ''; + }; + }; + + config = mkIf cfg.enable { + + environment.systemPackages = [ pkgs.xterm ]; + + environment.etc = { + + "X11/Xresource.d/xterm".source = pkgs.writeText "Xresource-xterm" '' + + XTerm*termName: xterm-256color + XTerm*selectToClipboard: true + + XTerm.*.bellIsUrgent: true + + ''; + + "X11/Xresource.d/xterm-font".source = let + fontFamily = "terminus"; + normalFont = fontSize: "-*-${fontFamily}-medium-*-*-*-${toString fontSize}-*-*-*-*-*-*-*"; + boldFont = fontSize: "-*-${fontFamily}-bold-*-*-*-${toString fontSize}-*-*-*-*-*-*-*"; + italicFont = normalFont; + itallicBoldFont = boldFont; + backupFont = fontSize: "xft:TerminessTTF Nerd Font:pixelsize=${toString fontSize}"; + in pkgs.writeText "Xresource-xterm-font" '' + + XTerm.allow_bold: true + XTerm.xftAntialias: true + + !! use xfontsel or fontmatrix to choose line + !XTerm.*.font: ${normalFont cfg.fontSize},${backupFont cfg.fontSize} + !XTerm.*.boldFont: ${boldFont cfg.fontSize},${backupFont cfg.fontSize} + !XTerm.*.italicFont: ${italicFont cfg.fontSize},${backupFont cfg.fontSize} + !XTerm.*.bolditalicFont: ${itallicBoldFont cfg.fontSize},${backupFont cfg.fontSize} + + XTerm.*.font: ${normalFont cfg.fontSize} + XTerm.*.boldFont: ${boldFont cfg.fontSize} + XTerm.*.italicFont: ${italicFont cfg.fontSize} + XTerm.*.bolditalicFont: ${itallicBoldFont cfg.fontSize} + ''; + + + "X11/Xresource.d/xterm-colors".source = + let + colorTheme = if (cfg.colorTheme == "dark") then '' + #define S_base03 #002b36 + #define S_base02 #073642 + #define S_base01 #586e75 + #define S_base00 #657b83 + #define S_base0 #839496 + #define S_base1 #93a1a1 + #define S_base2 #eee8d5 + #define S_base3 #fdf6e3 + + '' + else '' + #define S_base03 #fdf6e3 + #define S_base02 #eee8d5 + #define S_base01 #93a1a1 + #define S_base00 #839496 + #define S_base0 #657b83 + #define S_base1 #586e75 + #define S_base2 #073642 + #define S_base3 #002b36 + ''; + + in pkgs.writeText "Xresource-xterm-colors" '' + + !! Color Configuration + !! ------------------- + + !! Common + !! ------ + #define S_yellow #b58900 + #define S_orange #cb4b16 + #define S_red #dc322f + #define S_magenta #d33682 + #define S_violet #6c71c4 + #define S_blue #268bd2 + #define S_cyan #2aa198 + #define S_green #859900 + + !! ColorTheme + !! ---------- + ${colorTheme} + + XTerm*background: S_base03 + XTerm*foreground: S_base0 + XTerm*fading: 40 + XTerm*fadeColor: S_base03 + XTerm*cursorColor: S_base1 + XTerm*pointerColorBackground: S_base01 + XTerm*pointerColorForeground: S_base1 + + XTerm*color0: S_base02 + XTerm*color1: S_red + XTerm*color2: S_green + XTerm*color3: S_yellow + XTerm*color4: S_blue + XTerm*color5: S_magenta + XTerm*color6: S_cyan + XTerm*color7: S_base2 + XTerm*color9: S_orange + XTerm*color8: S_base03 + XTerm*color10: S_base01 + XTerm*color11: S_base00 + XTerm*color12: S_base0 + XTerm*color13: S_violet + XTerm*color14: S_base1 + XTerm*color15: S_base3 + ''; + + }; + + }; +} + + diff --git a/modules/services/castget.nix b/modules/services/castget.nix new file mode 100644 index 0000000..b84a461 --- /dev/null +++ b/modules/services/castget.nix @@ -0,0 +1,100 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + + cfg = config.custom.services.castget; + +in { + + options.custom.services.castget = { + enable = mkEnableOption "enable custom.services.castget"; + feeds = mkOption { + type = with types; attrsOf (submodule { + options = { + url = mkOption { + type = with types; str; + description = '' + url to the rss feed + ''; + }; + spool = mkOption { + type = with types; path; + description = '' + download enclosures to this directory. + ''; + }; + }; + }); + description = '' + configurations for the cast + ''; + }; + user = mkOption { + type = with types; string; + description = '' + user to run the systemd service as + ''; + }; + timerConfig = mkOption { + type = with types; attrsOf str; + default = { + OnCalendar = "daily"; + }; + example = { + OnCalendar = "00:05"; + RandomizedDelaySec = "5h"; + }; + description = '' + When to run the polling script. See man systemd.timer for details. + ''; + }; + serviceName = mkOption { + type = with types; string; + default = "castget"; + description = '' + the name of the castget systemd service + ''; + }; + }; + + config = mkIf cfg.enable { + + systemd.services."${cfg.serviceName}" = { + description = "castget polling service"; + after = [ "network.target" ]; + wantedBy = [ "multi-user.target" ]; + restartIfChanged = false; + serviceConfig.User = cfg.user; + + preStart = + let + mkSpools = mapAttrsToList (ignore: value: "mkdir -p ${value.spool}") cfg.feeds; + in + concatStringsSep "\n" mkSpools; + script = + let + channels = mapAttrsToList (key: ignore: key) cfg.feeds; + castget = "${pkgs.castget}/bin/castget"; + + configurationFile = + let + configurations = mapAttrsToList (key: value: '' + [${key}] + url=${value.url} + spool=${value.spool} + '') cfg.feeds; + in + (pkgs.writeText "castget-configuration" (concatStringsSep "" configurations)); + in + (concatMapStringsSep "\n" (channel: "${castget} --rcfile ${configurationFile} ${channel}") channels); + }; + + systemd.timers."${cfg.serviceName}" = { + wantedBy = [ "timers.target" ]; + timerConfig = cfg.timerConfig; + }; + + }; +} diff --git a/modules/services/home-assistant.nix b/modules/services/home-assistant.nix new file mode 100644 index 0000000..71af009 --- /dev/null +++ b/modules/services/home-assistant.nix @@ -0,0 +1,274 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + + cfg = config.services.homeAssistantConfig; + +in { + + options.services.homeAssistantConfig = mkOption { + default = null; + type = with types; nullOr (submodule { options = { + group = mkOption { + default = null; + example = { schlafzimmer = { view = false; entities = [ "switch.pal01" ]; }; }; + type = with types; nullOr (attrsOf ( submodule { + options = { + name = mkOption { + default = null; + type = with types; nullOr str; + description = '' + (string)(Optional)Name of the group. + ''; + }; + view = mkOption { + default = false; + type = with types; bool; + description = '' + (boolean)(Optional)If yes then the entry will be shown as a view (tab) at the top. Groups that are set to view: true cannot be used as entities in other views. + ''; + }; + icon = mkOption { + default = null; + type = with types; nullOr str; + description = '' + (string)(Optional)If the group is a view, this icon will show at the top in the frontend instead of the name. If the group is a view and both name and icon have been specified, the icon will appear at the top of the frontend and the name will be displayed as the mouse-over text. If it’s not a view, then the icon shows when this group is used in another group. + ''; + }; + control = mkOption { + default = null; + type = with types; nullOr str; + description = '' + (string)(Optional)Set value to hidden. If hidden then the group switch will be hidden. + ''; + }; + entities = mkOption { + type = with types; listOf str; + description = '' + (list)(Required)Array or comma delimited string, list of entities to group. + ''; + }; + all = mkOption { + default = true; + type = with types; bool; + description = '' + (boolean)(Optional)Set this to true if the group state should only turn on if all grouped entities are on. + ''; + }; + + }; + })); + }; + homeassistant = mkOption { + type = with types; (submodule { options = { + name = mkOption { + default = "Home"; + type = with types; str; + }; + time_zone = mkOption { + default = config.time.timeZone; + type = with types; str; + }; + latitude = mkOption { + default = 52.464031; + type = with types; float; + }; + longitude = mkOption { + default = 13.381925; + type = with types; float; + }; + elevation = mkOption { + default = 34; + type = with types; int; + }; + unit_system = mkOption { + default = "metric"; + type = with types; str; + }; + whitelist_external_dirs = mkOption { + default = null; + type = with types; nullOr (listOf str); + }; + auth_providers = mkOption { + default = null; + type = with types; nullOr (listOf attrs); + }; + customize = mkOption { + type = with types; attrsOf (submodule{ options = { + friendly_name = mkOption { + type = with types; str; + }; + entity_picture = mkOption { + default = null; + type = with types; nullOr str; + }; + icon = mkOption { + default = null; + type = with types; nullOr str; + }; + };}); + }; + };}); + }; + introduction = mkOption { + default = {}; + type = with types; attrs; + }; + frontend = mkOption { + default = {}; + type = with types; attrs; + }; + config = mkOption { + default = {}; + type = with types; attrs; + }; + http = mkOption { + default = null; + type = with types; nullOr attrs; + }; + discovery = mkOption { + default = null; + type = with types; nullOr attrs; + }; + history = mkOption { + default = null; + type = with types; nullOr attrs; + }; + logbook = mkOption { + default = null; + type = with types; nullOr attrs; + }; + logger = mkOption { + default = {}; + type = with types; attrs; + }; + lovelace = mkOption { + default = { mode = "yaml"; }; + type = with types; nullOr attrs; + }; + map = mkOption { + default = null; + type = with types; nullOr attrs; + }; + mqtt = mkOption { + default = null; + type = with types; nullOr attrs; + }; + sun = mkOption { + default = null; + type = with types; nullOr attrs; + }; + + switch = mkOption { + default = null; + type = with types; nullOr (listOf attrs); + }; + binary_sensor = mkOption { + default = null; + type = with types; nullOr (listOf attrs); + }; + sensor = mkOption { + default = null; + type = with types; nullOr (listOf attrs); + }; + prometheus = mkOption { + default = null; + type = with types; nullOr attrs; + }; + automation = mkOption { + default = null; + type = with types; nullOr (listOf attrs); + }; + media_player = mkOption { + default = null; + type = with types; nullOr (listOf attrs); + }; + mysensors = mkOption { + default = null; + type = with types; nullOr attrs; + }; + script = mkOption { + default = null; + type = with types; nullOr (attrsOf (submodule { + options = { + alias = mkOption { + default = null; + type = with types; nullOr str; + }; + sequence = mkOption { + default = []; + type = with types; listOf attrs; + }; + }; + })); + }; + input_number = mkOption { + default = null; + type = with types; nullOr (attrsOf attrs); + }; + input_text = mkOption { + default = null; + type = with types; nullOr (attrsOf attrs); + }; + input_select = mkOption { + default = null; + type = with types; nullOr (attrsOf attrs); + }; + input_boolean = mkOption { + default = null; + type = with types; (attrsOf attrs); + }; + input_datetime = mkOption { + default = null; + type = with types; (attrsOf attrs); + }; + calendar = mkOption { + default = []; + type = with types; listOf attrs; + }; + shell_command = mkOption { + default = null; + type = with types; nullOr (attrsOf str); + }; + + };}); + description = '' + home-assistant configuration + ''; + }; + + config = mkIf (cfg != null) { + services.home-assistant.config = + let + + sanitize = configuration: lib.getAttr (builtins.typeOf configuration) { + bool = configuration; + int = configuration; + string = configuration; + str = configuration; + float = configuration; + list = map sanitize configuration; + set = + let + stripped = lib.flip lib.filterAttrs configuration + (name: value: + name != "_module" + && name != "_ref" + && value != null + ); + recursiveSanitized = lib.mapAttrs (lib.const sanitize) stripped; + in + if ( length ( attrNames configuration ) == 0 ) + then + null + else + recursiveSanitized; + }; + + in + sanitize cfg ; + + }; +} diff --git a/modules/services/lektor.nix b/modules/services/lektor.nix new file mode 100644 index 0000000..e618840 --- /dev/null +++ b/modules/services/lektor.nix @@ -0,0 +1,178 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + + cfg = config.services.lektor; + +in { + + options.services.lektor = { + enable = mkEnableOption "enable services.lektor"; + user = mkOption { + default = "lektor"; + type = with types; str; + description = '' + name of the lektor service + ''; + }; + home = mkOption { + default = "/home/${cfg.user}"; + type = with types; str; + description = '' + home of the service + ''; + }; + repository = mkOption { + type = with types; str; + description = '' + Repository to get the lektor project from. + ''; + example = "git@github.com:lektor/lektor-website.git"; + }; + bind = mkOption { + default = "0.0.0.0"; + type = with types; str; + description = '' + Host to bind the lektor service to. + ''; + }; + serviceName = mkOption { + default = "lektor"; + type = with types; str; + description = '' + name of the system service (without the .service suffix) + ''; + }; + port = mkOption { + default = 5000; + type = with types; int; + description = '' + Port to bind the lektor service to. + ''; + }; + additionalScript = mkOption { + default = null; + type = with types; nullOr path; + description = '' + A script you can us as a hook before the lektor server start + (for example to creat your css or javascript files) + ''; + example = pkgs.writeShellScript "build" '' + ${pkgs.nix}/bin/nix-shell --run build"; + ''; + }; + #sshMatchBlocks = mkOption { + # default = []; + # type = with types; listOf attrs; + # description = '' + # a matchBlock from home-manager.users..programs.ssh.matchBlocks; + # ''; + #}; + host = mkOption { + type = with types; str; + description = '' + ssh host to pull from and push to + ''; + }; + sshKey = mkOption { + type = with types; str; + description = '' + todo : avoid this, or make sure the home folder is crypted + Warning the key will be copied into the home folder of the user + ssh key to use + ''; + }; + }; + + config = mkIf cfg.enable { + + # create User + users.users."${cfg.user}" = { + home = cfg.home; + createHome = true; + isSystemUser = true; + }; + + # create systemd service to start service + systemd.services."${cfg.serviceName}" = { + enable = true; + wantedBy = [ "multi-user.target" ]; + + environment.NIX_PATH = config.environment.variables.NIX_PATH; + serviceConfig = { + User = cfg.user; + # todo : this is not working properly + TimeoutStartSec = "infinity"; # it might take some time will this thing is up + + ExecStartPre = + let + + sshKeyTarget = "/run/keys.lektor/id_rsa"; + + sshConfig = pkgs.writeText "sshconfig" '' + Host ${cfg.host} + IdentityFile ${sshKeyTarget} + + Host * + ForwardAgent no + Compression no + ServerAliveInterval 0 + HashKnownHosts no + UserKnownHostsFile ~/.ssh/known_hosts + ControlMaster no + ControlPath ~/.ssh/master-%r@%n:%p + ControlPersist no + ''; + + sshKeyScript = pkgs.writers.writeDash "keyfile-gen" /* sh */ '' + set -x + + # setup ~/.ssh + mkdir -p ${cfg.home}/.ssh + chown ${cfg.user} ${cfg.home}/.ssh + chmod 700 ${cfg.home}/.ssh + + cp ${sshConfig} ${cfg.home}/.ssh/config + chown ${cfg.user} ${cfg.home}/.ssh/config + chmod 500 ${cfg.home}/.ssh/config + + mkdir -p ${dirOf sshKeyTarget} + chmod 700 ${dirOf sshKeyTarget} + chown ${cfg.user} ${dirOf sshKeyTarget} + cp ${toString cfg.sshKey} ${sshKeyTarget} + chown ${cfg.user} ${sshKeyTarget} + chmod 500 ${sshKeyTarget} + ''; + + cloneScript = pkgs.writers.writeDash "clone" /* sh */ '' + set -x + if [[ `ls ~/${cfg.user} | wc -l` == 0 ]] + then + rm ~/${cfg.user} + fi + ${pkgs.git}/bin/git clone ${cfg.repository} ~/${cfg.user} + ''; + + in [ + "+${sshKeyScript}" + "-${cloneScript}" + ]; + }; + + + # todo : add restart ruling + + script = /* sh */ '' + cd ~/${cfg.user} && \ + ${pkgs.git}/bin/git pull && \ + ${optionalString (cfg.additionalScript != null) "${cfg.additionalScript} &&"} \ + ${pkgs.lektor}/bin/lektor server \ + --host ${cfg.bind} \ + --port ${toString cfg.port} + ''; + }; + }; +} + diff --git a/modules/services/samba-share.nix b/modules/services/samba-share.nix new file mode 100644 index 0000000..5337b24 --- /dev/null +++ b/modules/services/samba-share.nix @@ -0,0 +1,72 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + + cfg = config.custom.samba-share; + +in { + + options.custom.samba-share = { + enable = mkEnableOption "enable custom.samba-share"; + folders = mkOption { + type = with types; attrsOf str; + description = '' + folders to share as readonly + ''; + example = { + public = "/srv/downloads/movies"; + }; + }; + }; + + config = mkMerge [ + (mkIf cfg.enable { + networking.firewall.enable = true; + networking.firewall.allowPing = true; + networking.firewall.allowedTCPPorts = [ 445 139 ]; + networking.firewall.allowedUDPPorts = [ 137 138 ]; + + services.samba = { + enable = true; + # services.samba.securityType = "share"; + extraConfig = '' + guest account = smbguest + map to guest = bad user + + # disable printing + load printers = no + printing = bsd + printcap name = /dev/null + disable spoolss = yes + ''; + + shares = + mapAttrs' (name: path: + { + name = name; + value = { + browsable = "yes"; + comment = "read only share {name}"; + path = path; + "read only" = "yes"; + "guest ok" = "yes"; + }; + }) cfg.folders; + }; + + users.users.smbguest = { + name = "smbguest"; + uid = config.ids.uids.smbguest; + description = "smb guest user"; + home = "/home/smbguest"; + createHome = true; + }; + + }) + (mkIf config.services.syncthing.enable { + users.groups.syncthing.members = [ "smbguest" ]; + }) + ]; +} diff --git a/modules/services/seafile.nix b/modules/services/seafile.nix new file mode 100644 index 0000000..065a2aa --- /dev/null +++ b/modules/services/seafile.nix @@ -0,0 +1,87 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + + cfg = config.custom.services.seafile; + +in { + + options.custom.services.seafile = { + enable = mkEnableOption "enable custom.services.seafile"; + hostname = mkOption { + type = with types; string; + description = '' + hostname of the seafile server + ''; + }; + port = mkOption { + type = with types; int; + description = '' + port on where ther server runs on + ''; + }; + home = mkOption { + type = with types; path; + description = '' + folder in where the seafile stuff gets stored + ''; + }; + serviceName = mkOption { + type = with types; string; + default = "seafile-docker"; + description = '' + name of the systemd service + ''; + }; + }; + + config = mkIf cfg.enable { + + virtualisation.docker.enable = true; + + systemd.services."${cfg.serviceName}" = { + enable = true; + description = "seafile service running as docker"; + after = [ "network.target" "docker.service" ]; + requires = [ "docker.service" ]; + wantedBy = [ "multi-user.target" ]; + script = /* sh */'' + # delete old instance to ensure update + ${pkgs.docker}/bin/docker stop seafile || true && ${pkgs.docker}/bin/docker rm -f seafile || true + # start instance + ${pkgs.docker}/bin/docker run \ + --name seafile \ + --env SEAFILE_SERVER_HOSTNAME=${cfg.hostname} \ + --env SEAFILE_ADMIN_EMAIL="root@${cfg.hostname}" \ + --env SEAFILE_ADMIN_PASSWORD="${lib.fileContents }" \ + --volume ${cfg.home}:/shared \ + --publish ${toString cfg.port}:80 \ + seafileltd/seafile:latest + ''; + }; + + }; + +} + + + +# ! todo +# requires = [ "${config.module.backup.services.encfs."seafile".serviceName}.service" ]; + + +# krops.keys."seafile".path = toString ; +# +# module.backup.services.encfs = { +# "seafile" = { +# enable = true; +# encryptedFolder = "/home/seafile.ct"; +# decryptedFolder = "/home/seafile"; +# keyFile = config.krops.keys."seafile".path; +# requires = [ ''${config.krops.keys."seafile".serviceName}.service'' ]; +# }; +# }; + + diff --git a/modules/services/sshd.nix b/modules/services/sshd.nix new file mode 100644 index 0000000..85aa65d --- /dev/null +++ b/modules/services/sshd.nix @@ -0,0 +1,63 @@ +{ pkgs, config, lib, ... }: + +with lib; + +let + + cfg = config.services.custom.ssh; + +in { + + options.services.custom.ssh = { + tools.enable = mkEnableOption "Add ssh tools"; + sshd = { + enable = mkEnableOption "Start sshd server"; + rootKeyFiles = mkOption { + type = with types; listOf path; + description = "keys to root login"; + default = [ ]; + }; + }; + }; + + + config = mkMerge [ + + (mkIf cfg.tools.enable { + environment.systemPackages = with pkgs; [ + # sshuttle + sshfs + ]; + }) + + (mkIf cfg.sshd.enable { + + services.openssh = { + enable = true; + forwardX11 = true; + passwordAuthentication = false; + }; + + users.users.root.openssh.authorizedKeys.keyFiles = cfg.sshd.rootKeyFiles ; + + services.openssh.extraConfig = '' + Banner /etc/sshd/banner-line + ''; + + environment.etc."sshd/banner-line".text = + let + text = config.networking.hostName; + size = 80 - (lib.stringLength text); + space = lib.fixedWidthString size " " ""; + in '' + ──────────────────────────────────────────────────────────────────────────────── + ${ space }${ text } + ''; + + } + ) + + + ]; + +} diff --git a/modules/services/transmission.nix b/modules/services/transmission.nix new file mode 100644 index 0000000..b0fbcb0 --- /dev/null +++ b/modules/services/transmission.nix @@ -0,0 +1,128 @@ +{ config, lib, ... }: + +with lib; +let + + + cfg = config.services.custom.transmission; + +in { + + + options.services.custom.transmission = { + enable = lib.mkEnableOption "transmission"; + home = lib.mkOption { + type = lib.types.path; + description = "where the configs are"; + }; + store = lib.mkOption { + type = lib.types.path; + description = "where to store"; + }; + hosts = lib.mkOption { + type = lib.types.str; + description = "allowed hostnames"; + }; + whitelist = lib.mkOption { + type = lib.types.str; + description = "Ip to listen to"; + }; + user = lib.mkOption { + type = lib.types.str; + description = "user to login"; + }; + password = lib.mkOption { + type = lib.types.str; + description = "password to login"; + }; + port = mkOption { + type = with types; int; + default = 51413; + description = '' + forwarded Port + ''; + }; + }; + + config = lib.mkIf cfg.enable { + + # because 2.94 is not supported by pass the popcorn + #nixpkgs.config.packageOverrides = pkgs: { + # transmission = + # (pkgs.transmission.overrideAttrs (old: rec { + # version = "2.93"; + # src = pkgs.fetchurl { + # url = "https://github.com/transmission/transmission-releases/raw/master/transmission-2.93.tar.xz"; + # sha256 = "02xrp49gsv4jkbzp37qrwlnb9nlja08s92dyvgdbr6a4187945c8"; + # }; + # })); + #}; + + services.transmission = { + enable = true; + home = "${cfg.home}"; + settings = { + + # Downloads + download-dir = "${cfg.store}/downloads"; + incomplete-dir-enabled = true; + incomplete-dir = "${cfg.store}/incomplete"; + + # RPC = UI connection + rpc-whitelist = "${cfg.whitelist}"; + rpc-host-whitelist = "${cfg.hosts}"; + rpc-user = "${cfg.user}"; + rpc-username = "${cfg.user}"; + rpc-password = "${cfg.password}"; + + # Start torrents as soon as they are added + start-added-torrents = true; + + # Encryption may help get around some ISP filtering, + # but at the cost of slightly higher CPU use. + # 0 = Prefer unencrypted connections, + # 1 = Prefer encrypted connections, + # 2 = Require encrypted connections; default = 1) + encryption = 2; + + # Enable Local Peer Discovery (LPD). + lpd-enabled = true; + + # Enable UPnP or NAT-PMP. + peer-port = cfg.port; + port-forwarding-enabled = true; + + # "normal" speed limits + speed-limit-down-enabled = true; + speed-limit-down = 800; + speed-limit-up-enabled = true ; + speed-limit-up = 50; + upload-slots-per-torrent = 8; + + # Queuing + # When true, Transmission will only download + # download-queue-size non-stalled torrents at once. + download-queue-enabled = true; + download-queue-size = 1; + + # When true, torrents that have not shared data for + # queue-stalled-minutes are treated as 'stalled' + # and are not counted against the queue-download-size + # and seed-queue-size limits. + queue-stalled-enabled = true; + queue-stalled-minutes = 60; + + # When true. Transmission will only seed seed-queue-size + # non-stalled torrents at once. + seed-queue-enabled = true; + seed-queue-size = 10; + + # umask of the moves that got downloaded + umask = 18; + + }; + }; + + }; +} + diff --git a/modules/services/videoencoder.nix b/modules/services/videoencoder.nix new file mode 100644 index 0000000..2446633 --- /dev/null +++ b/modules/services/videoencoder.nix @@ -0,0 +1,105 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + + cfg = config.service.videoencoder; + + # todo : escape output and input File + createEncoder = tmpFolder: inputFile: outputFile: /* sh */ '' + mkdir -p ${tmpFolder} + rm -rf ${tmpFolder}/* + TMP_FILE=`mktemp --dry-run ${tmpFolder}/XXXXXXXX.${cfg.format}` + + if [ ! -f "${outputFile}" ] + then + ${pkgs.ffmpeg}/bin/ffmpeg \ + -i "${inputFile}" \ + -filter:v scale=h='min(720\,ih)':w='min(1280\,iw)' \ + -vcodec libx264 \ + -preset veryslow \ + -profile:v ${cfg.profile} \ + ${optionalString (cfg.tune != null) "-tune ${cfg.tune}"} \ + -acodec aac \ + "$TMP_FILE" \ + -hide_banner \ + && cp $TMP_FILE "${outputFile}.${cfg.format}" \ + && rm $TMP_FILE + fi + ''; + +in { + + options.service.videoencoder = { + enable = mkEnableOption "enable service.videoencoder"; + + profile = mkOption { + type = with types; string; + default = "main"; + description = '' + -profile:v + ''; + }; + + tune = mkOption { + type = with types; nullOr (enum [ "film" "animation" "grain" "stillimage" ]); + default = null; + description = '' + -tune + ''; + }; + + format = mkOption { + type = with types; enum [ "mp4" "mkv" ]; + default = "mp4"; + description = '' + the format + ''; + }; + + fileConfig = mkOption { + type = with types; listOf (submodule { + options = { + inputFile = mkOption { + # todo make this path + type = with types; string; + description = '' + full path to the inputFile + ''; + }; + outputFile = mkOption { + type = with types; string; + description = '' + full path to the ouputFile + folder must exist + ''; + }; + }; + }); + description = '' + list of files to encode. + ''; + }; + }; + + config = mkIf cfg.enable { + + systemd.services."videoEncoding" = { + wantedBy = ["multi-user.target"]; + enable = true; + script = + let + myList = map ( value : + createEncoder "/tmp/videoencoder" value.inputFile value.outputFile + ) cfg.fileConfig; + in '' + set -x + ${concatStringsSep "\n" myList} + ''; + + }; + + }; + +} diff --git a/modules/system/audio.nix b/modules/system/audio.nix new file mode 100644 index 0000000..c275abd --- /dev/null +++ b/modules/system/audio.nix @@ -0,0 +1,155 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + + ladspaPath = "${pkgs.ladspaPlugins}/lib/ladspa"; + + jackScript = pkgs.writeShellScriptBin "jack" (lib.fileContents ); + + queueElement = { + options = { + plugin = mkOption { + type = with types; str; + description = "file name without suffix of the plugin"; + }; + label = mkOption { + type = with types; str; + description = "label of the queue element (needs to be correct)"; + }; + control = mkOption { + type = with types; listOf str; + description = "parameter of plugin"; + }; + }; + }; + + sinkElement = { + options = { + name = mkOption { + type = with types; str; + description = "name of the sink"; + }; + queue = mkOption { + type = with types; listOf (submodule queueElement); + description = "queues"; + }; + }; + }; + + cfg = config.system.custom.audio; + +in { + + options.system.custom.audio = { + enable = mkEnableOption "use PluseAudio"; + sinks = mkOption { + type = with types; listOf (submodule sinkElement); + description = "list of sinks"; + }; + }; + + config = mkIf cfg.enable { + + # add virtual midi module + # ----------------------- + boot = { + # to route midi signals + # between bitwig and vcvrack + kernelModules = [ "snd_virmidi" ]; + # index=-2 prevents from beeing recognised as the default + # audio device + # midi_devs limit the number of midi devices. + extraModprobeConfig = "options snd-virmidi index=-2 midi_devs=1"; + }; + + # LADSPA + # ------ + programs.bash.interactiveShellInit = /* sh */ '' + # set ladspa library path + # about testing the plugins check analyseplugin command + export LADSPA_PATH=${ladspaPath} + ''; + programs.zsh.interactiveShellInit = /* sh */ '' + # set ladspa library path + # about testing the plugins check analyseplugin command + export LADSPA_PATH=${ladspaPath} + ''; + + # PulseAudio + # ---------- + + # because of systemWide ensure main user is in audio group + system.custom.mainUser.extraGroups = [ "audio" ]; + + hardware.pulseaudio = { + enable = true; + + # all in audio group can do audio + systemWide = true; + + package = pkgs.pulseaudioLight.override { + jackaudioSupport = true; + # todo : check for bluetooth enable + bluetoothSupport = true; + }; + + extraConfig = '' + + # automatically switch to newly-connected devices + load-module module-switch-on-connect + + # http://plugin.org.uk/ladspa-swh/docs/ladspa-swh.html + # https://gavv.github.io/articles/pulseaudio-under-the-hood/#ladspa-plugin-sink + ${builtins.toString (flip map cfg.sinks (sink : '' + # ladspa sink : ${sink.name} + # ------------- + ${builtins.toString (flip imap0 (reverseList sink.queue) (index : queua: + let + sinkName = suffix : "${sink.name}${builtins.toString suffix}"; + sinkValue = "sink_name=${sinkName index}"; + sinkDescription = "sink_properties=device.description=${sinkName index}-${queua.label}"; + masterValue = if (index == 0) then "" else "master=${sinkName (index - 1)}"; + pluginValue = "plugin=${ladspaPath}/${queua.plugin}"; + labelValue = "label=${queua.label}"; + controlValue = "control=${builtins.toString (foldl (a: b: "${a},${b}") (head queua.control) (tail queua.control))}"; + in '' + # ${sinkName index} : ${queua.label} + load-module module-ladspa-sink ${sinkValue} ${sinkDescription} ${masterValue} ${pluginValue} ${labelValue} ${controlValue} + ''))} + ''))} + ''; + }; + + # Packages needed + # --------------- + environment.systemPackages = with pkgs ; [ + + jackScript + + # Music making + jack2Full + alsaUtils + patchage + zynaddsubfx + + # qjackctl + + + # LADSPA + # ------ + ladspaPlugins + ladspa-sdk + + # PulseAudio control + # ------------------ + pavucontrol + lxqt.pavucontrol-qt + + ]; + + }; + +} + diff --git a/modules/system/bluetooth.nix b/modules/system/bluetooth.nix new file mode 100644 index 0000000..f9b876f --- /dev/null +++ b/modules/system/bluetooth.nix @@ -0,0 +1,34 @@ +{ config, lib, pkgs, ... }: + +let + + cfg = config.system.custom.bluetooth; + +in { + + options.system.custom.bluetooth.enable = lib.mkEnableOption "enable bluetooth support"; + + config = lib.mkIf cfg.enable { + + hardware.bluetooth = { + enable = true; + powerOnBoot = true; + extraConfig = '' + [General] + AutoConnect=true + ''; + }; + + environment.systemPackages = with pkgs ; [ + + # bluetooth audio + # --------------- + # todo : check if pulseaudio is enabled + bluez + bluez-tools + + ]; + }; + +} + diff --git a/modules/system/font.nix b/modules/system/font.nix new file mode 100644 index 0000000..3f70e87 --- /dev/null +++ b/modules/system/font.nix @@ -0,0 +1,76 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + + cfg = config.system.custom.fonts; + +in { + + options.system.custom.fonts = { + enable = mkEnableOption "enable fonts"; + dpi = mkOption { + type = types.int; + default = 141; + description = '' + dpi of the monitor + ''; + }; + }; + + config = mkIf cfg.enable { + + fonts = { + + enableCoreFonts = true; + enableFontDir = true; + enableGhostscriptFonts = true; + + fontconfig = { + dpi = cfg.dpi; + subpixel = { + lcdfilter = "default"; + rgba = "rgb"; + }; + hinting = { + enable = true; + autohint = false; + }; + enable = true; + antialias = true; + defaultFonts = { + monospace = [ "inconsolata" ]; + }; + }; + + fonts = with pkgs; [ + + corefonts + hasklig + inconsolata + source-code-pro + symbola + ubuntu_font_family + + # symbol fonts + # ------------ + nerdfonts + powerline-fonts + font-awesome-ttf + fira-code-symbols + + # shell font + # ---------- + terminus_font + gohufont + + ]; + + }; + + }; + +} + + diff --git a/modules/system/mainUser.nix b/modules/system/mainUser.nix new file mode 100644 index 0000000..ec0d7d8 --- /dev/null +++ b/modules/system/mainUser.nix @@ -0,0 +1,76 @@ +{ config, pkgs, lib, ... }: + +with lib; + +let + + cfg = config.system.custom.mainUser; + + dockerGroup = + if (config.virtualisation.docker.enable) + then [ "docker" ] + else []; + + vboxGroup = + if (config.virtualisation.virtualbox.host.enable) + then [ "vboxusers" ] + else []; + +in { + + options.system.custom.mainUser = { + + enable = mkEnableOption "enable mainUser for a desktop system"; + + userName = mkOption { + type = with types; str; + description = '' + name of the main user + ''; + }; + + uid = mkOption { + type = with types; int; + default = 1337; + description = '' + uid of main user + ''; + }; + + extraGroups = mkOption { + default = []; + type = with types; listOf str; + description = '' + list of groups the main user should also be in + ''; + }; + + authorizedKeyFiles = mkOption { + default = []; + type = with types; listOf str; + description = '' + list of keys allowed to login as this user + ''; + }; + + }; + + config = mkIf cfg.enable { + + users = { + + mutableUsers = true; + defaultUserShell = pkgs.zsh; + + users.mainUser = { + isNormalUser = true; + name = cfg.userName; + uid = cfg.uid; + home = "/home/${cfg.userName}"; + initialPassword = cfg.userName; + extraGroups = [ "wheel" "networkmanager" "transmission" "wireshark" ] ++ dockerGroup ++ vboxGroup ++ cfg.extraGroups; + openssh.authorizedKeys.keyFiles = cfg.authorizedKeyFiles ; + }; + }; + }; +} diff --git a/modules/system/permown.nix b/modules/system/permown.nix new file mode 100644 index 0000000..70e8c18 --- /dev/null +++ b/modules/system/permown.nix @@ -0,0 +1,111 @@ +{ config, pkgs, lib, ... }: +with lib; +let + cfg = config.system.permown; +in { + + options.system.permown = mkOption { + default = {}; + type = with types; attrsOf (submodule ({ config, ... }: { + options = { + directory-mode = mkOption { + default = "=rwx"; + type = types.str; # TODO + }; + file-mode = mkOption { + default = "=rw"; + type = types.str; # TODO + }; + group = mkOption { + apply = x: if x == null then "" else x; + default = null; + type = types.nullOr types.str; + }; + owner = mkOption { + type = types.str; + }; + path = mkOption { + default = config._module.args.name; + type = types.path; + }; + umask = mkOption { + default = "0027"; + type = types.str; + }; + }; + })); + }; + + config = + let + plans = lib.attrValues cfg; + in + mkIf (plans != []) { + + system.activationScripts.permown = let + mkdir = plan: /* sh */ '' + ${pkgs.coreutils}/bin/mkdir -p ${plan.path} + ''; + in + concatMapStrings mkdir plans; + + + # genAttrs' = names: f: listToAttrs (map f names); + + systemd.services = listToAttrs (flip map plans (plan: { + name = "permown.${replaceStrings ["/"] ["_"] plan.path}"; + value = { + environment = { + DIR_MODE = plan.directory-mode; + FILE_MODE = plan.file-mode; + OWNER_GROUP = "${plan.owner}:${plan.group}"; + ROOT_PATH = plan.path; + }; + path = [ + pkgs.coreutils + pkgs.findutils + pkgs.inotifyTools + ]; + serviceConfig = { + ExecStart = pkgs.writers.writeDash "permown" '' + set -efu + + find "$ROOT_PATH" -exec chown -h "$OWNER_GROUP" {} + + find "$ROOT_PATH" -type d -exec chmod "$DIR_MODE" {} + + find "$ROOT_PATH" -type f -exec chmod "$FILE_MODE" {} + + + paths=/tmp/paths + rm -f "$paths" + mkfifo "$paths" + + inotifywait -mrq -e CREATE --format %w%f "$ROOT_PATH" > "$paths" & + inotifywaitpid=$! + + trap cleanup EXIT + cleanup() { + kill "$inotifywaitpid" + } + + while read -r path; do + if test -d "$path"; then + cleanup + exec "$0" "$@" + fi + chown -h "$OWNER_GROUP" "$path" + if test -f "$path"; then + chmod "$FILE_MODE" "$path" + fi + done < "$paths" + ''; + PrivateTmp = true; + Restart = "always"; + RestartSec = 10; + UMask = plan.umask; + }; + wantedBy = [ "multi-user.target" ]; + }; + })); + + }; + +} diff --git a/modules/system/wifi.nix b/modules/system/wifi.nix new file mode 100644 index 0000000..47a0e3a --- /dev/null +++ b/modules/system/wifi.nix @@ -0,0 +1,76 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + + cfg = config.system.custom.wifi; + +in { + + options.system.custom.wifi = { + enable = mkEnableOption "enable wifi"; + system = mkOption{ + default = "wpa_supplicant"; + type = with types; enum ["wpa_supplicant" "networkmanager"]; + }; + configurationFile = mkOption{ + default = null; + type = with types; nullOr path; + description = '' + the target of /etc/wpa_supplicant.conf + ''; + }; + interfaces = mkOption { + type = with types; listOf string; + default = []; + description = '' + list of interfaces to take care of, + if empty it will test all interfaces + ''; + }; + }; + + config = mkMerge [ + + (mkIf (cfg.system == "wpa_supplicant") { + networking.wireless.enable = true; + networking.wireless.interfaces = cfg.interfaces; + }) + + (mkIf (cfg.system == "networkmanager") { + networking.networkmanager.enable = true; + }) + + (mkIf (cfg.configurationFile != null) { + environment.etc."wpa_supplicant.conf".source = cfg.configurationFile; + }) + + (mkIf cfg.enable { + + networking.usePredictableInterfaceNames = true; + + hardware.enableRedistributableFirmware = true; + + environment.systemPackages = [ + + (pkgs.writeShellScriptBin "scan-wifi" '' + # todo : use column to make a nice view + ${pkgs.wirelesstools}/bin/iwlist scan | \ + grep -v "Interface doesn't support scanning" | \ + sed -e '/^\s*$/d' | \ + grep -e "ESSID" -e "Encrypt" | \ + sed -e "s/Encryption key:on/encrypted/g" | \ + sed -e "s/Encryption key:off/open/g" | \ + sed -e "s/ESSID://g" | \ + xargs -L 2 printf "%9s - '%s'\n" + '') + + ]; + }) + + ]; + +} + + diff --git a/modules/system/x11.nix b/modules/system/x11.nix new file mode 100644 index 0000000..db61779 --- /dev/null +++ b/modules/system/x11.nix @@ -0,0 +1,95 @@ +{ config, pkgs, lib, ... }: + +with lib; + +let + + cfg = config.system.custom.x11; + +in { + + options.system.custom.x11 = { + enable = mkEnableOption "enable x11"; + autoLoginUser = mkOption { + type = with types; str; + description = "user to login"; + }; + }; + + config = mkIf cfg.enable { + + services.xserver = { + + enable = true; + + # Configure video Drivers + # ----------------------- + videoDrivers = [ "intel" ]; + deviceSection = '' + Option "DRI" "2" + Option "TearFree" "true" + ''; + + # window-manager : Xmonad + # ----------------------- + desktopManager = { + default = "none"; + xterm.enable = false; + }; + displayManager.lightdm = { + enable = true; + autoLogin.enable = true; + autoLogin.user = cfg.autoLoginUser; + }; + windowManager = { + xmonad.enable = true; + xmonad.enableContribAndExtras = true; + default = "xmonad"; + }; + + + # mouse/touchpad + # -------------- + libinput = { + enable = true; + disableWhileTyping = true; + tapping = true; + scrollMethod = "twofinger"; + accelSpeed = "2"; + }; + + # Wacom configuraton + # ------------------ + modules = [ pkgs.xf86_input_wacom ]; + }; + + # Packages + # -------- + environment.systemPackages = with pkgs ; [ + + dmenu + arandr + xcalib + flameshot + xorg.xmodmap + feh + + ]; + + # Xresources config + # ----------------- + # spread the Xresource config + # across different files + # just add a file into `/etc/X11/Xresource.d/` and it will be + # evaluated. + services.xserver.displayManager.sessionCommands = '' + for file in `ls /etc/X11/Xresource.d/` + do + ${pkgs.xorg.xrdb}/bin/xrdb -merge /etc/X11/Xresource.d/$file + done + ''; + environment.etc."/X11/Xresource.d/.keep".text = ""; + + }; +} + diff --git a/pkgs/bepasty-client-cli/default.nix b/pkgs/bepasty-client-cli/default.nix new file mode 100644 index 0000000..7811ef5 --- /dev/null +++ b/pkgs/bepasty-client-cli/default.nix @@ -0,0 +1,23 @@ +{ lib, pkgs, pythonPackages, fetchFromGitHub, ... }: + +with pythonPackages; buildPythonPackage rec { + name = "bepasty-client-cli"; + propagatedBuildInputs = [ + python_magic + click + requests + ]; + + src = fetchFromGitHub { + owner = "bepasty"; + repo = "bepasty-client-cli"; + rev = "4b7135ba8ba1e17501de08ad7b6aca73c0d949d2"; + sha256 = "1svchyk9zai1vip9ppm12jm7wfjbdr9ijhgcd2n10xh73jrn9cnc"; + }; + + meta = { + homepage = https://github.com/bepasty/bepasty-client-cli; + description = "CLI client for bepasty-server"; + license = lib.licenses.bsd2; + }; +} diff --git a/pkgs/bitwig-studio/bitwig-studio-environment.nix b/pkgs/bitwig-studio/bitwig-studio-environment.nix new file mode 100644 index 0000000..4a3c17a --- /dev/null +++ b/pkgs/bitwig-studio/bitwig-studio-environment.nix @@ -0,0 +1,89 @@ +# NixOs fhs-user script +# --------------------- +# +# this is a script to start Bitwig Studio. +# it is necessary because without my VSTs won't run. + + +# function header +# --------------- +{ pkgs ? import {} }: + +# function call +# ------------- +(pkgs.buildFHSUserEnv { + + # name of the programm + # -------------------- + name = "bitwig"; + + # targetSystem packages + # --------------------- + # these are packages which are compiled for the target + # system architecture + targetPkgs = pkgs: with pkgs; [ + + # todo : check if they are needed + coreutils + curl + vim + tig + ack + bitwig-studio3 + liblo + zlib + fftw + minixml + libcxx + alsaLib + glibc + + gtk2-x11 + atk + mesa_glu + glib + pango + gdk_pixbuf + cairo + freetype + fontconfig + dbus + xorg.libX11 + xorg.libxcb + xorg.libXext + xorg.libXinerama + xlibs.libXi + xlibs.libXcursor + xlibs.libXdamage + xlibs.libXcomposite + xlibs.libXfixes + xlibs.libXrender + xlibs.libXtst + xlibs.libXScrnSaver + + gnome2.GConf + nss + nspr + expat + eudev + ]; + + # multilib packages + # ----------------- + # these are packages compiled for multiple system + # architectures (32bit/64bit) + multiPkgs = pkgs: with pkgs; [ + ]; + + # command + # ------- + # the script which should be run right after starting this enviornment + runScript = "/usr/bin/bitwig-studio"; + + # environment variables + # --------------------- + profile = '' + export TERM="xterm" + ''; + +}) diff --git a/pkgs/bitwig-studio/bitwig-studio1.nix b/pkgs/bitwig-studio/bitwig-studio1.nix new file mode 100644 index 0000000..8b26ba0 --- /dev/null +++ b/pkgs/bitwig-studio/bitwig-studio1.nix @@ -0,0 +1,100 @@ +{ stdenv, fetchurl, alsaLib, bzip2, cairo, dpkg, freetype, gdk_pixbuf +, glib, gtk2, harfbuzz, jdk, lib, xorg +, libbsd, libjack2, libpng +, libxkbcommon +, makeWrapper, pixman +, xdg_utils, zenity, zlib }: + +stdenv.mkDerivation rec { + name = "bitwig-studio-${version}"; + version = "1.3.16"; + + src = fetchurl { + url = "https://downloads.bitwig.com/stable/${version}/bitwig-studio-${version}.deb"; + sha256 = "0n0fxh9gnmilwskjcayvjsjfcs3fz9hn00wh7b3gg0cv3qqhich8"; + }; + + nativeBuildInputs = [ dpkg makeWrapper ]; + + unpackCmd = "mkdir root ; dpkg-deb -x $curSrc root"; + + dontBuild = true; + dontPatchELF = true; + dontStrip = true; + + libPath = with xorg; lib.makeLibraryPath [ + alsaLib bzip2.out cairo freetype gdk_pixbuf glib gtk2 harfbuzz libX11 libXau + libXcursor libXdmcp libXext libXfixes libXrender libbsd libjack2 libpng libxcb + libxkbfile pixman xcbutil xcbutilwm zlib + ]; + + binPath = lib.makeBinPath [ + xdg_utils zenity + ]; + + installPhase = '' + mkdir -p $out + cp -r opt/bitwig-studio $out/libexec + + # Use NixOS versions of these libs instead of the bundled ones. + ( + cd $out/libexec/lib/bitwig-studio + rm libbz2.so* libxkbfile.so* libXcursor.so* libXau.so* \ + libXdmcp.so* libpng16.so* libxcb*.so* libharfbuzz.so* \ + libcairo.so* libfreetype.so* + ln -s ${bzip2.out}/lib/libbz2.so.1.0.6 libbz2.so.1.0 + ) + + # Use our OpenJDK instead of Bitwig’s bundled—and commercial!—one. + rm -rf $out/libexec/lib/jre + ln -s ${jdk.home}/jre $out/libexec/lib/jre + + # Bitwig’s `libx11-windowing-system.so` has several problems: + # + # • has some old version of libxkbcommon linked statically (ಠ_ಠ), + # + # • hardcodes path to `/usr/share/X11/xkb`, + # + # • even if we redirected it with libredirect (after adding + # `eaccess()` to libredirect!), their version of libxkbcommon + # is unable to parse our xkeyboardconfig. Been there, done that. + # + # However, it suffices to override theirs with our libxkbcommon + # in LD_PRELOAD. :-) + + find $out -type f -executable \ + -not -name '*.so.*' \ + -not -name '*.so' \ + -not -path '*/resources/*' | \ + while IFS= read -r f ; do + patchelf \ + --set-interpreter $(cat ${stdenv.cc}/nix-support/dynamic-linker) \ + $f && \ + wrapProgram $f \ + --prefix PATH : "${binPath}" \ + --prefix LD_LIBRARY_PATH : "${libPath}" \ + --set LD_PRELOAD "${libxkbcommon.out}/lib/libxkbcommon.so" || true + done + + mkdir -p $out/bin + ln -s $out/libexec/bitwig-studio $out/bin/bitwig-studio + + cp -r usr/share $out/share + substitute usr/share/applications/bitwig-studio.desktop \ + $out/share/applications/bitwig-studio.desktop \ + --replace /usr/bin/bitwig-studio $out/bin/bitwig-studio + ''; + + meta = with stdenv.lib; { + description = "A digital audio workstation"; + longDescription = '' + Bitwig Studio is a multi-platform music-creation system for + production, performance and DJing, with a focus on flexible + editing tools and a super-fast workflow. + ''; + homepage = http://www.bitwig.com/; + license = licenses.unfree; + platforms = [ "x86_64-linux" ]; + maintainers = with maintainers; [ michalrus mrVanDalo ]; + }; +} diff --git a/pkgs/bitwig-studio/bitwig-studio2.nix b/pkgs/bitwig-studio/bitwig-studio2.nix new file mode 100644 index 0000000..e5a5cc7 --- /dev/null +++ b/pkgs/bitwig-studio/bitwig-studio2.nix @@ -0,0 +1,18 @@ +{ stdenv, fetchurl, bitwig-studio1, + xdg_utils, zenity, ffmpeg }: + +bitwig-studio1.overrideAttrs (oldAttrs: rec { + name = "bitwig-studio-${version}"; + version = "2.2.2"; + + src = fetchurl { + url = "https://downloads.bitwig.com/stable/${version}/bitwig-studio-${version}.deb"; + sha256 = "1x4wka32xlygmhdh9rb15s37zh5qjrgap2qk35y34c52lf5aak22"; + }; + + buildInputs = bitwig-studio1.buildInputs ++ [ ffmpeg ]; + + binPath = stdenv.lib.makeBinPath [ + ffmpeg xdg_utils zenity + ]; +}) diff --git a/pkgs/bitwig-studio/bitwig-studio3.nix b/pkgs/bitwig-studio/bitwig-studio3.nix new file mode 100644 index 0000000..115c465 --- /dev/null +++ b/pkgs/bitwig-studio/bitwig-studio3.nix @@ -0,0 +1,18 @@ +{ stdenv, fetchurl, bitwig-studio2, ... }: + +bitwig-studio2.overrideAttrs (oldAttrs: rec { + name = "bitwig-studio-${version}"; + version = "3.0"; + + src = fetchurl { + url = "https://downloads.bitwig.com/stable/${version}/bitwig-studio-${version}.deb"; + # sha256 = "1l19z6pfhr15cybqnj01nhq9wsqyfbrj5q6ksym3irwn2k0hp1jp"; # suppose to be the correct sha + sha256 = "0p7wi1srfzalb0rl94vqppfbnxdfwqzgg5blkdwkf4sx977aihpv"; + }; + + buildInputs = bitwig-studio2.buildInputs ++ [ ]; + + #binPath = stdenv.lib.makeBinPath [ + # ffmpeg xdg_utils zenity + #]; +}) diff --git a/pkgs/castget/default.nix b/pkgs/castget/default.nix new file mode 100644 index 0000000..e55b186 --- /dev/null +++ b/pkgs/castget/default.nix @@ -0,0 +1,24 @@ +{ stdenv, fetchurl, pkgconfig, + curl, glib, id3lib, libxml2, ... }: + + +stdenv.mkDerivation rec { + version = "1.2.4"; + name = "castget-${version}"; + + src = fetchurl { + url = "http://savannah.nongnu.org/download/castget/${name}.tar.bz2"; + sha256 = "0bb9pb1pn3d3x6a0l1d7l77gjq369g5v62bbnmg4k1jkxl633vli"; + }; + + buildInputs = + [ glib libxml2 curl id3lib pkgconfig ]; + + meta = with stdenv.lib; { + description = "a simple, command-line based RSS enclosure downloader. It is primarily intended for automatic, unattended downloading of podcasts."; + homepage = https://castget.johndal.com; + license = licenses.gpl2; + platforms = platforms.linux; + maintainers = with maintainers; [ mrVanDalo ]; + }; +} diff --git a/pkgs/default.nix b/pkgs/default.nix new file mode 100644 index 0000000..a11057d --- /dev/null +++ b/pkgs/default.nix @@ -0,0 +1,73 @@ +# This overlay extends nixpkgs . + +self: super: + +let + callPackage = super.lib.callPackageWith super; + unstablePkgs = import {}; +in + +{ + haskellPackages = super.haskellPackages.override { + overrides = self: super: { + image-generator = super.callPackage ./image-generator {}; + }; + }; + + bitwig-studio1 = super.bitwig-studio1.override{ + libxkbcommon = super.libxkbcommon.overrideAttrs( old: rec { + name = "libxkbcommon-0.7.2"; + src = super.fetchurl { + url = "https://xkbcommon.org/download/${name}.tar.xz"; + sha256 = "1n5rv5n210kjnkyrvbh04gfwaa7zrmzy1393p8nyqfw66lkxr918"; + }; + }); + }; + + gitlog2json = callPackage ./gitlog2json {}; + + bitwig-studio3 = callPackage ./bitwig-studio/bitwig-studio3.nix {}; + + bitwig-studio = callPackage ./bitwig-studio/bitwig-studio-environment.nix {}; + + geodatabase = callPackage ./geodatabase {}; + + landingpage = callPackage ./landingpage {}; + + bepasty-client-cli = callPackage ./bepasty-client-cli {}; + + emo = callPackage ./emoji {}; + + q = callPackage ./q {}; + + otpmenu = callPackage ./otpmenu {}; + + memo = callPackage ./memo {}; + + castget = callPackage ./castget {}; + + terranix = callPackage (super.fetchgit { + url = "https://git.ingolf-wagner.de/terranix/terranix.git"; + # rev = "2.1.0"; + rev = "9daeaece7ce0cfedb18567e8acc332a22c5daec6"; + sha256 = "0ikdd08yhkb6qb078a6a7av6c2s60n8nnz80ws6w718x7sfmswhm"; + }) { }; + + nixos-generators = callPackage (super.fetchgit { + url = "https://github.com/nix-community/nixos-generators.git"; + rev = "e006f95894b91fccf903d1b0620c5a18879ab91f"; + sha256 = "1cx54d8zyvgwb2kzj4blkambbm278icrgw5y1nicj54qrs7398n6"; + }) { }; + + radio-dj = callPackage (super.fetchgit { + url = "https://git.ingolf-wagner.de/crashburn_radio/radio_dj.git"; + rev = "0.1.5"; + sha256 = "04j6gcb6ayrcf7rxr0bkgd48zppiryhdyv7mvp0q12ngdkf2yagd"; + }) { }; + + lektor = let + python = import ./lektor-with-plugins/requirements.nix { pkgs = super.pkgs; }; + in + python.packages.Lektor; + +} diff --git a/pkgs/emoji/default.nix b/pkgs/emoji/default.nix new file mode 100644 index 0000000..b71a384 --- /dev/null +++ b/pkgs/emoji/default.nix @@ -0,0 +1,53 @@ +{ coreutils, dmenu, gnused, writeShellScriptBin , writeText, xdotool, ... }: + +let + + # from http://asciimoji.com/ + emoticons = writeText "emoticons" '' +¯\(°_o)/¯ | dunno lol shrug dlol +¯\_(ツ)_/¯ | dunno lol shrug dlol +( ͡° ͜ʖ ͡°) | lenny +¯\_( ͡° ͜ʖ ͡°)_/¯ | lenny shrug dlol +( ゚д゚) | aaah sad noo +ヽ(^o^)丿 | hi yay yey hello +(^o^; | ups hehe +(^∇^) | yay yey +┗(`皿´)┛ | angry argh +ヾ(^_^) byebye!! | bye +<(^.^<) <(^.^)> (>^.^)> (7^.^)7 (>^.^<) | dance +(-.-)Zzz... | sleep +(∩╹□╹∩) | oh noes woot +™ | tm +ζ | zeta +(╯°□°)╯ ┻━┻ | table flip +(」゜ロ゜)」 | why woot +(= ФェФ=) | cat +(。◕‿‿◕。) | cute +☜(゚ヮ゚☜) | you +x⸑x | dead +☉ ‿ ⚆ | derp +(҂◡_◡) ᕤ | endure +(*・‿・)ノ⌒*:・゚✧ | glitter +(⌐⊙_⊙) | nerd +WHΣИ $HΛLL WΣ MΣΣ† ΛGΛ|И? | when shall we meet again +✔ | check +(◕ᴥ◕ʋ) | dog +(ノ◕ヮ◕)ノ*:・゚✧ | excited +(❍ᴥ❍ʋ) | jake dog +L(° O °L) | lol +o()xxxx[{::::::::::::::::::> | sword +(ÒДÓױ) | what wat +Yᵒᵘ Oᶰˡʸ Lᶤᵛᵉ Oᶰᶜᵉ | yolo +⊹╰(⌣ʟ⌣)╯⊹ | zen +@}-,-`- | rose + ''; + +in +writeShellScriptBin "emoticons" '' + set -efu + + data=$(${coreutils}/bin/cat ${emoticons}) + emoticon=$(echo "$data" | ${dmenu}/bin/dmenu -l 10 | ${gnused}/bin/sed 's/ | .*//') + ${xdotool}/bin/xdotool type -- "$emoticon" + exit 0 +'' diff --git a/pkgs/geodatabase/default.nix b/pkgs/geodatabase/default.nix new file mode 100644 index 0000000..1bda602 --- /dev/null +++ b/pkgs/geodatabase/default.nix @@ -0,0 +1,25 @@ +{ stdenv, fetchurl, ... }: + +stdenv.mkDerivation rec { + version = "20190702"; + name = "geocities-${version}"; + src = fetchurl { + url = "https://geolite.maxmind.com/download/geoip/database/GeoLite2-City.tar.gz"; + sha256 = "0rd80jhgyv0pzmlcg0z8lmsn03yrcb8fj69cg87sjpy591bnki6x"; + }; + + dontBuild = true; + + installPhase = '' + mkdir -p $out/ + cp GeoLite2-City.mmdb $out/ + ''; + + meta = with stdenv.lib; { + description = "geo database"; + homepage = https://dev.maxmind.com/geoip/geoip2/geolite2/; + license = licenses.MIT; + platforms = platforms.linux; + maintainers = with maintainers; [ mrVanDalo ]; + }; +} diff --git a/pkgs/gitlog2json/default.nix b/pkgs/gitlog2json/default.nix new file mode 100644 index 0000000..972fca8 --- /dev/null +++ b/pkgs/gitlog2json/default.nix @@ -0,0 +1,9 @@ +{ pkgs, lib, ... }: + +pkgs.writers.writePython3Bin "gitlog2json" { + libraries = [ + pkgs.python3Packages.GitPython + pkgs.python3Packages.click + pkgs.python3Packages.elasticsearch + ]; +} (lib.fileContents ./gitlog2json.py) diff --git a/pkgs/gitlog2json/gitlog2json.py b/pkgs/gitlog2json/gitlog2json.py new file mode 100644 index 0000000..3e67948 --- /dev/null +++ b/pkgs/gitlog2json/gitlog2json.py @@ -0,0 +1,75 @@ +import datetime +from git import Repo +import os +import json +import click + +from elasticsearch import Elasticsearch + + +class GitLogger: + """to provide a log as dict of commits which are json printable""" + + def __init__(self, path): + """Create a GitStepper with the path to the git repository (not a bare repository)""" + self.repo = Repo(path) + + def log(self): + """return a dict of commits""" + commits = (self.repo.commit(logEntry) for logEntry in self.repo.iter_commits()) + return (self.to_dict(x) for x in commits) + + def to_dict(self,commit): + """create a dict out of a commit that is easy to json serialize""" + time_difference = commit.authored_datetime - commit.committed_datetime + return { + "author_email" : commit.author.email, + "author_name" : commit.author.name, + "authored_date" : commit.authored_datetime.isoformat(), + "files": [{"file":file,"changes":changes} for file,changes in commit.stats.files.items()], + "committed_date" : commit.committed_datetime.isoformat(), + "committer_email" : commit.committer.email, + "committer_name" : commit.committer.name, + "date_difference_in_seconds" : abs( time_difference.total_seconds() ), + "encoding" : commit.encoding, + "hash" : commit.hexsha, + "message" : commit.message , + "summary" : commit.summary, + "size" : commit.size, + "stats_total" : commit.stats.total, + "parents" : [parent.hexsha for parent in commit.parents], + } + +@click.command() +@click.argument("path", type=click.Path(exists=True), envvar='PWD') +@click.option("--host") +@click.option("--index") +@click.option("--port", default=9200) +def main(path, host, index, port): + if host: + if not index: + print("--index need to be set") + exit(1) + + print("Sending commits from %s to %s on index %s" % (path, host, index)) + es = Elasticsearch([ + {'host': host, 'port': port} + ]) + for entry in GitLogger(path).log(): + try: + es.index( + index=index, + doc_type="commit", + id=entry["hash"], + body=entry + ) + except Exception as e: + print(json.dumps(entry)) + print(e.info) + exit(1) + else: + for entry in GitLogger(path).log(): + print(json.dumps( entry )) + +if __name__ == '__main__': + main() diff --git a/pkgs/gitlog2json/log.py b/pkgs/gitlog2json/log.py new file mode 100644 index 0000000..86419a3 --- /dev/null +++ b/pkgs/gitlog2json/log.py @@ -0,0 +1,17 @@ +from git import Repo +import os +repo = Repo("/home/palo/dev/nixpkgs") +a = repo.head.log()[0] +current_hash = a.newhexsha +commit = repo.commit(current_hash) +commit.author +commit.committed_date +import json +json.dumps( { "commit_name" : commit.author.name, "message" : commit.message , "changes": commit.stats.files } ) +commit.committed_date +commit.committer.email +commit.parents +commit.encoding +commit.authored_datetime +commit.size +commit.stats.total diff --git a/pkgs/gitlog2json/shell.nix b/pkgs/gitlog2json/shell.nix new file mode 100644 index 0000000..61a54a4 --- /dev/null +++ b/pkgs/gitlog2json/shell.nix @@ -0,0 +1,17 @@ +{ pkgs ? import {} }: + +pkgs.mkShell { + + buildInputs = with pkgs; [ + pkgs.python3Packages.GitPython + pkgs.python3Packages.ipython + pkgs.python3Packages.elasticsearch + pkgs.python3Packages.click + + (pkgs.callPackage ./default.nix {}) + ]; + + shellHook = '' + HISTFILE=${toString ./.}/.history + ''; +} diff --git a/pkgs/image-generator/default.nix b/pkgs/image-generator/default.nix new file mode 100644 index 0000000..1d29edb --- /dev/null +++ b/pkgs/image-generator/default.nix @@ -0,0 +1,25 @@ +{ mkDerivation, base, colour, diagrams-cairo, diagrams-contrib +, diagrams-core, diagrams-lib, diagrams-svg, extra, fetchgit +, optparse-applicative, primes, random, stdenv +}: +mkDerivation { + pname = "image-generator"; + version = "0.1.1.0"; + src = fetchgit { + url = "https://git.ingolf-wagner.de/palo/image-generator.git"; + sha256 = "19f6zj06avcqk711yx88z9ymyibci4qcb4r7fjpjxqvi702kvc1f"; + rev = "a4d68ceca2e8e72cf75055b3796dd57b19265226"; + fetchSubmodules = true; + }; + isLibrary = true; + isExecutable = true; + libraryHaskellDepends = [ base ]; + executableHaskellDepends = [ + base colour diagrams-cairo diagrams-contrib diagrams-core + diagrams-lib diagrams-svg extra optparse-applicative primes random + ]; + doHaddock = false; + homepage = "https://git.ingolf-wagner.de/palo/image-generator"; + description = "https://git.ingolf-wagner.de/palo/image-generator"; + license = stdenv.lib.licenses.gpl3; +} diff --git a/pkgs/landingpage/default.nix b/pkgs/landingpage/default.nix new file mode 100644 index 0000000..5557951 --- /dev/null +++ b/pkgs/landingpage/default.nix @@ -0,0 +1,131 @@ +{ lib, writeTextFile, jsonConfig ? {} , title ? "Landing Page", destination ? "/index.html", ... }: + +with lib; + +writeTextFile { + name = "landingpage"; + destination = destination; + text = '' + + + + + ${title} + + + + + + + +${let + + createItemRow = { titel ? null, text ? null, items ? []}: + '' +
+ ${optionalString (titel != null) "

${title}

"} + ${optionalString (text != null) '' +
+
${text}
+
''} +
+ ${concatStringsSep "\n" (map createSubItem items)} +
+
'' ; + + + createSubItem = { label, href, image }: + # const shortLabel = (label.length > 28) ? `''${label.substring(0,25)}...` : label; + + '' + ''; + + in + concatStringsSep "\n" (map createItemRow jsonConfig.items) + } + + + +''; +} diff --git a/pkgs/lektor-with-plugins/README.md b/pkgs/lektor-with-plugins/README.md new file mode 100644 index 0000000..3d4e232 --- /dev/null +++ b/pkgs/lektor-with-plugins/README.md @@ -0,0 +1,12 @@ +# build + +``` +pypi2nix -V 3.6 -e lektor -E libffi -E openssl +``` + +# run + +``` +nix-shell requirements.nix -A interpreter +``` + diff --git a/pkgs/lektor-with-plugins/lektor-git/.gitignore b/pkgs/lektor-with-plugins/lektor-git/.gitignore new file mode 100644 index 0000000..463960b --- /dev/null +++ b/pkgs/lektor-with-plugins/lektor-git/.gitignore @@ -0,0 +1,5 @@ +dist +build +*.pyc +*.pyo +*.egg-info diff --git a/pkgs/lektor-with-plugins/lektor-git/README.md b/pkgs/lektor-with-plugins/lektor-git/README.md new file mode 100644 index 0000000..19195c6 --- /dev/null +++ b/pkgs/lektor-with-plugins/lektor-git/README.md @@ -0,0 +1,4 @@ +# shell + +This is where a description of your plugin goes. +Provide usage instructions here. diff --git a/pkgs/lektor-with-plugins/lektor-git/default.nix b/pkgs/lektor-with-plugins/lektor-git/default.nix new file mode 100644 index 0000000..4700c2d --- /dev/null +++ b/pkgs/lektor-with-plugins/lektor-git/default.nix @@ -0,0 +1,20 @@ +{ pkgs, ... }: + +pkgs.python36.pkgs.buildPythonPackage { + name = "lektor-git"; + version = "0.1"; + + src = ./.; + + prePatch = '' + + ls -lah + + substituteInPlace lektor_git.py \ + --replace \ + 'subprocess.run(["git"' \ + 'subprocess.run(["${pkgs.git}/bin/git"' + + ''; +} + diff --git a/pkgs/lektor-with-plugins/lektor-git/lektor_git.py b/pkgs/lektor-with-plugins/lektor-git/lektor_git.py new file mode 100644 index 0000000..71a7b9b --- /dev/null +++ b/pkgs/lektor-with-plugins/lektor-git/lektor_git.py @@ -0,0 +1,61 @@ +# -*- coding: utf-8 -*- +from lektor.pluginsystem import Plugin + +from lektor.publisher import Publisher, _patch_git_env +import subprocess +import uuid + + +class GitPlugin(Plugin): + name = 'git' + description = u'manage content via git.' + + def on_setup_env(self, **extra): + try: + self.env.add_publisher('git-publish', GitPublisher) + self.env.add_publisher('git-sync', GitSync) + except AttributeError: + from lektor.publisher import publishers + publishers['git-publish'] = GitPublisher + publishers['git-sync'] = GitSync + + +class GitPublisher(Publisher): + + def publish(self, target, credentials=None, **extra): + env = _patch_git_env({}) + + yield "Commiting content directory..." + subprocess.run(["git", "add", "content"], env=env) + subprocess.run(["git", "commit", "-m", "Added from preflight"], env=env) + + yield "Pushing to Git ..." + subprocess.run(["git", "push"], env=env) + + yield "Pulling from Git ..." + subprocess.run(["git", "pull"], env=env) + + + yield "Done" + return + +# pulls master +class GitSync(Publisher): + + def publish(self, target, credentials=None, **extra): + env = _patch_git_env({}) + + yield "Commit trash ..." + subprocess.run(["git", "add", "content"], env=env) + subprocess.run(["git", "commit", "-m", "trash"], env=env) + + yield "Checkout reset master ..." + subprocess.run(["git", "checkout", "-f", "master"], env=env) + subprocess.run(["git", "reset", "--hard", "origin/master"], env=env) + + yield "Pull Updates" + subprocess.run(["git", "pull"], env=env) + + yield "Done" + return + diff --git a/pkgs/lektor-with-plugins/lektor-git/setup.py b/pkgs/lektor-with-plugins/lektor-git/setup.py new file mode 100644 index 0000000..1e186ed --- /dev/null +++ b/pkgs/lektor-with-plugins/lektor-git/setup.py @@ -0,0 +1,38 @@ +import ast +import io +import re + +from setuptools import setup, find_packages + +with io.open('README.md', 'rt', encoding="utf8") as f: + readme = f.read() + +_description_re = re.compile(r'description\s+=\s+(?P.*)') + +with open('lektor_git.py', 'rb') as f: + description = str(ast.literal_eval(_description_re.search( + f.read().decode('utf-8')).group(1))) + +setup( + author='palo', + author_email='contact@ingolf-wagner.de', + description=description, + keywords='Lektor plugin', + license='MIT', + long_description=readme, + long_description_content_type='text/markdown', + name='lektor-git', + packages=find_packages(), + py_modules=['lektor_git'], + # url='[link to your repository]', + version='0.2', + classifiers=[ + 'Framework :: Lektor', + 'Environment :: Plugins', + ], + entry_points={ + 'lektor.plugins': [ + 'git = lektor_git:GitPlugin', + ] + } +) diff --git a/pkgs/lektor-with-plugins/lektor-git/shell.nix b/pkgs/lektor-with-plugins/lektor-git/shell.nix new file mode 100644 index 0000000..f35227d --- /dev/null +++ b/pkgs/lektor-with-plugins/lektor-git/shell.nix @@ -0,0 +1,23 @@ +{ pkgs ? import { } }: + +let + + callPackage = pkgs.lib.callPackageWith pkgs; + + bin = callPackage ./default.nix {}; + +in +pkgs.mkShell { + + # needed pkgs + # ----------- + buildInputs = with pkgs; [ + bin + ]; + + # run this on start + # ----------------- + #shellHook = '' + # HISTFILE=${toString ./.}/.history + #''; +} diff --git a/pkgs/lektor-with-plugins/lektor-markdown-header-anchors/default.nix b/pkgs/lektor-with-plugins/lektor-markdown-header-anchors/default.nix new file mode 100644 index 0000000..6bb7f96 --- /dev/null +++ b/pkgs/lektor-with-plugins/lektor-markdown-header-anchors/default.nix @@ -0,0 +1,17 @@ +{ pkgs, fetchFromGitHub, ... }: + +pkgs.python36.pkgs.buildPythonPackage rec { + + name = "lektor-markdown-header-anchors"; + + version = "0.3.1"; + + src = fetchFromGitHub{ + owner = "lektor"; + repo = "lektor-markdown-header-anchors"; + rev = "${version}"; + sha256 = "0f82rngfqhb1jk6ilrlw74wi2maxfvvc36k2509scckyh77hqbqf"; + }; + +} + diff --git a/pkgs/lektor-with-plugins/lektor-shell/.gitignore b/pkgs/lektor-with-plugins/lektor-shell/.gitignore new file mode 100644 index 0000000..463960b --- /dev/null +++ b/pkgs/lektor-with-plugins/lektor-shell/.gitignore @@ -0,0 +1,5 @@ +dist +build +*.pyc +*.pyo +*.egg-info diff --git a/pkgs/lektor-with-plugins/lektor-shell/README.md b/pkgs/lektor-with-plugins/lektor-shell/README.md new file mode 100644 index 0000000..19195c6 --- /dev/null +++ b/pkgs/lektor-with-plugins/lektor-shell/README.md @@ -0,0 +1,4 @@ +# shell + +This is where a description of your plugin goes. +Provide usage instructions here. diff --git a/pkgs/lektor-with-plugins/lektor-shell/default.nix b/pkgs/lektor-with-plugins/lektor-shell/default.nix new file mode 100644 index 0000000..afffe79 --- /dev/null +++ b/pkgs/lektor-with-plugins/lektor-shell/default.nix @@ -0,0 +1,9 @@ +{ pkgs, ... }: + +pkgs.python36.pkgs.buildPythonPackage { + name = "lektor-shell"; + version = "0.3"; + src = ./.; + # propagatedBuildInputs = [ pytest numpy pkgs.libsndfile ]; +} + diff --git a/pkgs/lektor-with-plugins/lektor-shell/lektor_shell.py b/pkgs/lektor-with-plugins/lektor-shell/lektor_shell.py new file mode 100644 index 0000000..6ffec88 --- /dev/null +++ b/pkgs/lektor-with-plugins/lektor-shell/lektor_shell.py @@ -0,0 +1,36 @@ +# -*- coding: utf-8 -*- +from lektor.pluginsystem import Plugin + +from lektor.publisher import Publisher, _patch_git_env +import subprocess + + +class ShellPlugin(Plugin): + name = 'shell' + description = u'Add your description here.' + + def on_setup_env(self, **extra): + try: + self.env.add_publisher('shell', ShellPublisher) + except AttributeError: + from lektor.publisher import publishers + publishers['shell'] = ShellPublisher + + +class ShellPublisher(Publisher): + + def publish(self, target, credentials=None, **extra): + yield "Commiting content directory... " + print("target") + print(target) + #subprocess.run(["git", "add", "content"]) + #subprocess.run(["git", "commit", "-m", "Added from preflight"]) + + yield "Pulling and merging from GitHub ..." + #subprocess.run(["git", "pull"]) + + yield "Pushing to GitHub ..." + #subprocess.run(["git", "push"]) + + yield "Done" + return diff --git a/pkgs/lektor-with-plugins/lektor-shell/setup.py b/pkgs/lektor-with-plugins/lektor-shell/setup.py new file mode 100644 index 0000000..34fdade --- /dev/null +++ b/pkgs/lektor-with-plugins/lektor-shell/setup.py @@ -0,0 +1,38 @@ +import ast +import io +import re + +from setuptools import setup, find_packages + +with io.open('README.md', 'rt', encoding="utf8") as f: + readme = f.read() + +_description_re = re.compile(r'description\s+=\s+(?P.*)') + +with open('lektor_shell.py', 'rb') as f: + description = str(ast.literal_eval(_description_re.search( + f.read().decode('utf-8')).group(1))) + +setup( + author='palo', + author_email='contact@ingolf-wagner.de', + description=description, + keywords='Lektor plugin', + license='MIT', + long_description=readme, + long_description_content_type='text/markdown', + name='lektor-shell', + packages=find_packages(), + py_modules=['lektor_shell'], + # url='[link to your repository]', + version='0.2', + classifiers=[ + 'Framework :: Lektor', + 'Environment :: Plugins', + ], + entry_points={ + 'lektor.plugins': [ + 'shell = lektor_shell:ShellPlugin', + ] + } +) diff --git a/pkgs/lektor-with-plugins/lektor-shell/shell.nix b/pkgs/lektor-with-plugins/lektor-shell/shell.nix new file mode 100644 index 0000000..f857281 --- /dev/null +++ b/pkgs/lektor-with-plugins/lektor-shell/shell.nix @@ -0,0 +1,25 @@ +{ pkgs ? import {} }: + +let + + bin = pkgs.python.pkgs.buildPythonPackage { + name = "lektor-shell"; + src = ./.; + # propagatedBuildInputs = [ pytest numpy pkgs.libsndfile ]; + }; + +in +pkgs.mkShell { + + # needed pkgs + # ----------- + buildInputs = with pkgs; [ + bin + ]; + + # run this on start + # ----------------- + shellHook = '' + HISTFILE=${toString ./.}/.history + ''; +} diff --git a/pkgs/lektor-with-plugins/requirements.nix b/pkgs/lektor-with-plugins/requirements.nix new file mode 100644 index 0000000..09aab30 --- /dev/null +++ b/pkgs/lektor-with-plugins/requirements.nix @@ -0,0 +1,546 @@ +# generated using pypi2nix tool (version: 1.8.1) +# See more at: https://github.com/garbas/pypi2nix +# +# COMMAND: +# pypi2nix -V 3.6 -e lektor -E libffi -E openssl +# + +{ pkgs ? import {} +}: + +let + + inherit (pkgs) makeWrapper; + inherit (pkgs.stdenv.lib) fix' extends inNixShell; + + pythonPackages = + import "${toString pkgs.path}/pkgs/top-level/python-packages.nix" { + inherit pkgs; + inherit (pkgs) stdenv; + python = pkgs.python36; + # patching pip so it does not try to remove files when running nix-shell + overrides = + self: super: { + bootstrapped-pip = super.bootstrapped-pip.overrideDerivation (old: { + patchPhase = old.patchPhase + '' + sed -i -e "s|paths_to_remove.remove(auto_confirm)|#paths_to_remove.remove(auto_confirm)|" -e "s|self.uninstalled = paths_to_remove|#self.uninstalled = paths_to_remove|" $out/${pkgs.python35.sitePackages}/pip/req/req_install.py + ''; + }); + }; + }; + + commonBuildInputs = with pkgs; [ libffi openssl ]; + commonDoCheck = false; + + withPackages = pkgs': + let + pkgs = builtins.removeAttrs pkgs' ["__unfix__"]; + interpreter = pythonPackages.buildPythonPackage { + name = "python36-interpreter"; + buildInputs = [ makeWrapper ] ++ (builtins.attrValues pkgs); + buildCommand = '' + mkdir -p $out/bin + ln -s ${pythonPackages.python.interpreter} $out/bin/${pythonPackages.python.executable} + for dep in ${builtins.concatStringsSep " " (builtins.attrValues pkgs)}; do + if [ -d "$dep/bin" ]; then + for prog in "$dep/bin/"*; do + if [ -f $prog ]; then + ln -s $prog $out/bin/`basename $prog` + fi + done + fi + done + for prog in "$out/bin/"*; do + wrapProgram "$prog" --prefix PYTHONPATH : "$PYTHONPATH" + done + pushd $out/bin + ln -s ${pythonPackages.python.executable} python + ln -s ${pythonPackages.python.executable} python3 + popd + ''; + passthru.interpreter = pythonPackages.python; + }; + in { + __old = pythonPackages; + inherit interpreter; + mkDerivation = pythonPackages.buildPythonPackage; + packages = pkgs; + overrideDerivation = drv: f: + pythonPackages.buildPythonPackage (drv.drvAttrs // f drv.drvAttrs // { meta = drv.meta; }); + withPackages = pkgs'': + withPackages (pkgs // pkgs''); + }; + + python = withPackages {}; + + generated = self: { + + "Babel" = python.mkDerivation { + name = "Babel-2.6.0"; + src = pkgs.fetchurl { url = "https://files.pythonhosted.org/packages/be/cc/9c981b249a455fa0c76338966325fc70b7265521bad641bf2932f77712f4/Babel-2.6.0.tar.gz"; sha256 = "8cba50f48c529ca3fa18cf81fa9403be176d374ac4d60738b839122dfaaa3d23"; }; + doCheck = commonDoCheck; + buildInputs = commonBuildInputs; + propagatedBuildInputs = [ + self."pytz" + ]; + meta = with pkgs.stdenv.lib; { + homepage = "http://babel.pocoo.org/"; + license = licenses.bsdOriginal; + description = "Internationalization utilities"; + }; + }; + + + + "Click" = python.mkDerivation { + name = "Click-7.0"; + src = pkgs.fetchurl { url = "https://files.pythonhosted.org/packages/f8/5c/f60e9d8a1e77005f664b76ff8aeaee5bc05d0a91798afd7f53fc998dbc47/Click-7.0.tar.gz"; sha256 = "5b94b49521f6456670fdb30cd82a4eca9412788a93fa6dd6df72c94d5a8ff2d7"; }; + doCheck = commonDoCheck; + buildInputs = commonBuildInputs; + propagatedBuildInputs = [ ]; + meta = with pkgs.stdenv.lib; { + homepage = "https://palletsprojects.com/p/click/"; + license = licenses.bsdOriginal; + description = "Composable command line interface toolkit"; + }; + }; + + + + "ExifRead" = python.mkDerivation { + name = "ExifRead-2.1.2"; + src = pkgs.fetchurl { url = "https://files.pythonhosted.org/packages/7b/cb/92b644626830115910cf2b36d3dfa600adbec86dff3207a7de3bfd6c6a60/ExifRead-2.1.2.tar.gz"; sha256 = "79e244f2eb466709029e8806fe5e2cdd557870c3db5f68954db0ef548d9320ad"; }; + doCheck = commonDoCheck; + buildInputs = commonBuildInputs; + propagatedBuildInputs = [ ]; + meta = with pkgs.stdenv.lib; { + homepage = "https://github.com/ianare/exif-py"; + license = licenses.bsdOriginal; + description = "Read Exif metadata from tiff and jpeg files."; + }; + }; + + + + "Flask" = python.mkDerivation { + name = "Flask-1.0.2"; + src = pkgs.fetchurl { url = "https://files.pythonhosted.org/packages/4b/12/c1fbf4971fda0e4de05565694c9f0c92646223cff53f15b6eb248a310a62/Flask-1.0.2.tar.gz"; sha256 = "2271c0070dbcb5275fad4a82e29f23ab92682dc45f9dfbc22c02ba9b9322ce48"; }; + doCheck = commonDoCheck; + buildInputs = commonBuildInputs; + propagatedBuildInputs = [ + self."Click" + self."Jinja2" + self."Werkzeug" + self."itsdangerous" + ]; + meta = with pkgs.stdenv.lib; { + homepage = "https://www.palletsprojects.com/p/flask/"; + license = licenses.bsdOriginal; + description = "A simple framework for building complex web applications."; + }; + }; + + + + "Jinja2" = python.mkDerivation { + name = "Jinja2-2.10"; + src = pkgs.fetchurl { url = "https://files.pythonhosted.org/packages/56/e6/332789f295cf22308386cf5bbd1f4e00ed11484299c5d7383378cf48ba47/Jinja2-2.10.tar.gz"; sha256 = "f84be1bb0040caca4cea721fcbbbbd61f9be9464ca236387158b0feea01914a4"; }; + doCheck = commonDoCheck; + buildInputs = commonBuildInputs; + propagatedBuildInputs = [ + self."Babel" + self."MarkupSafe" + ]; + meta = with pkgs.stdenv.lib; { + homepage = "http://jinja.pocoo.org/"; + license = licenses.bsdOriginal; + description = "A small but fast and easy to use stand-alone template engine written in pure python."; + }; + }; + + + + "Lektor" = python.mkDerivation { + name = "Lektor-3.1.3"; + src = pkgs.fetchurl { url = "https://files.pythonhosted.org/packages/00/02/43e93399b2f3974d7dfc50364d2d74a000f98bd0eedc406fd391769643e2/Lektor-3.1.3.tar.gz"; sha256 = "60a83e7a100780a58553324b396b0df32a2f584452184efbf87acefed85e564d"; }; + doCheck = commonDoCheck; + buildInputs = commonBuildInputs; + propagatedBuildInputs = [ + self."Babel" + self."Click" + self."ExifRead" + self."Flask" + self."Jinja2" + self."inifile" + self."mistune" + self."requests" + self."watchdog" + ]; + meta = with pkgs.stdenv.lib; { + homepage = "http://github.com/lektor/lektor/"; + license = licenses.bsdOriginal; + description = "A static content management system."; + }; + }; + + + + "MarkupSafe" = python.mkDerivation { + name = "MarkupSafe-1.1.1"; + src = pkgs.fetchurl { url = "https://files.pythonhosted.org/packages/b9/2e/64db92e53b86efccfaea71321f597fa2e1b2bd3853d8ce658568f7a13094/MarkupSafe-1.1.1.tar.gz"; sha256 = "29872e92839765e546828bb7754a68c418d927cd064fd4708fab9fe9c8bb116b"; }; + doCheck = commonDoCheck; + buildInputs = commonBuildInputs; + propagatedBuildInputs = [ ]; + meta = with pkgs.stdenv.lib; { + homepage = "https://palletsprojects.com/p/markupsafe/"; + license = licenses.bsdOriginal; + description = "Safely add untrusted strings to HTML/XML markup."; + }; + }; + + + + "PyYAML" = python.mkDerivation { + name = "PyYAML-5.1"; + src = pkgs.fetchurl { url = "https://files.pythonhosted.org/packages/9f/2c/9417b5c774792634834e730932745bc09a7d36754ca00acf1ccd1ac2594d/PyYAML-5.1.tar.gz"; sha256 = "436bc774ecf7c103814098159fbb84c2715d25980175292c648f2da143909f95"; }; + doCheck = commonDoCheck; + buildInputs = commonBuildInputs; + propagatedBuildInputs = [ ]; + meta = with pkgs.stdenv.lib; { + homepage = "https://github.com/yaml/pyyaml"; + license = licenses.mit; + description = "YAML parser and emitter for Python"; + }; + }; + + + + "Werkzeug" = python.mkDerivation { + name = "Werkzeug-0.15.1"; + src = pkgs.fetchurl { url = "https://files.pythonhosted.org/packages/72/60/f628e8920cbf54afa2a83b75b32a1e69b559b95514d1deb841823dd97830/Werkzeug-0.15.1.tar.gz"; sha256 = "ca5c2dcd367d6c0df87185b9082929d255358f5391923269335782b213d52655"; }; + doCheck = commonDoCheck; + buildInputs = commonBuildInputs; + propagatedBuildInputs = [ + self."watchdog" + ]; + meta = with pkgs.stdenv.lib; { + homepage = "https://palletsprojects.com/p/werkzeug/"; + license = licenses.bsdOriginal; + description = "The comprehensive WSGI web application library."; + }; + }; + + + + "argh" = python.mkDerivation { + name = "argh-0.26.2"; + src = pkgs.fetchurl { url = "https://files.pythonhosted.org/packages/e3/75/1183b5d1663a66aebb2c184e0398724b624cecd4f4b679cb6e25de97ed15/argh-0.26.2.tar.gz"; sha256 = "e9535b8c84dc9571a48999094fda7f33e63c3f1b74f3e5f3ac0105a58405bb65"; }; + doCheck = commonDoCheck; + buildInputs = commonBuildInputs; + propagatedBuildInputs = [ ]; + meta = with pkgs.stdenv.lib; { + homepage = "http://github.com/neithere/argh/"; + license = licenses.lgpl2; + description = "An unobtrusive argparse wrapper with natural syntax"; + }; + }; + + + + "asn1crypto" = python.mkDerivation { + name = "asn1crypto-0.24.0"; + src = pkgs.fetchurl { url = "https://files.pythonhosted.org/packages/fc/f1/8db7daa71f414ddabfa056c4ef792e1461ff655c2ae2928a2b675bfed6b4/asn1crypto-0.24.0.tar.gz"; sha256 = "9d5c20441baf0cb60a4ac34cc447c6c189024b6b4c6cd7877034f4965c464e49"; }; + doCheck = commonDoCheck; + buildInputs = commonBuildInputs; + propagatedBuildInputs = [ ]; + meta = with pkgs.stdenv.lib; { + homepage = "https://github.com/wbond/asn1crypto"; + license = licenses.mit; + description = "Fast ASN.1 parser and serializer with definitions for private keys, public keys, certificates, CRL, OCSP, CMS, PKCS#3, PKCS#7, PKCS#8, PKCS#12, PKCS#5, X.509 and TSP"; + }; + }; + + + + "certifi" = python.mkDerivation { + name = "certifi-2019.3.9"; + src = pkgs.fetchurl { url = "https://files.pythonhosted.org/packages/06/b8/d1ea38513c22e8c906275d135818fee16ad8495985956a9b7e2bb21942a1/certifi-2019.3.9.tar.gz"; sha256 = "b26104d6835d1f5e49452a26eb2ff87fe7090b89dfcaee5ea2212697e1e1d7ae"; }; + doCheck = commonDoCheck; + buildInputs = commonBuildInputs; + propagatedBuildInputs = [ ]; + meta = with pkgs.stdenv.lib; { + homepage = "https://certifi.io/"; + license = licenses.mpl20; + description = "Python package for providing Mozilla's CA Bundle."; + }; + }; + + + + "cffi" = python.mkDerivation { + name = "cffi-1.12.2"; + src = pkgs.fetchurl { url = "https://files.pythonhosted.org/packages/64/7c/27367b38e6cc3e1f49f193deb761fe75cda9f95da37b67b422e62281fcac/cffi-1.12.2.tar.gz"; sha256 = "e113878a446c6228669144ae8a56e268c91b7f1fafae927adc4879d9849e0ea7"; }; + doCheck = commonDoCheck; + buildInputs = commonBuildInputs; + propagatedBuildInputs = [ + self."pycparser" + ]; + meta = with pkgs.stdenv.lib; { + homepage = "http://cffi.readthedocs.org"; + license = licenses.mit; + description = "Foreign Function Interface for Python calling C code."; + }; + }; + + + + "chardet" = python.mkDerivation { + name = "chardet-3.0.4"; + src = pkgs.fetchurl { url = "https://files.pythonhosted.org/packages/fc/bb/a5768c230f9ddb03acc9ef3f0d4a3cf93462473795d18e9535498c8f929d/chardet-3.0.4.tar.gz"; sha256 = "84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae"; }; + doCheck = commonDoCheck; + buildInputs = commonBuildInputs; + propagatedBuildInputs = [ ]; + meta = with pkgs.stdenv.lib; { + homepage = "https://github.com/chardet/chardet"; + license = licenses.lgpl2; + description = "Universal encoding detector for Python 2 and 3"; + }; + }; + + + + "cryptography" = python.mkDerivation { + name = "cryptography-2.6.1"; + src = pkgs.fetchurl { url = "https://files.pythonhosted.org/packages/07/ca/bc827c5e55918ad223d59d299fff92f3563476c3b00d0a9157d9c0217449/cryptography-2.6.1.tar.gz"; sha256 = "26c821cbeb683facb966045e2064303029d572a87ee69ca5a1bf54bf55f93ca6"; }; + doCheck = commonDoCheck; + buildInputs = commonBuildInputs; + propagatedBuildInputs = [ + self."asn1crypto" + self."cffi" + self."idna" + self."pytz" + self."six" + ]; + meta = with pkgs.stdenv.lib; { + homepage = "https://github.com/pyca/cryptography"; + license = licenses.bsdOriginal; + description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers."; + }; + }; + + + + "idna" = python.mkDerivation { + name = "idna-2.8"; + src = pkgs.fetchurl { url = "https://files.pythonhosted.org/packages/ad/13/eb56951b6f7950cadb579ca166e448ba77f9d24efc03edd7e55fa57d04b7/idna-2.8.tar.gz"; sha256 = "c357b3f628cf53ae2c4c05627ecc484553142ca23264e593d327bcde5e9c3407"; }; + doCheck = commonDoCheck; + buildInputs = commonBuildInputs; + propagatedBuildInputs = [ ]; + meta = with pkgs.stdenv.lib; { + homepage = "https://github.com/kjd/idna"; + license = licenses.bsdOriginal; + description = "Internationalized Domain Names in Applications (IDNA)"; + }; + }; + + + + "inifile" = python.mkDerivation { + name = "inifile-0.4"; + src = pkgs.fetchurl { url = "https://files.pythonhosted.org/packages/af/9e/1cd6be0edcbeeb89a6d6ee101dc371a43fa1a19ffaa06ffe99b9e92a3053/inifile-0.4.zip"; sha256 = "891bc629f81477708581b30a7b0583bb5c9c2ee3c070afd4675ecd4f96b0d78d"; }; + doCheck = commonDoCheck; + buildInputs = commonBuildInputs; + propagatedBuildInputs = [ ]; + meta = with pkgs.stdenv.lib; { + homepage = ""; + license = licenses.bsdOriginal; + description = "A small INI library for Python."; + }; + }; + + + + "itsdangerous" = python.mkDerivation { + name = "itsdangerous-1.1.0"; + src = pkgs.fetchurl { url = "https://files.pythonhosted.org/packages/68/1a/f27de07a8a304ad5fa817bbe383d1238ac4396da447fa11ed937039fa04b/itsdangerous-1.1.0.tar.gz"; sha256 = "321b033d07f2a4136d3ec762eac9f16a10ccd60f53c0c91af90217ace7ba1f19"; }; + doCheck = commonDoCheck; + buildInputs = commonBuildInputs; + propagatedBuildInputs = [ ]; + meta = with pkgs.stdenv.lib; { + homepage = "https://palletsprojects.com/p/itsdangerous/"; + license = licenses.bsdOriginal; + description = "Various helpers to pass data to untrusted environments and back."; + }; + }; + + + + "mistune" = python.mkDerivation { + name = "mistune-0.8.4"; + src = pkgs.fetchurl { url = "https://files.pythonhosted.org/packages/2d/a4/509f6e7783ddd35482feda27bc7f72e65b5e7dc910eca4ab2164daf9c577/mistune-0.8.4.tar.gz"; sha256 = "59a3429db53c50b5c6bcc8a07f8848cb00d7dc8bdb431a4ab41920d201d4756e"; }; + doCheck = commonDoCheck; + buildInputs = commonBuildInputs; + propagatedBuildInputs = [ ]; + meta = with pkgs.stdenv.lib; { + homepage = "https://github.com/lepture/mistune"; + license = licenses.bsdOriginal; + description = "The fastest markdown parser in pure Python"; + }; + }; + + + + "pathtools" = python.mkDerivation { + name = "pathtools-0.1.2"; + src = pkgs.fetchurl { url = "https://files.pythonhosted.org/packages/e7/7f/470d6fcdf23f9f3518f6b0b76be9df16dcc8630ad409947f8be2eb0ed13a/pathtools-0.1.2.tar.gz"; sha256 = "7c35c5421a39bb82e58018febd90e3b6e5db34c5443aaaf742b3f33d4655f1c0"; }; + doCheck = commonDoCheck; + buildInputs = commonBuildInputs; + propagatedBuildInputs = [ ]; + meta = with pkgs.stdenv.lib; { + homepage = "http://github.com/gorakhargosh/pathtools"; + license = licenses.mit; + description = "File system general utilities"; + }; + }; + + + + "pyOpenSSL" = python.mkDerivation { + name = "pyOpenSSL-19.0.0"; + src = pkgs.fetchurl { url = "https://files.pythonhosted.org/packages/40/d0/8efd61531f338a89b4efa48fcf1972d870d2b67a7aea9dcf70783c8464dc/pyOpenSSL-19.0.0.tar.gz"; sha256 = "aeca66338f6de19d1aa46ed634c3b9ae519a64b458f8468aec688e7e3c20f200"; }; + doCheck = commonDoCheck; + buildInputs = commonBuildInputs; + propagatedBuildInputs = [ + self."cryptography" + self."six" + ]; + meta = with pkgs.stdenv.lib; { + homepage = "https://pyopenssl.org/"; + license = licenses.asl20; + description = "Python wrapper module around the OpenSSL library"; + }; + }; + + + + "pycparser" = python.mkDerivation { + name = "pycparser-2.19"; + src = pkgs.fetchurl { url = "https://files.pythonhosted.org/packages/68/9e/49196946aee219aead1290e00d1e7fdeab8567783e83e1b9ab5585e6206a/pycparser-2.19.tar.gz"; sha256 = "a988718abfad80b6b157acce7bf130a30876d27603738ac39f140993246b25b3"; }; + doCheck = commonDoCheck; + buildInputs = commonBuildInputs; + propagatedBuildInputs = [ ]; + meta = with pkgs.stdenv.lib; { + homepage = "https://github.com/eliben/pycparser"; + license = licenses.bsdOriginal; + description = "C parser in Python"; + }; + }; + + + + "pytz" = python.mkDerivation { + name = "pytz-2018.9"; + src = pkgs.fetchurl { url = "https://files.pythonhosted.org/packages/af/be/6c59e30e208a5f28da85751b93ec7b97e4612268bb054d0dff396e758a90/pytz-2018.9.tar.gz"; sha256 = "d5f05e487007e29e03409f9398d074e158d920d36eb82eaf66fb1136b0c5374c"; }; + doCheck = commonDoCheck; + buildInputs = commonBuildInputs; + propagatedBuildInputs = [ ]; + meta = with pkgs.stdenv.lib; { + homepage = "http://pythonhosted.org/pytz"; + license = licenses.mit; + description = "World timezone definitions, modern and historical"; + }; + }; + + + + "requests" = python.mkDerivation { + name = "requests-2.21.0"; + src = pkgs.fetchurl { url = "https://files.pythonhosted.org/packages/52/2c/514e4ac25da2b08ca5a464c50463682126385c4272c18193876e91f4bc38/requests-2.21.0.tar.gz"; sha256 = "502a824f31acdacb3a35b6690b5fbf0bc41d63a24a45c4004352b0242707598e"; }; + doCheck = commonDoCheck; + buildInputs = commonBuildInputs; + propagatedBuildInputs = [ + self."certifi" + self."chardet" + self."cryptography" + self."idna" + self."pyOpenSSL" + self."urllib3" + ]; + meta = with pkgs.stdenv.lib; { + homepage = "http://python-requests.org"; + license = licenses.asl20; + description = "Python HTTP for Humans."; + }; + }; + + + + "six" = python.mkDerivation { + name = "six-1.12.0"; + src = pkgs.fetchurl { url = "https://files.pythonhosted.org/packages/dd/bf/4138e7bfb757de47d1f4b6994648ec67a51efe58fa907c1e11e350cddfca/six-1.12.0.tar.gz"; sha256 = "d16a0141ec1a18405cd4ce8b4613101da75da0e9a7aec5bdd4fa804d0e0eba73"; }; + doCheck = commonDoCheck; + buildInputs = commonBuildInputs; + propagatedBuildInputs = [ ]; + meta = with pkgs.stdenv.lib; { + homepage = "https://github.com/benjaminp/six"; + license = licenses.mit; + description = "Python 2 and 3 compatibility utilities"; + }; + }; + + + + "urllib3" = python.mkDerivation { + name = "urllib3-1.24.1"; + src = pkgs.fetchurl { url = "https://files.pythonhosted.org/packages/b1/53/37d82ab391393565f2f831b8eedbffd57db5a718216f82f1a8b4d381a1c1/urllib3-1.24.1.tar.gz"; sha256 = "de9529817c93f27c8ccbfead6985011db27bd0ddfcdb2d86f3f663385c6a9c22"; }; + doCheck = commonDoCheck; + buildInputs = commonBuildInputs; + propagatedBuildInputs = [ + self."certifi" + self."cryptography" + self."idna" + self."pyOpenSSL" + ]; + meta = with pkgs.stdenv.lib; { + homepage = "https://urllib3.readthedocs.io/"; + license = licenses.mit; + description = "HTTP library with thread-safe connection pooling, file post, and more."; + }; + }; + + + + "watchdog" = python.mkDerivation { + name = "watchdog-0.9.0"; + src = pkgs.fetchurl { url = "https://files.pythonhosted.org/packages/bb/e3/5a55d48a29300160779f0a0d2776d17c1b762a2039b36de528b093b87d5b/watchdog-0.9.0.tar.gz"; sha256 = "965f658d0732de3188211932aeb0bb457587f04f63ab4c1e33eab878e9de961d"; }; + doCheck = commonDoCheck; + buildInputs = commonBuildInputs; + propagatedBuildInputs = [ + self."PyYAML" + self."argh" + self."pathtools" + ]; + meta = with pkgs.stdenv.lib; { + homepage = "http://github.com/gorakhargosh/watchdog"; + license = licenses.asl20; + description = "Filesystem events monitoring"; + }; + }; + + }; + localOverridesFile = ./requirements_override.nix; + overrides = import localOverridesFile { inherit pkgs python; }; + commonOverrides = [ + + ]; + allOverrides = + (if (builtins.pathExists localOverridesFile) + then [overrides] else [] ) ++ commonOverrides; + +in python.withPackages + (fix' (pkgs.lib.fold + extends + generated + allOverrides + ) + ) \ No newline at end of file diff --git a/pkgs/lektor-with-plugins/requirements_frozen.txt b/pkgs/lektor-with-plugins/requirements_frozen.txt new file mode 100644 index 0000000..e69de29 diff --git a/pkgs/lektor-with-plugins/requirements_override.nix b/pkgs/lektor-with-plugins/requirements_override.nix new file mode 100644 index 0000000..54dc27d --- /dev/null +++ b/pkgs/lektor-with-plugins/requirements_override.nix @@ -0,0 +1,30 @@ +{ pkgs, python }: +self: super: + +let + + callPackage = pkgs.lib.callPackageWith super; + + lektorShell = callPackage ./lektor-shell/default.nix { inherit pkgs; }; + lektorGit = callPackage ./lektor-git/default.nix { inherit pkgs; }; + lektorMarkdownHeaderAnchors = callPackage ./lektor-markdown-header-anchors/default.nix { + inherit pkgs; + fetchFromGitHub = pkgs.fetchFromGitHub; + }; + + inputs = [ + lektorShell + lektorGit + lektorMarkdownHeaderAnchors + ]; + +in { + + "Lektor" = python.overrideDerivation super."Lektor" (old: { + + propagatedBuildInputs = old.propagatedBuildInputs ++ inputs; + buildInputs = old.buildInputs ++ inputs; + + }); + +} diff --git a/pkgs/memo/default.nix b/pkgs/memo/default.nix new file mode 100644 index 0000000..c112cf0 --- /dev/null +++ b/pkgs/memo/default.nix @@ -0,0 +1,52 @@ +{ fetchFromGitHub, silver-searcher, tree, man, stdenv, + git, + pandocSupport ? true, pandoc ? null + , ... }: + +assert pandocSupport -> pandoc != null; + +stdenv.mkDerivation rec { + + name = "memo-${version}"; + + version = "0.6"; + + src = fetchFromGitHub { + owner = "mrVanDalo"; + repo = "memo"; + rev = "${version}"; + sha256 = "1cvjs36f6vxzfz5d63yhyw8j7gdw5hn6cfzccf7ag08lamjhfhbr"; + }; + + installPhase = let + pandocReplacement = if pandocSupport then + "pandoc_cmd=${pandoc}/bin/pandoc" + else + "#pandoc_cmd=pandoc"; + in '' + mkdir -p $out/{bin,share/man/man1,share/bash-completion/completions,share/zsh/site-functions} + substituteInPlace memo \ + --replace "ack_cmd=ack" "ack_cmd=${silver-searcher}/bin/ag" \ + --replace "tree_cmd=tree" "tree_cmd=${tree}/bin/tree" \ + --replace "man_cmd=man" "man_cmd=${man}/bin/man" \ + --replace "git_cmd=git" "git_cmd=${git}/bin/git" \ + --replace "pandoc_cmd=pandoc" "${pandocReplacement}" + mv memo $out/bin/ + mv doc/memo.1 $out/share/man/man1/memo.1 + mv completion/bash/memo.sh $out/share/bash-completion/completions/memo.sh + mv completion/zsh/_memo $out/share/zsh/site-functions/_memo + ''; + + meta = { + description = "A simple tool written in bash to memorize stuff"; + longDescription = '' + A simple tool written in bash to memorize stuff. + Memo organizes is structured through topics which are folders in ~/memo. + ''; + homepage = http://palovandalo.com/memo/; + downloadPage = https://github.com/mrVanDalo/memo/releases; + license = stdenv.lib.licenses.gpl3; + maintainers = [ stdenv.lib.maintainers.mrVanDalo ]; + platforms = stdenv.lib.platforms.all; + }; +} diff --git a/pkgs/otpmenu/default.nix b/pkgs/otpmenu/default.nix new file mode 100644 index 0000000..c2d891f --- /dev/null +++ b/pkgs/otpmenu/default.nix @@ -0,0 +1,56 @@ +{ stdenv, symlinkJoin, rofi, gnused, pass-otp, writeTextFile, writeShellScriptBin, xdotool }: + +let + + name = "otpmenu"; + + desktopFile = + writeTextFile { + name = "${name}.desktop" ; + destination = "/share/applications/${name}.desktop"; + text = '' + [Desktop Entry] + Categories=Application;Utility; + Comment=Enter MFA number with password otp plugins otp + Encoding=UTF-8 + Exec=${bin}/bin/${name} + Icon=gnome-lockscreen + Name=${name} + Terminal=false + Type=Application + ''; + }; + + + + bin = writeShellScriptBin name /* sh */ '' + set -efu + + x=$( + ${pass-otp}/bin/pass git ls-files '*/otp.gpg' \ + | ${gnused}/bin/sed 's:/otp\.gpg$::' \ + | ${rofi}/bin/rofi -dmenu -f -p OTP + ) + + otp=$(${pass-otp}/bin/pass otp code "$x/otp") + + printf %s "$otp" | ${xdotool}/bin/xdotool type -f - + ''; + +in + symlinkJoin rec { + version = "1.0.0"; + name = "otpMenu-${version}"; + paths = [ + bin + desktopFile + ]; + meta = with stdenv.lib; { + description = "similar to passmenu shows and prints otp"; + homepage = https://your.mama; + license = licenses.gpl3; + platforms = platforms.linux; + maintainers = with maintainers; [ mrVanDalo ]; + }; + } + diff --git a/pkgs/q/README.md b/pkgs/q/README.md new file mode 100644 index 0000000..1ebfe75 --- /dev/null +++ b/pkgs/q/README.md @@ -0,0 +1,6 @@ + +# how to build and test + +``` +nix-build -E 'with import { overlays = [ (import "${}/pkgs" )];} ; callPackage ./default.nix {}'; +``` diff --git a/pkgs/q/default.nix b/pkgs/q/default.nix new file mode 100644 index 0000000..c5f8147 --- /dev/null +++ b/pkgs/q/default.nix @@ -0,0 +1,334 @@ +{ pkgs, lib + # tzselect is your frind do find timezones + , timeZones ? [] + , timeColor ? 9 + , timeZoneColor ? 10 + , calBackgroundColor ? 10 + , calWeekColor ? 13 + , calDayColor ? 9 + , enableIntelBacklight ? true + , enableBattery ? true + , ... }: + +let + hrule = '' + hrule_cols=$(${pkgs.ncurses}/bin/tput cols) + hrule_index=0 + while [ $hrule_index -lt $hrule_cols ] + do + echo -n '─' + hrule_index=$(( 1 + $hrule_index )) + done + echo + ''; + + q-cal = let + + # Maximum width of cal's output. + calwidth = 23; + + # Number of space characters between two calendars. + hspace = 2; + + # Return number of columns required to print n calenders side by side. + need_width = n: + assert n >= 1; + n * calwidth + (n - 1) * hspace; + + lpad = n: c: s: + if lib.stringLength s < n + then lpad n c (c + s) + else s; + + pad = ''{ + ${pkgs.gnused}/bin/sed ' + # rtrim + s/ *$// + + # delete last empty line + ''${/^$/d} + ' \ + | ${pkgs.gawk}/bin/awk '{printf "%-${toString calwidth}s\n", $0}' \ + | ${pkgs.gnused}/bin/sed " + # colorize header + 1,2s/.*/[38;5;${toString calBackgroundColor}m&/ + + # highlight current week + s/^$(${pkgs.coreutils}/bin/date +%W)/[38;5;${toString calWeekColor}m&/ + + # colorize week number + s/^[ 1-9][0-9]/[38;5;${toString calBackgroundColor}m&/ + " + }''; + in '' + cols=$(${pkgs.ncurses}/bin/tput cols) + ${pkgs.coreutils}/bin/paste \ + <(if test $cols -ge ${toString (need_width 3)}; then + ${pkgs.utillinux}/bin/cal -mw \ + $(${pkgs.coreutils}/bin/date +'%m %Y' -d 'last month') \ + | ${pad} + fi) \ + <(if test $cols -ge ${toString (need_width 1)}; then + ${pkgs.utillinux}/bin/cal -mw \ + | ${pkgs.gnused}/bin/sed ' + # colorize day of month + s/\(^\| \)'"$(${pkgs.coreutils}/bin/date +%e)"'\>/[38;5;${toString calDayColor}m&/ + ' \ + | ${pad} + fi) \ + <(if test $cols -ge ${toString (need_width 2)}; then + ${pkgs.utillinux}/bin/cal -mw \ + $(${pkgs.coreutils}/bin/date +'%m %Y' -d 'next month') \ + | ${pad} + fi) \ + | ${pkgs.gnused}/bin/sed ' + s/^\t// + s/\t$// + s/\t/${lpad hspace " " ""}/g + ' + ''; + + q-timeZoneDate = zone: + let dateString = comment: '' '+%Y-%m-%dT[;38;5;${toString timeColor}m%H:%M:%S[;38;5;${toString timeZoneColor}m%:z ${comment}' ''; + timeZoneVariable = lib.optionalString (zone != null) "TZ=${zone}"; + comment = lib.optionalString (zone != null) " : ${zone}"; + in /* sh */ '' + ${timeZoneVariable} ${pkgs.coreutils}/bin/date ${dateString comment} + ''; + + q-timeZoneDates = if timeZones == [] then + q-timeZoneDate null + else + lib.concatMapStringsSep "\n" q-timeZoneDate timeZones; + + q-gitdir = '' + if test -d .git; then + #git status --porcelain + branch=$( + ${pkgs.git}/bin/git branch \ + | ${pkgs.gnused}/bin/sed -rn 's/^\* (.*)/\1/p' + ) + echo "± $LOGNAME@''${HOSTNAME-$(${pkgs.nettools}/bin/hostname)}:$PWD .git $branch" + fi + ''; + + q-intel_backlight = '' + cd /sys/class/backlight/intel_backlight + = .42) full_color = "2" + else if (charge >= .23) full_color = "3" + else full_color = "1" + + left_arrow = 1 + middle_arrow = 1 + right_arrow = 1 + if (full_bars == 0) { + left_arrow = 0 + middle_arrow = 0 + } + if (empty_bars == 0) { + middle_arrow = 0 + right_arrow = 0 + } + + empty_color = "0"; + return sgr("38;5;" 8) sgr("48;5;" full_color) strdup("",left_arrow) strdup(" ", full_bars) sgr("48;5;" empty_color) sgr("38;5;" full_color) strdup("",middle_arrow) strdup(" ", empty_bars) sgr() sgr("38;5;" empty_color) strdup("",right_arrow) sgr() + } + + function sgr(p) { + return "\x1b[" p "m" + } + + function strdup(s,n,t) { + t = sprintf("%"n"s","") + gsub(/ /,s,t) + return t + } + + END { + name = ENVIRON["POWER_SUPPLY_NAME"] + + charge_unit = "Ah" + charge_now = ENVIRON["POWER_SUPPLY_CHARGE_NOW"] / 10^6 + charge_full = ENVIRON["POWER_SUPPLY_CHARGE_FULL"] / 10^6 + + current_unit = "A" + current_now = ENVIRON["POWER_SUPPLY_CURRENT_NOW"] / 10^6 + + energy_unit = "Wh" + energy_now = ENVIRON["POWER_SUPPLY_ENERGY_NOW"] / 10^6 + energy_full = ENVIRON["POWER_SUPPLY_ENERGY_FULL"] / 10^6 + + power_unit = "W" + power_now = ENVIRON["POWER_SUPPLY_POWER_NOW"] / 10^6 + + voltage_unit = "V" + voltage_now = ENVIRON["POWER_SUPPLY_VOLTAGE_NOW"] / 10^6 + voltage_min_design = ENVIRON["POWER_SUPPLY_VOLTAGE_MIN_DESIGN"] / 10^6 + + #printf "charge_now: %s\n", charge_now + #printf "charge_full: %s\n", charge_full + #printf "current_now: %s\n", current_now + #printf "energy_now: %s\n", energy_now + #printf "energy_full: %s\n", energy_full + #printf "energy_full: %s\n", ENVIRON["POWER_SUPPLY_ENERGY_FULL"] + #printf "energy_full: %s\n", ENVIRON["POWER_SUPPLY_ENERGY_FULL"] / 10^6 + #printf "power_now: %s\n", power_now + #printf "voltage_now: %s\n", voltage_now + + if (current_now == 0 && voltage_now != 0) { + current_now = power_now / voltage_now + } + if (power_now == 0) { + power_now = current_now * voltage_now + } + if (charge_now == 0 && voltage_min_design != 0) { + charge_now = energy_now / voltage_min_design + } + if (energy_now == 0) { + energy_now = charge_now * voltage_min_design + } + if (charge_full == 0 && voltage_min_design != 0) { + charge_full = energy_full / voltage_min_design + } + if (energy_full == 0) { + energy_full = charge_full * voltage_min_design + } + + if (charge_now == 0 || charge_full == 0) { + die("unknown charge") + } + + charge_ratio = charge_now / charge_full + + out = out sprintf("%20s │", name) + out = out sprintf(" %s", print_bar(10, charge_ratio)) + out = out sprintf(" %d%", charge_ratio * 100) + out = out sprintf(" %.2f%s", charge_now, charge_unit) + if (current_now != 0) { + out = out sprintf("/%.1f%s", current_now, current_unit) + } + out = out sprintf(" %d%s", energy_full, energy_unit) + if (power_now != 0) { + out = out sprintf("/%.1f%s", power_now, power_unit) + } + if (current_now != 0) { + out = out sprintf(" %s", print_hm(charge_now / current_now)) + } + + print out + } + ' + ''; + in '' + for uevent in /sys/class/power_supply/*/uevent; do + ${power_supply} "$uevent" || : + done + ''; + + q-virtualization = '' + printf '%20s │ %s\n' "VT" \ + $(${pkgs.systemd}/bin/systemd-detect-virt) + ''; + + q-wireless = '' + for dev in $( + ${pkgs.iw}/bin/iw dev \ + | ${pkgs.gnused}/bin/sed -n 's/^\s*Interface\s\+\([0-9a-z]\+\)$/\1/p' + ); do + inet=$(${pkgs.iproute}/bin/ip addr show $dev \ + | ${pkgs.gnused}/bin/sed -n ' + s/.*inet \([0-9]\+\.[0-9]\+\.[0-9]\+\.[0-9]\+\).*/\1/p + ') \ + || unset inet + ssid=$(${pkgs.iw}/bin/iw dev $dev link \ + | ${pkgs.gnused}/bin/sed -n ' + s/.*\tSSID: \(.*\)/\1/p + ') \ + || unset ssid + printf '%20s │ %s %s\n' $dev ''${inet+ $inet} ''${ssid+ $ssid} + done + ''; + + q-online = '' + if ${pkgs.curl}/bin/curl -s google.com >/dev/null; then + echo ' status │ online' + else + echo ' status │ offline ' + fi + ''; + + q-thermal_zone = '' + for i in /sys/class/thermal/thermal_zone*; do + type=$(${pkgs.coreutils}/bin/cat $i/type) + temp=$(${pkgs.coreutils}/bin/cat $i/temp) + printf '%20s │ %s°C\n' $type $(echo $temp / 1000 | ${pkgs.bc}/bin/bc) + done + ''; + + q-task-active = '' + ${pkgs.taskwarrior}/bin/task export +ACTIVE status:pending | ${pkgs.jq}/bin/jq --raw-output '.[] | "⇒ \(.id) \(.description)"' + ''; + +in + +# bash needed for <(...) +pkgs.writers.writeBashBin "q" '' + set -eu + export PATH=/var/empty + ${hrule} + ${q-cal} + ${hrule} + ${q-timeZoneDates} + ${hrule} + ${lib.optionalString enableIntelBacklight "(${q-intel_backlight}) &"} + ${lib.optionalString enableBattery "(${q-power_supply}) &"} + (${q-virtualization}) & + (${q-wireless}) & + (${q-online}) & + (${q-thermal_zone}) & wait + ${hrule} + ${q-task-active} + ${hrule} +'' diff --git a/shell.nix b/shell.nix new file mode 100644 index 0000000..e3329ed --- /dev/null +++ b/shell.nix @@ -0,0 +1,200 @@ +let + + +#ops = import ../plops ; +ops = import ((import {}).fetchgit { + url = "https://github.com/mrVanDalo/plops.git"; + rev = "bad0f386afe20cb6a6b8692a3ec365556f8bdabb"; + sha256 = "1qfc7kkfg83dy1jliw3afaq7q758b4ybz9md74g5fqpqjdxhxrnw"; +}); + +lib = ops.lib; +pkgs = ops.pkgs; + +source = { + + raspberryNixPkgs = { + nixpkgs.git = { + ref = (ops.importJson ./.channelRaspberryStable.json).rev; + url = https://github.com/NixOS/nixpkgs-channels; + }; + nixpkgs-unstable.git = { + ref = (ops.importJson ./.channelRaspberryUnstable.json).rev; + url = https://github.com/NixOS/nixpkgs-channels; + }; + }; + + nixPkgs = { + nixpkgs.git = { + ref = (ops.importJson ./.channelStable.json).rev; + url = https://github.com/NixOS/nixpkgs-channels; + }; + nixpkgs-unstable.git = { + ref = (ops.importJson ./.channelUnstable.json).rev; + url = https://github.com/NixOS/nixpkgs-channels; + }; + }; + + system = name: { + system.file = toString ./system; + configs.file = toString ./configs; + nixos-config.symlink = "configs/${name}/configuration.nix"; + }; + + desktopSecrets = { + desktop_secrets.pass = { + dir = toString ~/.password-store; + name = "krops/desktop_secrets"; + }; + }; + + keys = name: { + keys.pass = { + dir = toString ~/.password-store; + name = "krops/${name}/keys"; + }; + }; + + secrets = name: { + secrets.pass = { + dir = toString ~/.password-store; + name = "krops/${name}/secrets"; + }; + common_secrets.pass = { + dir = toString ~/.password-store; + name = "krops/common_secrets"; + }; + }; + + modules = { + modules.file = toString ./modules; + library.file = toString ./library; + pkgs.file = toString ./pkgs; + assets.file = toString ./assets; + + nix-writers.git = { + url = https://cgit.krebsco.de/nix-writers/; + ref = (ops.importJson ./.nix-writers.json).rev; + }; + + #backup-module.file = toString ~/dev/backup; + backup-module.git = { + url = https://git.ingolf-wagner.de/nix-modules/backup.git; + ref = "1.3.3"; + }; + + #kops-lib.file = toString ~/dev/krops-lib; + krops-lib.git = { + url = https://git.ingolf-wagner.de/nix-modules/krops.git; + ref = "1.0.2"; + }; + + #cluster-module.file = toString ~/dev/cluster-module; + cluster-module.git = { + url = https://git.ingolf-wagner.de/nix-modules/cluster.git; + ref = "1.2.0"; + }; + + #home-manager.file = toString ~/dev/home-manager; + home-manager.git = { + url = https://github.com/rycee/home-manager.git; + ref = "024d1aa227978fe2dae2fb3e56bab9a7237c2401"; + }; + + background-image-generators.git = { + url = https://git.ingolf-wagner.de/nix-modules/background-image-generators.git; + ref = "1.0.0"; + }; + + cleverca22.git = { + url = https://github.com/mrVanDalo/nixos-configs.git; + ref = "76260ad60cd99d40ab25df1400b0663d48e736db"; + }; + + wetten.file = toString ./wetten; + + }; + +}; + +serverDeployment = name: { host ? "${name}.private", user ? "root" }: + with ops; + jobs "deploy-${name}" "${user}@${host}" [ + (populateTmpfs (source.keys name)) + (populate (source.secrets name)) + (populate (source.system name)) + (populate source.modules) + (populate source.nixPkgs) + switch +]; + +serverPushSecrets = name: { host ? "${name}.private", user ? "root" }: + with ops; + jobs "push-${name}" "${user}@${host}" [ + (populateTmpfs (source.keys name)) + (populate (source.secrets name)) +]; + +desktopDeployment = name: { + host ? "${name}.private", + target ? "/var/src/", + user ? "root", + commandPrefix ? "deploy", + enableSwitch ? true + }: + with ops; + jobs "${commandPrefix}-${name}" "${user}@${host}${target}" ([ + (populate (source.secrets name)) + (populate (source.system name)) + (populate source.modules) + (populate source.desktopSecrets) + (populate source.nixPkgs) + ] ++ (if enableSwitch then [ switch ] else [])) ; + +cleanupNix = name: + let + target = { + host = "${name}.private"; + user = "root"; + port = "22"; + }; + in + pkgs.writers.writeDashBin "clean-${name}" /* sh */ '' + set -eu + ${pkgs.openssh}/bin/ssh \ + ${target.user}@${target.host} -p ${target.port} \ + nix-collect-garbage -d + ''; + + +# generate tasks + +servers = with lib; + let + serverList = [ "workhorse" "sputnik" "porani" ]; + deployments = flip map serverList ( name: serverDeployment name {} ); + secretPushes = flip map serverList ( name: serverPushSecrets name {} ); + cleanup = flip map serverList ( name: cleanupNix name ); + in + deployments ++ secretPushes ++ cleanup; + +desktops = with lib; + let + desktopList = [ "pepe" "workout" "sterni" ]; + deployments = flip map desktopList (name: desktopDeployment name {} ); + cleanup = flip map desktopList ( name: cleanupNix name ); + install = flip map desktopList (name: desktopDeployment name { + commandPrefix = "install"; + host = "wz7tdziakduqtmqbbt65ttmmj2q23jkjdyeyg2vfwe52vbvsp6tjimqd.onion"; + target = "/mnt/var/src"; + enableSwitch = false; + } ); + in + deployments ++ cleanup ++ install; + +in +pkgs.mkShell { + + buildInputs = with pkgs; + servers ++ desktops; +} diff --git a/system/all/default.nix b/system/all/default.nix new file mode 100644 index 0000000..4cc4f8b --- /dev/null +++ b/system/all/default.nix @@ -0,0 +1,73 @@ +{ lib, config, pkgs, ... }: +{ + imports = [ + + + + + + + # needed + + + # cross-compiling + + + ./grub.nix + ./tinc.nix + ./sshd.nix + ./sshd-known-hosts-private.nix + ./sshd-known-hosts-public.nix + ./sshd-known-hosts-bootup.nix + ./packages.nix + ./restic.nix + ./syncthing.nix + ./sftp-user.nix + + ./nginx.nix + ./nginx-landingpage.nix + ./networking-qos.nix + + ]; + + + # provide overlays + # ----------------- + nixpkgs.overlays = [ + (import "${}") + (import "${}/pkgs") + ]; + + # allow un-free + # ------------- + nixpkgs.config.allowUnfree = true; + environment.variables.NIXPKGS_ALLOW_UNFREE = "1"; + + # some system stuff + # ----------------- + time.timeZone = "Europe/Berlin"; + i18n = { + consoleFont = "Lat2-Terminus16"; + consoleKeyMap = "us"; + defaultLocale = "en_US.UTF-8"; + }; + + # swappiness + # ---------- + # 0 = only when running out of RAM + # 100 = always swapp + boot.kernel.sysctl."vm.swappiness" = 0; + + + # rewire NIX_PATH + # --------------- + environment.variables.NIX_PATH = lib.mkForce "/var/src"; + + # Shell configuration + # ------------------- + programs.custom = { + bash.enable = true; + zsh.enable = true; + }; + +} diff --git a/system/all/grub.nix b/system/all/grub.nix new file mode 100644 index 0000000..45dcf07 --- /dev/null +++ b/system/all/grub.nix @@ -0,0 +1,22 @@ +{ pkgs, lib, config , ... }: +let + falloutGrubTheme = pkgs.fetchgit { + url = "https://github.com/shvchk/fallout-grub-theme.git"; + rev = "fe27cbc99e994d50bb4269a9388e3f7d60492ffa"; + sha256 = "1z8zc4k2mh8d56ipql8vfljvdjczrrna5ckgzjsdyrndfkwv8ghw"; + }; +in +{ + + boot.loader.grub.extraConfig = '' + set theme=($drive1)//themes/fallout-grub-theme/theme.txt + ''; + + boot.loader.grub.splashImage = "${falloutGrubTheme}/background.png"; + + system.activationScripts.copyGrubTheme = '' + mkdir -p /boot/themes + cp -R ${falloutGrubTheme}/ /boot/themes/fallout-grub-theme + ''; + +} diff --git a/system/all/networking-qos.nix b/system/all/networking-qos.nix new file mode 100644 index 0000000..a1bca18 --- /dev/null +++ b/system/all/networking-qos.nix @@ -0,0 +1,125 @@ +{ pkgs, config, lib, ... }: +{ + + options.configuration.fireqos = with lib; { + enable = mkEnableOption "enable"; + interface = mkOption { + default = "enp8s0"; + type = with types; str; + }; + # nix-shell -p speedtest_cli --run speedtest + input = mkOption { + default = 4200; + type = with types; int; + description = "in kbit"; + }; + # nix-shell -p speedtest_cli --run speedtest + output = mkOption { + default = 1200; + type = with types; int; + description = "in kbit"; + }; + balance = mkOption { + type = with types; bool; + description = '' + balance all, this will not prioritise anything. + ''; + }; + }; + + config = + let + kbits = number: + import (pkgs.runCommand "round-${toString number}" {} ''awk 'BEGIN{printf "\"%ikbit\"", ${toString number}}' > $out''); + + interface = config.configuration.fireqos.interface; + input = "${toString config.configuration.fireqos.input}kbit"; + output = "${toString config.configuration.fireqos.output}kbit"; + tincInput = kbits (config.configuration.fireqos.input * 0.7); + tincOutput = kbits (config.configuration.fireqos.output * 0.7); + useBalancedForExperimenting = false; + + tincPorts = + lib.mapAttrsToList + (name: configuration: toString configuration.port) + config.module.cluster.services.tinc; + + in { + + # https://firehol.org/tutorial/fireqos-new-user/ + services.fireqos.enable = config.configuration.fireqos.enable; + services.fireqos.config = '' + + # ------------------- world + + interface ${interface} world-in input rate ${input} ${lib.optionalString useBalancedForExperimenting "balanced"} + + class ssh commit 300kbit + match tcp port 22 + + class http commit 80% + match tcp port 80,443 + + class tinc commit 80% + match port ${lib.concatStringsSep "," tincPorts} + + class surfing commit 30% + match tcp sports 0:1023 # include TCP traffic from port 0-1023 + + class torrent + match tcp dports ${toString config.services.custom.transmission.port} + + interface ${interface} world-out output rate ${output} ${lib.optionalString useBalancedForExperimenting "balanced"} + + class ssh commit 500kbit + match tcp port 22 + + class http commit 80% + match tcp port 80,443 + + class tinc commit 80% + match port ${lib.concatStringsSep "," tincPorts} + + class surfing commit 5% + match tcp dports 0:1023 # include TCP traffic to port 0-1023 + + class torrent + match tcp sports ${toString config.services.custom.transmission.port} + + # ------------------- tinc + + interface tinc.private tinc bidirectional input rate ${tincInput} output rate ${tincOutput} ${lib.optionalString useBalancedForExperimenting "balanced"} + + class ssh commit 300kbit + match tcp port 22,2222 + + # public servers + class public commit 80% + match port 80,443 + match port 3000 # gogs + match port 8000 # bepasty + + class homeassistant commit 100kbit + match tcp port ${toString config.services.home-assistant.port} + + class prometheus commit 100kbit + match tcp port 19999 # netdata + match tcp port 9113 # netdata exporter + match port 11201 # graylog sink + + class wuis commit 100kbit + match port 8384 # syncthing + match port 8123 # home-assistant + match port 5656 # grafana + match port 8080 # kodi + match port 9090 # prometheus + match port 9000 # graylog + + class syncthing + match port 22000 + + ''; + + }; + +} diff --git a/system/all/nginx-landingpage.nix b/system/all/nginx-landingpage.nix new file mode 100644 index 0000000..95b09d2 --- /dev/null +++ b/system/all/nginx-landingpage.nix @@ -0,0 +1,214 @@ +{ config, lib, pkgs, ... }: +{ + + services.nginx.virtualHosts."mia.${config.networking.hostName}.private" = { + + locations."/" = { + root = pkgs.landingpage.override{ jsonConfig = { + items = [ + { + items = [ + { + label= "github"; + href = "https://github.com/miaEngiadina"; + image = "https://media.giphy.com/media/l0MYEpMgixXtNRgrK/giphy.gif"; + } + { + label= "Confluence"; + href = "https://fysitech.atlassian.net/wiki/spaces/DI/overview"; + image = "https://media.giphy.com/media/TfMcfnr6USBtm/giphy.gif"; + } + { + label= "Kanban Board"; + href = "https://fysitech.atlassian.net/jira/software/projects/DPE/boards/1"; + image = "https://media.giphy.com/media/10zsjaH4g0GgmY/giphy.gif"; + } + + ]; + } + ]; + }; }; + }; + }; + + services.nginx.virtualHosts."${config.networking.hostName}.private" = { + default = true; + locations."/" = { + root = pkgs.landingpage.override{ jsonConfig = { + items = [ + { + # text = "hallo"; + items = [ + + { + label= "Dashboard"; + href = "http://kruck.private:5656"; + image = "https://media.giphy.com/media/eLmaUW5dJak2k/giphy.gif"; + } + { + label = "Prometheus"; + href = "http://prometheus.workhorse.private/"; + image = "https://media.giphy.com/media/1NLZYcJGLM9mo/giphy.gif"; + } + { + label = "Graylog"; + href = "http://graylog.workhorse.private/"; + image = "https://media.giphy.com/media/6oeRBKg7mwEZnSnYkn/giphy.gif"; + } + { + label = "Jenkins"; + href = "http://jenkins.schasch.private/"; + image = "https://media.giphy.com/media/nQYnLFII2sFcQ/giphy.gif"; + } + { + label = "HomeAssistant"; + href = "http://porani.private:8123/lovelace/view_overview"; + image = "https://media.giphy.com/media/3o6ZtosYxN9Eo3AAZq/giphy.gif"; + } + { + label = "Kodi"; + href = "http://porani.private:8080/"; + image = "https://media.giphy.com/media/d9wPasV7ukkta/giphy.gif"; + } + { + label = "Hetzner Cloud"; + href = "https://console.hetzner.cloud/projects"; + image = "https://media.giphy.com/media/NECZ8crkbXR0k/giphy.gif"; + } + { + label = "Transmission"; + href = "http://transmission.kruck.private/"; + image = "https://media.giphy.com/media/9ryQgA3d0BVoe7iZl0/giphy.gif"; + } + { + label = "Pass the Popcorn"; + href = "https://passthepopcorn.me/"; + image = "https://media.giphy.com/media/NipFetnQOuKhW/giphy.gif"; + } + { + label = "redacted"; + href = "https://redacted.ch/"; + image = "https://media.giphy.com/media/ku5EcFe4PNGWA/giphy.gif"; + } + { + label = "Kibana Workhorse"; + href = "http://kibana.workhorse.private/"; + image = "https://media.giphy.com/media/24sVlirH2qPTO/giphy.gif"; + } + { + label = "Kibana Workout"; + href = "http://kibana.workout.private/"; + image = "https://media.giphy.com/media/24sVlirH2qPTO/giphy.gif"; + } + { + label = "Cups"; + href = "http://localhost:631/"; + image = "https://media.giphy.com/media/7hU7x4GPurk2c/giphy.gif"; + } + ]; + } + { + text = "Betfair"; + items = [ + { + label = "betfair"; + href = "https://www.betfair.com/exchange/plus/football"; + image = "https://media.giphy.com/media/3og0ILXHf8hmHmET1C/giphy.gif"; + } + { + label = "token"; + href = "https://docs.developer.betfair.com/visualisers/api-ng-account-operations/"; + image = "https://media.giphy.com/media/aeIlR57TpTimI/giphy.gif"; + } + { + label = "api doku"; + href = "https://docs.developer.betfair.com/display/1smk3cen4v3lu3yomq5qye0ni/Reference+Guide"; + image = "https://media.giphy.com/media/11bKAQfWd0Yo0w/giphy.gif"; + } + ]; + } + { + text = "Lektor"; + items = [ + { + label = "Terranix"; + href = "http://terranix.schasch.private"; + image = "https://media.giphy.com/media/nGtOFccLzujug/giphy.gif"; + } + { + label = "tech-blog"; + href = "http://techblog.schasch.private"; + image = "https://media.giphy.com/media/nGtOFccLzujug/giphy.gif"; + } + ]; + } + { + text = "NixOS"; + items = [ + { + label = "NixOS Manual"; + href = "https://nixos.org/nixos/manual/"; + image = "https://media.giphy.com/media/dsdVyKkSqccEzoPufX/giphy.gif"; + } + { + label = "Nixpkgs Manual"; + href = "https://nixos.org/nixpkgs/manual/"; + image = "https://media.giphy.com/media/dsdVyKkSqccEzoPufX/giphy.gif"; + } + { + label = "NixOS Reference"; + href = "https://storage.googleapis.com/files.tazj.in/nixdoc/manual.html#sec-functions-library"; + image = "https://media.giphy.com/media/LkjlH3rVETgsg/giphy.gif"; + } + { + label = "Nix Packages"; + href = "https://nixos.org/nixos/packages.html"; + image = "https://media.giphy.com/media/l2YWlohvjPnsvkdEc/giphy.gif"; + } + { + label = "NixOS Options"; + href = "https://nixos.org/nixos/options.html"; + image = "https://media.giphy.com/media/3fiw51MvIWcGjMhy9a/giphy.gif"; + } + { + label = "NixOS Language specific helpers"; + href = "https://nixos.wiki/wiki/Language-specific_package_helpers"; + image = "https://media.giphy.com/media/LkjlH3rVETgsg/giphy.gif"; + } + { + label = "NixOS Weekly"; + href = "https://weekly.nixos.org/"; + image = "https://media.giphy.com/media/lXiRLb0xFzmreM8k8/giphy.gif"; + } + { + label = "NixOS Security"; + href = "https://broken.sh/"; + image = "https://media.giphy.com/media/BqILAHjH1Ttm0/giphy.gif"; + } + { + label = "NixOS RFCs"; + href = "https://github.com/NixOS/rfcs/"; + image = "https://media.giphy.com/media/Uq9bGjGKg08M0/giphy.gif"; + } + ]; + } + { + text = "Syncthings"; + items = map ( + {name, host ? "${name}.private", ... }: + { + label = name; + href = "http://${host}:8384/"; + image = "https://media.giphy.com/media/JoyU4vuzwj6ZA7Ging/giphy.gif"; + } + ) ( + map + (name: { inherit name; }) + (lib.attrNames config.module.cluster.services.tinc."private".hosts) + ); + } + ]; + };}; + }; + }; +} diff --git a/system/all/nginx.nix b/system/all/nginx.nix new file mode 100644 index 0000000..edd37d4 --- /dev/null +++ b/system/all/nginx.nix @@ -0,0 +1,29 @@ +{ pkgs, ... }: +let + access_log_sink = "workhorse.private:12304"; + error_log_sink = "workhorse.private:12305"; +in +{ + # for graylog logging + services.nginx.commonHttpConfig = '' + log_format graylog2_json escape=json '{ "timestamp": "$time_iso8601", ' + '"facility": "nginx", ' + '"remote_addr": "$remote_addr", ' + '"body_bytes_sent": $body_bytes_sent, ' + '"request_time": $request_time, ' + '"response_status": $status, ' + '"request": "$request", ' + '"request_method": "$request_method", ' + '"host": "$host",' + '"upstream_cache_status": "$upstream_cache_status",' + '"upstream_addr": "$upstream_addr",' + '"http_x_forwarded_for": "$http_x_forwarded_for",' + '"http_referrer": "$http_referer", ' + '"http_user_agent": "$http_user_agent" }'; + + access_log syslog:server=${access_log_sink} graylog2_json; + error_log syslog:server=${error_log_sink}; + ''; + + services.nginx.package = pkgs.nginxMainline; +} diff --git a/system/all/packages.nix b/system/all/packages.nix new file mode 100644 index 0000000..50c4bd2 --- /dev/null +++ b/system/all/packages.nix @@ -0,0 +1,93 @@ +{ config, pkgs, lib, ... }: + +let + + pastebin = pkgs.writers.writeDashBin "pastebin" /* sh */ '' + exec ${pkgs.bepasty-client-cli}/bin/bepasty-cli \ + --lifetime 1m \ + --url http://workhorse.private:8000 \ + --pass ${lib.fileContents } \ + "$@" | sed -e s/workhorse.private:8000/paste.ingolf-wagner.de/ + ''; + + memoryUsage = pkgs.writers.writeDashBin "memory-total-usage" /* sh */ '' + echo " %CPU %MEM MEM : PROCESS" + echo "------- ------- ------------- -------" + ps aux | awk '{mem[$11]+=int($6/1024)}; {cpuper[$11]+=$3};{memper[$11]+=$4}; END {for (i in mem) {printf "%6.2f%% %6.2f%% %10.2f MB : %s\n", cpuper[i],memper[i],mem[i],i}}' | sort -k3nr | head -n 5 + ''; + + prefetch-git-rendered = pkgs.writeShellScriptBin "nix-prefetch-git-rendered" /* sh */ '' + ${pkgs.nix-prefetch-scripts}/bin/nix-prefetch-git "$@" \ + | ${pkgs.jq}/bin/jq --raw-output '"pkgs.fetchgit{ + url = \"\(.url)\"; + rev = \"\(.rev)\"; + sha256 = \"\(.sha256)\"; + };"' + ''; + + prefetch-url-rendered = pkgs.writeShellScriptBin "nix-prefetch-url-rendered" /* sh */ '' + HASH=$( ${pkgs.nix}/bin/nix-prefetch-url "$1" ) + cat <; + repo = "sftp::backup/remote-${config.networking.hostName}"; + requires = []; + extraArguments = [ + "sftp.command='ssh backup@${server} -i ${toString } -s sftp'" + ]; + initialize = true; + timerConfig = { + OnCalendar = "daily"; + Persistent = "true"; + }; + dirs = config.backup.all.restic.dirs; + }; + in + { + "on-porani" = setup "porani.private"; + "on-workhorse" = setup "workhorse.private"; + "on-workout" = setup "workout.private"; + }; + }; +} diff --git a/system/all/sftp-user.nix b/system/all/sftp-user.nix new file mode 100644 index 0000000..1351549 --- /dev/null +++ b/system/all/sftp-user.nix @@ -0,0 +1,18 @@ +{ config, pkgs, lib, ... }: +{ + + module.backup.sftpUser = { + + # my backup user + "backup" = { + enable = true; + initialize = true; + home = toString /backup/remote/backup; + authorizedKeys.keyFiles = [ + ( toString ) + ] ++ config.users.users.root.openssh.authorizedKeys.keyFiles; + }; + + }; + +} diff --git a/system/all/shell.nix b/system/all/shell.nix new file mode 100644 index 0000000..e1d333c --- /dev/null +++ b/system/all/shell.nix @@ -0,0 +1,5 @@ +{ config, lib, ... }: +{ + + +} diff --git a/system/all/sshd-known-hosts-bootup.nix b/system/all/sshd-known-hosts-bootup.nix new file mode 100644 index 0000000..275796c --- /dev/null +++ b/system/all/sshd-known-hosts-bootup.nix @@ -0,0 +1,46 @@ +{ lib, pkgs, ... }: +with lib; +let + + computers = { + workhorse = { + onionId = fileContents ; + publicKey = "ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBB+sHmukNa2TmtBDCqN+LVaYblvHztD/ziK2cbKR8dEHztF0YBS60MHMpbGPOII5NVMUY6Z2OHFBQi9X6PG1YBY="; + }; + porani = { + onionId = fileContents ; + publicKey = "ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBGFaTRGqMd/rKpyMUP6wVbgiWFOUvUV2qS/B5Xe02UUch/wxR4fTCY+vnzku5K0V/qqJpjYLgHotwZFqO/8lFu4="; + }; + }; + +in +{ + + services.openssh.knownHosts = mapAttrs' (name: { onionId, publicKey, ... }: { + name = "${name}-init-ssh"; + value = { hostNames = [ onionId ]; inherit publicKey; }; + }) computers; + + environment.systemPackages = + let + + ssh = mapAttrsToList (name: { onionId, ... }: + pkgs.writers.writeDashBin "ssh-boot-to-${name}" '' + ${pkgs.tor}/bin/torify ${pkgs.openssh}/bin/ssh root@${onionId} -p 23 + '') computers; + + password = mapAttrsToList (name: { onionId, ... }: + pkgs.writers.writeDashBin "unlock-boot-${name}" '' + ${pkgs.tor}/bin/torify ${pkgs.openssh}/bin/ssh root@${onionId} -p 23 ' + echo -n "enter password : " + read password + echo "$password" > /crypt-ramfs/passphrase + ' + '') computers; + + in + ssh ++ password; + + + +} diff --git a/system/all/sshd-known-hosts-private.nix b/system/all/sshd-known-hosts-private.nix new file mode 100644 index 0000000..ce71490 --- /dev/null +++ b/system/all/sshd-known-hosts-private.nix @@ -0,0 +1,53 @@ +# generated by updateSshKeys.sh +{ config, lib, ... }: +{ + + services.openssh.knownHosts = { + "sterni.private" = { + hostNames = [ + "sterni.private" + config.module.cluster.services.tinc.private.hosts.sterni.tincIp + ]; + publicKey = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQC2qlEEnS0GmB93UL+Nzqk991amYk3tvQKjPvPP7XBfLksPQ0BhvUFy0fchnYLwxDgFydF4KjL6M2QttfRGWbcE/Ui0UczSpgw0GR+ou9tdQetq/iG963pvNvJvfu0ckfwMG4ia2WoSj4/SRKlpYwFwsqXzOgKo9lCauMcoNP6UsdqIhdcZJD9/VSNz9RTq+vdEIGs8Ldvq7NgPjPe5abct85fwwenOX+LyaG+5DQt5hAUdjFSXGRw5fZvaGteqO1TraQOgoJWvbJlPwFkSJnxnbi/6yibMBakNpVkCqSYMEDFVmFmGU4VOhZ2ukm3BkdiyML81LaawXnIwB0G2/ICFE2IuE9TvWj49k/T+KSzTmcS4tcq+rLcKGKNaWL/Rz6KvT3W4pz6Dv9pfeJYNkJP7J1lu84pMc4UZMAo87Ps4QDlV8yvDCw8htIFnGRKpu4AOXlKs97SLiovWGCiyFYpm+uPV9Lk6KjEqMGTfw537Cr1e6xcvwZ9FOJsk3dLL4o21MEsDIpwiAn7yCnVsDSsglRk5nhYFtrvZvkijyWk05v6ZkyT+zBw1qNSOEAi8NS/dkbbaDT2wy+WOggcjzU+LnDjmtWedPAaVRJK83aeSsl27cMdeKms+8TNbjhCyGKvG2lzXg0n13QYs5/93Bm9urGWqF8AplPEgOm1GJvJLOw== root@sterni"; + }; + "workout.private" = { + hostNames = [ + "workout.private" + config.module.cluster.services.tinc.private.hosts.workout.tincIp + ]; + publicKey = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQCuaaOYiwmQBiVqh1WRnP3SiOgkX7d3sZkE/E6F8hrIHcl77fOaaLZt1JizrZDWJAfBoZJtNzJiCxJeG3FZ+Gm3TH462yau7JnzYQPDV/nCeWFAviUcfS3xz2CrK7m5ukUIAglWyFO1MajF190TcSE2xnQ4stJ3XNl42cQA6MXUdUQJEqafTItRFN82Y7acwzALUTTaT++g3PzjRWLMwTz1k35V4OCsm+9WF0FAjuJCHQgZqiqPduu4sX+JKqmUZTtlZ9yYs1bp6yfjcmjGHuQLJUKQxMKLL5ZU4RaXSKmsg5M/kpWqO9HKJpuL2KoRll3S9AlWGY5iq9KuJeNnYj/YO4b9F4ycNQFuHNhmJiwnfcfz8WUaEqnKwq3aJcTW0SqBTdHeJ//WJCnI3qLQNQ2PfXaR0UZ5+hJHL0EsJbPiWmzaWws2XvYvawevggidwNqS9dvKS8PAYPiLkFi/AXVaMg6FOfppP+iKS/s0ua7DCVJuicHHoPwXre50oc0nhgVUGXnPOhvf9GIkJweUb3hgRuNuACWQWCMt5YyfFS2Zf+vpbteNbYoj2YP5hV/TPwlOrTHKTItfWcIUg0rmU0LS/WQfZMihUnLAq4mpao3saQ/pN/yNwa9Vqg8ah46opcval59g+fLsMKXhvGo/vBmGc/uhrCouqtvrdKrO4QhsKw== root@workout"; + }; + "sputnik.private" = { + hostNames = [ + "sputnik.private" + config.module.cluster.services.tinc.private.hosts.sputnik.tincIp + ]; + publicKey = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDZwxp9syIYpQPNML6L5bcRCglpKCWm3/6hYpvecybhWmMmIg0Mqi+VBICL1tNVU3SI2akSaYhYa5JSQPu9iANYIcxzg7pOY+bZf36w79fMpnGGsu/dfKZtN8dL2EOOdgu2Dz120aVgvgB0bM0wsp2rD1mXlrOAZ9SH2Knun/r0ZRYW6dnRXStFPQzmEtLg6KeEUfQ09yoHOkjEbHA3CiqLAtUQnwctf2h8K+Ppc8uTeDyv5WXtdfSmyUQwKuLfIOxMA4I2mFOPb5d+xmY8e0raRopMgeP1MVmj+8B4ZH2u6l4WeVVHxywRAMgN/ljQlBjl+cqcsk6yZro+GNRM+ch17RQUfoZGrY6pfVHExu6UhiMy/dfPkhEmpzw7Pl5NT1bssRO3BUgbNOyI0JZdrnzXnlDGJSS8ZEaavHaALbD0K+QSzGbmwcvAXh+/QnpMo/Uuiomo8Gc5BzHORgEBo3PICITAgyDlmNbYeVOP9XejrfcCJABMGvlwICji+5K5xpEuPmpgQSJBOf/ZBubaxOb/GCVtRUjSMe+i4CT9sPGAaDISEKNFbxdGYmy3e13OXQ9jq5l1FykYY/pxMjgDAPdRVKOYdCZ0tWW/pnzvmRlYyuy+UwIPvlyhC6NM7FWK8Ef2IPoc4stALvsqnByb1p8lBFfi6VSR9TKiwXZ1c4EH9Q== root@nixos"; + }; + "workhorse.private" = { + hostNames = [ + "workhorse.private" + config.module.cluster.services.tinc.private.hosts.workhorse.tincIp + ]; + publicKey = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDaNYDLDRH///qgyaEtueb6HNhF+ZyVDk6QKgN7xbrfa5LN+XBjgeLjK4Cw6BOIeZ2e0plbPaUbfqWmNsky7tBVSx2MzITRQf6aUPrSyijsEH5vXrH2Cy6aGJqpzXQYXglqHLP8S0cnMwIed50zSO8uNDwmQ787zZChfF+tk5RhuzMuSBVXE7Gg8NHA9rGygqzb+F05b3wDGFkuNQORv8e4Tau9uakRaFa9DzENdQMu91YIFpgT76YuwQnKz6YJytmPGeqTS0qcJCBEikDST/+8bCegK4sx7RJI38eoN9ZIrmxNGz/iQbl1BmD/147khqzj6/uKL0uDR2Bc+F2/tAzdxPpieTN4XlDCf6GRFvjGq/Wv52hPsVq88VmtFfoNoEpdN480MJG+EerppxhdGDXg6FqwYOnw4ezblTky6zxjW+fYhbo0Y5YVTEhoO1hEaODT9OAtacXTR2WpXl3sIwmptM7Gg7THtM1+tv5+4v/frVvrwjuu/n0pJkY3gyKiMepuxWOwmYpg9Zpt7p/y1pCzwY+Bd1frO8f60fwtXBiMcTFAO16F0GrQcqrWIblK5fYREvQ4raRNf6rapZXP/cY1IWRA0vMDG1Y8RJFj20cnHQ1cZRWLsoo4pp4/6GluuqGzMwu7A0FMVAIo7EeaV3Zx4VD2oHBL4DUWREuc9jFasQ== root@workhorse"; + }; + "porani.private" = { + hostNames = [ + "porani.private" + config.module.cluster.services.tinc.private.hosts.porani.tincIp + ]; + publicKey = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDoANrFaqJwNwSRGECqfZSUX8K86Nb7S6+ed25bLPrLM9MyNdlQJu1qKYk7+VafUUm1cHGrYXtf9kzvBVR6CWWKlZQd90MaevmsFKwhHqeLtvwKI3VsdlkCLALseaKsGtIk6X7/o8rfrZvHELGGddieJK4A0y7+iRJWCb85JhCeV8RfYfJO9HSFvpr1ppGAn83mmBKim9CoAFQJlOnC/XbYGo0KMcUdO0unrVfPWpdy3Pi12rFdABd3A7YHvQz3UDFEQijAVw7N5k+BthoTvkEYfiCgnIEATBpag6Go9BrdlI2LebI2TQwyXP27OqRDyDJdXaxsqaya09hta9Uh3k7usLF4Tzy6aeLjtGiTNxa7AUP5+IhipMA1/aDiiu7b9fpK/JmbvZV3LUtOvqLvaheDIzNPAi24qaZT7EmyAva7ufrF8lUg8Bms6dQ/6dZ/mq2nS6iJAAGqIoPSGWQAdDdlCDFz3WhcQyrvbOZhEK6Ksn9EC2L7MqXbBTtJSb5PLUhOTbMzvAvq2jTAwECLcHt1vQsEk0oZ3+72rC8SBCzbWxSZygiHQK9xXFFmeX1HN35/NWHlVQkh0kG9TQAsa9obnRQDDGceXwAqqWyzoSXIDk1qjKgey7rhJZAE2lynxpShAG7k7iVdqOi6GnnB7NEeyGAl6V+fl4vUpu2NU8EdJw=="; + }; + "pepe.private" = { + hostNames = [ + "pepe.private" + config.module.cluster.services.tinc.private.hosts.pepe.tincIp + ]; + publicKey = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDJ8n/ac1AdrQg5cDtSmU+F9i8klgm/q/l7bITrBkDpRXC3TjFCcfK8oSq7gXCvEnPKGiWEEb80G/kDM7YkIffNIg1HFgtb/req7eKEP1VOBRm2Eu4k1/KSV1A3ssvfKbrH2ntwupuhCU6KwISpkvdc7LNomt9ZZ70f6qUpU9OPu9jlQDCV9G6xboeIdNeRabYXtOB+g24Ev/SbaOr6VcIapAQc1j3eqJo3u2bdVQfzIeVkxfwjlQimSvFX0cLTi3P0NDf0oIXL+AwhSziLWt8NDf1n+gR9tZgEu/vRUUcPBMS7a1NYoHXy9KryIQbK3qCh8dRwsE17zTlasmZ+o9Ki6nsGbId1MKx0O9VunDpdB146JCN/Z5LZy/g0GMfB5SjBbxayC3epi84Cy9MEy+xZA4pAFsLttPn1xYNUoc+L/5X4IKH/xDZSQZw2Dbg9AGj1gfwJofqPOccWcmH0dqE7ZA7Jkj9afwqdPNMyC0d3jqTJQFnodYvRewWmgLVlnRiFKqY8OCxtr8KFDbRpqml5SpI9cq6czxWzqzag1RR/fB4aoeNfHytvU3fbGSl2A6WGh9DplO1R1f/n559HN7z/i6CmtqAsqnPQpe8ms15r9Tj35fAxyeV5XSqtAWsAFKd3l6t3/XQOS1bF+ooyudfo9dAtuT2V82sPolo98L4v7w== root@pepe"; + }; + "cracksucht.de" = { + hostNames = [ "cracksucht.de" ]; + publicKey = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDVqpWzX+C7veO/1MDSdh5ukFhpI4cfXevbl6DVb9gVt1wdYB0JsiMiWfl13MZJy9iEP/KfwRLYmu8i36tDR9uJfHQyLK8G7q2DhrleIPgM3dFCdDU1QtulE8hEq/ZsqzMn/QIHYIipIqzNfmC/xnpX2gIo09T7EY+n863ALlj+GqxMb4nr2XDLY+Lllo2yMzylJIz9q8U5hOmzrlCnBpf2MPMwanHXnZXj2CmO80VyBHnAMJ/h72AN1qzDaHFlhxh0Li/POc1bpDjiVjiUPgimHZWpi3VObxWLLn2zf+RH2lx0yXMccSEnkWvHp+Ll5apIUUS+vTlDo3niWpEfGZLl root@debian"; + }; + }; +} diff --git a/system/all/sshd-known-hosts-public.nix b/system/all/sshd-known-hosts-public.nix new file mode 100644 index 0000000..5d00b11 --- /dev/null +++ b/system/all/sshd-known-hosts-public.nix @@ -0,0 +1,66 @@ +{ config, pkgs, lib, ... }: + +with lib; + +{ + + services.openssh.knownHosts = { + github = { + hostNames = [ + "*.github.com" + # List generated with + # curl -sS https://api.github.com/meta | jq -r .git[] | cidr2glob + "192.30.252.*" + "192.30.253.*" + "192.30.254.*" + "192.30.255.*" + "185.199.108.*" + "185.199.109.*" + "185.199.110.*" + "185.199.111.*" + "13.229.188.59" + "13.250.177.223" + "18.194.104.89" + "18.195.85.27" + "35.159.8.160" + "52.74.223.119" + ]; + publicKey = "ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ=="; + }; + gitlab = { + hostNames = [ "gitlab.com" ]; + publicKey = "ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBFSMqzJeV9rUzU4kWitGjeR4PWSa29SPqJ1fVkhtj3Hw9xjLVXVYrU9QlYWrOLXBpQ6KWjbjTDTdDkoohFzgbEY="; + }; + # c-base + "bnd-cbase" = { + hostNames = [ "bnd.cbrp3.c-base.org" ]; + publicKey = "ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBKDknNl4M2WZChp1N/eRIpem2AEOceGIqvjo0ptBuwxUn0w0B8MGTVqoI+pnUVypORJRoNrLPOAkmEVr32BDN3E="; + }; + "shell.cbase" = { + hostNames = [ "shell.c-base.org" ]; + publicKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOBKBn0mZtG3KWxpFqqcog8zvdIVrZmwj+ARujuNIAfo"; + }; + "kgb.cbase" = { + hostNames = [ "kgb.cbrp3.c-base.org" ]; + publicKey = "ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBAdyl7fnnCqomghJ1TDbh5FWFQWFwoO1Y1U/FpmWd8a9RcQvN0Izhg/7A+7ptDxbmpVii8hqfghlqUwtvVy7jo8="; + }; + "cns.cbase" = { + hostNames = [ "cns.c-base.org" ]; + publicKey = "ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBOtlyLA2nMK9Uqpv4EbWS+rZ9Mx4bAjURmH+zrXkuRGBcU1cKm+TZfWe9/rPX57KaMPBDyIygOJIsM2T5SqX90A="; + }; + "lassulus" = { + hostNames = [ "[lassul.us]:45621" ]; + publicKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAsANFdMi825qWQXQbWLYuNZ6/fARt3lnh1KStQHQQMD"; + }; + renoise = { + hostNames = [ "[git.renoise.com]:2229" "[94.130.128.97]:2229" ]; + publicKey = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCmIOTjQsD1TaD9MiECcRqwfAXfRdbI+2pkuF+zhBUkrX41NA4LzifPY4Iw3PlklE0YGIOzYyNitzkdgxIWkeqa0Y9iL3gGZBuLFORj5YXWlDKB2RrPAsZRL8y69y4H6RWPpL6DHHsf9eT+HgRzWzzn5nUFLfkCsuM96BqjIKN1pinIBcE6gst1UUSwSTjK8XZA5d4BiSrLF4HiNXnDm+qniYGbGkzZcjn1ua+l0GdGbfg9TotFnSK/QXgN3MeHHDZKnIjOIkOXCY+L5URe0RHo6pBFdj+BLr211AJhB52MrDNudQcY6eSQiJ08LeE6SkcrsQO/VZ/JnOkHxHd2mOyH"; + }; + "git.ingolf-wagner.de" = { + hostNames = [ "[git.ingolf-wagner.de]:443" ]; + publicKey = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCvJoz+6Ew0L518+jhue69hm0nEzVBuyUWDRUM3QnOQCCmGgFFXq+iTxgYoo2e3qYFUV0CmYK548ZKBB/nGUmrRwT06sJXtOCmVsBCMxBX6KNEBxKns8urQqWZ/ShzuKhpZmC9EuB25QVXCkUuc1aXtVgLng8Ucke/kOHE/HcwB4Sb7SCNP7pF4/mBpuH9cONs21HkxE6Aj85LSSJCRwiyL+WBEibDcDVy+W5hicAp/m7sL+sezFkNzru0X10G1kuC01+HZT8I5Be3xQ9llWkMkVaO5L7N9+SUXxZSMtwI9uEU8iPuXhb9ETyIR530kipydOljD6nA3hRC12nnE2T0d"; + }; + + }; + +} diff --git a/system/all/sshd.nix b/system/all/sshd.nix new file mode 100644 index 0000000..0c56cec --- /dev/null +++ b/system/all/sshd.nix @@ -0,0 +1,22 @@ +{ config, pkgs, lib, ... }: + +with lib; + +{ + + # not needed anymore + # programs.ssh.hostKeyAlgorithms = [ "ssh-rsa" "ssh-ed25519" "ecdsa-sha2-nistp256" ]; + + services.custom.ssh = { + tools.enable = true; + sshd = { + enable = true; + rootKeyFiles = [ + ( toString ) + ]; + }; + }; + +} + + diff --git a/system/all/syncthing.nix b/system/all/syncthing.nix new file mode 100644 index 0000000..a76e811 --- /dev/null +++ b/system/all/syncthing.nix @@ -0,0 +1,165 @@ +{ config, lib, pkgs, ... }: +with lib; +{ + + test.services.syncthing = { + guiAddress = "${config.networking.hostName}.private:8384"; + declarative = { + overrideDevices = true; + devices = let + device = name: id: + { + "${name}" = { + name = name; + id = id; + addresses = [ "tcp://${name}.private:22000" "tcp://${name}.private:21027" ]; + }; + }; + in + (device "workhorse" "AFSAKB6-JLH4QAS-DSRMPI3-6PVCIHF-IIAVLPC-STPNO3Y-YRDU5NW-QD445QI") + // (device "pepe" "SZLXFW3-VTAC7UB-V2Z7CHE-3VZAYPL-6D72AK6-OCDMPZP-G4FPY5P-FL6ZVAG") + // (device "kruck" "7NXJTB6-XPQD5AO-Z6LY4GZ-UGCLPJI-3EQSZ4B-YT4OV2F-NWAI2BN-OE3IEQW") + // (device "schasch" "FLY7DHI-TJLEQBJ-JZNC4YV-NBX53Z2-ZBRWADL-BKSFXYZ-L4FMDVH-MOSEVAQ") + // (device "workout" "DZOOAKG-GI2SVOS-QEVMFL7-TRHVTPQ-ADIJEVH-RH5WV3J-6M7MJHC-C53EOAC") + // (device "porani" "6YOIA4E-X52ZD5Z-FPNWPRS-77QIMMU-VDIXVZB-6BPQN7A-FFJDU4W-EXEGFAI") + // (device "sterni" "NFQP2DG-IK5SEL3-JTOV3HW-HF2EPAO-JQK3VSW-NKVMPFH-LZE6SEQ-INZ25QC") + // { + smartphone = { + name = "smartphone"; + id = "P6MFODE-PO7CRVB-5RL5AMX-HG4D2CE-C2NC7M4-RYHGX2N-VUU2DWL-C6GVPQN"; + addresses = [ "dynamic" ]; + }; + } + // { + bumba = { + name = "windows-bumba"; + id = "JS7PWTO-VKFGBUP-GNFLSWP-MGFJ2KH-HLO2LKW-V3RPCR6-PCB5SQC-42FCKQZ"; + addresses = [ "dynamic" ]; + }; + } + // { + mors = { + name = "lassulus-mors"; + id = "ZPRS57K-YK32ROQ-7A6MRAV-VOYXQ3I-CQCXISZ-C5PCV2A-GSFLG3I-K7UGGAH"; + addresses = [ "tcp://mors.r:22000" ]; + }; + }; + + folders = { + book = { + id = "wwbvs-5lfbh"; + watch = false; + devices = [ "workout" "pepe" "sterni" ]; + }; + desktop-encrypted = { + id = "ebnth-pfven"; + watch = false; + devices = [ "workout" "workhorse" "pepe" "sterni" ]; + }; + fotos-encrypted = { + id = "ddkrc-mevxd"; + watch = false; + devices = [ "workout" "workhorse" "pepe" "sterni" ]; + }; + finance-encrypted = { + id = "gl7rx-sdsnx"; + watch = false; + devices = [ "workout" "workhorse" "pepe" "sterni" ]; + }; + movies = { + id = "vatmy-c2qf4"; + watch = false; + devices = [ "workhorse" "porani" ]; + }; + porn = { + id = "vatmy-c2qf4"; + watch = false; + devices = [ "workhorse" "porani" ]; + }; + music-library = { + id = "gytmq-r2zrx"; + watch = false; + devices = [ "porani" "workout" "workhorse" "pepe" "sterni" ]; + }; + music-library-free = { + id = "mu9mn-zgvsw"; + watch = false; + devices = [ "workout" "workhorse" "mors" ]; + }; + music-projects = { + id = "acfhu-r4t4f"; + watch = false; + devices = [ "workout" "workhorse" "pepe" "sterni" ]; + }; + podcasts = { + id = "yvzmx-hcomd"; + watch = false; + devices = [ "workhorse" "porani" ]; + }; + samples = { + id = "pcgkj-tjucd"; + watch = false; + devices = [ "workout" "workhorse" "sterni" ]; + }; + series = { + id = "all-series"; + watch = false; + devices = [ "workhorse" "porani" ]; + }; + smartphone-music = { + id = "0vjze-xvs8n"; + watch = false; + devices = [ "workout" "smartphone" ]; + }; + smartphone-fotos = { + id = "e5823_jtbr-photos"; + watch = false; + devices = [ "sterni" "workout" "pepe" "smartphone" ]; + }; + video-material = { + id = "wgkun-fec5h"; + watch = false; + devices = [ "workout" "workhorse" ]; + }; + + # one on one + porani-workout = { + devices = [ "porani" "workout" ]; + watch = false; + }; + porani-pepe = { + devices = [ "porani" "pepe" ]; + watch = false; + }; + windows-sync = { + id = "hcity-p5ikc"; + watch = false; + devices = [ "schasch" "bumba" "workout" "kruck" ]; + }; + workout-pepe = { + devices = [ "pepe" "workout" ]; + watch = false; + }; + }; + + }; + }; + + + # convenience script to know which folder needs to be configured + environment.systemPackages = + let + folders = config.test.services.syncthing.declarative.folders; + computers = unique (flatten (mapAttrsToList (_: value: value.devices) folders)); + isComputerInDeviceList = computer: deviceList: (unique deviceList) == (unique (deviceList ++ [ computer ])); + getFolderNames = computer: naturalSort (builtins.attrNames (filterAttrs (_: folder: isComputerInDeviceList computer folder.devices) folders)); + computerMap = foldl (acumulator: computer: acumulator // { "${computer}" = getFolderNames computer; } ) {} computers; + printTemplate = folder: ''${folder}.path = "";''; + in + mapAttrsToList (computer: folders: pkgs.writeShellScriptBin "syncthing.${computer}" '' + cat < ]; + + networking.firewall.trustedInterfaces = [ "tinc.private" ]; + + # nix-shell -p tinc_pre --run "tinc --config . generate-keys 4096" + module.cluster.services.tinc = { + "retiolum" = { + networkSubnet = "10.243.0.0/16"; + port = 720; + extraConfig = '' + LocalDiscovery = yes + AutoConnect = yes + ''; + privateEd25519KeyFile = toString ; + privateRsaKeyFile = toString ; + hosts = { + pepe = { + tincIp = "10.243.23.1"; + publicKey = lib.fileContents ; + }; + sterni = { + tincIp = "10.243.23.3"; + publicKey = lib.fileContents ; + }; + workhorse = { + tincIp = "10.243.23.5"; + publicKey = lib.fileContents ; + }; + workout = { + tincIp = "10.243.23.4"; + publicKey = lib.fileContents ; + }; + }; + }; + "private" = { + networkSubnet = "10.23.42.0/24"; + extraConfig = '' + LocalDiscovery = yes + ''; + privateEd25519KeyFile = toString ; + privateRsaKeyFile = toString ; + hosts = { + workout = { + tincIp = "10.23.42.27"; + publicKey = lib.fileContents ; + }; + pepe = { + tincIp = "10.23.42.26"; + publicKey = lib.fileContents ; + }; + sterni = { + tincIp = "10.23.42.24"; + # publicKey = lib.fileContents ; + publicKey = lib.fileContents ; + }; + porani = { + tincIp = "10.23.42.31"; + publicKey = lib.fileContents ; + }; + workhorse = { + tincIp = "10.23.42.21"; + publicKey = lib.fileContents ; + }; + sputnik = { + realAddress = [ + # "195.201.134.247:443" + "static.247.134.201.195.clients.your-server.de:443" + ]; + tincIp = "10.23.42.122"; + publicKey = lib.fileContents ; + }; + }; + }; + }; + + + # retiolum stuff + networking.extraHosts = builtins.readFile (toString "${retiolum}/etc.hosts"); + systemd.services."tinc.retiolum" = { + preStart = '' + cp -R ${retiolum}/hosts /etc/tinc/retiolum/ || true + ''; + }; + +} + + diff --git a/system/desktop/audio.nix b/system/desktop/audio.nix new file mode 100644 index 0000000..3fdd231 --- /dev/null +++ b/system/desktop/audio.nix @@ -0,0 +1,74 @@ +{ config, lib, pkgs, ... }: +let + + library = import { inherit pkgs lib; }; + + mixxxBin = pkgs.writeShellScriptBin "mixxx" + "${pkgs.mixxx}/bin/mixxx --settingsPath ${config.users.users.mainUser.home}/music-library/mixxx"; + mixxxDesktop = library.desktopFile mixxxBin { longName = "Mixxx"; }; + + mixxxFreeBin = pkgs.writeShellScriptBin "mixxx-free" + "${pkgs.mixxx}/bin/mixxx --settingsPath ${config.users.users.mainUser.home}/music-library-free/mixxx"; + mixxxFreeDesktop = library.desktopFile mixxxFreeBin { longName = "Mixxx"; }; + +in { + + system.custom.audio = { + enable = true; + sinks = [ + { + name = "movieLimiterSink"; + queue = [ + { + # compress all sounds + plugin = "dyson_compress_1403"; + label = "dysonCompress"; + control = [ + "0" # peak limit (dB) + "1" # release time (secons) + "0.2" # fast compression ration (unknown what that means) + "0.8" # compression ratio + ]; + } + { + # limit sound + plugin = "fast_lookahead_limiter_1913"; + label = "fastLookaheadLimiter"; + control = [ + "20" # input gain (db) + "-10" # limit (db) + "1.1" # release time (s) + ]; + } + { + # avoid deep sounds + plugin = "dj_eq_1901"; + label = "dj_eq"; + control = [ + "-9" # low gain (db) (100Hz) + "0" # mid gain (db) (1000Hz) + "0" # high gain (db) (10000Hz) + ]; + } + ]; + } + ]; + }; + + programs.custom = { + easytag.enable = true; + espeak.enable = true; + }; + + environment.systemPackages = with pkgs; [ + audacious + sox + id3v2 + + mixxxBin + mixxxDesktop + mixxxFreeBin + mixxxFreeDesktop + ]; + +} diff --git a/system/desktop/browser.nix b/system/desktop/browser.nix new file mode 100644 index 0000000..13d0981 --- /dev/null +++ b/system/desktop/browser.nix @@ -0,0 +1,62 @@ +{ config, lib, ... }: +let + backupFolder = "~/desktop"; + homeFolder = "/browsers"; +in { + programs.custom.browser = { + enable = true; + configList = { + development = { + home = "${homeFolder}/development-browser"; + homeBackup = "${backupFolder}/development-browser"; + }; + google = { + home = "${homeFolder}/google-browser"; + homeBackup = "${backupFolder}/google-browser"; + }; + finance = { + home = "${homeFolder}/finance-browser"; + homeBackup = "${backupFolder}/finance-browser"; + }; + facebook = { + home = "${homeFolder}/facebook-browser"; + homeBackup = "${backupFolder}/facebook-browser"; + }; + shopping = { + home = "${homeFolder}/shopping-browser"; + homeBackup = "${backupFolder}/shopping-browser"; + }; + mindcurv = { + home = "${homeFolder}/mindcurv-browser"; + homeBackup = "${backupFolder}/mindcurv-browser"; + }; + cbase = { + home = "${homeFolder}/cbase-browser"; + homeBackup = "${backupFolder}/cbase-browser"; + }; + nz-browser = { + home = "${homeFolder}/nz-browser"; + homeBackup = "${backupFolder}/nz-browser"; + }; + + + firefox-tmp = { + browserType = "firefox"; + home = "${homeFolder}/firefox-tmp"; + homeBackup = "${backupFolder}/firefox-tmp-browser"; + }; + chromium-tmp = { + browserType = "chrome"; + home = "${homeFolder}/chromium-tmp"; + homeBackup = "${backupFolder}/chrome-tmp-browser"; + }; + google-tmp = { + browserType = "google"; + home = "${homeFolder}/google-tmp"; + homeBackup = "${backupFolder}google-tmp-browser"; + }; + + + }; + }; +} diff --git a/system/desktop/cachix.nix b/system/desktop/cachix.nix new file mode 100644 index 0000000..11d6e64 --- /dev/null +++ b/system/desktop/cachix.nix @@ -0,0 +1,12 @@ +# WARN: this file will get overwritten by $ cachix use +{ pkgs, lib, ... }: + +let + folder = ./cachix; + toImport = name: value: folder + ("/" + name); + filterCaches = key: value: value == "regular" && lib.hasSuffix ".nix" key; + imports = lib.mapAttrsToList toImport (lib.filterAttrs filterCaches (builtins.readDir folder)); +in { + inherit imports; + nix.binaryCaches = ["https://cache.nixos.org/"]; +} diff --git a/system/desktop/cachix/all-hies.nix b/system/desktop/cachix/all-hies.nix new file mode 100644 index 0000000..17818d6 --- /dev/null +++ b/system/desktop/cachix/all-hies.nix @@ -0,0 +1,11 @@ +{ + nix = { + binaryCaches = [ + "https://all-hies.cachix.org" + ]; + binaryCachePublicKeys = [ + "all-hies.cachix.org-1:JjrzAOEUsD9ZMt8fdFbzo3jNAyEWlPAwdVuHw4RD43k=" + ]; + + }; +} diff --git a/system/desktop/default.nix b/system/desktop/default.nix new file mode 100644 index 0000000..5c86b9b --- /dev/null +++ b/system/desktop/default.nix @@ -0,0 +1,76 @@ +{ config, pkgs, lib, ... }: +{ + + imports = [ + + + #./icecast.nix + ./audio.nix + ./browser.nix + ./cachix.nix + ./direnv.nix + ./dnsmasq.nix + ./encfs.nix + ./home-manager.nix + ./mail-stuff.nix + ./mc.nix + ./network.nix + ./packages.nix + ./pass.nix + ./remote-install.nix + ./restic.nix + ./size.nix + ./sshd.nix + ./suspend.nix + ./user.nix + ./x11.nix + ./xlock.nix + ./yubikey.nix + ]; + + programs.custom = { + + urxvt = { + enable = true; + colorTheme = "light"; + }; + xterm = { + enable = true; + colorTheme = "light"; + }; + + shellTools.enable = true; + taskwarrior.enable = true; + curlScripts.enable = true; + git.enable = true; + citate.enable = true; + vim.enable = true; + + q = { + enable = true; + timeZones = [ "Europe/Berlin" "Pacific/Auckland" ]; + }; + + }; + + services.urxvtd.enable = true; + + system.custom = { + bluetooth.enable = true; + }; + + # overwrite use zram on small RAM systems + fileSystems."/share/" = lib.mkDefault { + device = "tmpfs"; + fsType = "tmpfs"; + }; + + # overwrite use zram on small RAM systems + fileSystems."/browsers/" = lib.mkDefault { + device = "tmpfs"; + fsType = "tmpfs"; + }; + +} + + diff --git a/system/desktop/direnv.nix b/system/desktop/direnv.nix new file mode 100644 index 0000000..e5ae5b9 --- /dev/null +++ b/system/desktop/direnv.nix @@ -0,0 +1,15 @@ +{ config, pkgs, ... }: +{ + + environment.systemPackages = [ pkgs.direnv ]; + + home-manager.users.mainUser.programs.direnv.enable = true; + + programs.zsh.interactiveShellInit = '' + eval "$(${pkgs.direnv}/bin/direnv hook zsh)" + ''; + programs.bash.interactiveShellInit = '' + eval "$(${pkgs.direnv}/bin/direnv hook bash)" + ''; + +} diff --git a/system/desktop/dnsmasq.nix b/system/desktop/dnsmasq.nix new file mode 100644 index 0000000..fccf45c --- /dev/null +++ b/system/desktop/dnsmasq.nix @@ -0,0 +1,16 @@ +{ config, lib, pkgs, ... }: + +with lib; + +{ + services.dnsmasq = { + enable = true; + extraConfig = '' + ${concatStringsSep "\n" ( + flip mapAttrsToList config.module.cluster.services.tinc."private".hosts (name: attrs: + "address=/.${name}.private/${attrs.tincIp}" + ) + )} + ''; + }; +} diff --git a/system/desktop/encfs.nix b/system/desktop/encfs.nix new file mode 100644 index 0000000..ed0c696 --- /dev/null +++ b/system/desktop/encfs.nix @@ -0,0 +1,30 @@ +{ config, lib, pkgs, ... }: +{ + + module.backup.services.encfs = + let + mainUser = config.users.users.mainUser; + in { + "fotos" = { + user = mainUser.name; + bootDelay = 0; + keyFile = toString ; + encryptedFolder = "${mainUser.home}/private/.fotos.ct"; + decryptedFolder = "${mainUser.home}/fotos"; + }; + "desktop" = { + user = mainUser.name; + bootDelay = 0; + keyFile = toString ; + encryptedFolder = "${mainUser.home}/.desktop.ct"; + decryptedFolder = "${mainUser.home}/desktop"; + }; + "finance" = { + user = mainUser.name; + bootDelay = 0; + keyFile = toString ; + encryptedFolder = "${mainUser.home}/.finance.ct"; + decryptedFolder = "${mainUser.home}/finance"; + }; + }; +} diff --git a/system/desktop/home-manager.nix b/system/desktop/home-manager.nix new file mode 100644 index 0000000..5117c46 --- /dev/null +++ b/system/desktop/home-manager.nix @@ -0,0 +1,192 @@ +{ pkgs, lib, config, ... }: +with lib; +let + xmodmapConfig = pkgs.writeText "xmodmap" '' + ! + ! Swap Caps_Lock and Control_L + ! + + ! replace capslock keys with Escape Keys + ! remove Lock = Caps_Lock + clear Lock + add Lock = Scroll_Lock + + keysym Caps_Lock = Escape + + ! Set Right function Key to Windows-key + keycode 135 = Super_R NoSymbol Super_R NoSymbol Super_R + + ! Map umlauts to RIGHT ALT + + keycode 108 = Mode_switch + keysym e = e E EuroSign + keysym c = c C cent + keysym a = a A adiaeresis Adiaeresis + keysym o = o O odiaeresis Odiaeresis + keysym u = u U udiaeresis Udiaeresis + keysym s = s S ssharp + ''; +in +{ + + imports = [ + ./home-manager/spacemacs.nix + ./home-manager/spacevim.nix + ./home-manager/ssh.nix + ./home-manager/xmonad.nix + ]; + + home-manager.users.mainUser = { + + programs.git = { + enable = true; + userName = "Ingolf Wagner"; + userEmail = "contact@ingolf-wagner.de"; + signing = { + key = "42AC51C9482D0834CF488AF1389EC2D64AC71EAC"; + signByDefault = true; + }; + }; + + programs.gpg = { + enable = true; + settings = { + auto-key-locate = "local"; + keyid-format = "long"; + utf8-strings = ""; + verbose = ""; + with-fingerprint = ""; + keyserver = "hkp://pgp.mit.edu"; + personal-digest-preferences = "SHA512"; + cert-digest-algo = "SHA512"; + default-preference-list = "SHA512 SHA384 SHA256 SHA224 AES256 AES192 AES CAST5 ZLIB BZIP2 ZIP Uncompressed"; + }; + }; + + programs.htop = { + enable = true; + highlightBaseName = true; + treeView = true; + }; + + xdg.configFile."albert/albert.conf".text = '' + [General] + hotkey=Meta+Space + showTray=false + telemetry=false + terminal=urxvt -e + + [org.albert.extension.applications] + enabled=true + fuzzy=true + use_generic_name=true + use_keywords=true + + [org.albert.extension.calculator] + enabled=true + + [org.albert.extension.hashgenerator] + enabled=true + + [org.albert.frontend.widgetboxmodel] + alwaysOnTop=true + clearOnHide=false + displayIcons=true + displayScrollbar=false + displayShadow=false + hideOnClose=false + hideOnFocusLoss=true + itemCount=5 + showCentered=true + theme=SolarizedBrightViolet + ''; + + + xdg.configFile."Code/User/settings.json".text = builtins.toJSON { + "keyboard.dispatch" = "keyCode"; + "explorer.confirmDragAndDrop" = false; + "editor.tabSize" = 2; + "window.zoomLevel" = -1; + "git.enableSmartCommit" = true; + "files.autoSave" = "onFocusChange"; + "terminal.integrated.setLocaleVariables" = true; + "terminal.external.linuxExec" = "xterm"; + "explorer.confirmDelete" = false; + "todo-tree.tags" = [ "todo" "TODO" "fixme" "FIXME" ]; + "workbench.colorTheme" = "Solarized Light"; + }; + + xdg.configFile."mimeapps.list".text = '' + [Default Applications] + text/html=browser-select.desktop + x-scheme-handler/http=browser-select.desktop + x-scheme-handler/https=browser-select.desktop + x-scheme-handler/about=browser-select.desktop + x-scheme-handler/mailto=thunderbird.desktop; + x-scheme-handler/unknown=browser-select.desktop + image/png=sxiv.desktop + image/jpeg=sxiv.desktop + ''; + + home.file.".xprofile".text = + '' + # load keyboard mappings + ${pkgs.xorg.xmodmap}/bin/xmodmap ${xmodmapConfig} + + # to allow sudo commands to access X + # todo : only allow the browsers and rambox access + ${pkgs.xorg.xhost}/bin/xhost + + + # no shitty pcspkr crap + ${pkgs.xorg.xset}/bin/xset -b + + # no sleeping monitor + ${pkgs.xorg.xset}/bin/xset -dpms + ${pkgs.xorg.xset}/bin/xset s off + + ${pkgs.flameshot}/bin/flameshot & + + # cleanup xmonad + rm -f ~/.xmonad/xmonad.state + ''; + + }; + + environment.systemPackages = + let + library = import { inherit pkgs lib; }; + + fixKeyboard = pkgs.writeScriptBin "fix-Keyboard" /* sh */ '' + ${pkgs.xorg.xmodmap}/bin/xmodmap ${xmodmapConfig} + ''; + + fixXhost = pkgs.writeScriptBin "fix-xhost" /* sh */ '' + ${pkgs.xorg.xhost}/bin/xhost + &> /dev/null + ''; + + fixX = pkgs.writeScriptBin "fix-X" /* sh */ '' + + ${fixKeyboard}/bin/fix-Keyboard + + for file in `ls ~/.screenlayout` + do + echo $file + ~/.screenlayout/$file &> /dev/null + RETURN_CODE=$? + + if [[ $RETURN_CODE -eq 0 ]] + then + exit 0; + fi + + done + ''; + in + [ + fixX + fixXhost + (library.desktopFile fixX { longName = "fix X";}) + fixKeyboard + (library.desktopFile fixKeyboard { longName = "fix keyboard";}) + ]; + +} diff --git a/system/desktop/home-manager/spacemacs.nix b/system/desktop/home-manager/spacemacs.nix new file mode 100644 index 0000000..85ad8e5 --- /dev/null +++ b/system/desktop/home-manager/spacemacs.nix @@ -0,0 +1,228 @@ +{ pkgs, lib, config, ... }: +let + + user = "mainUser"; + userName = config.users.users.mainUser.name; + home = config.users.users.mainUser.home; + fontSize = config.programs.custom.urxvt.fontSize; + + startupBanner = pkgs.fetchurl{ + url = "https://github.com/NixOS/nixos-homepage/raw/master/logo/nix-wiki.png"; + sha256 = "1hrz7wr7i0b2bips60ygacbkmdzv466lsbxi22hycg42kv4m0173"; + }; + + ticks = "\"''\""; + + unstable = import {}; + +in +{ + + environment.systemPackages = [ + # needed for the SPC p g + pkgs.universal-ctags + pkgs.nodePackages.tern + unstable.emacs + ]; + + # download git repositories into the home folder + systemd.services = + let + clone = + repository: folder: branch: + { + enable = true; + wantedBy = [ "multi-user.target" ]; + description = "clone ${repository} to ${folder}"; + serviceConfig.User = userName; + unitConfig.ConditionPathExists = "!${folder}"; + script = '' + ${pkgs.git}/bin/git clone ${repository} --branch ${branch} ${folder} + ''; + }; + in + { + spacemacs-pull = clone "https://github.com/syl20bnr/spacemacs" "${home}/.emacs.d" "master"; + # todo move this to spacevim.nix + spacevim-pull = clone "https://github.com/SpaceVim/SpaceVim.git" "${home}/.SpaceVim" "master"; + }; + + home-manager.users."${user}" = { + + # a file which needs to be included at the end + home.file.".spacemacs.d/hook-init.el".text = '' + ;; -*- mode: emacs-lisp -*- + ;; just add (load "~/.spacemacs.d/hook-init.el") in your dotspacemacs/init function + + ;; overrides of dotspacemacs/init () + (setq + + ;; List of themes, the first of the list is loaded when spacemacs starts. + ;; Press T n to cycle to the next theme in the list (works great + ;; with 2 themes variants, one dark and one lixft:inconsolata:pixelsizeght) + dotspacemacs-themes '(solarized-light solarized-dark) + + ;; Specify the startup banner. Default value is `official', it displays + ;; the official spacemacs logo. An integer value is the index of text + ;; banner, `random' chooses a random text banner in `core/banners' + ;; directory. A string value must be a path to an image format supported + ;; by your Emacs build. + ;; If the value is nil then no banner is displayed. (default 'official) + dotspacemacs-startup-banner "${startupBanner}" + + ;; Default font, or prioritized list of fonts. `powerline-scale' allows to + ;; quickly tweak the mode-line size to make separators look not too crappy. + dotspacemacs-default-font '("Terminus" + :size ${toString fontSize} + :weight normal + :width normal + :powerline-scale 1.1) + + ) ;; eof + + + ''; + + home.file.".spacemacs.d/hook-layers.el".text = '' + ;; -*- mode: emacs-lisp -*- + ;; just add (load "~/.spacemacs.d/hook-layers.el") in your dotspacemacs/layers function + + (let + ((user-layers dotspacemacs-configuration-layers)) + (setq + dotspacemacs-configuration-layers + (append user-layers + '( python + ansible + rust + windows-scripts + javascript + typescript + html + yaml + auto-completion + git + markdown + restclient + emacs-lisp + nixos + spell-checking + syntax-checking + systemd + lua + terraform + graphviz + c-c++ + (haskell :variables + haskell-enable-hindent t + haskell-completion-backend 'lsp + haskell-enable-hindent-style "gibiansky" + haskell-process-type 'cabal-new-repl) + )))) + + (let + ((user-packages dotspacemacs-additional-packages )) + (setq + dotspacemacs-additional-packages + (append user-packages + '( lsp-mode + lsp-ui + lsp-haskell + direnv + )))) + ''; + + # a file which needs to be included at the end + home.file.".spacemacs.d/hook-user-config.el".text = '' + ;; -*- mode: emacs-lisp -*- + ;; just add (load "~/.spacemacs.d/hook-user-config.el") in your dotspacemacs/user-config function + + (let ((n 2)) + (setq coffee-tab-width n) + (setq javascript-indent-level n) + (setq js-indent-level n) + (setq js2-basic-offset n) + (setq web-mode-markup-indent-offset n) + (setq web-mode-css-indent-offset n) + (setq web-mode-code-indent-offset n) + (setq css-indent-offset n)) + + ;; configure indent function correctly + (add-hook 'nix-mode-hook + '(lambda () + (setq indent-tabs-mode nil) + (setq tab-width 2) + (setq indent-line-function (quote nix-indent-line)))) + + ;; lsp setup for haskell + ;; hie-wrapper must be configured in the direnv setup + ;; make sure cabal update was executed once on the machine + (setq lsp-haskell-process-path-hie "hie-wrapper") + (setq lsp-response-timeout 60) + (require 'lsp-haskell) + ;; (add-hook 'haskell-mode-hook #'lsp) + (add-hook 'haskell-mode-hook #'direnv-update-environment) + ''; + + + + home.file.".ctags.d/terraform.ctags".text = '' + --langdef=terraform + --langmap=terraform:.tf.tfvars + --regex-terraform=/^[[:space:]]*resource[[:space:]]*"([^"]*)"[[:space:]]*"([^"]*)"/\1.\2/r,Resource/ + --regex-terraform=/^[[:space:]]*data[[:space:]]*"([^"]*)"[[:space:]]*"([^"]*)"/\1.\2/d,Data/ + --regex-terraform=/^[[:space:]]*variable[[:space:]]*"([^"]*)"/\1/v,Variable/ + --regex-terraform=/^[[:space:]]*provider[[:space:]]*"([^"]*)"/\1/p,Provider/ + --regex-terraform=/^[[:space:]]*module[[:space:]]*"([^"]*)"/\1/m,Module/ + --regex-terraform=/^[[:space:]]*output[[:space:]]*"([^"]*)"/\1/o,Output/ + --regex-terraform=/^([a-z0-9_]+)[[:space:]]*=/\1/f,TFVar/ + ''; + + home.file.".spacemacs.d/old/polymode.el".text = '' + ;; not used at the moment + (define-hostmode poly-nix-hostmode + :mode 'nix-mode) + + (define-innermode poly-nix-lisp-metadata-innermode + :mode 'emacs-lisp-mode + :head-matcher (rx "/* lisp */" (one-or-more space) ${ticks} (zero-or-more space) line-end) + :tail-matcher (rx ${ticks} (zero-or-more space) ";" (zero-or-more space) line-end) + :head-mode 'host + :tail-mode 'host) + + (define-innermode poly-nix-shell-metadata-innermode + :mode 'shell-script-mode + :head-matcher (rx "/* sh */" (one-or-more space) ${ticks} (zero-or-more space) line-end) + :tail-matcher (rx ${ticks} (zero-or-more space) ";" (zero-or-more space) line-end) + :head-mode 'host + :tail-mode 'host) + + (define-innermode poly-nix-python-metadata-innermode + :mode 'python-mode + :head-matcher (rx "/* python */" (one-or-more space) ${ticks} (zero-or-more space) line-end) + :tail-matcher (rx ${ticks} (zero-or-more space) ";" (zero-or-more space) line-end) + :head-mode 'host + :tail-mode 'host) + + (define-innermode poly-nix-haskell-metadata-innermode + :mode 'haskell-mode + :head-matcher (rx "/* haskell */" (one-or-more space) ${ticks} (zero-or-more space) line-end) + :tail-matcher (rx ${ticks} (zero-or-more space) ";" (zero-or-more space) line-end) + :head-mode 'host + :tail-mode 'host) + + (define-polymode poly-nix-mode + :hostmode 'poly-nix-hostmode + :innermodes '(poly-nix-lisp-metadata-innermode + poly-nix-shell-metadata-innermode + poly-nix-haskell-metadata-innermode + poly-nix-python-metadata-innermode)) + + ;; remove nix-mode from auto load and replace it with poly-nix-mode + (setq auto-mode-alist (rassq-delete-all 'nix-mode auto-mode-alist)) + (add-to-list 'auto-mode-alist '("\\.nix\\'" . poly-nix-mode)) + ''; + + + }; +} diff --git a/system/desktop/home-manager/spacevim.nix b/system/desktop/home-manager/spacevim.nix new file mode 100644 index 0000000..ce3dc54 --- /dev/null +++ b/system/desktop/home-manager/spacevim.nix @@ -0,0 +1,39 @@ +{ lib, pkgs, ... }: +{ + environment.systemPackages = let + spacevimRepo = pkgs.fetchgit{ + url = "https://github.com/SpaceVim/SpaceVim.git"; + rev = "9b354e05b4716b645ba6366e1265a5048a0c23d5"; + sha256 = "1mn28hf857kp0jmbgd89cf5mk4dg53jcbqqrbr9zi3b854sa9ads"; + }; + + vimRc = pkgs.writeText "vimrc" '' + " search/grep case insensitive + :set ignorecase + + " tabs should always be 2 spaces + set et ts=2 sts=2 sw=2 + + " show Trailing Whitespaces + :set list listchars=tab:»·,trail:¶ + + " start spacevim + source ${spacevimRepo}/init.vim + + " configure command cross + "":hi CursorLine cterm=NONE ctermbg=0 guibg=#073642 + "":hi CursorColumn cterm=NONE ctermbg=0 guibg=#073642 + ""set cursorline + ""set cursorcolumn + + " disable noisy indentLine + let g:indentLine_enabled = 0 + ''; + in [ + + # vim + (pkgs.writers.writeDashBin "spacevim" '' + exec ${pkgs.neovim}/bin/nvim -u ${vimRc} "$@" + '') + ]; +} diff --git a/system/desktop/home-manager/ssh.nix b/system/desktop/home-manager/ssh.nix new file mode 100644 index 0000000..2653331 --- /dev/null +++ b/system/desktop/home-manager/ssh.nix @@ -0,0 +1,61 @@ +{ lib, ... }: +with lib; +{ + + home-manager.users.mainUser = { + programs.ssh.enable = true; + programs.ssh.matchBlocks = { + "lassul.us" = { + identityFile = "~/.ssh/card_rsa.pub"; + identitiesOnly = true; + user = "download"; + port = 45621; + }; + "*.private" = { + identityFile = "~/.ssh/card_rsa.pub"; + identitiesOnly = true; + extraOptions.HostKeyAlgorithms = "ssh-rsa"; + user = "root"; + }; + "*.ingolf-wagner.de" = { + identityFile = "~/.ssh/card_rsa.pub"; + identitiesOnly = true; + extraOptions.HostKeyAlgorithms = "ssh-rsa"; + user = "root"; + }; + "*.renoise.com" = { + identityFile = "~/.ssh/card_rsa.pub"; + identitiesOnly = true; + }; + "*.sononym.net" = { + identityFile = "~/.ssh/card_rsa.pub"; + identitiesOnly = true; + }; + "github.com" = { + identityFile = "~/.ssh/card_rsa.pub"; + identitiesOnly = true; + hostname = "ssh.github.com"; + user = "root"; + }; + "es5.siteground.eu" = { + identityFile = "~/.ssh/card_rsa.pub"; + identitiesOnly = true; + user = "ingolfwa"; + port = 18765; + }; + "bitbucket.org" = { + identityFile = "~/.ssh/card_rsa.pub"; + identitiesOnly = true; + }; + "static.247.134.201.195.clients.your-server.de" = { + identityFile = "~/.ssh/card_rsa.pub"; + identitiesOnly = true; + }; + "*.onion" = { + identityFile = "~/.ssh/card_rsa.pub"; + identitiesOnly = true; + user = "root"; + }; + }; + }; +} diff --git a/system/desktop/home-manager/xmonad.nix b/system/desktop/home-manager/xmonad.nix new file mode 100644 index 0000000..9a0230a --- /dev/null +++ b/system/desktop/home-manager/xmonad.nix @@ -0,0 +1,32 @@ +{ pkgs, lib, config, ... }: +let + + nixCommands = { height, width }: pkgs.writeText "NixCommands.hs" /* haskell */ '' + module NixCommands where + + nixStartIrc = "${pkgs.rxvt_unicode}/bin/urxvt -e irc" + nixStartAudacious = "${pkgs.audacious}/bin/audacious" + nixStartFlameshot = "${pkgs.flameshot}/bin/flameshot gui -p /share/" + nixInvertColors = "${pkgs.xcalib}/bin/xcalib -invert -alter" + nixStartRedshift = "${pkgs.redshift}/bin/redshift -O 6100 -g 0.9:0.9:0.9 -b 0.9" + nixResetRedshift = "${pkgs.redshift}/bin/redshift -x" + nixSetCursorImage = "${pkgs.xorg.xsetroot}/bin/xsetroot -cursor_name left_ptr" + nixSetBackground = "${pkgs.haskellPackages.image-generator}/bin/image-generator --height ${toString height} --width ${toString width} --output /dev/shm/background.png && ${pkgs.feh}/bin/feh --bg-scale /dev/shm/background.png" + nixStartAlbert = "${pkgs.albert}/bin/albert" + nixStartCopyq = "${pkgs.copyq}/bin/copyq" + nixStartTerminal = "${pkgs.rxvt_unicode_with-plugins}/bin/urxvtc" +''; +in { + + home-manager.users.mainUser = { + home.file.".xmonad/xmonad.hs".source = ./xmonad/Main.hs; + home.file.".xmonad/lib/NixCommands.hs".source = nixCommands { + height = config.configuration.desktop.height; + width = config.configuration.desktop.width; + }; + home.file.".xmonad/lib/SolarizedLight.hs".source = ./xmonad/SolarizedLight.hs; + home.file.".xmonad/lib/SolarizedDark.hs".source = ./xmonad/SolarizedDark.hs; + home.file.".xmonad/lib/FloatKeys.hs".source = ./xmonad/FloatKeys.hs; + home.file.".xmonad/lib/TabbedFix.hs".source = ./xmonad/TabbedFix.hs; + }; +} diff --git a/system/desktop/home-manager/xmonad/.envrc b/system/desktop/home-manager/xmonad/.envrc new file mode 100644 index 0000000..4134ad9 --- /dev/null +++ b/system/desktop/home-manager/xmonad/.envrc @@ -0,0 +1,4 @@ +use nix ./env.nix +use nix ./lsp.nix +use nix ./shell.nix + diff --git a/system/desktop/home-manager/xmonad/.gitignore b/system/desktop/home-manager/xmonad/.gitignore new file mode 100644 index 0000000..db30022 --- /dev/null +++ b/system/desktop/home-manager/xmonad/.gitignore @@ -0,0 +1,23 @@ +dist +dist-* +cabal-dev +*.o +*.hi +*.hie +*.chi +*.chs.h +*.dyn_o +*.dyn_hi +.hpc +.hsenv +.cabal-sandbox/ +cabal.sandbox.config +*.prof +*.aux +*.hp +*.eventlog +.stack-work/ +cabal.project.local +cabal.project.local~ +.HTF/ +.ghc.environment.* \ No newline at end of file diff --git a/system/desktop/home-manager/xmonad/FloatKeys.hs b/system/desktop/home-manager/xmonad/FloatKeys.hs new file mode 100644 index 0000000..8ae8309 --- /dev/null +++ b/system/desktop/home-manager/xmonad/FloatKeys.hs @@ -0,0 +1,127 @@ +----------------------------------------------------------------------------- +-- | +-- Module : XMonad.Actions.FloatKeys +-- Copyright : (c) Karsten Schoelzel +-- License : BSD +-- +-- Maintainer : Karsten Schoelzel +-- Stability : stable +-- Portability : unportable +-- +-- Move and resize floating windows. +----------------------------------------------------------------------------- + +module FloatKeys ( + -- * Usage + -- $usage + keysMoveWindow, + keysMoveWindowTo, + keysResizeWindow, + keysAbsResizeWindow) where + +import XMonad +import Control.Arrow ((***)) + +-- $usage +-- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@: +-- +-- > import XMonad.Actions.FloatKeys +-- +-- Then add appropriate key bindings, for example: +-- +-- > , ((modm, xK_d ), withFocused (keysResizeWindow (-10,-10) (1,1))) +-- > , ((modm, xK_s ), withFocused (keysResizeWindow (10,10) (1,1))) +-- > , ((modm .|. shiftMask, xK_d ), withFocused (keysAbsResizeWindow (-10,-10) (1024,752))) +-- > , ((modm .|. shiftMask, xK_s ), withFocused (keysAbsResizeWindow (10,10) (1024,752))) +-- > , ((modm, xK_a ), withFocused (keysMoveWindowTo (512,384) (1%2,1%2))) +-- +-- For detailed instructions on editing your key bindings, see +-- "XMonad.Doc.Extending#Editing_key_bindings". + +-- | @keysMoveWindow (dx, dy)@ moves the window by @dx@ pixels to the +-- right and @dy@ pixels down. +keysMoveWindow :: D -> Window -> X () +keysMoveWindow (dx,dy) w = whenX (isClient w) $ withDisplay $ \d -> do + io $ raiseWindow d w + wa <- io $ getWindowAttributes d w + io $ moveWindow d w (fromIntegral (fromIntegral (wa_x wa) + dx)) + (fromIntegral (fromIntegral (wa_y wa) + dy)) + float w + +-- | @keysMoveWindowTo (x, y) (gx, gy)@ moves the window relative +-- point @(gx, gy)@ to the point @(x,y)@, where @(gx,gy)@ gives a +-- position relative to the window border, i.e. @gx = 0@ is the left +-- border, @gx = 1@ is the right border, @gy = 0@ is the top border, and +-- @gy = 1@ the bottom border. +-- +-- For example, on a 1024x768 screen: +-- +-- > keysMoveWindowTo (512,384) (1%2, 1%2) -- center the window on screen +-- > keysMoveWindowTo (1024,0) (1, 0) -- put window in the top right corner +keysMoveWindowTo :: P -> G -> Window -> X () +keysMoveWindowTo (x,y) (gx, gy) w = whenX (isClient w) $ withDisplay $ \d -> do + io $ raiseWindow d w + wa <- io $ getWindowAttributes d w + io $ moveWindow d w (x - round (gx * fromIntegral (wa_width wa))) + (y - round (gy * fromIntegral (wa_height wa))) + float w + +type G = (Rational, Rational) +type P = (Position, Position) + +-- | @keysResizeWindow (dx, dy) (gx, gy)@ changes the width by @dx@ +-- and the height by @dy@, leaving the window-relative point @(gx, +-- gy)@ fixed. +-- +-- For example: +-- +-- > keysResizeWindow (10, 0) (0, 0) -- make the window 10 pixels larger to the right +-- > keysResizeWindow (10, 0) (0, 1%2) -- does the same, unless sizeHints are applied +-- > keysResizeWindow (10, 10) (1%2, 1%2) -- add 5 pixels on each side +-- > keysResizeWindow (-10, -10) (0, 1) -- shrink the window in direction of the bottom-left corner +keysResizeWindow :: D -> G -> Window -> X () +keysResizeWindow = keysMoveResize keysResizeWindow' + +-- | @keysAbsResizeWindow (dx, dy) (ax, ay)@ changes the width by @dx@ +-- and the height by @dy@, leaving the screen absolute point @(ax, +-- ay)@ fixed. +-- +-- For example: +-- +-- > keysAbsResizeWindow (10, 10) (0, 0) -- enlarge the window; if it is not in the top-left corner it will also be moved down and to the right. +keysAbsResizeWindow :: D -> D -> Window -> X () +keysAbsResizeWindow = keysMoveResize keysAbsResizeWindow' + +keysAbsResizeWindow' :: SizeHints -> P -> D -> D -> D -> (P,D) +keysAbsResizeWindow' sh (x,y) (w,h) (dx,dy) (ax, ay) = ((round nx, round ny), (nw, nh)) + where + (minw, minh) = maybe (10,10) ((***) (max 10) (max 10)) $ sh_min_size sh + (nw, nh) = if w + dx > minw && h + dy > minh then applySizeHintsContents sh (w + dx, h + dy) + else (w, h) + nx :: Rational + nx = fromIntegral (ax * w + nw * (fromIntegral x - ax)) / fromIntegral w + ny :: Rational + ny = fromIntegral (ay * h + nh * (fromIntegral y - ay)) / fromIntegral h + +keysResizeWindow' :: SizeHints -> P -> D -> D -> G -> (P,D) +keysResizeWindow' sh (x,y) (w,h) (dx,dy) (gx, gy) = ((nx, ny), (nw, nh)) + where + -- Prevent shrinking a window too small and getting one's foot shot + (minw, minh) = maybe (10,10) ((***) (max 10) (max 10)) $ sh_min_size sh + (nw, nh) = if w + dx > minw && h + dy > minh then applySizeHintsContents sh (w + dx, h + dy) + else (w, h) + nx = round $ fromIntegral x + gx * fromIntegral w - gx * fromIntegral nw + ny = round $ fromIntegral y + gy * fromIntegral h - gy * fromIntegral nh + +keysMoveResize :: (SizeHints -> P -> D -> a -> b -> (P,D)) -> a -> b -> Window -> X () +keysMoveResize f move resize w = whenX (isClient w) $ withDisplay $ \d -> do + io $ raiseWindow d w + wa <- io $ getWindowAttributes d w + sh' <- io $ getWMNormalHints d w + let sh = sh' {sh_resize_inc = Nothing, sh_aspect = Nothing} + wa_dim = (fromIntegral $ wa_width wa, fromIntegral $ wa_height wa) + wa_pos = (fromIntegral $ wa_x wa, fromIntegral $ wa_y wa) + (wn_pos, wn_dim) = f sh wa_pos wa_dim move resize + io $ resizeWindow d w `uncurry` wn_dim + io $ moveWindow d w `uncurry` wn_pos + float w diff --git a/system/desktop/home-manager/xmonad/LICENSE b/system/desktop/home-manager/xmonad/LICENSE new file mode 100644 index 0000000..45644ff --- /dev/null +++ b/system/desktop/home-manager/xmonad/LICENSE @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/system/desktop/home-manager/xmonad/Main.hs b/system/desktop/home-manager/xmonad/Main.hs new file mode 100644 index 0000000..9901c0d --- /dev/null +++ b/system/desktop/home-manager/xmonad/Main.hs @@ -0,0 +1,525 @@ +{-# LANGUAGE FlexibleContexts #-} + +module Main where + + +import qualified Data.Map as M +import Data.Monoid (All, Endo) +import Data.Ratio ((%)) +import FloatKeys (keysResizeWindow) +import NixCommands +import qualified SolarizedLight as Solarized +import System.Exit +import XMonad +import XMonad.Actions.CopyWindow (copy, copyToAll, kill1, + killAllOtherCopies, + wsContainingCopies) +import XMonad.Actions.CycleWS (toggleWS') +import XMonad.Actions.DynamicProjects (Project (..), + dynamicProjects) +import XMonad.Actions.DynamicWorkspaces (addHiddenWorkspace, removeEmptyWorkspaceAfterExcept, + renameWorkspace, + withWorkspace) +import XMonad.Actions.UpdatePointer (updatePointer) +import XMonad.Actions.Warp (warpToScreen) +import XMonad.Hooks.DynamicLog (PP (..), dynamicLog, shorten, + statusBar, wrap) +import XMonad.Hooks.ManageHelpers (doCenterFloat) +import XMonad.Hooks.SetWMName (setWMName) +import XMonad.Hooks.UrgencyHook (BorderUrgencyHook (..), + SpawnUrgencyHook (..), + withUrgencyHook) +import XMonad.Layout.BoringWindows (boringWindows, clearBoring, + focusDown, focusUp, + markBoring) +import XMonad.Layout.Mosaic (Aspect (Reset), mosaic) +import XMonad.Layout.NoBorders (noBorders, smartBorders) +import XMonad.Layout.ResizableTile (MirrorResize (MirrorExpand, MirrorShrink), + ResizableTall (..)) +import XMonad.Layout.Simplest (Simplest (..)) +import XMonad.Layout.SubLayouts (GroupMsg (..), onGroup, + pullGroup, subLayout, + subTabbed) +import XMonad.Layout.Tabbed (TabbedDecoration, addTabs, + addTabsAlways, shrinkText) +import XMonad.Layout.WindowNavigation (configurableNavigation, + noNavigateBorders) +import XMonad.Prompt (XPConfig (..)) +import qualified XMonad.StackSet as W +import XMonad.Util.EZConfig (additionalKeysP) +import XMonad.Util.Scratchpad (scratchpadManageHook, + scratchpadSpawnAction) +import XMonad.Util.SpawnOnce (spawnOnce) +import XMonad.Util.Types (Direction2D (D, L, R, U)) + +import TabbedFix (historyLayout, runAllPending) +import XMonad.Layout.StateFull (focusTracking) + +-- only needed to retrigger a build +import XMonad.Layout.DwmStyle + +------------------------------------------------------------------------ +-- +-- Layouts +-- +------------------------------------------------------------------------ + +selectionColor :: String +selectionColor = Solarized.violet + +nonSelectionColor :: String +nonSelectionColor = Solarized.base02 + + +-- http://hackage.haskell.org/package/xmonad-contrib-0.15/docs/XMonad-Layout-Tabbed.html#t:Theme + +-- todo : when there is only one window there should not be a decoration bar, when there are 2 there should be a decoration bar +-- ResizableTall is same as Tall but has resizable rightside window +myLayout = (windowConfiguration $ myTabbed $ mySubLayout $ boringWindows resizeableTall) ||| noBorders Full +-- needed for rebuild sometimes +-- myLayout = dwmStyle shrinkText def ( layoutHook def ) ||| noBorders Full + where + resizeableTall = ResizableTall nmaster delta ratio [] + -- The default number of windows in the master pane + nmaster = 1 + -- Default proportion of screen occupied by master pane + ratio = 12 / 20 + -- Percent of screen to increment by when resizing panes + delta = 3 / 100 + + windowConfiguration = configurableNavigation noNavigateBorders + + myTabbed x = smartBorders $ addTabsAlways shrinkText tabDecoration x + + mySubLayout x = subLayout [] Simplest x + + tabDecoration = def { activeColor = selectionColor + , activeBorderColor = selectionColor + , activeTextColor = Solarized.base03 + , inactiveColor = nonSelectionColor + , inactiveBorderColor = nonSelectionColor + , inactiveTextColor = Solarized.base0 + , fontName = "-*-terminus-medium-*-*-*-10101010-*-*-*-*-*-*-*" + , decoHeight = 11 + } + + +-- ------------------------------------------------------------ +-- +-- predefined workspaces +-- +-- ------------------------------------------------------------ +-- default workspaces they will always be there. +-- And they are protected against renaming +myWorkspaces :: [String] +myWorkspaces = ["1", "2", "3", "4"] + +-- workspaces names to be used only by one program, partly spawning on startup. +autoSpawnWorkspaces = [ "-copyq" ] + +-- theses workspaces should not be removed by the workspace +-- switch commands +nonRemovableWorkspaces = myWorkspaces ++ autoSpawnWorkspaces + +-- projects +-- named workspaces with predefined behavior +projects :: [Project] +projects = + [ Project { projectName = "chat" + , projectDirectory = "~/" + , projectStartHook = Just $ do spawn nixStartIrc + } + , Project { projectName = "audio" + , projectDirectory = "~/music-library" + , projectStartHook = Just $ do spawn nixStartAudacious + } + , Project { projectName = "nixos" + , projectDirectory = "~/dev/krops" + , projectStartHook = Nothing + } + ] + +-- ------------------------------------------------------------ +-- +-- key definitions +-- +-- ------------------------------------------------------------ +myKeys :: XConfig Layout -> M.Map (ButtonMask, KeySym) (X ()) +myKeys XConfig {modMask = modm} = + M.fromList $ + -- ------------------------------------------------------------ + -- + -- predefined workspaces + -- + -- ------------------------------------------------------------ + -- + -- mod-[1..9], Switch to workspace N + [ ( (m .|. modm, k) + , removeEmptyWorkspaceAfterExcept nonRemovableWorkspaces $ windows $ f i) + | (i, k) <- zip myWorkspaces [xK_1 .. xK_9] + , (f, m) <- [(W.greedyView, 0)] + ] ++ + -- mod--[1..9] move window to workspace N + -- mod--[1..9] copy window to workspace N + [ ((m .|. modm, k), windows $ f i) + | (i, k) <- zip myWorkspaces [xK_1 .. xK_9] + , (f, m) <- [(W.shift, shiftMask), (copy, controlMask)] + ] + +-- ------------------------------------------------------------ +-- +-- select next Screen/Monitor. +-- (works for 2 and 1 monitor, but might also work for more) +-- +-- ------------------------------------------------------------ +selectNextScreen :: X () +selectNextScreen = do + W.StackSet {W.current = current, W.visible = visible} <- gets windowset + warpToScreen (nextScreen current visible) (1 % 2) (1 % 2) + where + nextScreen current [] = W.screen current + nextScreen _ (x:_) = W.screen x + +isFloat :: Window -> X Bool +isFloat w = gets windowset >>= \ws -> return (M.member w $ W.floating ws) + +-- | add different shortcuts for different type +-- of situation. Floating or Tiling +floatTileCommand :: X () -> X () -> Window -> X () +floatTileCommand forFloating forTileing window = do + floating <- isFloat window + if floating + then forFloating + else forTileing + +toggleFloating :: W.RationalRect -> Window -> X () +toggleFloating position = + floatTileCommand + (withFocused (windows . W.sink)) + (withFocused (windows . (`W.float` position))) + +multiKeys [] = [] +multiKeys ((key, command):xs) = (createMultiKey key command) ++ multiKeys xs + where + createMultiKey keyString command = + [("M4-" ++ keyString, command), ("M4-z " ++ keyString, command)] + +myAdditionaKeys :: [(String, X ())] +myAdditionaKeys + -- ------------------------------------------------------------ + -- + -- dynamic workspaces + -- + -- ------------------------------------------------------------ + -- switch to workspace + = + (multiKeys + [ ( "`" + , removeEmptyWorkspaceAfterExcept nonRemovableWorkspaces $ + withWorkspace autoXPConfig (windows . W.greedyView)) + -- move focused window to workspace + , ("S-", withWorkspace myXPConfig (windows . W.shift)) + -- copy focused window to workspace + , ("C-", withWorkspace myXPConfig (windows . copy)) + -- make windows "sticky" by copy and remove them to and from all other windows + , ( "s" + , do copies <- wsContainingCopies + if not (null copies) + then do killAllOtherCopies + clearBoring + else do windows copyToAll + markBoring) + -- rename workspace but make sure myWorkspaces still exist + , ( "r" + , do renameWorkspace myXPConfig + sequence_ [addHiddenWorkspace ws | ws <- myWorkspaces]) + , ("", toggleWS' ["NSP"]) + ]) ++ + -- ------------------------------------------------------------ + -- + -- launch applications + -- + -- ------------------------------------------------------------ + (multiKeys + -- launch a terminal + [ ("", spawn $ XMonad.terminal defaults) + , ("q", kill1) + -- open scratchpad + , ("-", scratchpadSpawnAction defaults) + ]) ++ + [ ( "" + -- create screenshot + , spawn nixStartFlameshot) + -- invert color for bright or dark days + , ("", spawn nixInvertColors) + ] ++ + -- ------------------------------------------------------------ + -- + -- Window and Layout + -- + -- ------------------------------------------------------------ + (multiKeys + [ + -- remove window from tabbed group + ("i", withFocused (sendMessage . UnMerge)) + -- merge with left window + , ("", sendMessage $ pullGroup L) + , ("S-", sendMessage $ pullGroup L) + -- merge with right window + , ("", sendMessage $ pullGroup R) + , ("S-", sendMessage $ pullGroup R) + -- merge with upper window + , ("", sendMessage $ pullGroup U) + , ("S-", sendMessage $ pullGroup U) + -- merge with lower window + , ("", sendMessage $ pullGroup D) + , ("S-", sendMessage $ pullGroup D) + -- Change the selection in the tabbed Subgroup + , ("o", onGroup W.focusDown') + + -- Move focus to the next window + , ("j", do sendMessage FirstLayout + focusDown) + -- Move focus to the previous window + , ("k", do sendMessage FirstLayout + focusUp) + -- Swap the focused window and the master window + , ("", windows W.swapMaster) + -- Swap the focused window with the next window + , ("S-j", do sendMessage FirstLayout + windows W.swapDown) + -- Swap the focused window with the previous window + , ("S-k", do sendMessage FirstLayout + windows W.swapUp) + -- Rotate through the available layout algorithms + , ("f", sendMessage NextLayout) + -- Shrink the current area + -- Shrink the master area + , ( "h" + , withFocused $ + floatTileCommand + (withFocused (keysResizeWindow (10, 0) (1, 1 % 2))) + (do sendMessage Shrink + sendMessage Reset)) + -- Expand the master area + , ( "l" + , withFocused $ + floatTileCommand + (withFocused (keysResizeWindow (-10, 0) (1, 1 % 2))) + (do sendMessage Expand + sendMessage Reset)) + -- Expand the current area + , ( "S-l" + , withFocused $ + floatTileCommand + (withFocused (keysResizeWindow (0, -10) (1 % 2, 1))) + (do sendMessage MirrorExpand + sendMessage Reset)) + , ( "S-h" + , withFocused $ + floatTileCommand + (withFocused (keysResizeWindow (0, 10) (1 % 2, 1))) + (do sendMessage MirrorShrink + sendMessage Reset)) + -- Toggle window tiling/floating + , ("t", withFocused $ toggleFloating (W.RationalRect 0.65 0.65 0.35 0.35)) + -- Increment the number of windows in the master area + , (",", sendMessage (IncMasterN 1)) + -- Deincrement the number of windows in the master area + , (".", sendMessage (IncMasterN (-1))) + ]) ++ + -- ------------------------------------------------------------ + -- + -- Xmonad Commands + -- + -- ------------------------------------------------------------ + -- Quit xmonad + (multiKeys + [ ("S-q", io exitSuccess) + -- restart xmonad + , ("S-r", spawn "xmonad --recompile; xmonad --restart") + -- select next screen/monitor + , ("", selectNextScreen) + -- move window next screen/monitor + -- , ("M4-S-", moveWindowToNextScreen) + ]) ++ + -- ------------------------------------------------------------ + -- + -- Volume Control + -- + -- ------------------------------------------------------------ + [ ("", spawn "amixer set Master 5%+") + , ("", spawn "amixer set Master 5%-") + , ("", spawn "amixer set Master toggle") + ] ++ + -- ------------------------------------------------------------ + -- + -- Redshift + -- + -- ------------------------------------------------------------ + [ ("M4-", spawn nixStartRedshift) + , ("M4-", spawn nixResetRedshift) + + ] + +------------------------------------------------------------------------ +-- Mouse bindings: default actions bound to mouse events +-- +mouse :: XConfig t -> M.Map (KeyMask, Button) (Window -> X ()) +-- mouse _ = M.empty +mouse XConfig {XMonad.modMask = modm} = + M.fromList + -- mod-button1, Set the window to floating mode and move by dragging + [ ( (modm, button1) + , \w -> do + focus w + mouseMoveWindow w + windows W.shiftMaster) + -- mod-button2, Raise the window to the top of the stack + , ( (modm, button2) + , \w -> do + focus w + windows W.shiftMaster) + -- mod-button3, Set the window to floating mode and resize by dragging + , ( (modm, button3) + , \w -> do + focus w + mouseResizeWindow w + windows W.shiftMaster) + -- you may also bind events to the mouse scroll wheel (button4 and button5) + ] + + + +------------------------------------------------------------------------ +-- Window rules: +-- Execute arbitrary actions and WindowSet manipulations when managing +-- a new window. You can use this to, for example, always float a +-- particular program, or have a client always appear on a particular +-- workspace. +-- +-- To find the property name associated with a program, use +-- > xprop | grep WM_CLASS +-- and click on the client you're interested in. +-- +-- To match on the WM_NAME, you can use 'title' in the same way that +-- 'className' and 'resource' are used below. +-- +myManageHook :: Query (Endo WindowSet) +myManageHook = + composeAll + [ className =? "Gimp" --> doFloat + , title =? "fzfmenu" --> doCenterFloat + , resource =? "copyq" --> doShift "-copyq" + , scratchpadManageHook + (W.RationalRect + -- | percentage distance from left + 0.2 + -- | percentage distance from top + 0.2 + -- | width + 0.6 + -- | height + 0.6) + ] + +------------------------------------------------------------------------ +-- Event handling +-- * EwmhDesktops users should change this to ewmhDesktopsEventHook +-- +-- Defines a custom handler function for X Events. The function should +-- return (All True) if the default handler is to be run afterwards. To +-- combine event hooks use mappend or mconcat from Data.Monoid. +-- +myEventHook :: Event -> X All +myEventHook = mempty + +------------------------------------------------------------------------ +-- Status bars and logging +-- Perform an arbitrary action on each internal state change or X event. +-- See the 'XMonad.Hooks.DynamicLog' extension for examples. +-- +myLogHook :: X () +myLogHook = do + dynamicLog + -- make sure the pointer always follows the focused window, when we use shortcuts + updatePointer (0.5, 0.5) (0, 0) + +------------------------------------------------------------------------ +-- Startup hook +-- Perform an arbitrary action each time xmonad starts or is restarted +-- with mod-q. Used by, e.g., XMonad.Layout.PerWorkspace to initialize +-- per-workspace layout choices. +-- +-- By default, do nothing. +startUp :: X () +startUp + -- java fix + = do + setWMName "LG3D" + spawn nixSetCursorImage + spawn nixSetBackground + spawn nixStartAlbert + spawnOnce nixStartCopyq + + +------------------------------------------------------------------------ +-- Now run xmonad with all the defaults we set up. +-- Run xmonad with the settings you specify. No need to modify this. +-- +main :: IO () +main = do + xmonad $ withUrgencyHook (SpawnUrgencyHook "echo emit Urgency ") $ dynamicProjects projects $ defaults + +myTerm :: FilePath +myTerm = nixStartTerminal + +-- A structure containing your configuration settings, overriding +-- fields in the default config. Any you don't override, will +-- use the defaults defined in xmonad/XMonad/Config.hs +-- +-- No need to modify this. +-- +defaults = + def + { terminal = myTerm + + -- Whether focus follows the mouse pointer. + , focusFollowsMouse = True + -- Whether clicking on a window to focus also passes the click to the window + , clickJustFocuses = False + + -- color configuration + , normalBorderColor = nonSelectionColor + , focusedBorderColor = selectionColor + , borderWidth = 1 + + -- modMask lets you specify which modkey you want to use. + -- mod1Mask ("left alt"). + -- mod3Mask ("right alt") + -- mod4Mask ("windows key") + , modMask = mod4Mask + , workspaces = nonRemovableWorkspaces + -- key bindings + , keys = myKeys + , mouseBindings = mouse + -- hooks, layouts + , layoutHook = focusTracking $ historyLayout myLayout + , manageHook = myManageHook + , handleEventHook = myEventHook + , logHook = myLogHook <> runAllPending + , startupHook = startUp + } `additionalKeysP` + myAdditionaKeys + +autoXPConfig :: XPConfig +autoXPConfig = myXPConfig {autoComplete = Just 5000} + +myXPConfig :: XPConfig +myXPConfig = + def + { bgColor = Solarized.base03 + , fgColor = Solarized.base0 + , promptBorderWidth = 0 + , font = "xft:inconsolata:pixelsize=18:antialias=true:hinting=true" + } diff --git a/system/desktop/home-manager/xmonad/NixCommands.hs b/system/desktop/home-manager/xmonad/NixCommands.hs new file mode 100644 index 0000000..a4ae014 --- /dev/null +++ b/system/desktop/home-manager/xmonad/NixCommands.hs @@ -0,0 +1,15 @@ +-- this is just a dummy and will not be used + +module NixCommands where + +nixStartIrc = "" +nixStartAudacious = "" +nixStartFlameshot = "" +nixInvertColors = "" +nixStartRedshift = "" +nixResetRedshift = "" +nixSetCursorImage = "" +nixSetBackground = "" +nixStartAlbert = "" +nixStartCopyq = "" +nixStartTerminal = "" diff --git a/system/desktop/home-manager/xmonad/Setup.hs b/system/desktop/home-manager/xmonad/Setup.hs new file mode 100644 index 0000000..23bdd9c --- /dev/null +++ b/system/desktop/home-manager/xmonad/Setup.hs @@ -0,0 +1,3 @@ +-- this is only here to satisfy my haskell mode +import Distribution.Simple +main = defaultMain diff --git a/system/desktop/home-manager/xmonad/SolarizedDark.hs b/system/desktop/home-manager/xmonad/SolarizedDark.hs new file mode 100644 index 0000000..cabf5ac --- /dev/null +++ b/system/desktop/home-manager/xmonad/SolarizedDark.hs @@ -0,0 +1,49 @@ +module SolarizedDark where + +base0 :: String +base0 = "#839496" + +base00 :: String +base00 = "#657b83" + +base01 :: String +base01 = "#586e75" + +base02 :: String +base02 = "#073642" + +base03 :: String +base03 = "#002b36" + +base1 :: String +base1 = "#93a1a1" + +base2 :: String +base2 = "#eee8d5" + +base3 :: String +base3 = "#fdf6e3" + +blue :: String +blue = "#268bd2" + +cyan :: String +cyan = "#2aa198" + +green :: String +green = "#859900" + +magenta :: String +magenta = "#d33682" + +orange :: String +orange = "#cb4b16" + +red :: String +red = "#dc322f" + +violet :: String +violet = "#6c71c4" + +yellow :: String +yellow = "#b58900" diff --git a/system/desktop/home-manager/xmonad/SolarizedLight.hs b/system/desktop/home-manager/xmonad/SolarizedLight.hs new file mode 100644 index 0000000..f942ec3 --- /dev/null +++ b/system/desktop/home-manager/xmonad/SolarizedLight.hs @@ -0,0 +1,49 @@ +module SolarizedLight where + +blue :: String +blue = "#268bd2" + +cyan :: String +cyan = "#2aa198" + +green :: String +green = "#859900" + +magenta :: String +magenta = "#d33682" + +orange :: String +orange = "#cb4b16" + +red :: String +red = "#dc322f" + +violet :: String +violet = "#6c71c4" + +yellow :: String +yellow = "#b58900" + +base0 :: String +base0 = "#657b83" + +base00 :: String +base00 = "#839496" + +base01 :: String +base01 = "#93a1a1" + +base02 :: String +base02 = "#eee8d5" + +base03 :: String +base03 = "#fdf6e3" + +base1 :: String +base1 = "#586e75" + +base2 :: String +base2 = "#073642" + +base3 :: String +base3 = "#002b36" diff --git a/system/desktop/home-manager/xmonad/TabbedFix.hs b/system/desktop/home-manager/xmonad/TabbedFix.hs new file mode 100644 index 0000000..239a409 --- /dev/null +++ b/system/desktop/home-manager/xmonad/TabbedFix.hs @@ -0,0 +1,103 @@ +-- A fix to refocus windows in a sublayout +-- copied and manipulated from https://github.com/wz1000/xmonad-config/blob/master/xmonad.hs +-- thx wz1000 + +{-# LANGUAGE TypeSynonymInstances #-} +{-# LANGUAGE MultiParamTypeClasses #-} + +module TabbedFix (historyLayout, runAllPending) where + +import XMonad +import qualified XMonad.StackSet as W +import qualified Data.List as L +import qualified XMonad.Util.ExtensibleState as ES +import Control.DeepSeq (force) +import XMonad.Layout.LayoutModifier (LayoutModifier, ModifiedLayout(ModifiedLayout), modifyLayout) + +newtype PendingActions = PendingActions { getPending :: [X()] } +instance ExtensionClass PendingActions where + initialValue = PendingActions [] + + +-- Add action to stack +addAction :: X () -> X () +addAction x = ES.modify (\(PendingActions xs) -> PendingActions (x:xs)) + +runAllPending :: X () +runAllPending = do + PendingActions actions <- ES.get + ES.put (PendingActions []) + sequence_ actions + +newtype FocusHistory = FocusHistory { + getFocusHistory :: [Window] + } deriving (Read, Show, Typeable) + +instance ExtensionClass FocusHistory where + initialValue = FocusHistory [] + extensionType = PersistentExtension + +data FocusLayout a = FocusLayout deriving (Read,Show,Typeable) + +historyLayout :: l Window -> ModifiedLayout FocusLayout l Window +historyLayout = ModifiedLayout FocusLayout + +instance LayoutModifier FocusLayout Window where + modifyLayout fh ws rct = do + wold <- getFocused + history <- getFocusHistory <$> ES.get + wnew <- windowHistoryHook wold + case wnew of + Nothing -> runLayout ws rct + Just w -> do + let oldstack = W.stack ws + let mw = L.find (`elem` W.integrate' oldstack) history + let newstack = if (w `elem` (W.integrate' oldstack)) + then until ((w==) . W.focus) W.focusUp' <$> oldstack + else case mw of + Just w -> until ((w==) . W.focus) W.focusUp' <$> oldstack + Nothing -> oldstack + modifyWindowSet (W.focusWindow w) + addAction $ do + maybe (return ()) makeBorderNormal wold + windows id + runLayout ws{W.stack = newstack} rct + +windowHistoryHook Nothing = return Nothing +windowHistoryHook (Just w) = do + hist <- getFocusHistory <$> ES.get + curws <- gets $ W.index . windowset + withWindowSet $ \allws -> + case hist of + [] -> do + ES.put $ FocusHistory[w] + return Nothing + (prev:xs) + | prev == w -> return Nothing + -- Previous focus was removed from ws, focus on previous existing window in current ws + | not (prev `elem` curws) -> do + let hist' = filter (`W.member` allws) xs + ES.put (FocusHistory $ force $ hist') + return $ L.find (\x -> x `elem` curws ) hist' + -- Add current focus to history + | otherwise -> do + ES.put $ FocusHistory $ force $ (w:L.delete w hist) + return Nothing + +makeBorderRed :: Window -> X () +makeBorderRed w = + withDisplay $ \d -> io $ do + setWindowBorder d w 0xff0000 + +-- wz1000: palo: btw, you will need to change the color in makeBorderNormal to your unfocused border color +makeBorderNormal w = + withDisplay $ \d -> io $ do + setWindowBorder d w 0x2b2b2b + +makeBorderFocused w = + withDisplay $ \d -> io $ do + setWindowBorder d w 0xcccccc + + +getFocused :: X (Maybe Window) +getFocused = withWindowSet (return . W.peek) diff --git a/system/desktop/home-manager/xmonad/current-project.nix b/system/desktop/home-manager/xmonad/current-project.nix new file mode 100644 index 0000000..33755ba --- /dev/null +++ b/system/desktop/home-manager/xmonad/current-project.nix @@ -0,0 +1,15 @@ +# created by cabal2nix +{ mkDerivation, base, deepseq, stdenv, xmonad, xmonad-contrib +, xmonad-extras +}: +mkDerivation { + pname = "palos-xmonad"; + version = "0.1.0.0"; + src = ./.; + isLibrary = false; + isExecutable = true; + executableHaskellDepends = [ + base deepseq xmonad xmonad-contrib xmonad-extras + ]; + license = stdenv.lib.licenses.gpl3; +} diff --git a/system/desktop/home-manager/xmonad/env.nix b/system/desktop/home-manager/xmonad/env.nix new file mode 100644 index 0000000..0953c8b --- /dev/null +++ b/system/desktop/home-manager/xmonad/env.nix @@ -0,0 +1,11 @@ +{ pkgs ? import { + overlays = [ + (self: super: { + haskellPackages = super.haskellPackages.override { + overrides = self: super: { + current-project = super.callPackage ./current-project.nix { }; + }; + }; + })]; +}}: +pkgs.haskellPackages.current-project.env diff --git a/system/desktop/home-manager/xmonad/lsp.nix b/system/desktop/home-manager/xmonad/lsp.nix new file mode 100644 index 0000000..283900f --- /dev/null +++ b/system/desktop/home-manager/xmonad/lsp.nix @@ -0,0 +1,13 @@ +{ pkgs ? import {} }: +let + all-hies = import (fetchTarball "https://github.com/infinisil/all-hies/tarball/master") {}; +in +pkgs.mkShell { + buildInputs = with pkgs; [ + haskellPackages.hoogle + haskellPackages.hindent + haskellPackages.hlint + haskellPackages.stylish-haskell + #(all-hies.selection { selector = p: {inherit (p) ghc864; }; }) + ]; +} diff --git a/system/desktop/home-manager/xmonad/palos-xmonad.cabal b/system/desktop/home-manager/xmonad/palos-xmonad.cabal new file mode 100644 index 0000000..682dd63 --- /dev/null +++ b/system/desktop/home-manager/xmonad/palos-xmonad.cabal @@ -0,0 +1,22 @@ +-- this is only here to satisfy my haskell mode in emacs + +cabal-version: 2.4 +name: palos-xmonad +version: 0.1.0.0 +license: GPL-3.0-only +license-file: LICENSE +author: Ingolf Wagner +maintainer: contact@ingolf-wagner.de +category: Graphics +extra-source-files: CHANGELOG.md + +executable palos-xmonad + main-is: Main.hs + -- other-modules: + other-extensions: TypeSynonymInstances, MultiParamTypeClasses + build-depends: base + , xmonad + , deepseq + , xmonad-contrib + , xmonad-extras + default-language: Haskell2010 diff --git a/system/desktop/home-manager/xmonad/shell.nix b/system/desktop/home-manager/xmonad/shell.nix new file mode 100644 index 0000000..95fd70f --- /dev/null +++ b/system/desktop/home-manager/xmonad/shell.nix @@ -0,0 +1,14 @@ +{ pkgs ? import {} }: +let + updateCabal = pkgs.writeShellScriptBin "update-cabal" /* sh */ '' + cd ${toString ./.} + echo "# created by cabal2nix " > ${toString ./.}/current-project.nix + ${pkgs.cabal2nix}/bin/cabal2nix . >> ${toString ./.}/current-project.nix + ''; +in +pkgs.mkShell { + buildInputs = with pkgs; [ + updateCabal + cabal2nix + ]; +} diff --git a/system/desktop/icecast.nix b/system/desktop/icecast.nix new file mode 100644 index 0000000..ef6ed92 --- /dev/null +++ b/system/desktop/icecast.nix @@ -0,0 +1,61 @@ +# -------------------------------------------------- +# How to use? +# * start the icecast +# * connect via mixxx to it. +# * add the podcast to mpd in the same network +# -------------------------------------------------- + +{ pkgs, config, lib, ... }: + +let + user = "username"; + password = "password"; + mountPoint = "/radio.mp3"; + maxListeners = 20; +in + +{ + + services.icecast = { + enable = true; + hostname = config.networking.hostName; + admin = { + user = "palo"; + password = "palo"; + }; + # http://icecast.org/docs/icecast-2.4.1/config-file.html + extraConf = '' + + ${mountPoint} + ${user} + ${password} + ${toString maxListeners} + 3600 + UTF8 + 1 + Palos Awesome Stream + Kick ass Tracks + https://ingolf-wagner.de + classical + 320 + application/ogg + vorbis + 1 + 65536 + 4096 + + ''; + }; + + # use port which I can see in iptable -L -v -n + networking.firewall = { + allowedTCPPorts = [ config.services.icecast.listen.port ]; + allowedUDPPorts = [ config.services.icecast.listen.port ]; + }; + + # don't want to have the service running all the time + # --------------------------------------------------- + systemd.services.icecast.wantedBy = lib.mkForce []; + systemd.services.icecast.after = lib.mkForce []; + +} diff --git a/system/desktop/mail-stuff.nix b/system/desktop/mail-stuff.nix new file mode 100644 index 0000000..70c9802 --- /dev/null +++ b/system/desktop/mail-stuff.nix @@ -0,0 +1,375 @@ +{ config, pkgs, lib, ... }: +let + passcmd = id: "${pkgs.pass}/bin/pass ${id}"; + ticks = "''"; +in +{ + # Maildir <-> Server communication + # -------------------------------- + # mbsync: MailDir <-> IMAP + # msmtp: sendmail interface sending mails through your provider. + + # client backend + # -------------- + # notmuch: Tagdatabase for Emails + # afew: Autotagger using notmuch + # muchsync: notmuch database synctool + + # clients + # ------- + # alot + # astroid + # neomutt + + home-manager.users.mainUser.accounts.email.accounts = { + palo_van_dalo-gmx = { + primary = false; + address = "palo_van_dalo@gmx.de"; + aliases = [ ]; + realName = "Ingolf Wagner"; + userName = "palo_van_dalo@gmx.de"; + passwordCommand = passcmd "mail/gmx/palo_van_dalo@gmx.de"; + smtp = { + host = "smtp.gmx.net"; + port = 465; + }; + notmuch.enable = true; + msmtp = { + enable = true; + }; + }; + ingolf-wagner-gmx = { + primary = false; + address = "ingolf.wagner@gmx.de"; + aliases = [ ]; + realName = "Ingolf Wagner"; + userName = "ingolf.wagner@gmx.de"; + passwordCommand = passcmd "mail/gmx/ingolf.wagner@gmx.de"; + smtp = { + host = "smtp.gmx.net"; + port = 465; + }; + notmuch.enable = true; + msmtp = { + enable = true; + }; + }; + pali_palo = { + primary = false; + address = "pali_palo@web.de"; + aliases = [ ]; + realName = "Ingolf Wagner"; + userName = "pali_palo@web.de"; + passwordCommand = passcmd "mail/web.de/pali_palo@web.de"; + smtp = { + host = "smtp.web.de"; + port = 465; + }; + notmuch.enable = true; + msmtp = { + enable = true; + # msmtp --serverinfo --tls --tls-certcheck=off -a gmail + # tls.fingerprint = "77:2F:E1:F0:1C:9C:00:45:36:D5:0B:25:17:76:AC:7F:0E:79:68:27:8C:E9:E1:F6:BD:DF:F1:6F:1E:8C:85:18"; + # tls.fingerprint = "3F:B7:F9:7A:AC:9C:D7:C4:2E:8A:C1:F9:90:B5:D7:D1:8E:E2:F7:7D:9D:DB:FA:01:55:27:D2:79:5F:F8:C1:64"; + }; + }; + gmail = { + # for google accounts you have to allow 'less secure apps' in accounts.google.com + primary = true; + address = "palipalo9@googlemail.com"; + aliases = [ ]; + realName = "Ingolf Wagner"; + userName = "palipalo9@googlemail.com"; + passwordCommand = passcmd "mail/gmail/palipalo9@googlemail.com"; + smtp = { + host = "smtp.gmail.com"; + port = 465; + }; + notmuch.enable = true; + msmtp = { + enable = true; + # msmtp --serverinfo --tls --tls-certcheck=off -a gmail + # tls.fingerprint = "77:2F:E1:F0:1C:9C:00:45:36:D5:0B:25:17:76:AC:7F:0E:79:68:27:8C:E9:E1:F6:BD:DF:F1:6F:1E:8C:85:18"; + # tls.fingerprint = "3F:B7:F9:7A:AC:9C:D7:C4:2E:8A:C1:F9:90:B5:D7:D1:8E:E2:F7:7D:9D:DB:FA:01:55:27:D2:79:5F:F8:C1:64"; + }; + gpg = { + encryptByDefault = true; + signByDefault = true; + key = "42AC51C9482D0834CF488AF1389EC2D64AC71EAC"; + }; + }; + ingolf-wagner = { + primary = false; + address = "contact@ingolf-wagner.de"; + aliases = [ ]; + realName = "Ingolf Wagner"; + userName = "contact@ingolf-wagner.de"; + passwordCommand = passcmd "mail/siteground/contact@ingolf-wagner.de"; + smtp = { + host = "securees5.sgcpanel.com"; + port = 587; + tls.useStartTls = true; + }; + notmuch.enable = true; + msmtp = { + enable = true; + # msmtp --serverinfo --tls --tls-certcheck=off -a ingolf-wagner + tls.fingerprint = "33:B9:77:B6:69:2C:0C:BC:ED:28:12:79:02:AC:00:4E:E3:EE:31:EF:5E:C8:12:1C:02:5D:13:0B:BA:C0:1E:5F"; + }; + gpg = { + encryptByDefault = true; + signByDefault = true; + key = "42AC51C9482D0834CF488AF1389EC2D64AC71EAC"; + }; + }; + c-base = { + primary = false; + address = "palo@c-base.org"; + aliases = [ ]; + realName = "Ingolf Wagner"; + userName = "palo"; + passwordCommand = passcmd "mail/c-base/palo@c-base.org"; + smtp = { + host = "c-mail.c-base.org"; + port = 465; + }; + notmuch.enable = true; + msmtp = { + enable = true; + # msmtp --serverinfo --tls --tls-certcheck=off -a c-base + tls.fingerprint = "24:12:1C:85:BC:24:38:F9:16:80:8F:EC:0D:1B:46:66:E0:8C:2F:2A:4C:F3:AE:6B:08:9F:BE:E1:6C:9E:CA:C3"; + }; + gpg = { + encryptByDefault = true; + signByDefault = true; + key = "42AC51C9482D0834CF488AF1389EC2D64AC71EAC"; + }; + }; + }; + + # install mail programs + home-manager.users.mainUser.programs.msmtp.enable = true; + home-manager.users.mainUser.programs.notmuch.enable = true; + + # not working for some reason + # maybe update home-manager + #home-manager.users.mainUser.services.muchsync = { + # remotes = { + # server = { + # frequency = "*:0/10"; + # remote.host = "mailfetcher@sterni.private"; + # }; + # }; + #}; + + # configure astroid ui + home-manager.users.mainUser.programs.astroid = { + enable = true; + extraConfig = { + startup.queries.inbox = "tag:inbox AND NOT tag:killed"; + }; + externalEditor = "${pkgs.neovim-qt}/bin/nvim-qt -- -c 'set ft=mail' '+set fileencoding=utf-8' '+set ff=unix' '+set enc=utf-8' '+set fo+=w' %1"; + }; + + # configure alot + home-manager.users.mainUser.programs.alot = { + enable = true; + #name mono fg mono bg 16c fg 16c bg 256c fg 256c bg + # | | | | | | + # v v v v v v + #normal= 'bold,underline', '', 'light red, bold, underline', 'light green', 'light red, bold, underline', '#8f6' + extraConfig = '' + theme = "solarized_light_real" + auto_remove_unread = True + ask_subject = True + handle_mouse = True + initial_command = "search tag:inbox AND NOT tag:discourse" + input_timeout = 0.3 + exclude_tags = "killed" + prefer_plaintext = True + thread_indent_replies = 4 + + [tags] + [[flagged]] + translated = ⚑ + normal = ${ticks},${ticks},'light red',${ticks},'light red',${ticks} + focus = ${ticks},${ticks},'light red',${ticks},'light red',${ticks} + [[replied]] + translated = ⏎ + normal = ${ticks},${ticks},'light red',${ticks},'light red',${ticks} + focus = ${ticks},${ticks},'light red',${ticks},'light red',${ticks} + ''; + }; + + home-manager.users.mainUser.xdg.configFile."alot/themes/solarized_light_real".text = '' + + +############################################################################### +# SOLARIZED LIGHT +# +# colour theme for alot. © 2012 Patrick Totzke, GNU GPL3+ +# http://ethanschoonover.com/solarized +# https://github.com/pazz/alot +############################################################################### +# +# Define mappings from solarized colour names to urwid attribute names for 16 +# and 256 colour modes. These work well assuming you use the solarized term +# colours via Xressources/Xdefaults. You might want to change this otherwise + +16_base3 = 'dark gray' +16_base2 = 'black' +16_base1 = 'light green' +16_base0 = 'yellow' +16_base00 = 'light blue' +16_base01 = 'light cyan' +16_base02 = 'light gray' +16_base03 = 'white' +16_yellow = 'brown' +16_orange = 'light red' +16_red = 'dark red' +16_magenta = 'dark magenta' +16_violet = 'light magenta' +16_blue = 'dark blue' +16_cyan = 'dark cyan' +16_green = 'dark green' + +# Use a slightly different mapping here to be able to use "bold" in 256c mode + +256_base3 = 'dark gray' +256_base2 = 'black' +256_base1 = 'light green' +256_base0 = 'yellow' +256_base00 = 'g50' #808080 +256_base01 = 'g52' #848484 - approximates #8a8a8a +256_base02 = 'light gray' +256_base03 = 'white' +256_yellow = 'brown' +256_orange = 'light red' +256_red = 'dark red' +256_magenta = 'dark magenta' +256_violet = 'light magenta' +256_blue = 'dark blue' +256_cyan = '#0aa' #00afaf +256_green = 'dark green' + +# This is the actual alot theme +[global] + footer = 'standout','default','%(16_base01)s','%(16_base2)s','%(256_base01)s','%(256_base2)s' + body = 'default','default','%(16_base00)s','%(16_base3)s','%(256_base00)s','%(256_base3)s' + notify_error = 'standout','default','%(16_base3)s','%(16_red)s','%(256_base3)s','%(256_red)s' + notify_normal = 'default','default','%(16_base00)s','%(16_base2)s','%(256_base00)s','%(256_base2)s' + prompt = 'default','default','%(16_base00)s','%(16_base2)s','%(256_base00)s','%(256_base2)s' + tag = 'default','default','%(16_yellow)s','%(16_base3)s','%(256_yellow)s','%(256_base3)s' + tag_focus = 'standout','default','%(16_base3)s','%(16_yellow)s','%(256_base3)s','%(256_yellow)s' +[help] + text = 'default','default','%(16_base00)s','%(16_base2)s','%(256_base00)s','%(256_base2)s' + section = 'underline','default','%(16_base01)s,underline','%(16_base2)s','%(256_base01)s,underline','%(256_base2)s' + title = 'standout','default','%(16_base01)s','%(16_base2)s','%(256_base01)s','%(256_base2)s' +[namedqueries] + line_focus = 'standout','default','%(16_base2)s','%(16_yellow)s','%(256_base2)s','%(256_yellow)s' + line_even = 'default','default','%(16_base00)s','%(16_base3)s','%(256_base00)s','%(256_base3)s' + line_odd = 'default','default','%(16_base00)s','%(16_base2)s','%(256_base00)s','%(256_base2)s' +[taglist] + line_focus = 'standout','default','%(16_base2)s','%(16_yellow)s','%(256_base2)s','%(256_yellow)s' + line_even = 'default','default','%(16_base00)s','%(16_base3)s','%(256_base00)s','%(256_base3)s' + line_odd = 'default','default','%(16_base00)s','%(16_base2)s','%(256_base00)s','%(256_base2)s' +[bufferlist] + line_focus = 'standout','default','%(16_base2)s','%(16_yellow)s','%(256_base2)s','%(256_yellow)s' + line_even = 'default','default','%(16_base00)s','%(16_base3)s','%(256_base00)s','%(256_base3)s' + line_odd = 'default','default','%(16_base00)s','%(16_base2)s','%(256_base00)s','%(256_base2)s' +[thread] + attachment = 'default','default','%(16_base00)s','%(16_base3)s','%(256_base00)s','%(256_base3)s' + attachment_focus = 'underline','default','%(16_base2)s','%(16_yellow)s','%(256_base2)s','%(256_yellow)s' + body = 'default','default','%(16_base00)s','%(16_base3)s','%(256_base00)s','%(256_base3)s' + body_focus = 'default','default','%(16_base00)s','%(16_base3)s','%(256_base00)s','%(256_base2)s' + arrow_bars = 'default','default','%(16_yellow)s','%(16_base3)s','%(256_yellow)s','%(256_base3)s' + arrow_heads = 'default','default','%(16_yellow)s','%(16_base3)s','%(256_yellow)s','%(256_base3)s' + header = 'default','default','%(16_base00)s','%(16_base2)s','%(256_base00)s','%(256_base2)s' + header_key = 'default','default','%(16_magenta)s','%(16_base2)s','%(256_magenta)s','%(256_base2)s' + header_value = 'default','default','%(16_blue)s','%(16_base2)s','%(256_blue)s','%(256_base2)s' + [[summary]] + even = 'default','default','%(16_base00)s','%(16_base2)s','%(256_base00)s','%(256_base2)s' + focus = 'standout','default','%(16_base3)s','%(16_yellow)s','%(256_base3)s','%(256_yellow)s' + odd = 'default','default','%(16_base00)s','%(16_base3)s','%(256_base00)s','%(256_base3)s' +[envelope] + body = 'default','default','%(16_base00)s','%(16_base3)s','%(256_base00)s','%(256_base3)s' + header = 'default','default','%(16_base00)s','%(16_base2)s','%(256_base00)s','%(256_base2)s' + header_key = 'default','default','%(16_orange)s','%(16_base2)s','%(256_orange)s','%(256_base2)s' + header_value = 'default','default','%(16_violet)s','%(16_base2)s','%(256_violet)s','%(256_base2)s' +[search] + [[threadline]] + normal = 'default','default','%(16_base01)s','%(16_base3)s','%(256_base01)s','%(256_base3)s' + focus = 'default','default','%(16_base01)s,underline','%(16_base3)s','%(256_base01)s,underline','%(256_base3)s' + parts = mailcount,date,tags,authors,subject + [[[date]]] + normal = 'default','default','%(16_base01)s','%(16_base3)s','%(256_base01)s','%(256_base3)s' + focus = 'default','default','%(16_base01)s,underline','%(16_base3)s','%(256_base01)s,underline','%(256_base3)s' + [[[mailcount]]] + normal = 'default','default','%(16_base01)s','%(16_base3)s','%(256_base01)s','%(256_base3)s' + focus = 'default','default','%(16_base01)s,underline','%(16_base3)s','%(256_base01)s,underline','%(256_base3)s' + [[[tags]]] + normal = 'bold','default','%(16_yellow)s','%(16_base3)s','%(256_yellow)s','%(256_base3)s' + focus = 'bold','default','%(16_yellow)s,underline','%(16_base3)s','%(256_yellow)s,underline','%(256_base3)s' + [[[authors]]] + normal = 'default,underline','default','%(16_blue)s','%(16_base3)s','%(256_blue)s','%(256_base3)s' + focus = 'default,underline','default','%(16_blue)s,underline','%(16_base3)s','%(256_blue)s,underline','%(256_base3)s' + width = 'fit',0,30 + [[[subject]]] + normal = 'default','default','%(16_base00)s','%(16_base3)s','%(256_base00)s','%(256_base3)s' + focus = 'default','default','%(16_base00)s,underline','%(16_base3)s','%(256_base00)s,underline','%(256_base3)s' + width = 'weight',1 + [[[content]]] + normal = 'default','default','%(16_base1)s','%(16_base3)s','%(256_base1)s','%(256_base3)s' + focus = 'default','default','%(16_base1)s,underline','%(16_base3)s','%(256_base1)s,underline','%(256_base3)s' + [[threadline-unread]] + normal = 'default','default','%(16_base01)s,bold','%(16_base2)s','%(256_base01)s,bold','%(256_base2)s' + tagged_with = 'unread' + [[[date]]] + normal = 'default','default','%(16_base01)s,bold','%(16_base2)s','%(256_base01)s,bold','%(256_base2)s' + [[[mailcount]]] + normal = 'default','default','%(16_base01)s,bold','%(16_base2)s','%(256_base01)s,bold','%(256_base2)s' + [[[tags]]] + normal = 'bold','default','%(16_yellow)s','%(16_base2)s','%(256_yellow)s','%(256_base2)s' + [[[authors]]] + normal = 'default,underline','default','%(16_violet)s','%(16_base2)s','%(256_violet)s','%(256_base2)s' + [[[subject]]] + normal = 'default','default','%(16_base02)s,bold','%(16_base2)s','%(256_base02)s,bold','%(256_base2)s' + [[[content]]] + normal = 'default','default','%(16_base1)s,bold','%(16_base2)s','%(256_base1)s,bold','%(256_base2)s' + ''; + + + + # enable html emails + home-manager.users.mainUser.home.file.".mailcap".text = '' + text/html; ${pkgs.elinks}/bin/elinks -dump ; copiousoutput; + ''; + + environment.systemPackages = let + mailSync = pkgs.writeShellScriptBin "mail-sync" '' + ${pkgs.muchsync}/bin/muchsync mailfetcher@workhorse.private --nonew + ''; + mailSend = pkgs.writeShellScriptBin "mail-send" '' + ${pkgs.msmtp}/bin/msmtp-queue -r + ''; + mailView = pkgs.writeShellScriptBin "mail-view" '' + ${pkgs.alot}/bin/alot "$@" + ''; + mail = pkgs.writeShellScriptBin "mail" '' + ${mailSync}/bin/mail-sync + ${mailView}/bin/mail-view + ${mailSend}/bin/mail-send + ${mailSync}/bin/mail-sync + ''; + in + [ + pkgs.notmuch + pkgs.alot + pkgs.muchsync + mail + mailSync + mailView + mailSend + ]; + +} diff --git a/system/desktop/mc.nix b/system/desktop/mc.nix new file mode 100644 index 0000000..2c651f4 --- /dev/null +++ b/system/desktop/mc.nix @@ -0,0 +1,341 @@ +{ config, pkgs, ... }: + +let + mcExt = pkgs.writeText "mc.ext" '' + # gitfs changeset + regex/^\[git\] + Open=%cd %p/changesetfs:// + View=%cd %p/patchsetfs:// + + ### Archives ### + + # .tgz, .tpz, .tar.gz, .tar.z, .tar.Z, .ipk, .gem + regex/\.t([gp]?z|ar\.g?[zZ])$|\.ipk$|\.gem$ + Open=%cd %p/utar:// + + shell/.tar.bz + # Open=%cd %p/utar:// + + regex/\.t(ar\.bz2|bz2?|b2)$ + Open=%cd %p/utar:// + + # .tar.lzma, .tlz + regex/\.t(ar\.lzma|lz)$ + Open=%cd %p/utar:// + + # .tar.xz, .txz + regex/\.t(ar\.xz|xz)$ + Open=%cd %p/utar:// + + # .tar.F - used in QNX + shell/.tar.F + # Open=%cd %p/utar:// + + # .qpr/.qpk - QNX Neutrino package installer files + regex/\.qp[rk]$ + Open=%cd %p/utar:// + + # tar + shell/i/.tar + Open=%cd %p/utar:// + + # lha + type/^LHa\ .*archive + Open=%cd %p/ulha:// + + # arj + regex/i/\.a(rj|[0-9][0-9])$ + Open=%cd %p/uarj:// + + # cab + shell/i/.cab + Open=%cd %p/ucab:// + + # ha + shell/i/.ha + Open=%cd %p/uha:// + + # rar + regex/i/\.r(ar|[0-9][0-9])$ + Open=%cd %p/urar:// + + # ALZip + shell/i/.alz + Open=%cd %p/ualz:// + + # cpio + shell/.cpio.Z + Open=%cd %p/ucpio:// + + shell/.cpio.xz + Open=%cd %p/ucpio:// + + shell/.cpio.gz + Open=%cd %p/ucpio:// + + shell/i/.cpio + Open=%cd %p/ucpio:// + + # 7zip archives (they are not man pages) + shell/i/.7z + Open=%cd %p/u7z:// + + # patch + regex/\.(diff|patch)(\.bz2)$ + Open=%cd %p/patchfs:// + + regex/\.(diff|patch)(\.(gz|Z))$ + Open=%cd %p/patchfs:// + + # ls-lR + regex/(^|\.)ls-?lR(\.gz|Z|bz2)$ + Open=%cd %p/lslR:// + + # trpm + shell/.trpm + Open=%cd %p/trpm:// + + # RPM packages (SuSE uses *.spm for source packages) + regex/\.(src\.rpm|spm)$ + Open=%cd %p/rpm:// + + shell/.rpm + Open=%cd %p/rpm:// + + # deb + regex/\.u?deb$ + Open=%cd %p/deb:// + + # dpkg + shell/.debd + Open=%cd %p/debd:// + + # apt + shell/.deba + Open=%cd %p/deba:// + + # ISO9660 + shell/i/.iso + Open=%cd %p/iso9660:// + + + regex/\.(diff|patch)$ + Open=%cd %p/patchfs:// + + # ar library + regex/\.s?a$ + Open=%cd %p/uar:// + + # gplib + shell/i/.lib + Open=%cd %p/ulib:// + + + # Mailboxes + type/^ASCII\ mail\ text + Open=%cd %p/mailfs:// + + + ### Sources ### + + # C/C++ + regex/i/\.(c|cc|cpp)$ + Include=editor + + # C/C++ header + regex/i/\.(h|hh|hpp)$ + Include=editor + + # Fortran + shell/i/.f + Include=editor + + # Assembler + regex/i/\.(s|asm)$ + Include=editor + + include/editor + Open=%var{EDITOR:${pkgs.vim}/bin/vim} %f + + ### Images ### + + shell/i/.gif + Include=image + + regex/i/\.jpe?g$ + Include=image + + shell/i/.bmp + Include=image + + shell/i/.png + Include=image + + shell/i/.jng + Include=image + + shell/i/.mng + Include=image + + shell/i/.tiff + Include=image + + shell/.ico + Include=image + + include/image + Open=${pkgs.sxiv}/bin/sxiv %f + View=${pkgs.sxiv}/bin/sxiv %f + + ### Sound files ### + + regex/i/\.(wav|snd|voc|au|smp|aiff|snd|m4a|ape|aac|wv)$ + Include=audio + + regex/i/\.(mod|s3m|xm|it|mtm|669|stm|ult|far)$ + Include=audio + + shell/i/.waw22 + Include=audio + + shell/i/.mp3 + Include=audio + + regex/i/\.og[gax]$ + Include=audio + + regex/i/\.(spx|flac)$ + Include=audio + + regex/i/\.(midi?|rmid?)$ + Include=audio + + shell/i/.wma + Include=audio + + include/audio + Open=${pkgs.mpv}/bin/mpv %f + View=${pkgs.mpv}/bin/mpv %f + + ### Video ### + + shell/i/.avi + Include=video + + regex/i/\.as[fx]$ + Include=video + + shell/i/.divx + Include=video + + shell/i/.mkv + Include=video + + regex/i/\.(mov|qt)$ + Include=video + + regex/i/\.(mp4|m4v|mpe?g)$ + Include=video + + # MPEG-2 TS container + H.264 codec + shell/i/.mts + Include=video + + shell/i/.ts + Include=video + + shell/i/.vob + Include=video + + shell/i/.wmv + Include=video + + regex/i/\.fl[icv]$ + Include=video + + shell/i/.ogv + Include=video + + # WebM + shell/i/.webm + Include=video + + type/WebM + Include=video + + include/video + Open=${pkgs.mpv}/bin/mpv %f + View=${pkgs.mpv}/bin/mpv %f + + + ### Documents ### + + # PDF + shell/i/.pdf + Open=zathura %f + View=zathura %f + + ### Miscellaneous ### + + # Makefile + regex/[Mm]akefile$ + Open=make -f %f %{Enter parameters} + + + ### Plain compressed files ### + + # ace + shell/i/.ace + Open=%cd %p/uace:// + Extract=unace x %f + + # arc + shell/i/.arc + Open=%cd %p/uarc:// + Extract=arc x %f '*' + Extract (with flags)=I=%{Enter any Arc flags:}; if test -n "$I"; then arc x $I %f; fi + + # zip + shell/i/.zip + Open=%cd %p/uzip:// + + # zip + type/i/^zip\ archive + Open=%cd %p/uzip:// + + # jar(zip) + type/i/^Java\ Jar\ file\ data\ \(zip\) + Open=%cd %p/uzip:// + + # zoo + shell/i/.zoo + Open=%cd %p/uzoo:// + + ### Default ### + + # Default target for anything not described above + default/* + Open=vim %f + View=vim %f + + ''; + +in { + environment.systemPackages = [ + (pkgs.symlinkJoin { + name = "mc"; + paths = [ + (pkgs.writers.writeDashBin "mc" '' + export MC_DATADIR=${pkgs.write "mc-ext" { + "/mc.ext".link = mcExt; + "/sfs.ini".text = ""; + }}; + export TERM=xterm-256color + exec ${pkgs.mc}/bin/mc -S xoria256 "$@" + '') + pkgs.mc + ]; + }) + ]; +} + diff --git a/system/desktop/network.nix b/system/desktop/network.nix new file mode 100644 index 0000000..495b0da --- /dev/null +++ b/system/desktop/network.nix @@ -0,0 +1,13 @@ +{ config, pkgs, lib, ... }: +{ + + system.custom.wifi = { + enable = true; + configurationFile = toString ; + system = "networkmanager"; + }; + + environment.etc."NetworkManager/system-connections".source = + toString ; + +} diff --git a/system/desktop/packages.nix b/system/desktop/packages.nix new file mode 100644 index 0000000..ad688f8 --- /dev/null +++ b/system/desktop/packages.nix @@ -0,0 +1,293 @@ +{ pkgs, config, lib, ... }: + +with lib; + +let + + unstablePkgs = import {}; + + library = import { inherit pkgs lib; }; + + seafileClient = unstablePkgs.seafile-client.override{ + seafile-shared = unstablePkgs.seafile-shared; + }; + + replaceLinks = pkgs.writers.writeBashBin "replace-link-with-content" /* sh */ '' + if [ ! -L "$1" ] + then + echo "$1 does not exist or is not a file" + exit 1 + fi + + cp -rL "$1" "$1.backup" + unlink "$1" + mv "$1.backup" "$1" + ''; + + pandocScript = inputFormat: outputFormat: pkgs.writers.writeDashBin "pandoc-from-${inputFormat}-to-${outputFormat}" '' + ${pkgs.pandoc}/bin/pandoc \ + --from ${inputFormat} \ + --to ${outputFormat} \ + "$@" + ''; + + # show keyboard input on desktop for screencasts + screenKey = pkgs.symlinkJoin { + name = "screen-keys"; + paths = + let + screenKeyScript = { position ? "bottom", size ? "small", ... }: pkgs.writeShellScriptBin "screenkeys-${position}-${size}" /* sh */ '' + ${pkgs.screenkey}/bin/screenkey \ + --no-detach \ + --bg-color '#fdf6e3' \ + --font-color '#073642' \ + -p ${position} \ + -s ${size} \ + "$@" + ''; + in + lib.flatten ( + lib.flip map [ "large" "small" "medium" ] ( + size: + lib.flip map [ "top" "center" "bottom" ] ( + position: + screenKeyScript { inherit size position ;} + ) + ) + ); + }; + + + connectToSpeaker = name: id: pkgs.writeShellScriptBin "connect-to-speaker-${name}" /* sh */ '' + # hacky script because I have problems with + # automatically connecting to trusted bluetooth devices. + + echo "Connect to Speaker ${name}" + + bluetoothctl <)) + + screenKey + replaceLinks + + (pkgs.pidgin-with-plugins.override { + ## Add whatever plugins are desired (see nixos.org package listing). + plugins = [ + pkgs.pidgin-otr + pkgs.purple-facebook + pkgs.purple-discord + pkgs.purple-matrix + pkgs.purple-hangouts + pkgs.pidgin-latex + pkgs.pidgin-opensteamworks + pkgs.pidgin-skypeweb + pkgs.telegram-purple + pkgs.purple-lurch + ]; + }) + + haskellPackages.image-generator + + ] ++ (lib.crossLists pandocScript [ ["markdown" "mediawiki"] ["mediawiki" "docbook5" "html5" "man"] ]); +} diff --git a/system/desktop/pass.nix b/system/desktop/pass.nix new file mode 100644 index 0000000..09e011c --- /dev/null +++ b/system/desktop/pass.nix @@ -0,0 +1,40 @@ +{ lib, pkgs, ... }: + +with lib; + +let + + # desktop file + # ------------ + # makes it possible to be used by other programs + desktopFile = name: bin: + pkgs.writeTextFile { + name = "${name}.desktop"; + destination = "/share/applications/${name}.desktop"; + text = '' + [Desktop Entry] + Categories=Application;Utility; + Comment=password dialog + Encoding=UTF-8 + Exec=${bin} + Icon=gnome-lockscreen + Name=${name} + Terminal=false + Type=Application + ''; + }; + +in { + + environment.systemPackages = [ + pkgs.pass-otp + (desktopFile "passmenu" "${pkgs.pass-otp}/bin/passmenu --type -l 10") + + # todo ein script machen was hier tut + # zbarimg -q --raw 2018-12-18-114509.png | pass otp insert mindcurv/cloudamqp/otp + pkgs.zbar + + pkgs.otpmenu + + ]; +} diff --git a/system/desktop/remote-install.nix b/system/desktop/remote-install.nix new file mode 100644 index 0000000..a205df9 --- /dev/null +++ b/system/desktop/remote-install.nix @@ -0,0 +1,20 @@ +{ pkgs, ... }: +{ + services.tor = { + enable = true; + client.enable = true; + hiddenServices.liveos.map = [ + { port = 1337; } + ]; + }; + + environment.systemPackages = [ + (pkgs.writeShellScriptBin "remote-install-start-service" '' + echo "starting announcment server to receive remote-install iso onion id" + ${pkgs.nmap}/bin/ncat -k -l -p 1337 + '') + (pkgs.writeShellScriptBin "remote-install-get-hiddenReceiver" '' + sudo cat /var/lib/tor/onion/liveos/hostname + '') + ]; +} diff --git a/system/desktop/restic.nix b/system/desktop/restic.nix new file mode 100644 index 0000000..547efbe --- /dev/null +++ b/system/desktop/restic.nix @@ -0,0 +1,15 @@ +{ + + backup.services.restic = { + "on-porani".enable = false; + "on-workhorse".enable = true; + "on-workout".enable = true; + }; + + backup.all.restic.dirs = [ + "/home/palo/.gnupg" + "/home/palo/.ssh" + "/home/palo/.password-store" + ]; + +} diff --git a/system/desktop/size.nix b/system/desktop/size.nix new file mode 100644 index 0000000..edff16a --- /dev/null +++ b/system/desktop/size.nix @@ -0,0 +1,28 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + + cfg = config.configuration.desktop; + +in { + + options.configuration.desktop = { + height = mkOption { + default = 900; + type = with types; int; + description = '' + height of the dektop monitor + ''; + }; + width = mkOption { + default = 1600; + type = with types; int; + description = '' + width of the desktop monitor + ''; + }; + }; + +} diff --git a/system/desktop/sshd.nix b/system/desktop/sshd.nix new file mode 100644 index 0000000..d7225aa --- /dev/null +++ b/system/desktop/sshd.nix @@ -0,0 +1,7 @@ +{ config, ... }: +{ + # make sure ssh is only available trough the tinc + networking.firewall.extraCommands = '' + iptables -t nat -A PREROUTING ! -i tinc.private -p tcp -m tcp --dport 22 -j REDIRECT --to-ports 0 + ''; +} diff --git a/system/desktop/suspend.nix b/system/desktop/suspend.nix new file mode 100644 index 0000000..bcec897 --- /dev/null +++ b/system/desktop/suspend.nix @@ -0,0 +1,29 @@ +{ pkgs, config, ... }: + +{ + systemd.services.screenlock = { + before = [ "sleep.target" ]; + requiredBy = [ "sleep.target" ]; + environment = + let + display = if (config.services.xserver.display != null) + then config.services.xserver.display + else 0; + in { + DISPLAY = ":${toString display}"; + }; + script = '' + ${pkgs.xlockmore}/bin/xlock -mode life1d -size 1 & + sleep 4 + ''; + serviceConfig = { + SyslogIdentifier = "screenlock"; + # Type = "simple"; + Type = "forking"; + User = config.users.users.mainUser.name; + }; + }; + + services.logind.lidSwitch = "suspend"; + +} diff --git a/system/desktop/user.nix b/system/desktop/user.nix new file mode 100644 index 0000000..4430a32 --- /dev/null +++ b/system/desktop/user.nix @@ -0,0 +1,14 @@ +{ config, lib, pkgs, ... }: +{ + programs.custom.zsh.mainUser = config.users.users.mainUser.name; + + system.custom.mainUser = { + enable = true; + userName = "palo"; + authorizedKeyFiles = + config.users.users.root.openssh.authorizedKeys.keyFiles; + }; + + + +} diff --git a/system/desktop/x11.nix b/system/desktop/x11.nix new file mode 100644 index 0000000..bf4d292 --- /dev/null +++ b/system/desktop/x11.nix @@ -0,0 +1,19 @@ +{ config, pkgs, lib, ... }: +{ + + environment.systemPackages = with pkgs; [ + xclip + xtrlock-pam + xorg.xev + ]; + + system.custom.x11 = { + enable = true; + autoLoginUser = config.users.users.mainUser.name; + }; + + system.custom.fonts.enable = true; + +} + + diff --git a/system/desktop/xlock.nix b/system/desktop/xlock.nix new file mode 100644 index 0000000..9b83b8a --- /dev/null +++ b/system/desktop/xlock.nix @@ -0,0 +1,41 @@ +{ lib, pkgs, ... }: + +with lib; + +let + + name = "lock"; + + # desktop file + # ------------ + # makes it possible to be used by other programs + desktopFile = + pkgs.writeTextFile { + name = "${name}.desktop" ; + destination = "/share/applications/${name}.desktop"; + text = '' + [Desktop Entry] + Categories=Application;Utility; + Comment=Screen Saver + Encoding=UTF-8 + Exec=${lockProgram}/bin/${name} + Icon=gnome-lockscreen + Name=${name} + Terminal=false + Type=Application + ''; + }; + + # the lock program + lockProgram = + pkgs.writeShellScriptBin "${name}" '' + ${pkgs.xlockmore}/bin/xlock -mode life1d -size 1 + ''; + +in { + + environment.systemPackages = [ + lockProgram + desktopFile + ]; +} diff --git a/system/desktop/yubikey.nix b/system/desktop/yubikey.nix new file mode 100644 index 0000000..6364bfe --- /dev/null +++ b/system/desktop/yubikey.nix @@ -0,0 +1,50 @@ +# References: +# * https://github.com/drduh/YubiKey-Guide +# * https://nixos.wiki/wiki/Yubikey +{ pkgs, ... }: +{ + services.pcscd.enable = true; + services.udev.packages = [ + + pkgs.yubikey-personalization + + # additional services, but I just want gpg + # pkgs.libu2f-host + + ]; + + environment.systemPackages = [ + + # for `gpg --export $keyid | hokey lint` to check keys + pkgs.haskellPackages.hopenpgp-tools + + # for otp keys (but I use pass otp) + # pkgs.yubioath-desktop + + (pkgs.writers.writeDashBin "gpg-reset-yubikey-id" '' + echo "reset gpg to make new key available" + set -x + set -e + ${pkgs.psmisc}/bin/killall gpg-agent + rm -r ~/.gnupg/private-keys-v1.d/ + echo "now the new key should work" + '') + + ]; + + # use gpg for ssh + # --------------- + environment.shellInit = '' + export GPG_TTY="$(tty)" + gpg-connect-agent /bye + export SSH_AUTH_SOCK="/run/user/$UID/gnupg/S.gpg-agent.ssh" + ''; + programs = { + ssh.startAgent = false; + gnupg.agent = { + enable = true; + enableSSHSupport = true; + }; + }; + +} diff --git a/system/proxy/default.nix b/system/proxy/default.nix new file mode 100644 index 0000000..d66d4c9 --- /dev/null +++ b/system/proxy/default.nix @@ -0,0 +1,14 @@ +{ config, lib, pkgs, ... }: +{ + + imports = [ + + + + + ]; + + services.sshguard.enable = true; + +} + diff --git a/system/server/default.nix b/system/server/default.nix new file mode 100644 index 0000000..851318e --- /dev/null +++ b/system/server/default.nix @@ -0,0 +1,25 @@ +{ config, lib, pkgs, ... }: +{ + + imports = [ + + ./netdata.nix + ./initssh.nix + ./graylog-exporter.nix + ./prometheus-exporters.nix + ]; + + # make sure laptops stay awake when closing the montior + services.logind.lidSwitch = "ignore"; + powerManagement.enable = false; + powerManagement.cpuFreqGovernor = "ondemand"; + powerManagement.scsiLinkPolicy = "min_power"; + + # config vim + programs.custom.vim.enable = true; + + # no need to to start a service + environment.systemPackages = [ pkgs.mosh ]; + +} + diff --git a/system/server/graylog-exporter.nix b/system/server/graylog-exporter.nix new file mode 100644 index 0000000..92a0922 --- /dev/null +++ b/system/server/graylog-exporter.nix @@ -0,0 +1,5 @@ +{ + # send data to graylog + services.SystemdJournal2Gelf.enable = true; + services.SystemdJournal2Gelf.graylogServer = "workhorse.private:11201"; +} diff --git a/system/server/initssh.nix b/system/server/initssh.nix new file mode 100644 index 0000000..e83d7c3 --- /dev/null +++ b/system/server/initssh.nix @@ -0,0 +1,117 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + + cfg = config.configuration.init-ssh; + +in { + + options.configuration.init-ssh = { + + enable = mkOption { + default = "disable"; + type = with types; enum [ "disable" "prepare" "enabled" ]; + }; + + kernelModules = mkOption { + type = with types; listOf str; + }; + + port = mkOption { + default = 23; + type = with types; int; + }; + + authorizedKeys = mkOption { + type = with types; listOf str; + }; + + hostDSSKey = mkOption { + default = null; + type = with types; nullOr path; + description = '' + you only need one host key + nix-shell -p dropbear --run "dropbearkey -t dss -f ./host_dss_key" + ''; + }; + hostECDSAKey = mkOption { + default = null; + type = with types; nullOr path; + description = '' + you only need one host key + nix-shell -p dropbear --run "dropbearkey -t ecdsa -f ./host_ecdsa_key" + ''; + }; + hostRSAKey = mkOption { + default = null; + type = with types; nullOr path; + description = '' + you only need one host key + nix-shell -p dropbear --run "dropbearkey -t rsa -f ./host_rsa_key" + ''; + }; + + }; + + config = mkMerge [ + + (mkIf (cfg.enable != "disable") { + services.tor = { + enable = true; + client.enable = true; + hiddenServices.bootup.map = [ + { port = 23; } + ]; + }; + }) + + (mkIf (cfg.enable == "enabled") { + + # tor setup + boot.initrd.secrets = { + "/etc/tor/onion/bootup" = /var/lib/tor/onion/bootup; + "/etc/tor/tor.rc" = (pkgs.writeText "tor.rc" '' + DataDirectory /etc/tor + SOCKSPort 127.0.0.1:9050 IsolateDestAddr + SOCKSPort 127.0.0.1:9063 + HiddenServiceDir /etc/tor/onion/bootup + HiddenServicePort ${toString cfg.port} 127.0.0.1:${toString cfg.port} + ''); + }; + + boot.initrd.extraUtilsCommands = '' + copy_bin_and_libs ${pkgs.tor}/bin/tor + ''; + + boot.initrd.network.postCommands = + '' + echo "tor: preparing onion folder" + # have to do this otherwise tor does not want to start + chmod -R 700 /etc/tor + + echo "tor: starting tor" + tor -f /etc/tor/tor.rc --verify-config + tor -f /etc/tor/tor.rc & + ''; + + # ssh setup + # todo add the ssh host fingerprint to your trusted stuff + # todo set ssh host key here + boot.initrd.network.enable = true; + boot.initrd.network.ssh = { + enable = true; + authorizedKeys = cfg.authorizedKeys; + port = cfg.port; + }; + boot.initrd.availableKernelModules = cfg.kernelModules; + boot.initrd.network.ssh.hostDSSKey = cfg.hostDSSKey; + boot.initrd.network.ssh.hostECDSAKey = cfg.hostECDSAKey; + boot.initrd.network.ssh.hostRSAKey = cfg.hostRSAKey; + }) + ]; +} + + + diff --git a/system/server/netdata.nix b/system/server/netdata.nix new file mode 100644 index 0000000..da4336b --- /dev/null +++ b/system/server/netdata.nix @@ -0,0 +1,16 @@ +{ lib, pkgs, ... }: +{ + services.netdata = { + enable = true; + # https://docs.netdata.cloud/daemon/config/ + config = { + global = { + "memory mode" = "ram"; + "debug log" = "none"; + "access log" = "none"; + "error log" = "syslog"; + }; + }; + + }; +} diff --git a/system/server/prometheus-exporters.nix b/system/server/prometheus-exporters.nix new file mode 100644 index 0000000..6f0e06f --- /dev/null +++ b/system/server/prometheus-exporters.nix @@ -0,0 +1,9 @@ +{ config, lib, ... }: +{ + config = lib.mkMerge [ + (lib.mkIf config.services.nginx.enable { + services.prometheus.exporters.nginx.enable = true; + services.nginx.statusPage = true; + }) + ]; +} diff --git a/terranix/.gitignore b/terranix/.gitignore new file mode 100644 index 0000000..a28903b --- /dev/null +++ b/terranix/.gitignore @@ -0,0 +1,3 @@ +*.backup +.history +.terraform diff --git a/terranix/graylog/README.md b/terranix/graylog/README.md new file mode 100644 index 0000000..708323d --- /dev/null +++ b/terranix/graylog/README.md @@ -0,0 +1,17 @@ + +# The idea + +on all messages are pipelines which are quick and forward traffic to +dedicated streams, on theses streams the more costly but also richer +pipelines are triggered. + +* avoid extractors, because they are applied on every message. + + +# Use Generic Geo Ip Location plugin (at the end) + +this way I don't have to parse everything myself. + +# Use Content Packs + +* for nginx diff --git a/terranix/graylog/config.nix b/terranix/graylog/config.nix new file mode 100644 index 0000000..2a3dd12 --- /dev/null +++ b/terranix/graylog/config.nix @@ -0,0 +1,138 @@ +# https://github.com/suzuki-shunsuke/go-graylog/tree/master/terraform +{ pgks, lib, ... }: +{ + + imports = [ + ./modules + ./config/elasticsearch.nix + ./config/gogs.nix + ./config/home-assistant.nix + ./config/kernel.nix + #./config/nginx.nix + ./config/sshd.nix + ./config/sslh.nix + ./config/sshguard.nix + ./config/tinc.nix + ]; + + # ---- [ default ] + + data."graylog_index_set".default.index_prefix = "graylog"; + + # ---- [ junk ] + + resource."graylog_index_set".junk = { + title = "junk index"; + index_prefix = "trash"; + + # https://godoc.org/github.com/suzuki-shunsuke/go-graylog#pkg-constants + rotation_strategy_class = "org.graylog2.indexer.rotation.strategies.SizeBasedRotationStrategy"; + rotation_strategy = { + type = "org.graylog2.indexer.rotation.strategies.SizeBasedRotationStrategyConfig"; + max_size = 1024 * 1024 * 10; + }; + + retention_strategy_class = "org.graylog2.indexer.retention.strategies.DeletionRetentionStrategy"; + retention_strategy = { + type = "org.graylog2.indexer.retention.strategies.DeletionRetentionStrategyConfig"; + max_number_of_indices = 10; + }; + + index_analyzer = "standard"; + shards = 1; + index_optimization_max_num_segments = 1; + field_type_refresh_interval = 10000; + writable = "true"; + }; + + graylog.stream.junk = { + index_set_id = "\${graylog_index_set.junk.id}"; + }; + + # ---- [ thread ] + + resource."graylog_index_set".thread = { + title = "thread"; + index_prefix = "thread"; + + # https://godoc.org/github.com/suzuki-shunsuke/go-graylog#pkg-constants + rotation_strategy_class = "org.graylog2.indexer.rotation.strategies.SizeBasedRotationStrategy"; + rotation_strategy = { + type = "org.graylog2.indexer.rotation.strategies.SizeBasedRotationStrategyConfig"; + max_size = 1024 * 1024 * 10; + }; + + retention_strategy_class = "org.graylog2.indexer.retention.strategies.DeletionRetentionStrategy"; + retention_strategy = { + type = "org.graylog2.indexer.retention.strategies.DeletionRetentionStrategyConfig"; + max_number_of_indices = 20; + }; + + index_analyzer = "standard"; + shards = 1; + index_optimization_max_num_segments = 1; + field_type_refresh_interval = 10000; + writable = "true"; + }; + + graylog.stream.thread = { + index_set_id = "\${graylog_index_set.thread.id}"; + #pipelines = [ "\${graylog_pipeline.processThreads.id}" ]; + }; + + #resource."graylog_stream_rule"."is_thread" = { + # field = "is_thread"; + # value = "true"; + # stream_id = "\${graylog_stream.thread.id}"; + # description = "route everything that is a thread"; + # #type = 0; + # #inverted = false; + #}; + + + # not necessary because we have a geoip resolver + + #graylog.pipeline.processThreads = { + # source = '' + # stage 0 match all + # rule "extract source_ip position"; + # ''; + # description = "process messages of the thread stream(TF)"; + #}; + + #resource."graylog_pipeline_rule".extractSourceIpPosition = { + # description = ""; + # source = '' + # rule "extract source_ip position" + # when + # has_field("source_ip") + # then + # let geo = lookup("geo_city_lookup", to_string($message.source_ip)); + # set_field("ip_geolocation", geo["coordinates"]); + # set_field("ip_geo_country_code", geo["country"].iso_code); + # set_field("ip_geo_country_name", geo["country"].names.en); + # set_field("ip_geo_city_name", geo["city"].names.en); + # end + # ''; + #}; + + #resource."graylog_pipeline_rule".extractRemoteIpPosition = { + # description = ""; + # source = '' + # rule "extract remote_addr position" + # when + # has_field("remote_addr") + # then + # let geo = lookup("geo_city_lookup", to_string($message.remote_addr)); + # set_field("ip_geolocation", geo["coordinates"]); + # set_field("ip_geo_country_code", geo["country"].iso_code); + # set_field("ip_geo_country_name", geo["country"].names.en); + # set_field("ip_geo_city_name", geo["city"].names.en); + # end + # ''; + #}; + + #graylog.all_messages.rules = [ "extract remote_addr position" ]; + +} + diff --git a/terranix/graylog/config/elasticsearch.nix b/terranix/graylog/config/elasticsearch.nix new file mode 100644 index 0000000..8fb7390 --- /dev/null +++ b/terranix/graylog/config/elasticsearch.nix @@ -0,0 +1,49 @@ +# filters elasticsearch messages +{ + resource."graylog_pipeline_rule" = { + + routeToElasticSearchMessage = { + + description = "route elasticsearch messages to elasticsearch stream (TF)"; + source = '' + rule "route elasticsearch message" + when + to_string($message.facility) == "elasticsearch" + then + route_to_stream(id:"''${ graylog_stream.elasticsearch.id }", remove_from_default: true); + end + ''; + }; + + elasticsearchJunk = { + source = '' + rule "mark and route elasticsearch junk" + when + starts_with(to_string($message.message), "Received short packet") + then + set_field("is_junk", true); + route_to_stream(id:"''${graylog_stream.junk.id}", remove_from_default: true); + end + ''; + description = "mark elasticsearch noise as junk (TF)"; + }; + + }; + + graylog.all_messages.rules = ["route elasticsearch message"]; + + graylog.stream.elasticsearch = { + index_set_id = "\${data.graylog_index_set.default.id}"; + pipelines = [ "\${graylog_pipeline.processElasticSearchMessage.id}" ]; + }; + + graylog.pipeline.processElasticSearchMessage = { + source = '' + stage 0 match all + rule "mark and route elasticsearch junk"; + ''; + description = "process messages of the elasticsearch stream(TF)"; + }; + + +} diff --git a/terranix/graylog/config/gogs.nix b/terranix/graylog/config/gogs.nix new file mode 100644 index 0000000..afb4986 --- /dev/null +++ b/terranix/graylog/config/gogs.nix @@ -0,0 +1,36 @@ +# filters gogs messages +{ + resource."graylog_pipeline_rule" = { + + routeToGogsMessage = { + + description = "route gogs messages to gogs stream (TF)"; + source = '' + rule "route gogs message" + when + to_string($message.facility) == "gogs" + then + route_to_stream(id:"''${ graylog_stream.gogs.id }", remove_from_default: true); + end + ''; + }; + + }; + + graylog.all_messages.rules = ["route gogs message"]; + + graylog.stream.gogs = { + index_set_id = "\${data.graylog_index_set.default.id}"; + #pipelines = [ "\${graylog_pipeline.processGogsMessage.id}" ]; + }; + + #graylog.pipeline.processGogsMessage = { + # source = '' + # stage 0 match all + # rule "extract firewall deny"; + # ''; + # description = "process messages of the gogs stream(TF)"; + #}; + + +} diff --git a/terranix/graylog/config/home-assistant.nix b/terranix/graylog/config/home-assistant.nix new file mode 100644 index 0000000..78f482d --- /dev/null +++ b/terranix/graylog/config/home-assistant.nix @@ -0,0 +1,37 @@ +# filters kernel messages +{ + resource."graylog_pipeline_rule" = { + + routeToHomeAssistant = { + + description = "route hass messages to hass stream (TF)"; + source = '' + rule "route hass message" + when + to_string($message.facility) == "hass" + then + route_to_stream(id:"''${ graylog_stream.homeassistant.id }", remove_from_default: true); + end + ''; + }; + + }; + + graylog.all_messages.rules = ["route hass message"]; + + graylog.stream.homeassistant = { + index_set_id = "\${data.graylog_index_set.default.id}"; + #pipelines = [ "\${graylog_pipeline.processHomeAssistantMessage.id}" ]; + #pipelines = [ "\${graylog_pipeline.processHomeAssistantMessage.id}" ]; + }; + + #graylog.pipeline.processHomeAssistantMessage = { + # source = '' + # stage 0 match all + # rule "extract firewall deny"; + # ''; + # description = "process messages of the kernel stream(TF)"; + #}; + + +} diff --git a/terranix/graylog/config/kernel.nix b/terranix/graylog/config/kernel.nix new file mode 100644 index 0000000..76d625d --- /dev/null +++ b/terranix/graylog/config/kernel.nix @@ -0,0 +1,50 @@ +# filters kernel messages +{ + resource."graylog_pipeline_rule" = { + + routeToKernelMessage = { + + description = "route kernel messages to kernel stream (TF)"; + source = '' + rule "route kernel message" + when + to_string($message.facility) == "kernel" + then + route_to_stream(id:"''${ graylog_stream.kernel.id }", remove_from_default: true); + end + ''; + }; + + extractFirewallDeny ={ + description = "extract information form a firewall deny (TF)"; + source = '' + rule "extract firewall deny" + when + starts_with(to_string($message.message), "refused connection:") + then + set_fields(grok("SRC=%{IP:source_ip} .* DPT=%{NUMBER:destination_port}", to_string($message.message))); + set_field("is_thread", true); + route_to_stream(id:"''${ graylog_stream.thread.id }"); + end + ''; + }; + + }; + + graylog.all_messages.rules = ["route kernel message"]; + + graylog.stream.kernel = { + index_set_id = "\${data.graylog_index_set.default.id}"; + pipelines = [ "\${graylog_pipeline.processKernelMessage.id}" ]; + }; + + graylog.pipeline.processKernelMessage = { + source = '' + stage 0 match all + rule "extract firewall deny"; + ''; + description = "process messages of the kernel stream(TF)"; + }; + + +} diff --git a/terranix/graylog/config/nginx.nix b/terranix/graylog/config/nginx.nix new file mode 100644 index 0000000..2b7f108 --- /dev/null +++ b/terranix/graylog/config/nginx.nix @@ -0,0 +1,37 @@ +# filters nginx messages +{ config, ... }: +{ + resource."graylog_pipeline_rule" = { + + # not working for some reason + extractHttpCode = { + description = "extract thread information nginx access (TF)"; + source = '' + rule "extract response code" + when + has_field("response_status") + then + set_field("response_status_description", lookup_value("http_codes_description", to_long($message.response_status))); + end + ''; + }; + + }; + + graylog.pipeline.processNginxMessage = { + source = '' + stage 99 match all + rule "extract response code"; + ''; + #streamId = config.graylog.all_messages.streamId; + #streamId = "\${data.graylog_stream.nginx.id}"; + }; + + resource.graylog_pipeline_connection.processNginxMessage = { + stream_id = "\${data.graylog_stream.nginx.id}"; + pipeline_ids = ["\${graylog_pipeline.processNginxMessage.id}"]; + }; + + data.graylog_stream.nginx.title = "nginx"; + +} diff --git a/terranix/graylog/config/sshd.nix b/terranix/graylog/config/sshd.nix new file mode 100644 index 0000000..966596d --- /dev/null +++ b/terranix/graylog/config/sshd.nix @@ -0,0 +1,36 @@ +# filters sshd messages +{ + resource."graylog_pipeline_rule" = { + + routeToSshdMessage = { + + description = "route sshd messages to sshd stream (TF)"; + source = '' + rule "route sshd message" + when + to_string($message.facility) == "sshd" + then + route_to_stream(id:"''${ graylog_stream.sshd.id }", remove_from_default: true); + end + ''; + }; + + }; + + graylog.all_messages.rules = ["route sshd message"]; + + graylog.stream.sshd = { + index_set_id = "\${data.graylog_index_set.default.id}"; + #pipelines = [ "\${graylog_pipeline.processSshdMessage.id}" ]; + }; + + #graylog.pipeline.processSshdMessage = { + # source = '' + # stage 0 match all + # rule "mark and route sshd junk"; + # ''; + # description = "process messages of the sshd stream(TF)"; + #}; + + +} diff --git a/terranix/graylog/config/sshguard.nix b/terranix/graylog/config/sshguard.nix new file mode 100644 index 0000000..ece427d --- /dev/null +++ b/terranix/graylog/config/sshguard.nix @@ -0,0 +1,50 @@ +# filters sshguard messages +{ + resource."graylog_pipeline_rule" = { + + routeToSshGuardMessage = { + + description = "route sshguard messages to sshguard stream (TF)"; + source = '' + rule "route sshguard message" + when + to_string($message.facility) == "sshguard" + then + route_to_stream(id:"''${ graylog_stream.sshguard.id }", remove_from_default: true); + end + ''; + }; + + extractAttack ={ + description = "extract sshguard attack information (TF)"; + source = '' + rule "extract sshguard attack" + when + starts_with(to_string($message.message), "Attack from") + then + set_fields(grok(pattern:"Attack from \"%{IPV4:source_ip}\"", value: to_string($message.message), only_named_captures: true)); + set_field("is_thread", true); + route_to_stream(id:"''${ graylog_stream.thread.id }"); + end + ''; + }; + + }; + + graylog.all_messages.rules = ["route sshguard message"]; + + graylog.stream.sshguard = { + index_set_id = "\${data.graylog_index_set.default.id}"; + pipelines = [ "\${graylog_pipeline.processSshGuardMessage.id}" ]; + }; + + graylog.pipeline.processSshGuardMessage = { + source = '' + stage 0 match all + rule "extract sshguard attack"; + ''; + description = "process messages of the sshguard stream(TF)"; + }; + + +} diff --git a/terranix/graylog/config/sslh.nix b/terranix/graylog/config/sslh.nix new file mode 100644 index 0000000..9646d55 --- /dev/null +++ b/terranix/graylog/config/sslh.nix @@ -0,0 +1,50 @@ +# filters sslh messages +{ + resource."graylog_pipeline_rule" = { + + routeToSslhMessage = { + + description = "route sslh messages to sslh stream (TF)"; + source = '' + rule "route sslh message" + when + to_string($message.facility) == "sslh" + then + route_to_stream(id:"''${ graylog_stream.sslh.id }", remove_from_default: true); + end + ''; + }; + + sslhJunk = { + source = '' + rule "mark and route sslh junk" + when + starts_with(to_string($message.message), "client socket closed") + then + drop_message(); + //set_field("is_junk", true); + //route_to_stream(id:"''${graylog_stream.junk.id}", remove_from_default: true); + end + ''; + description = "mark tinc noise as junk (TF)"; + }; + + }; + + graylog.all_messages.rules = ["route sslh message"]; + + graylog.stream.sslh = { + index_set_id = "\${data.graylog_index_set.default.id}"; + pipelines = [ "\${graylog_pipeline.processSslhMessage.id}" ]; + }; + + graylog.pipeline.processSslhMessage = { + source = '' + stage 0 match all + rule "mark and route sslh junk"; + ''; + description = "process messages of the sslh stream(TF)"; + }; + + +} diff --git a/terranix/graylog/config/tinc.nix b/terranix/graylog/config/tinc.nix new file mode 100644 index 0000000..7249c84 --- /dev/null +++ b/terranix/graylog/config/tinc.nix @@ -0,0 +1,50 @@ +# filters tinc messages +{ + resource."graylog_pipeline_rule" = { + + routeToTincMessage = { + + description = "route tinc messages to tinc stream (TF)"; + source = '' + rule "route tinc message" + when + to_string($message.facility) == "tincd" + then + route_to_stream(id:"''${ graylog_stream.tinc.id }", remove_from_default: true); + end + ''; + }; + + tincJunk = { + source = '' + rule "mark and route tinc junk" + when + starts_with(to_string($message.message), "Received short packet") + then + drop_message(); + //set_field("is_junk", true); + //route_to_stream(id:"''${graylog_stream.junk.id}", remove_from_default: true); + end + ''; + description = "mark tinc noise as junk (TF)"; + }; + + }; + + graylog.all_messages.rules = ["route tinc message"]; + + graylog.stream.tinc = { + index_set_id = "\${data.graylog_index_set.default.id}"; + pipelines = [ "\${graylog_pipeline.processTincMessage.id}" ]; + }; + + graylog.pipeline.processTincMessage = { + source = '' + stage 0 match all + rule "mark and route tinc junk"; + ''; + description = "process messages of the tinc stream(TF)"; + }; + + +} diff --git a/terranix/graylog/content-packs/graylog3-content-pack-nginx-json-master/LICENSE b/terranix/graylog/content-packs/graylog3-content-pack-nginx-json-master/LICENSE new file mode 100644 index 0000000..336ca91 --- /dev/null +++ b/terranix/graylog/content-packs/graylog3-content-pack-nginx-json-master/LICENSE @@ -0,0 +1,13 @@ +Copyright 2019 Paul Barfuss + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/terranix/graylog/content-packs/graylog3-content-pack-nginx-json-master/README.md b/terranix/graylog/content-packs/graylog3-content-pack-nginx-json-master/README.md new file mode 100644 index 0000000..fb9c007 --- /dev/null +++ b/terranix/graylog/content-packs/graylog3-content-pack-nginx-json-master/README.md @@ -0,0 +1,23 @@ +### Configuring nginx + +You need to run at least nginx version 1.11.8, with `escape=json` support. + +**Add this to your nginx configuration file and restart the service:** + + log_format graylog2_json escape=json '{ "timestamp": "$time_iso8601", ' + '"remote_addr": "$remote_addr", ' + '"body_bytes_sent": $body_bytes_sent, ' + '"request_time": $request_time, ' + '"response_status": $status, ' + '"request": "$request", ' + '"request_method": "$request_method", ' + '"host": "$host",' + '"upstream_cache_status": "$upstream_cache_status",' + '"upstream_addr": "$upstream_addr",' + '"http_x_forwarded_for": "$http_x_forwarded_for",' + '"http_referrer": "$http_referer", ' + '"http_user_agent": "$http_user_agent" }'; + + # replace the hostnames with the IP or hostname of your Graylog2 server + access_log syslog:server=graylog.server.org:12304 graylog2_json; + error_log syslog:server=graylog.server.org:12305; diff --git a/terranix/graylog/content-packs/graylog3-content-pack-nginx-json-master/content-pack-nginx-graylog3.json b/terranix/graylog/content-packs/graylog3-content-pack-nginx-json-master/content-pack-nginx-graylog3.json new file mode 100644 index 0000000..3c5b1de --- /dev/null +++ b/terranix/graylog/content-packs/graylog3-content-pack-nginx-json-master/content-pack-nginx-graylog3.json @@ -0,0 +1,1211 @@ +{ + "v": "1", + "id": "d7dc82ff-529b-488a-b1de-b12b32e756bb", + "rev": 3, + "name": "nginx_json_graylog3", + "summary": "Graylog 3.0+ compatible version of nginx_json content pack", + "description": "", + "vendor": "Originally created by petestorey26 and updated by paulbarfuss for graylog3.0+", + "url": "https://github.com/paulbarfuss/graylog3-content-pack-nginx-json", + "parameters": [], + "entities": [ + { + "v": "1", + "type": { + "name": "dashboard", + "version": "1" + }, + "id": "b7c3a54b-3ed4-4b73-9452-2731a18846c8", + "data": { + "title": { + "@type": "string", + "@value": "NGINX Overview" + }, + "description": { + "@type": "string", + "@value": "Overview of requests handled by NGINX" + }, + "widgets": [ + { + "id": { + "@type": "string", + "@value": "ab3138d7-9790-4c71-a804-f59ff5692e0f" + }, + "description": { + "@type": "string", + "@value": "Requests last 24h" + }, + "type": { + "@type": "string", + "@value": "STREAM_SEARCH_RESULT_COUNT" + }, + "cache_time": { + "@type": "integer", + "@value": 10 + }, + "time_range": { + "type": { + "@type": "string", + "@value": "relative" + }, + "range": { + "@type": "integer", + "@value": 300 + } + }, + "configuration": { + "timerange": { + "type": { + "@type": "string", + "@value": "relative" + }, + "range": { + "@type": "integer", + "@value": 300 + } + }, + "lower_is_better": { + "@type": "boolean", + "@value": false + }, + "stream_id": { + "@type": "string", + "@value": "3b4da8c0-e9f8-42f9-8f41-9222caa8f407" + }, + "trend": { + "@type": "boolean", + "@value": false + }, + "query": { + "@type": "string", + "@value": "*" + } + }, + "position": null + } + ] + }, + "constraints": [ + { + "type": "server-version", + "version": ">=3.0.0+db6cf59" + } + ] + }, + { + "v": "1", + "type": { + "name": "input", + "version": "1" + }, + "id": "fa2ca431-c30d-455d-98b0-9ee703760760", + "data": { + "title": { + "@type": "string", + "@value": "nginx access log" + }, + "configuration": { + "expand_structured_data": { + "@type": "boolean", + "@value": false + }, + "recv_buffer_size": { + "@type": "integer", + "@value": 1048576 + }, + "port": { + "@type": "integer", + "@value": 12304 + }, + "number_worker_threads": { + "@type": "integer", + "@value": 4 + }, + "force_rdns": { + "@type": "boolean", + "@value": false + }, + "allow_override_date": { + "@type": "boolean", + "@value": true + }, + "bind_address": { + "@type": "string", + "@value": "0.0.0.0" + }, + "store_full_message": { + "@type": "boolean", + "@value": false + } + }, + "static_fields": { + "from_nginx": { + "@type": "string", + "@value": "true" + }, + "nginx_access": { + "@type": "string", + "@value": "true" + } + }, + "type": { + "@type": "string", + "@value": "org.graylog2.inputs.syslog.udp.SyslogUDPInput" + }, + "global": { + "@type": "boolean", + "@value": true + }, + "extractors": [ + { + "target_field": { + "@type": "string", + "@value": "json" + }, + "condition_value": { + "@type": "string", + "@value": "" + }, + "order": { + "@type": "integer", + "@value": 2 + }, + "converters": [], + "configuration": { + "replacement": { + "@type": "string", + "@value": "-" + }, + "regex": { + "@type": "string", + "@value": ".*" + } + }, + "source_field": { + "@type": "string", + "@value": "json" + }, + "title": { + "@type": "string", + "@value": "Empty JSON field" + }, + "type": { + "@type": "string", + "@value": "REGEX_REPLACE" + }, + "cursor_strategy": { + "@type": "string", + "@value": "COPY" + }, + "condition_type": { + "@type": "string", + "@value": "NONE" + } + }, + { + "target_field": { + "@type": "string", + "@value": "" + }, + "condition_value": { + "@type": "string", + "@value": "" + }, + "order": { + "@type": "integer", + "@value": 1 + }, + "converters": [], + "configuration": { + "flatten": { + "@type": "boolean", + "@value": true + }, + "list_separator": { + "@type": "string", + "@value": ", " + }, + "kv_separator": { + "@type": "string", + "@value": "=" + }, + "key_prefix": { + "@type": "string", + "@value": "" + }, + "key_separator": { + "@type": "string", + "@value": "_" + }, + "replace_key_whitespace": { + "@type": "boolean", + "@value": false + }, + "key_whitespace_replacement": { + "@type": "string", + "@value": "_" + } + }, + "source_field": { + "@type": "string", + "@value": "json" + }, + "title": { + "@type": "string", + "@value": "Extract JSON fields" + }, + "type": { + "@type": "string", + "@value": "JSON" + }, + "cursor_strategy": { + "@type": "string", + "@value": "COPY" + }, + "condition_type": { + "@type": "string", + "@value": "NONE" + } + }, + { + "target_field": { + "@type": "string", + "@value": "json" + }, + "condition_value": { + "@type": "string", + "@value": "" + }, + "order": { + "@type": "integer", + "@value": 0 + }, + "converters": [], + "configuration": { + "regex_value": { + "@type": "string", + "@value": "nginx:\\s+(.*)" + } + }, + "source_field": { + "@type": "string", + "@value": "message" + }, + "title": { + "@type": "string", + "@value": "Get JSON from syslog message" + }, + "type": { + "@type": "string", + "@value": "REGEX" + }, + "cursor_strategy": { + "@type": "string", + "@value": "COPY" + }, + "condition_type": { + "@type": "string", + "@value": "NONE" + } + }, + { + "target_field": { + "@type": "string", + "@value": "message" + }, + "condition_value": { + "@type": "string", + "@value": "" + }, + "order": { + "@type": "integer", + "@value": 3 + }, + "converters": [], + "configuration": { + "replacement": { + "@type": "string", + "@value": "$1" + }, + "regex": { + "@type": "string", + "@value": ".*request\": \"(.*?)\".*" + } + }, + "source_field": { + "@type": "string", + "@value": "message" + }, + "title": { + "@type": "string", + "@value": "Reduced message to path" + }, + "type": { + "@type": "string", + "@value": "REGEX_REPLACE" + }, + "cursor_strategy": { + "@type": "string", + "@value": "COPY" + }, + "condition_type": { + "@type": "string", + "@value": "NONE" + } + } + ] + }, + "constraints": [ + { + "type": "server-version", + "version": ">=3.0.0+db6cf59" + } + ] + }, + { + "v": "1", + "type": { + "name": "input", + "version": "1" + }, + "id": "540d1628-ceed-49d4-8960-068c5afaa993", + "data": { + "title": { + "@type": "string", + "@value": "nginx error log" + }, + "configuration": { + "expand_structured_data": { + "@type": "boolean", + "@value": false + }, + "recv_buffer_size": { + "@type": "integer", + "@value": 1048576 + }, + "port": { + "@type": "integer", + "@value": 12305 + }, + "number_worker_threads": { + "@type": "integer", + "@value": 4 + }, + "force_rdns": { + "@type": "boolean", + "@value": false + }, + "allow_override_date": { + "@type": "boolean", + "@value": true + }, + "bind_address": { + "@type": "string", + "@value": "0.0.0.0" + }, + "store_full_message": { + "@type": "boolean", + "@value": false + } + }, + "static_fields": { + "nginx_error": { + "@type": "string", + "@value": "true" + }, + "from_nginx": { + "@type": "string", + "@value": "true" + } + }, + "type": { + "@type": "string", + "@value": "org.graylog2.inputs.syslog.udp.SyslogUDPInput" + }, + "global": { + "@type": "boolean", + "@value": true + }, + "extractors": [ + { + "target_field": { + "@type": "string", + "@value": "server" + }, + "condition_value": { + "@type": "string", + "@value": "server" + }, + "order": { + "@type": "integer", + "@value": 1 + }, + "converters": [], + "configuration": { + "regex_value": { + "@type": "string", + "@value": "server:\\s(.+?)(,|$)" + } + }, + "source_field": { + "@type": "string", + "@value": "message" + }, + "title": { + "@type": "string", + "@value": "server" + }, + "type": { + "@type": "string", + "@value": "REGEX" + }, + "cursor_strategy": { + "@type": "string", + "@value": "COPY" + }, + "condition_type": { + "@type": "string", + "@value": "STRING" + } + }, + { + "target_field": { + "@type": "string", + "@value": "timestamp" + }, + "condition_value": { + "@type": "string", + "@value": "" + }, + "order": { + "@type": "integer", + "@value": 0 + }, + "converters": [ + { + "type": { + "@type": "string", + "@value": "DATE" + }, + "configuration": { + "date_format": { + "@type": "string", + "@value": "yyyy/MM/dd HH:mm:ss " + } + } + } + ], + "configuration": { + "regex_value": { + "@type": "string", + "@value": "^.*:\\s(\\d\\d\\d\\d/\\d\\d/\\d\\d\\s\\d\\d:\\d\\d:\\d\\d)\\s.*$" + } + }, + "source_field": { + "@type": "string", + "@value": "message" + }, + "title": { + "@type": "string", + "@value": "Timestamp" + }, + "type": { + "@type": "string", + "@value": "REGEX" + }, + "cursor_strategy": { + "@type": "string", + "@value": "COPY" + }, + "condition_type": { + "@type": "string", + "@value": "NONE" + } + }, + { + "target_field": { + "@type": "string", + "@value": "remote_addr" + }, + "condition_value": { + "@type": "string", + "@value": "client" + }, + "order": { + "@type": "integer", + "@value": 2 + }, + "converters": [], + "configuration": { + "regex_value": { + "@type": "string", + "@value": "client:\\s(.+?)(,|$)" + } + }, + "source_field": { + "@type": "string", + "@value": "message" + }, + "title": { + "@type": "string", + "@value": "remote_addr/client" + }, + "type": { + "@type": "string", + "@value": "REGEX" + }, + "cursor_strategy": { + "@type": "string", + "@value": "COPY" + }, + "condition_type": { + "@type": "string", + "@value": "STRING" + } + }, + { + "target_field": { + "@type": "string", + "@value": "host" + }, + "condition_value": { + "@type": "string", + "@value": "host" + }, + "order": { + "@type": "integer", + "@value": 3 + }, + "converters": [], + "configuration": { + "regex_value": { + "@type": "string", + "@value": "host:\\s\"(.+?)\"(,|$)" + } + }, + "source_field": { + "@type": "string", + "@value": "message" + }, + "title": { + "@type": "string", + "@value": "host" + }, + "type": { + "@type": "string", + "@value": "REGEX" + }, + "cursor_strategy": { + "@type": "string", + "@value": "COPY" + }, + "condition_type": { + "@type": "string", + "@value": "STRING" + } + }, + { + "target_field": { + "@type": "string", + "@value": "request_verb" + }, + "condition_value": { + "@type": "string", + "@value": "request" + }, + "order": { + "@type": "integer", + "@value": 5 + }, + "converters": [], + "configuration": { + "regex_value": { + "@type": "string", + "@value": "request:\\s\"(GET|HEAD|POST|PUT|DELETE|TRACE|OPTIONS|CONNECT|PATCH).+\"(,|$)" + } + }, + "source_field": { + "@type": "string", + "@value": "message" + }, + "title": { + "@type": "string", + "@value": "request_verb" + }, + "type": { + "@type": "string", + "@value": "REGEX" + }, + "cursor_strategy": { + "@type": "string", + "@value": "COPY" + }, + "condition_type": { + "@type": "string", + "@value": "STRING" + } + }, + { + "target_field": { + "@type": "string", + "@value": "request_path" + }, + "condition_value": { + "@type": "string", + "@value": "request" + }, + "order": { + "@type": "integer", + "@value": 4 + }, + "converters": [], + "configuration": { + "regex_value": { + "@type": "string", + "@value": "request:\\s\"(.+?)\"(,|$)" + } + }, + "source_field": { + "@type": "string", + "@value": "message" + }, + "title": { + "@type": "string", + "@value": "request_path/request" + }, + "type": { + "@type": "string", + "@value": "REGEX" + }, + "cursor_strategy": { + "@type": "string", + "@value": "COPY" + }, + "condition_type": { + "@type": "string", + "@value": "STRING" + } + } + ] + }, + "constraints": [ + { + "type": "server-version", + "version": ">=3.0.0+db6cf59" + } + ] + }, + { + "v": "1", + "type": { + "name": "stream", + "version": "1" + }, + "id": "40645de4-746e-4ec0-86ec-47d893ded9b6", + "data": { + "alarm_callbacks": [], + "outputs": [], + "remove_matches": { + "@type": "boolean", + "@value": false + }, + "title": { + "@type": "string", + "@value": "nginx HTTP 4XXs" + }, + "stream_rules": [ + { + "type": { + "@type": "string", + "@value": "GREATER" + }, + "field": { + "@type": "string", + "@value": "response_status" + }, + "value": { + "@type": "string", + "@value": "399" + }, + "inverted": { + "@type": "boolean", + "@value": false + }, + "description": { + "@type": "string", + "@value": "" + } + }, + { + "type": { + "@type": "string", + "@value": "SMALLER" + }, + "field": { + "@type": "string", + "@value": "response_status" + }, + "value": { + "@type": "string", + "@value": "500" + }, + "inverted": { + "@type": "boolean", + "@value": false + }, + "description": { + "@type": "string", + "@value": "" + } + }, + { + "type": { + "@type": "string", + "@value": "EXACT" + }, + "field": { + "@type": "string", + "@value": "from_nginx" + }, + "value": { + "@type": "string", + "@value": "true" + }, + "inverted": { + "@type": "boolean", + "@value": false + }, + "description": { + "@type": "string", + "@value": "" + } + } + ], + "alert_conditions": [], + "matching_type": { + "@type": "string", + "@value": "AND" + }, + "disabled": { + "@type": "boolean", + "@value": false + }, + "description": { + "@type": "string", + "@value": "All requests that were answered with a HTTP code in the 400 range by nginx" + }, + "default_stream": { + "@type": "boolean", + "@value": false + } + }, + "constraints": [ + { + "type": "server-version", + "version": ">=3.0.0+db6cf59" + } + ] + }, + { + "v": "1", + "type": { + "name": "stream", + "version": "1" + }, + "id": "5a0abcb1-b5af-4239-96f6-d8fc786c54be", + "data": { + "alarm_callbacks": [], + "outputs": [], + "remove_matches": { + "@type": "boolean", + "@value": false + }, + "title": { + "@type": "string", + "@value": "nginx requests" + }, + "stream_rules": [ + { + "type": { + "@type": "string", + "@value": "EXACT" + }, + "field": { + "@type": "string", + "@value": "nginx_access" + }, + "value": { + "@type": "string", + "@value": "true" + }, + "inverted": { + "@type": "boolean", + "@value": false + }, + "description": { + "@type": "string", + "@value": "" + } + } + ], + "alert_conditions": [], + "matching_type": { + "@type": "string", + "@value": "AND" + }, + "disabled": { + "@type": "boolean", + "@value": false + }, + "description": { + "@type": "string", + "@value": "All requests that were logged into the nginx access_log" + }, + "default_stream": { + "@type": "boolean", + "@value": false + } + }, + "constraints": [ + { + "type": "server-version", + "version": ">=3.0.0+db6cf59" + } + ] + }, + { + "v": "1", + "type": { + "name": "stream", + "version": "1" + }, + "id": "3b4da8c0-e9f8-42f9-8f41-9222caa8f407", + "data": { + "alarm_callbacks": [], + "outputs": [], + "remove_matches": { + "@type": "boolean", + "@value": false + }, + "title": { + "@type": "string", + "@value": "nginx" + }, + "stream_rules": [ + { + "type": { + "@type": "string", + "@value": "EXACT" + }, + "field": { + "@type": "string", + "@value": "from_nginx" + }, + "value": { + "@type": "string", + "@value": "true" + }, + "inverted": { + "@type": "boolean", + "@value": false + }, + "description": { + "@type": "string", + "@value": "" + } + } + ], + "alert_conditions": [], + "matching_type": { + "@type": "string", + "@value": "AND" + }, + "disabled": { + "@type": "boolean", + "@value": false + }, + "description": { + "@type": "string", + "@value": "all message to nginx_access and nginx_error" + }, + "default_stream": { + "@type": "boolean", + "@value": false + } + }, + "constraints": [ + { + "type": "server-version", + "version": ">=3.0.0+db6cf59" + } + ] + }, + { + "v": "1", + "type": { + "name": "stream", + "version": "1" + }, + "id": "6bfbdd7e-638a-4ff5-a3e0-327a21bad701", + "data": { + "alarm_callbacks": [], + "outputs": [], + "remove_matches": { + "@type": "boolean", + "@value": false + }, + "title": { + "@type": "string", + "@value": "nginx HTTP 404s" + }, + "stream_rules": [ + { + "type": { + "@type": "string", + "@value": "EXACT" + }, + "field": { + "@type": "string", + "@value": "response_status" + }, + "value": { + "@type": "string", + "@value": "404" + }, + "inverted": { + "@type": "boolean", + "@value": false + }, + "description": { + "@type": "string", + "@value": "" + } + }, + { + "type": { + "@type": "string", + "@value": "EXACT" + }, + "field": { + "@type": "string", + "@value": "from_nginx" + }, + "value": { + "@type": "string", + "@value": "true" + }, + "inverted": { + "@type": "boolean", + "@value": false + }, + "description": { + "@type": "string", + "@value": "" + } + } + ], + "alert_conditions": [], + "matching_type": { + "@type": "string", + "@value": "AND" + }, + "disabled": { + "@type": "boolean", + "@value": false + }, + "description": { + "@type": "string", + "@value": "All requests that were answered with a HTTP 404 by nginx" + }, + "default_stream": { + "@type": "boolean", + "@value": false + } + }, + "constraints": [ + { + "type": "server-version", + "version": ">=3.0.0+db6cf59" + } + ] + }, + { + "v": "1", + "type": { + "name": "stream", + "version": "1" + }, + "id": "be3273d1-ff76-4ab5-8471-f7f2c3a8593e", + "data": { + "alarm_callbacks": [], + "outputs": [], + "remove_matches": { + "@type": "boolean", + "@value": false + }, + "title": { + "@type": "string", + "@value": "nginx HTTP 5XXXs" + }, + "stream_rules": [ + { + "type": { + "@type": "string", + "@value": "GREATER" + }, + "field": { + "@type": "string", + "@value": "response_status" + }, + "value": { + "@type": "string", + "@value": "499" + }, + "inverted": { + "@type": "boolean", + "@value": false + }, + "description": { + "@type": "string", + "@value": "" + } + }, + { + "type": { + "@type": "string", + "@value": "SMALLER" + }, + "field": { + "@type": "string", + "@value": "response_status" + }, + "value": { + "@type": "string", + "@value": "600" + }, + "inverted": { + "@type": "boolean", + "@value": false + }, + "description": { + "@type": "string", + "@value": "" + } + }, + { + "type": { + "@type": "string", + "@value": "EXACT" + }, + "field": { + "@type": "string", + "@value": "from_nginx" + }, + "value": { + "@type": "string", + "@value": "true" + }, + "inverted": { + "@type": "boolean", + "@value": false + }, + "description": { + "@type": "string", + "@value": "" + } + } + ], + "alert_conditions": [], + "matching_type": { + "@type": "string", + "@value": "AND" + }, + "disabled": { + "@type": "boolean", + "@value": false + }, + "description": { + "@type": "string", + "@value": "All requests that were answered with a HTTP code in the 500 range by nginx" + }, + "default_stream": { + "@type": "boolean", + "@value": false + } + }, + "constraints": [ + { + "type": "server-version", + "version": ">=3.0.0+db6cf59" + } + ] + }, + { + "v": "1", + "type": { + "name": "stream", + "version": "1" + }, + "id": "1a3bec0f-34e6-41dc-9d38-fb0997fef588", + "data": { + "alarm_callbacks": [], + "outputs": [], + "remove_matches": { + "@type": "boolean", + "@value": false + }, + "title": { + "@type": "string", + "@value": "nginx errors" + }, + "stream_rules": [ + { + "type": { + "@type": "string", + "@value": "EXACT" + }, + "field": { + "@type": "string", + "@value": "nginx_error" + }, + "value": { + "@type": "string", + "@value": "true" + }, + "inverted": { + "@type": "boolean", + "@value": false + }, + "description": { + "@type": "string", + "@value": "" + } + } + ], + "alert_conditions": [], + "matching_type": { + "@type": "string", + "@value": "AND" + }, + "disabled": { + "@type": "boolean", + "@value": false + }, + "description": { + "@type": "string", + "@value": "All requests that were logged into the nginx error_log" + }, + "default_stream": { + "@type": "boolean", + "@value": false + } + }, + "constraints": [ + { + "type": "server-version", + "version": ">=3.0.0+db6cf59" + } + ] + } + ] +} \ No newline at end of file diff --git a/terranix/graylog/content-packs/journal2Gelf/download.json b/terranix/graylog/content-packs/journal2Gelf/download.json new file mode 100644 index 0000000..1a5ffd2 --- /dev/null +++ b/terranix/graylog/content-packs/journal2Gelf/download.json @@ -0,0 +1 @@ +{"id":"2e0a8254-6356-4fff-b956-883de11d0e4f","rev":1,"v":"1","name":"Systemd Sink","summary":"SystemD synk stuff","description":"Used for Journald2Gelf stuff ","vendor":"palo","url":"","created_at":"2019-10-17T16:19:12.642Z","server_version":"3.0.2+1686930","parameters":[],"entities":[{"id":"26439aa8-e05f-4571-a8cb-03be586ee23d","type":{"name":"input","version":"1"},"v":"1","data":{"title":{"@type":"string","@value":"Systemd Logging"},"configuration":{"recv_buffer_size":{"@type":"integer","@value":262144},"port":{"@type":"integer","@value":11201},"number_worker_threads":{"@type":"integer","@value":4},"bind_address":{"@type":"string","@value":"0.0.0.0"},"decompress_size_limit":{"@type":"integer","@value":8388608}},"static_fields":{},"type":{"@type":"string","@value":"org.graylog2.inputs.gelf.udp.GELFUDPInput"},"global":{"@type":"boolean","@value":true},"extractors":[]},"constraints":[{"type":"server-version","version":">=3.0.2+1686930"}]}]} \ No newline at end of file diff --git a/terranix/graylog/modules/all-messages.nix b/terranix/graylog/modules/all-messages.nix new file mode 100644 index 0000000..1bc5c30 --- /dev/null +++ b/terranix/graylog/modules/all-messages.nix @@ -0,0 +1,46 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + + cfg = config.graylog.all_messages; + +in { + + options.graylog.all_messages = { + streamId = mkOption { + type = with types; str; + default = "000000000000000000000001"; + description = '' + id of "All Messages" stream; + ''; + }; + rules = mkOption { + default = []; + type = with types; listOf str; + example = [ "route sshd" "route kernel" "mark junk" ]; + description = '' + all the rules which should be called on the pipeline operating on the + all_messages input + ''; + }; + }; + + config = mkIf (cfg.rules != []) { + graylog.pipeline.mainsorting = { + source = + let + rules = map (rule: " rule \"${rule}\";") cfg.rules; + in + '' + stage 0 match either + ${concatStringsSep "\n" rules} + ''; + + description = "main sorting pipeline (TF)"; + streamId = cfg.streamId; + }; + }; + +} diff --git a/terranix/graylog/modules/default.nix b/terranix/graylog/modules/default.nix new file mode 100644 index 0000000..c93eab3 --- /dev/null +++ b/terranix/graylog/modules/default.nix @@ -0,0 +1,8 @@ +{ + imports = [ + ./all-messages.nix + ./provider.nix + ./pipeline.nix + ./stream.nix + ]; +} diff --git a/terranix/graylog/modules/pipeline.nix b/terranix/graylog/modules/pipeline.nix new file mode 100644 index 0000000..f49a5cf --- /dev/null +++ b/terranix/graylog/modules/pipeline.nix @@ -0,0 +1,105 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + + cfg = config.graylog.pipeline; + +in { + + options.graylog.pipeline = mkOption { + default = {}; + type = with types; attrsOf (submodule ({ name , ... }: { + options = { + name = mkOption { + type = with types; str; + default = name; + description = '' + name of the pipeline + ''; + }; + streamId = mkOption { + type = with types; nullOr str; + default = null; + example = "000000000000000001"; + description = '' + stream id on which this pipeline should operate + dont use terraform references here. + ''; + }; + description = mkOption { + type = with types; str; + default = ""; + description = '' + description of the pipeline + ''; + }; + # todo : create proper module system here + source = mkOption { + type = with types; str; + description = '' + source of the pipeline (without the header and the end) + ''; + }; + }; + })); + }; + + config = + let + allPipelines = cfg; + allPipelineConnections = mapAttrsToList ( + name: values: + { + "${values.streamId}" = "\${graylog_pipeline.${name}.id}"; + } + ) (filterAttrs(name: values: values.streamId != null) allPipelines); + collected = foldAttrs (n: a: [n] ++ a) [] allPipelineConnections; + in + mkIf (cfg != {}) { + + # create pipelines + resource."graylog_pipeline" = + mapAttrs ( + name: pipelineConfig: + { + source = '' + pipeline "${pipelineConfig.name}" + ${pipelineConfig.source} + end + ''; + description = pipelineConfig.description; + } + ) + allPipelines; + + resource."graylog_pipeline_connection" = + let + mapping = filter ( + name: + builtins.match ".*\\$.*" name != null + ) (builtins.attrNames collected); + in + + mkAssert ( mapping == [] ) + '' + graylog.pipeline..streamId = + ${concatStringsSep "\n " mapping} + is not valid. + + use graylog.stream..pipelines instead + '' + (mapAttrs ( + name: pipelineConfig: + { + stream_id = name; + pipeline_ids = pipelineConfig; + } + ) + collected); + + + }; + +} diff --git a/terranix/graylog/modules/provider.nix b/terranix/graylog/modules/provider.nix new file mode 100644 index 0000000..7c0f9f0 --- /dev/null +++ b/terranix/graylog/modules/provider.nix @@ -0,0 +1,14 @@ +{ + + variable.web_endpoint_uri.description = ""; + variable.auth_name.description = ""; + variable.auth_password.description = ""; + + provider."graylog" = { + web_endpoint_uri = "\${var.web_endpoint_uri}"; + auth_name = "\${var.auth_name}"; + auth_password = "\${var.auth_password}"; + api_version = "v3"; + }; + +} diff --git a/terranix/graylog/modules/stream.nix b/terranix/graylog/modules/stream.nix new file mode 100644 index 0000000..fad29cb --- /dev/null +++ b/terranix/graylog/modules/stream.nix @@ -0,0 +1,54 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + + cfg = config.graylog.stream; + +in { + + options.graylog.stream = mkOption { + default = {}; + type = with types; attrsOf (submodule ({ name, ... }: { + options = { + title = mkOption { + default = name; + type = with types; str; + }; + index_set_id = mkOption { + type = with types; str; + }; + disabled = mkOption { + default = false; + type = with types; bool; + }; + matching_type = mkOption { + default = "AND"; + type = with types; str; + }; + pipelines = mkOption { + default = []; + type = with types; listOf str; + }; + }; + })); + }; + + config = mkIf (cfg != {}) { + resource.graylog_stream = + mapAttrs ( + name: value: { inherit (value) title index_set_id disabled matching_type;}) + cfg; + + resource.graylog_pipeline_connection = + mapAttrs ( + name: pipelineConfig: + { + stream_id = "\${graylog_stream.${name}.id}"; + pipeline_ids = pipelineConfig.pipelines; + } + ) + cfg; + }; +} diff --git a/terranix/graylog/shell.nix b/terranix/graylog/shell.nix new file mode 100644 index 0000000..318d268 --- /dev/null +++ b/terranix/graylog/shell.nix @@ -0,0 +1,73 @@ +{ pkgs ? import { } }: + +let + + terranix = pkgs.callPackage (pkgs.fetchgit { + url = "https://github.com/mrVanDalo/terranix.git"; + rev = "6097722f3a94972a92d810f3a707351cd425a4be"; + sha256 = "1d8w82mvgflmscvq133pz9ynr79cgd5qjggng85byk8axj6fg6jw"; + }) { }; + + # a custom provider for terraform + graylog = pkgs.buildGoModule rec { + name = "terraform-provider-graylog-${version}"; + version = "v3.3.0"; + + subPackages = [ "./terraform" ]; + + src = pkgs.fetchFromGitHub { + owner = "suzuki-shunsuke"; + repo = "go-graylog"; + sha256 = "12b0d70qzwaqgzksiyc7ia86g7869b1a6mfymqzkp2h5h4kcwcfh"; + rev = "${version}"; + }; + + modSha256 = "0zbly0wyqa4jw6h54b1y03j6v1c5fqgslfdyrzii9rpq3y6g0kkf"; + + postInstall = "mv $out/bin/terraform{,-provider-graylog_${version}}"; + + meta = with pkgs.stdenv.lib; { + homepage = https://github.com/suzuki-shunsuke/go-graylog; + description = "Terraform provider is used to manage graylog."; + platforms = platforms.linux; + license = licenses.mpl20; + maintainers = with maintainers; [ palo ]; + }; + }; + + terraform = pkgs.terraform.withPlugins(p: [ + graylog + ]); + +in pkgs.mkShell { + + buildInputs = [ + + # terraform wrapper to set access variables + # ----------------------------------------- + (pkgs.writeShellScriptBin "terraform" '' + export TF_VAR_web_endpoint_uri="http://schasch.private:9000/api" + export TF_VAR_auth_name=admin + export TF_VAR_auth_password=yourpassword + ${terraform}/bin/terraform "$@" + '') + + # terranix to avoid HCL + # --------------------- + terranix + + # tooling + # ------- + pkgs.terraform-landscape + pkgs.terraform-docs + + ]; + + shellHook = '' + # save shell history in project folder + HISTFILE=${toString ./.history} + # configure password store to use subfolder + export PASSWORD_STORE_DIR=./secrets + ''; + +} diff --git a/terranix/servers/config.nix b/terranix/servers/config.nix new file mode 100644 index 0000000..65ba2ac --- /dev/null +++ b/terranix/servers/config.nix @@ -0,0 +1,35 @@ +{ config , ... }: +let + + get = element: object: + "\${ ${object."_ref"}.${element} }"; + + getVariable = name: + "\${ var.${name} }"; + +in { + + hcloud = { + enable = true; + + resource.server."tinc_node" = { + name = "tinc-node-nurnberg"; + image = "ubuntu-18.04"; + server_type = "cx11"; + backups = false; + # datacenter = "nbg1-dc3"; + location = "nbg1"; + labels = { + system = "nixos"; + }; + }; + }; + + output = { + "${config.hcloud.resource.server."tinc_node".name}-ip4_address".value = + get "ipv4_address" config.hcloud.resource.server."tinc_node"; + "${config.hcloud.resource.server."tinc_node".name}-ip6_address".value = + get "ipv6_address" config.hcloud.resource.server."tinc_node"; + }; + +} diff --git a/terranix/servers/modules/nix-server.nix b/terranix/servers/modules/nix-server.nix new file mode 100644 index 0000000..57f44f3 --- /dev/null +++ b/terranix/servers/modules/nix-server.nix @@ -0,0 +1,36 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + + cfg = config.hcloud.nixserver; + +in { + + options.hcloud.nixserver = { + enable = mkEnableOption '' + create a nixos server on hetzner. + this module will take car of everything needed + to be done, to install stuff on it. + + wip + ''; + }; + + config = mkIf cfg.enable { + hcloud.resource = { + server."todo" = { + name = "todo-module-created-server"; + image = "ubuntu-18.04"; + iso = "nixos-graphical-18.09.1195.bf7930d582b-x86_64-linux.iso"; + server_type = "cx11"; + location = "nbg1"; + rescue = "linux64"; + labels = { + system = "nixos"; + }; + }; + }; + }; +} diff --git a/terranix/servers/shell.nix b/terranix/servers/shell.nix new file mode 100644 index 0000000..a01a8f7 --- /dev/null +++ b/terranix/servers/shell.nix @@ -0,0 +1,34 @@ +{ pkgs ? import {} }: +let + + #terraform = terraform-current; + terraform = pkgs.terraform; + terraform-current = pkgs.terraform.overrideAttrs( old: rec { + version = "0.11.10"; + name = "terraform-${version}"; + src = pkgs.fetchFromGitHub { + owner = "hashicorp"; + repo = "terraform"; + rev = "v${version}"; + sha256 = "08mapla89g106bvqr41zfd7l4ki55by6207qlxq9caiha54nx4nb"; + }; + }); + +in pkgs.mkShell { + + # needed pkgs + # ----------- + buildInputs = with pkgs; [ + + (pkgs.writeShellScriptBin "terraform" '' + export TF_VAR_hcloud_api_token=`${pkgs.pass}/bin/pass development/hetzner.com/api-token` + ${terraform}/bin/terraform "$@" + '') + ]; + + # run this on start + # ----------------- + shellHook = '' + HISTFILE=${toString ./.}/.history + ''; +} diff --git a/terranix/servers/terraform.tfstate b/terranix/servers/terraform.tfstate new file mode 100644 index 0000000..856cff9 --- /dev/null +++ b/terranix/servers/terraform.tfstate @@ -0,0 +1,56 @@ +{ + "version": 3, + "terraform_version": "0.11.8", + "serial": 8, + "lineage": "7e62f96d-8ac5-3176-737b-1a6a2e7812db", + "modules": [ + { + "path": [ + "root" + ], + "outputs": { + "tinc-node-nurnberg-ip4_address": { + "sensitive": false, + "type": "string", + "value": "195.201.134.247" + }, + "tinc-node-nurnberg-ip6_address": { + "sensitive": false, + "type": "string", + "value": "2a01:4f8:1c1c:65e6::" + } + }, + "resources": { + "hcloud_server.tinc_node": { + "type": "hcloud_server", + "depends_on": [], + "primary": { + "id": "963656", + "attributes": { + "backup_window": "", + "backups": "false", + "datacenter": "nbg1-dc3", + "id": "963656", + "image": "ubuntu-18.04", + "ipv4_address": "195.201.134.247", + "ipv6_address": "2a01:4f8:1c1c:65e6::", + "ipv6_network": "2a01:4f8:1c1c:65e6::/64", + "keep_disk": "false", + "labels.%": "1", + "labels.system": "nixos", + "location": "nbg1", + "name": "tinc-node-nurnberg", + "server_type": "cx11", + "status": "running" + }, + "meta": {}, + "tainted": false + }, + "deposed": [], + "provider": "provider.hcloud" + } + }, + "depends_on": [] + } + ] +} diff --git a/updateChannels.sh b/updateChannels.sh new file mode 100644 index 0000000..0ebbdc2 --- /dev/null +++ b/updateChannels.sh @@ -0,0 +1,25 @@ +#!/usr/bin/env bash + +function fetch (){ + local rev=$1 + local output=$2 + local url=${3:-https://github.com/NixOS/nixpkgs-channels.git} + + echo + echo + echo "update $url to rev $1" + nix-prefetch-git \ + --url ${url} \ + --rev ${rev} \ + > ${output} + +} + +fetch "refs/heads/nixos-19.03" .channelStable.json +fetch "refs/heads/nixos-unstable" .channelUnstable.json + +fetch "refs/tags/v1.4.2" .krops.json "https://git.ingolf-wagner.de/krebs/krops.git" +fetch "refs/tags/v3.2.0" .nix-writers.json "https://cgit.krebsco.de/nix-writers/" +fetch "ef1e4480cf8af45cfdeac597b2f1b1af33923e93" .nixos-generators.json "https://github.com/nix-community/nixos-generators.git" + +