diff --git a/common/default.nix b/common/default.nix index fc761fc..7be500e 100644 --- a/common/default.nix +++ b/common/default.nix @@ -76,6 +76,7 @@ bat niv sqlite-interactive + hacc-scripts ]; security.acme.defaults.email = "info+acme@hacc.space"; diff --git a/parsons/uffd.nix b/parsons/uffd.nix index 747ed76..a1d9a35 100644 --- a/parsons/uffd.nix +++ b/parsons/uffd.nix @@ -101,6 +101,18 @@ startAt = "*:0/15"; }; + systemd.services.uffd-account-expiry-notification = { + enable = true; + wantedBy = [ "multi-user.target" ]; + after = [ "network.target" ]; + serviceConfig.Type = "simple"; + path = [ pkgs.hacc-scripts pkgs.sqlite-interactive pkgs.postfix ]; + script = '' + uffd-unused-accounts-notification.scm -v admin + ''; + startAt = "weekly"; + }; + sops.secrets."auamost/secrets.fish" = { }; environment.systemPackages = with pkgs; [ curl jq ]; diff --git a/pkgs/default.nix b/pkgs/default.nix index e1e6bc4..7f34184 100644 --- a/pkgs/default.nix +++ b/pkgs/default.nix @@ -26,6 +26,8 @@ let uffd = oldstable.callPackage ./uffd { }; + hacc-scripts = callPackage ./scripts {}; + inherit (oldstable) uwsgi flask; # TODO: once on nixos 24.05, remove this inherit diff --git a/pkgs/scripts/default.nix b/pkgs/scripts/default.nix new file mode 100644 index 0000000..8cb017f --- /dev/null +++ b/pkgs/scripts/default.nix @@ -0,0 +1,15 @@ +{ stdenvNoCC, gauche }: + +stdenvNoCC.mkDerivation { + name = "hacc-utility-scripts"; + + src = ./.; + + buildInputs = [ gauche ]; + + installPhase = '' + chmod +x *.scm + mkdir -p $out/bin + cp *.scm $out/bin + ''; +} diff --git a/pkgs/scripts/uffd-unused-accounts-notification.scm b/pkgs/scripts/uffd-unused-accounts-notification.scm new file mode 100644 index 0000000..cf7fa92 --- /dev/null +++ b/pkgs/scripts/uffd-unused-accounts-notification.scm @@ -0,0 +1,121 @@ +#!/usr/bin/env gosh + +(use gauche.process) +(use text.csv) +(use scheme.list) +(use gauche.parseopt) +(use util.match) + +(define cutoff-date "2023-01-01") + +(define sqlite-path "/persist/containers/uffd/uffd/db.sqlite") +(define sqlite-query + "select displayname, mail, max(expires) as last_login from oauth2token join user on user_id=user.id group by user_id having last_login < '2023-01-01' +union all select displayname, mail, '2022' from user where not exists (select * from oauth2token where user_id = user.id);") + +(define dry #f) +(define verbose #f) +(define very-verbose #f) + +(define (main args) + (let-args (cdr args) + ((averbose "v|verbose") + (averyverbose "very-verbose") + (adry "n|dry-run") + (help "h|help" => (cut show-help (car args))) + . restargs + ) + (set! dry adry) + (set! verbose averbose) + (when averyverbose + (set! verbose #t) + (set! very-verbose #t)) + (match restargs + [("admin") (do-admin-mail)] + [("send-reminder") (send-reminder-mails)] + [("list-accounts") (do-list-accounts)] + [_ (display "unknown command") (exit 1)])) + 0) + +(define (do-admin-mail) + (send-email "admin@hacc.space" "unused accounts list" (mk-admin-mail unused-accounts)) + (when verbose + (display "done"))) + +(define (do-list-accounts) + (display (string-join + (map + (lambda (row) (format "~a (~a)" (list-ref row 0) (list-ref row 1))) + unused-accounts) + "\n"))) + +(define (send-reminder-mails) + (map (lambda (row) + (send-email (list-ref row 1) "Unbenutzter infra4future.de Account" (mk-email (list-ref row 0) (list-ref row 2)))) + unused-accounts) + (when verbose + (display "done"))) + + +(define csv-reader + (make-csv-reader #\,)) + +(define unused-accounts + (map (lambda (str) (with-input-from-string str csv-reader)) + ;; (process-output->string-list `(cat example.csv)))) + (process-output->string-list `(sqlite3 -csv ,sqlite-path ,sqlite-query)))) + +(define (mk-email displayname last-login) + #" +Subject: meow +Hallo ~|displayname|! + +Wir haben schon lange (seit über einem Jahr; dein letzter Login war um ~|last-login|) +nichts mehr von dir gehört und würden demnächst deinen Account löschen wollen. +Solltest du ihn noch benötigen logge dich bitte einfach auf https://login.infra4future.de ein. +Falls nicht, musst du weiter nichts tun und wir werden deine Account in ca. 3 Monaten löschen. + +Viele Grüße, +das Infra4Future Team +") + +(define (mk-admin-mail rows) + (format #" +Meow! + +this is the uffd-unused-accounts-notification.scm script. There are currently +~~s accounts which have not logged in since ~|cutoff-date|. To mass-send account +expiry reminders, invoke this script with the \"send-reminder\" option. To see a +list of these accounts, invoke it with the \"list-accounts\" option. + +(invoke me,, 🥺) +" (length unused-accounts))) + +; utility definitions + +(define (send-email address subject text) + (when verbose + (display (format "sending email to ~a\n" address))) + (let ([text (string-append "subject: " subject "\n" text "\n")]) + (when very-verbose + (display text)) + (call-with-output-process + (if dry '(cat) `(sendmail ,address)) + (lambda (port) (display text port)) + :on-abnormal-exit :ignore))) + +(define (show-help progname) + (display #" +~|progname|: unused account expiry helper script. + +Invoke as `~|progname| [options] admin' to send a list of unused accounts to administrators. + +Invoke as `~|progname| [options] send-reminder' to send a reminder email to all +currently unused accounts. + +Options: + -v --verbose show which emails are being sent + -n --dry-run print emails to stdout instead + -h --help show this help +")) +