summaryrefslogtreecommitdiff
path: root/trivionomicon/modules
diff options
context:
space:
mode:
Diffstat (limited to 'trivionomicon/modules')
-rw-r--r--trivionomicon/modules/athena-bccr/default.nix14
-rw-r--r--trivionomicon/modules/athena-bccr/hm.nix19
-rw-r--r--trivionomicon/modules/athena-bccr/options.nix42
-rw-r--r--trivionomicon/modules/athena-bccr/sys.nix100
-rw-r--r--trivionomicon/modules/default.nix3
-rw-r--r--trivionomicon/modules/laptop/default.nix10
-rw-r--r--trivionomicon/modules/laptop/sys.nix11
-rw-r--r--trivionomicon/modules/mediawiki/default.nix13
-rw-r--r--trivionomicon/modules/mediawiki/options.nix62
-rw-r--r--trivionomicon/modules/mediawiki/sys.nix32
-rw-r--r--trivionomicon/modules/nix-registry/default.nix16
-rw-r--r--trivionomicon/modules/nix-registry/hm.nix23
-rw-r--r--trivionomicon/modules/nix-registry/options.nix19
-rw-r--r--trivionomicon/modules/socialpredict/default.nix11
-rw-r--r--trivionomicon/modules/socialpredict/options.nix78
-rw-r--r--trivionomicon/modules/socialpredict/sys.nix102
-rw-r--r--trivionomicon/modules/soju/default.nix13
-rw-r--r--trivionomicon/modules/soju/options.nix16
-rw-r--r--trivionomicon/modules/soju/sys.nix47
-rw-r--r--trivionomicon/modules/sway/default.nix13
-rw-r--r--trivionomicon/modules/sway/options.nix3
-rw-r--r--trivionomicon/modules/sway/sys.nix45
-rw-r--r--trivionomicon/modules/thinkpad/default.nix11
-rw-r--r--trivionomicon/modules/thinkpad/sys.nix30
-rw-r--r--trivionomicon/modules/trivionomiconMotd/default.nix10
-rw-r--r--trivionomicon/modules/trivionomiconMotd/sys.nix22
-rw-r--r--trivionomicon/modules/waybar/default.nix13
-rw-r--r--trivionomicon/modules/waybar/hm.nix207
-rw-r--r--trivionomicon/modules/waybar/options.nix23
-rw-r--r--trivionomicon/modules/yubico/default.nix13
-rw-r--r--trivionomicon/modules/yubico/hm.nix9
-rw-r--r--trivionomicon/modules/yubico/sys.nix14
32 files changed, 1044 insertions, 0 deletions
diff --git a/trivionomicon/modules/athena-bccr/default.nix b/trivionomicon/modules/athena-bccr/default.nix
new file mode 100644
index 0000000..93c5660
--- /dev/null
+++ b/trivionomicon/modules/athena-bccr/default.nix
@@ -0,0 +1,14 @@
+{
+ config,
+ lib,
+ pkgs,
+ doctrine,
+ ...
+}:
+doctrine.lib.mkModule {
+ inherit config;
+ name = "athena-bccr";
+ hm = ./hm.nix;
+ sys = ./sys.nix;
+ options = ./options.nix;
+}
diff --git a/trivionomicon/modules/athena-bccr/hm.nix b/trivionomicon/modules/athena-bccr/hm.nix
new file mode 100644
index 0000000..df41f12
--- /dev/null
+++ b/trivionomicon/modules/athena-bccr/hm.nix
@@ -0,0 +1,19 @@
+{
+ pkgs,
+ lib,
+ cfg,
+ doctrine,
+ ...
+}: let
+ athena =
+ (pkgs.${doctrine.prefix}.athena-bccr.override {
+ inherit (cfg) mirror;
+ }).${
+ cfg.release
+ };
+in {
+ home.packages = [
+ athena.firmador
+ (athena.gaudi.override {inherit (cfg) gaudiHash;})
+ ];
+}
diff --git a/trivionomicon/modules/athena-bccr/options.nix b/trivionomicon/modules/athena-bccr/options.nix
new file mode 100644
index 0000000..7b6cf93
--- /dev/null
+++ b/trivionomicon/modules/athena-bccr/options.nix
@@ -0,0 +1,42 @@
+{lib, ...}:
+with lib.types; {
+ hm = {
+ gaudiHash = lib.mkOption {
+ type = nullOr str;
+ default = null;
+ description = "hash of the Gaudi client";
+ };
+
+ mirror = lib.mkOption {
+ type = nullOr str;
+ default = null;
+ description = "release zip mirror base URL, if null then the release zip must be manually added to the Nix store";
+ };
+
+ release = lib.mkOption {
+ type = str;
+ default = "latest";
+ description = "pinned athena-bccr release tag";
+ };
+ };
+
+ sys = {
+ group = lib.mkOption {
+ type = str;
+ default = "users";
+ description = "user group with full access to the smartcard reader";
+ };
+
+ mirror = lib.mkOption {
+ type = nullOr str;
+ default = null;
+ description = "release zip mirror base URL, if null then the release zip must be manually added to the Nix store";
+ };
+
+ release = lib.mkOption {
+ type = str;
+ default = "latest";
+ description = "pinned athena-bccr release tag";
+ };
+ };
+}
diff --git a/trivionomicon/modules/athena-bccr/sys.nix b/trivionomicon/modules/athena-bccr/sys.nix
new file mode 100644
index 0000000..bd7d758
--- /dev/null
+++ b/trivionomicon/modules/athena-bccr/sys.nix
@@ -0,0 +1,100 @@
+{
+ config,
+ pkgs,
+ lib,
+ cfg,
+ doctrine,
+ ...
+}: let
+ athena =
+ (pkgs.${doctrine.prefix}.athena-bccr.override {
+ inherit (cfg) mirror;
+ }).${
+ cfg.release
+ };
+
+ inherit (athena) vendor;
+
+ driver = athena.card-driver.lib;
+ scmiddleware = "${driver}/lib/SCMiddleware";
+in {
+ environment = {
+ etc =
+ {
+ "pkcs11/modules/${vendor}".text = ''
+ module: ${athena.pkcs11-module}
+ '';
+ }
+ // lib.optionalAttrs (vendor == "athena") {
+ "Athena".source = "${driver}/etc/Athena";
+ }
+ // lib.optionalAttrs (vendor == "idopte") {
+ "idoss.conf".source = "${driver}/etc/idoss.conf";
+ "idoss.lic".source = "${driver}/etc/idoss.lic";
+ "SCMiddleware".source = scmiddleware;
+ };
+
+ systemPackages = [athena.card-driver];
+ };
+
+ security = {
+ #FIXME: Extremadamente peligroso si BCCR o MICITT caen, investigar política nacional de root CA
+ pki.certificateFiles = ["${athena.bccr-cacerts}/root-ca.pem"];
+
+ polkit = {
+ enable = lib.mkDefault true;
+
+ extraConfig = ''
+ polkit.addRule(function(action, subject) {
+ if ((action.id == "org.debian.pcsc-lite.access_pcsc" || action.id == "org.debian.pcsc-lite.access_card") &&
+ subject.isInGroup("users")) {
+ return polkit.Result.YES;
+ }
+ });
+ '';
+ };
+ };
+
+ services = {
+ pcscd.enable = true;
+
+ udev.extraRules =
+ lib.optionalString (vendor == "athena") ''
+ # Athena Smartcard Solutions, Inc. ASEDrive V3CR
+ ATTRS{idVendor}=="0dc3", ATTRS{idProduct}=="1004", MODE="660", GROUP="${cfg.group}", TAG+="uaccess"
+ ''
+ + lib.optionalString (vendor == "idopte") ''
+ # Bit4id Srl miniLector-s
+ ACTION=="add", SUBSYSTEM=="usb", ENV{PRODUCT}=="25dd/1101*", RUN+="${config.systemd.package}/bin/systemctl start --no-block idopte-reader.target"
+ ACTION=="remove", SUBSYSTEM=="usb", ENV{PRODUCT}=="25dd/1101*", RUN+="${config.systemd.package}/bin/systemctl stop --no-block idopte-reader.target"
+ '';
+ };
+
+ systemd = lib.mkIf (vendor == "idopte") {
+ #TODO: make this run as a non-root user
+ services.idopte-cache = {
+ description = "Idopte cache server";
+
+ after = ["smartcard.target"];
+ bindsTo = ["idopte-reader.target"];
+ wantedBy = ["idopte-reader.target"];
+
+ serviceConfig = {
+ Type = "forking";
+ PIDFile = "/run/idoCacheSrv.pid";
+ RuntimeDirectory = "idoss";
+
+ ExecStart = "${scmiddleware}/idocachesrv";
+ };
+ };
+
+ targets.idopte-reader = {
+ description = "Idopte USB reader inserted";
+
+ wants = ["smartcard.target"];
+ before = ["smartcard.target"];
+ };
+ };
+
+ users.groups.${cfg.group} = {};
+}
diff --git a/trivionomicon/modules/default.nix b/trivionomicon/modules/default.nix
new file mode 100644
index 0000000..0c0fd4c
--- /dev/null
+++ b/trivionomicon/modules/default.nix
@@ -0,0 +1,3 @@
+{doctrine, ...}: {
+ imports = builtins.attrValues (doctrine.lib.importAll {root = ./.;});
+}
diff --git a/trivionomicon/modules/laptop/default.nix b/trivionomicon/modules/laptop/default.nix
new file mode 100644
index 0000000..b908d47
--- /dev/null
+++ b/trivionomicon/modules/laptop/default.nix
@@ -0,0 +1,10 @@
+{
+ config,
+ doctrine,
+ ...
+}:
+doctrine.lib.mkModule {
+ inherit config;
+ name = "laptop";
+ sys = ./sys.nix;
+}
diff --git a/trivionomicon/modules/laptop/sys.nix b/trivionomicon/modules/laptop/sys.nix
new file mode 100644
index 0000000..252f49c
--- /dev/null
+++ b/trivionomicon/modules/laptop/sys.nix
@@ -0,0 +1,11 @@
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}: {
+ services = {
+ tlp.enable = lib.mkDefault true;
+ upower.enable = lib.mkDefault true;
+ };
+}
diff --git a/trivionomicon/modules/mediawiki/default.nix b/trivionomicon/modules/mediawiki/default.nix
new file mode 100644
index 0000000..2ed69c2
--- /dev/null
+++ b/trivionomicon/modules/mediawiki/default.nix
@@ -0,0 +1,13 @@
+{
+ config,
+ lib,
+ pkgs,
+ doctrine,
+ ...
+}:
+doctrine.lib.mkModule {
+ inherit config;
+ name = "mediawiki";
+ sys = ./sys.nix;
+ options = ./options.nix;
+}
diff --git a/trivionomicon/modules/mediawiki/options.nix b/trivionomicon/modules/mediawiki/options.nix
new file mode 100644
index 0000000..bb39a14
--- /dev/null
+++ b/trivionomicon/modules/mediawiki/options.nix
@@ -0,0 +1,62 @@
+{lib, ...}:
+with lib.types; {
+ sys = {
+ hostName = lib.mkOption {
+ type = str;
+ description = "used for nginx virtualhost. no protocol";
+ example = "wiki.posixlycorrect.com";
+ };
+
+ name = lib.mkOption {
+ type = str;
+ description = "name of the wiki";
+ example = "posixlycorrect wiki";
+ };
+
+ passwordFile = lib.mkOption {
+ type = types.path;
+ description = "A file containing the initial password for the administrator account 'admin'";
+ example = "/run/keys/mediawiki-password";
+ };
+
+ skins = lib.mkOption {
+ type = types.attrsOf (types.nullOr str);
+ description = "skins for mediawiki";
+ default = {};
+ example = '' {
+ citizen = "flakes.mediawikiSkinCitizen";
+ };'';
+ };
+
+ extraConfig = lib.mkOption {
+ type = str;
+ default = "";
+ example = ''
+ # Disable anonymous editing and account creation
+ $wgGroupPermissions['*']['edit'] = false;
+ $wgGroupPermissions['*']['createaccount'] = false;
+ '';
+ };
+
+ extensions = lib.mkOption {
+ type = types.attrsOf (types.nullOr types.path);
+ description = "some extensions are included and can enabled by passing null";
+ default = {};
+ example = '' {
+ VisualEditor = null;
+ CategoryTree = null;
+ CiteThisPage = null;
+ Scribunto = null;
+ Cite = null;
+ CodeEditor = null;
+ Math = null;
+ MultimediaViewer = null;
+ PdfHandler = null;
+ Poem = null;
+ SecureLinkFixer = null;
+ WikiEditor = null;
+ ParserFunctions = null;
+ };'';
+ };
+ };
+}
diff --git a/trivionomicon/modules/mediawiki/sys.nix b/trivionomicon/modules/mediawiki/sys.nix
new file mode 100644
index 0000000..b6a9273
--- /dev/null
+++ b/trivionomicon/modules/mediawiki/sys.nix
@@ -0,0 +1,32 @@
+{
+ pkgs,
+ lib,
+ cfg,
+ doctrine,
+ ...
+}:
+with lib; {
+ services = {
+ nginx = {
+ virtualHosts.${cfg.hostName} = {
+ enableACME = true;
+ forceSSL = true;
+ extraConfig = ''
+ proxy_headers_hash_max_size 512;
+ proxy_headers_hash_bucket_size 128;
+ '';
+ };
+ };
+ mediawiki = {
+ enable = true;
+ name = cfg.name;
+ webserver = "nginx";
+ nginx.hostName = cfg.hostName;
+ database.type = "postgres";
+ passwordFile = cfg.passwordFile;
+ skins = cfg.skins;
+ extraConfig = cfg.extraConfig;
+ extensions = cfg.extensions;
+ };
+ };
+}
diff --git a/trivionomicon/modules/nix-registry/default.nix b/trivionomicon/modules/nix-registry/default.nix
new file mode 100644
index 0000000..8406d88
--- /dev/null
+++ b/trivionomicon/modules/nix-registry/default.nix
@@ -0,0 +1,16 @@
+{
+ config,
+ lib,
+ pkgs,
+ doctrine,
+ flakes,
+ ...
+}:
+doctrine.lib.mkModule {
+ inherit config;
+ name = "nix-registry";
+ hm = ./hm.nix;
+ options = ./options.nix;
+
+ passthru = {inherit flakes;};
+}
diff --git a/trivionomicon/modules/nix-registry/hm.nix b/trivionomicon/modules/nix-registry/hm.nix
new file mode 100644
index 0000000..1c57e95
--- /dev/null
+++ b/trivionomicon/modules/nix-registry/hm.nix
@@ -0,0 +1,23 @@
+{
+ pkgs,
+ lib,
+ cfg,
+ flakes,
+ ...
+}: let
+ registryName = name:
+ if name == "self"
+ then cfg.renameSelf
+ else name;
+
+ registryFilter = {
+ nixpkgs = true;
+ unstable = true;
+ self = cfg.renameSelf != null;
+ };
+in {
+ nix.registry =
+ lib.mapAttrs'
+ (name: value: lib.nameValuePair (registryName name) {flake = value;})
+ (lib.filterAttrs (name: _: registryFilter.${name} or cfg.allInputs) flakes);
+}
diff --git a/trivionomicon/modules/nix-registry/options.nix b/trivionomicon/modules/nix-registry/options.nix
new file mode 100644
index 0000000..e8898ec
--- /dev/null
+++ b/trivionomicon/modules/nix-registry/options.nix
@@ -0,0 +1,19 @@
+{lib, ...}:
+with lib.types; {
+ hm = {
+ allInputs = mkOption {
+ type = bool;
+ default = default;
+ description = ''
+ Include all flake inputs. If false, only 'nixpkgs' and 'unstable'
+ (if available) will be added to the flake registry by default.
+ '';
+ };
+
+ renameSelf = mkOption {
+ type = nullOr str;
+ default = "self";
+ description = "Registry name to use for the 'self' input";
+ };
+ };
+}
diff --git a/trivionomicon/modules/socialpredict/default.nix b/trivionomicon/modules/socialpredict/default.nix
new file mode 100644
index 0000000..f821bf4
--- /dev/null
+++ b/trivionomicon/modules/socialpredict/default.nix
@@ -0,0 +1,11 @@
+{
+ config,
+ doctrine,
+ ...
+}:
+doctrine.lib.mkModule {
+ inherit config;
+ name = "socialpredict";
+ options = ./options.nix;
+ sys = ./sys.nix;
+}
diff --git a/trivionomicon/modules/socialpredict/options.nix b/trivionomicon/modules/socialpredict/options.nix
new file mode 100644
index 0000000..bb2ad5e
--- /dev/null
+++ b/trivionomicon/modules/socialpredict/options.nix
@@ -0,0 +1,78 @@
+{
+ config,
+ doctrine,
+ lib,
+ modulesPath,
+ pkgs,
+ ...
+}:
+with lib.types; let
+ inherit (pkgs.${doctrine.prefix}) socialpredict;
+in {
+ sys = {
+ frontend = lib.mkOption {
+ type = package;
+ default = socialpredict.frontend;
+ defaultText = "pkgs.\${doctrine.prefix}.frontend";
+ description = "socialpredict frontend package";
+ };
+
+ backend = lib.mkOption {
+ type = package;
+ default = socialpredict.backend;
+ defaultText = "pkgs.\${doctrine.prefix}.backend";
+ description = "socialpredict backend package";
+ };
+
+ package = lib.mkOption {
+ type = package;
+ default = pkgs.${doctrine.prefix}.socialpredict;
+ defaultText = "pkgs.\${doctrine.prefix}.socialpredict";
+ description = "socialpredict package";
+ };
+
+ database = lib.mkOption {
+ type = str;
+ default = "socialpredict";
+ description = "database name";
+ };
+
+ user = lib.mkOption {
+ type = str;
+ default = "socialpredict";
+ description = "user that will run the backend";
+ };
+
+ group = lib.mkOption {
+ type = str;
+ default = "socialpredict";
+ description = "group that will run the backend";
+ };
+
+ backendPort = lib.mkOption {
+ type = port;
+ description = "backend port";
+ };
+
+ initialAdminPassword = lib.mkOption {
+ type = str;
+ default = "change-me";
+ description = "initial password of the 'admin' user";
+ };
+
+ domain = lib.mkOption {
+ type = nullOr str;
+ default = null;
+ description = "domain host";
+ };
+
+ nginx = lib.mkOption {
+ type = submodule (
+ lib.recursiveUpdate (import "${modulesPath}/services/web-servers/nginx/vhost-options.nix" {inherit config lib;}) {}
+ );
+
+ default = {};
+ description = "extra nginx virtual host config";
+ };
+ };
+}
diff --git a/trivionomicon/modules/socialpredict/sys.nix b/trivionomicon/modules/socialpredict/sys.nix
new file mode 100644
index 0000000..36e5272
--- /dev/null
+++ b/trivionomicon/modules/socialpredict/sys.nix
@@ -0,0 +1,102 @@
+{
+ cfg,
+ doctrine,
+ lib,
+ pkgs,
+ ...
+}: {
+ services = {
+ nginx = lib.mkIf (cfg.domain != null) {
+ enable = true;
+
+ virtualHosts.${cfg.domain} = lib.mkMerge [
+ cfg.nginx
+ {
+ locations = {
+ "/" = {
+ root = "${cfg.frontend}";
+ index = "index.html";
+ tryFiles = "$uri $uri/ /index.html =404";
+ };
+
+ "/api/" = {
+ proxyPass = "http://localhost:${toString cfg.backendPort}/";
+ };
+
+ "= /env-config.js" = {
+ alias = "${pkgs.writeText "socialpredict-env-config.js" ''
+ window.__ENV__ = {
+ DOMAIN_URL: "https://${cfg.domain}",
+ API_URL: "https://${cfg.domain}/api"
+ };
+ ''}";
+ };
+ };
+ }
+ ];
+ };
+
+ postgresql = {
+ enable = true;
+
+ ensureUsers = [
+ {
+ name = cfg.user;
+ ensureDBOwnership = cfg.user == cfg.database;
+ }
+ ];
+
+ ensureDatabases = [cfg.database];
+ };
+ };
+
+ systemd.services.socialpredict = {
+ after = ["postgresql.service"];
+ wants = ["postgresql.service"];
+ wantedBy = ["multi-user.target"];
+
+ environment = {
+ ADMIN_PASSWORD = cfg.initialAdminPassword;
+ BACKEND_PORT = toString cfg.backendPort;
+ POSTGRES_URL = "postgresql:///${cfg.database}?host=/var/run/postgresql";
+ };
+
+ serviceConfig = {
+ Group = cfg.group;
+ User = cfg.user;
+
+ ExecStart = lib.getExe cfg.backend;
+
+ KeyringMode = "private";
+ LockPersonality = true;
+ MemoryDenyWriteExecute = true;
+ NoNewPrivileges = true;
+ PrivateMounts = "yes";
+ PrivateTmp = "yes";
+ ProtectControlGroups = true;
+ ProtectHome = "yes";
+ ProtectHostname = true;
+ ProtectKernelModules = true;
+ ProtectKernelTunables = true;
+ ProtectSystem = "strict";
+ RemoveIPC = true;
+ RestrictAddressFamilies = ["AF_UNIX" "AF_INET" "AF_INET6"];
+ RestrictNamespaces = true;
+ RestrictRealtime = true;
+ RestrictSUIDSGID = true;
+ SystemCallArchitectures = "native";
+
+ ReadWritePaths = [
+ "/var/run/postgresql"
+ ];
+ };
+ };
+
+ users = {
+ groups.${cfg.group} = {};
+ users.${cfg.user} = {
+ inherit (cfg) group;
+ isSystemUser = true;
+ };
+ };
+}
diff --git a/trivionomicon/modules/soju/default.nix b/trivionomicon/modules/soju/default.nix
new file mode 100644
index 0000000..2b302f0
--- /dev/null
+++ b/trivionomicon/modules/soju/default.nix
@@ -0,0 +1,13 @@
+{
+ config,
+ lib,
+ pkgs,
+ doctrine,
+ ...
+}:
+doctrine.lib.mkModule {
+ inherit config;
+ name = "soju";
+ sys = ./sys.nix;
+ options = ./options.nix;
+}
diff --git a/trivionomicon/modules/soju/options.nix b/trivionomicon/modules/soju/options.nix
new file mode 100644
index 0000000..06c3381
--- /dev/null
+++ b/trivionomicon/modules/soju/options.nix
@@ -0,0 +1,16 @@
+{lib, ...}:
+with lib.types; {
+ sys = {
+ fullyQualifiedDomain = lib.mkOption {
+ type = str;
+ example = "soju.trivionomicon.com";
+ description = "fully qualified domain name to be used by soju";
+ };
+
+ port = lib.mkOption {
+ type = port;
+ default = 6697;
+ description = "port to be used by soju";
+ };
+ };
+}
diff --git a/trivionomicon/modules/soju/sys.nix b/trivionomicon/modules/soju/sys.nix
new file mode 100644
index 0000000..83c3560
--- /dev/null
+++ b/trivionomicon/modules/soju/sys.nix
@@ -0,0 +1,47 @@
+{
+ config,
+ pkgs,
+ lib,
+ cfg,
+ doctrine,
+ ...
+}:
+with lib; {
+ security.acme.certs."${cfg.fullyQualifiedDomain}" = {
+ reloadServices = ["soju.service"];
+ group = "soju";
+ };
+
+ networking.firewall.allowedTCPPorts = [cfg.port];
+
+ services.soju = let
+ sojuCertDir = config.security.acme.certs."${cfg.fullyQualifiedDomain}".directory;
+ in {
+ enable = true;
+ hostName = "${cfg.fullyQualifiedDomain}";
+ listen = ["ircs://[::]:${toString cfg.port}"];
+ tlsCertificate = "${sojuCertDir}/fullchain.pem";
+ tlsCertificateKey = "${sojuCertDir}/key.pem";
+ };
+
+ systemd.services.soju = {
+ after = ["acme-${cfg.fullyQualifiedDomain}.service"];
+ serviceConfig = {
+ DynamicUser = mkForce false; # fuck dynamic users
+ User = "soju";
+ Group = "soju";
+ ProtectSystem = "strict";
+ ProtectHome = "read-only";
+ PrivateTmp = true;
+ RemoveIPC = true;
+ };
+ };
+
+ users = {
+ users.soju = {
+ isSystemUser = true;
+ group = "soju";
+ };
+ groups.soju = {};
+ };
+}
diff --git a/trivionomicon/modules/sway/default.nix b/trivionomicon/modules/sway/default.nix
new file mode 100644
index 0000000..9f49e7c
--- /dev/null
+++ b/trivionomicon/modules/sway/default.nix
@@ -0,0 +1,13 @@
+{
+ config,
+ lib,
+ pkgs,
+ doctrine,
+ ...
+}:
+doctrine.lib.mkModule {
+ inherit config;
+ name = "sway";
+ sys = ./sys.nix;
+ options = ./options.nix;
+}
diff --git a/trivionomicon/modules/sway/options.nix b/trivionomicon/modules/sway/options.nix
new file mode 100644
index 0000000..e433039
--- /dev/null
+++ b/trivionomicon/modules/sway/options.nix
@@ -0,0 +1,3 @@
+{...}: {
+ sys = {};
+}
diff --git a/trivionomicon/modules/sway/sys.nix b/trivionomicon/modules/sway/sys.nix
new file mode 100644
index 0000000..9c8b664
--- /dev/null
+++ b/trivionomicon/modules/sway/sys.nix
@@ -0,0 +1,45 @@
+{
+ pkgs,
+ lib,
+ ...
+}: {
+ services.libinput.enable = true;
+ hardware.graphics.enable = true;
+
+ xdg.portal = {
+ enable = true;
+ wlr.enable = true;
+ extraPortals = with pkgs; [xdg-desktop-portal-gtk];
+ xdgOpenUsePortal = true;
+
+ # warning: xdg-desktop-portal 1.17 reworked how portal implementations are loaded, you
+ # should either set `xdg.portal.config` or `xdg.portal.configPackages`
+ # to specify which portal backend to use for the requested interface.
+ #
+ # https://github.com/flatpak/xdg-desktop-portal/blob/1.18.1/doc/portals.conf.rst.in
+ #
+ # If you simply want to keep the behaviour in < 1.17, which uses the first
+ # portal implementation found in lexicographical order, use the following:
+ #
+ # xdg.portal.config.common.default = "*";
+ config.common.default = "*";
+ };
+
+ environment = {
+ sessionVariables.NIXOS_OZONE_WL = "1";
+
+ systemPackages = with pkgs; [
+ qt5.qtwayland
+ qt6.qtwayland
+ ];
+ };
+
+ programs = {
+ gtklock = {
+ enable = lib.mkDefault true;
+
+ config = {};
+ modules = [];
+ };
+ };
+}
diff --git a/trivionomicon/modules/thinkpad/default.nix b/trivionomicon/modules/thinkpad/default.nix
new file mode 100644
index 0000000..e210947
--- /dev/null
+++ b/trivionomicon/modules/thinkpad/default.nix
@@ -0,0 +1,11 @@
+{
+ config,
+ doctrine,
+ ...
+}:
+doctrine.lib.mkModule {
+ inherit config;
+ name = "thinkpad";
+ sys = ./sys.nix;
+ requires = ["laptop"];
+}
diff --git a/trivionomicon/modules/thinkpad/sys.nix b/trivionomicon/modules/thinkpad/sys.nix
new file mode 100644
index 0000000..bc96146
--- /dev/null
+++ b/trivionomicon/modules/thinkpad/sys.nix
@@ -0,0 +1,30 @@
+{
+ config,
+ pkgs,
+ lib,
+ ...
+}: {
+ # For suspending to RAM to work, set Config -> Power -> Sleep State to "Linux" in EFI.
+ # See https://wiki.archlinux.org/index.php/Lenovo_ThinkPad_X1_Carbon_(Gen_6)#Suspend_issues
+ # Fingerprint sensor requires a firmware-update to work.
+
+ boot = {
+ extraModulePackages = with config.boot.kernelPackages; [acpi_call];
+ extraModprobeConfig = "options iwlwifi 11n_disable=1 wd_disable=1";
+
+ # acpi_call makes tlp work for newer thinkpads
+ kernelModules = ["acpi_call"];
+
+ # Force use of the thinkpad_acpi driver for backlight control.
+ # This allows the backlight save/load systemd service to work.
+ kernelParams = ["acpi_backlight=native"];
+ };
+
+ hardware.firmware = [pkgs.sof-firmware];
+
+ services = {
+ fprintd.enable = lib.mkDefault true;
+ thinkfan.enable = lib.mkDefault true;
+ tp-auto-kbbl.enable = lib.mkDefault true;
+ };
+}
diff --git a/trivionomicon/modules/trivionomiconMotd/default.nix b/trivionomicon/modules/trivionomiconMotd/default.nix
new file mode 100644
index 0000000..0844b5a
--- /dev/null
+++ b/trivionomicon/modules/trivionomiconMotd/default.nix
@@ -0,0 +1,10 @@
+{
+ config,
+ doctrine,
+ ...
+}:
+doctrine.lib.mkModule {
+ inherit config;
+ name = "trivionomiconMotd";
+ sys = ./sys.nix;
+}
diff --git a/trivionomicon/modules/trivionomiconMotd/sys.nix b/trivionomicon/modules/trivionomiconMotd/sys.nix
new file mode 100644
index 0000000..5b38e3d
--- /dev/null
+++ b/trivionomicon/modules/trivionomiconMotd/sys.nix
@@ -0,0 +1,22 @@
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}: {
+ users.motd = ''
+ _ _ _ _
+ | | | | | | | |
+ _ __ _____ _____ _ __ ___ __| | | |__ _ _ | |_| |__ ___
+ | '_ \ / _ \ \ /\ / / _ \ '__/ _ \/ _` | | '_ \| | | | | __| '_ \ / _ \
+ | |_) | (_) \ V V / __/ | | __/ (_| | | |_) | |_| | | |_| | | | __/
+ | .__/ \___/ \_/\_/ \___|_| \___|\__,_| |_.__/ \__, | \__|_| |_|\___|
+ | | __/ |
+ |_|_____ _____ _______ _______ ____ _ _|___/_ __ __ _____ _____ ____ _ _
+ |__ __| __ \|_ _\ \ / /_ _/ __ \| \ | |/ __ \| \/ |_ _/ ____/ __ \| \ | |
+ | | | |__) | | | \ \ / / | || | | | \| | | | | \ / | | || | | | | | \| |
+ | | | _ / | | \ \/ / | || | | | . ` | | | | |\/| | | || | | | | | . ` |
+ | | | | \ \ _| |_ \ / _| || |__| | |\ | |__| | | | |_| || |___| |__| | |\ |
+ |_| |_| \_\_____| \/ |_____\____/|_| \_|\____/|_| |_|_____\_____\____/|_| \_|
+ '';
+}
diff --git a/trivionomicon/modules/waybar/default.nix b/trivionomicon/modules/waybar/default.nix
new file mode 100644
index 0000000..97cacf3
--- /dev/null
+++ b/trivionomicon/modules/waybar/default.nix
@@ -0,0 +1,13 @@
+{
+ config,
+ lib,
+ pkgs,
+ doctrine,
+ ...
+}:
+doctrine.lib.mkModule {
+ inherit config;
+ name = "waybar";
+ hm = ./hm.nix;
+ options = ./options.nix;
+}
diff --git a/trivionomicon/modules/waybar/hm.nix b/trivionomicon/modules/waybar/hm.nix
new file mode 100644
index 0000000..6149a63
--- /dev/null
+++ b/trivionomicon/modules/waybar/hm.nix
@@ -0,0 +1,207 @@
+{
+ lib,
+ pkgs,
+ cfg,
+ doctrine,
+ ...
+}:
+with lib; {
+ programs.waybar = {
+ enable = true;
+ settings = {
+ mainBar = {
+ layer = "top";
+ position = "top";
+ height = 20;
+ spacing = 0;
+
+ modules-left = [
+ "sway/workspaces"
+ "sway/mode"
+ ];
+ modules-center = [
+ "clock"
+ ];
+
+ modules-right =
+ [
+ "keyboard-state"
+ "privacy"
+ "idle_inhibitor"
+ "cpu"
+ "memory"
+ "disk"
+ "temperature"
+ "tray"
+ ]
+ ++ lists.optionals cfg.battery [
+ "battery"
+ ];
+ battery = mkIf cfg.battery {
+ format = "{capacity}% {icon}";
+ format-plugged = "{capacity}% 󱐥{icon}";
+ format-icons = ["󰂃" "󰁺" "󰁻" "󰁼" "󰁽" "󰁾" "󰁿" "󰂀" "󰂁" "󰂂" "󰁹"];
+ states = {
+ warning = 20;
+ critical = 10;
+ };
+ };
+ keyboard-state = {
+ capslock = true;
+ format.capslock = "{icon}";
+ format-icons = {
+ locked = "󰘲 ";
+ unlocked = "";
+ };
+ };
+ idle_inhibitor = {
+ format = "{icon}";
+ format-icons = {
+ activated = " ";
+ deactivated = " ";
+ };
+ };
+ tray = {
+ icon-size = 13;
+ spacing = 8;
+ };
+ clock = {
+ interval = 60;
+ format = "{:%A %B %d %Y %H:%M}";
+ tooltip = false;
+ };
+ cpu = {
+ format = " {usage}%";
+ tooltip = false;
+ };
+ memory = {
+ format = " {percentage}% ";
+ tooltip = true;
+ tooltip-format = "{used}/{total}";
+ };
+ disk = {
+ format = " {specific_used:0.0f}/{specific_total:0.0f}";
+ unit = "GiB";
+ tooltip = false;
+ };
+ temperature = {
+ format = " {temperatureC}°C";
+ };
+ privacy = {
+ icon-size = 12;
+ };
+ };
+ };
+ style = ''
+ * {
+ font-family: "${cfg.fontFamily}", monospace;
+ font-size: ${cfg.fontSize};
+ font-weight: 500;
+ border: none;
+ box-shadow: none;
+ }
+
+ /* Entire bar: solid black, no border */
+ window#waybar {
+ background: #000000;
+ color: #eaeaea;
+ margin: 0;
+ padding: 0;
+ }
+
+ /* Optional: small edge breathing room (comment out if you want edge-to-edge) */
+ /* window#waybar { margin: 3px 6px 0 6px; } */
+
+ /* Module containers */
+ .modules-left, .modules-center, .modules-right {
+ padding: 0;
+ margin: 0 6px;
+ }
+
+ /* Subtle separators between modules (no boxes) */
+ .modules-left > widget:not(:first-child),
+ .modules-center > widget:not(:first-child),
+ .modules-right > widget:not(:first-child) {
+ margin-left: 12px;
+ padding-left: 12px;
+ border-left: 1px solid rgba(255, 255, 255, 0.08);
+ }
+
+ /* Tightest possible workspaces */
+ #workspaces { padding: 0; margin: 0; }
+ #workspaces button {
+ margin: 0;
+ padding: 0 3px;
+ min-width: 0;
+ border-radius: 0;
+ background: transparent;
+ color: #cfcfcf;
+ }
+ #workspaces button:hover {
+ background: rgba(255, 255, 255, 0.06);
+ }
+ #workspaces button.active,
+ #workspaces button.focused {
+ background: rgba(255, 255, 255, 0.10);
+ color: #ffffff;
+ box-shadow: inset 0 -2px #ffffff;
+ }
+ #workspaces button.urgent {
+ background: rgba(255, 80, 80, 0.25);
+ box-shadow: inset 0 -2px #ff5050;
+ }
+
+ /* Focused window title: single line, no glow */
+ #window {
+ padding: 0 6px;
+ margin: 0;
+ color: #dedede;
+ }
+
+ /* Sway mode indicator: visible only when active, no bloat */
+ #mode {
+ padding: 0 6px;
+ margin: 0;
+ background: rgba(255, 255, 255, 0.10);
+ color: #ffffff;
+ box-shadow: inset 0 -2px #ffffff;
+ }
+
+ /* Status modules — keep them flat and compact */
+ #clock, #battery, #network, #pulseaudio, #backlight, #cpu, #memory, #temperature, #tray {
+ padding: 0 6px;
+ margin: 0;
+ background: transparent;
+ color: #eaeaea;
+ }
+
+ /* States (battery, network, audio) */
+ #battery.charging { color: #27f902; }
+ #battery.warning:not(.charging) { color: #fc8b02; }
+ #battery.critical:not(.charging) { color: #fc0000; }
+
+ #network.disconnected { color: #ffb4b4; }
+ #pulseaudio.muted { color: #9aa0a6; }
+
+ /* Tray: compress icons */
+ #tray > .passive { opacity: 0.6; }
+ #tray > .needs-attention { opacity: 1; }
+
+ /* Tooltips: clean and readable */
+ tooltip {
+ background: rgba(30, 30, 30, 0.95);
+ border: 1px solid rgba(255, 255, 255, 0.08);
+ color: #eaeaea;
+ padding: 6px 8px;
+ }
+
+ /* Remove any leftover borders around everything */
+ #custom-*, #idle_inhibitor, #privacy, #bluetooth {
+ border: none;
+ background: transparent;
+ margin: 0;
+ padding: 0 6px;
+ }
+ '';
+ };
+}
diff --git a/trivionomicon/modules/waybar/options.nix b/trivionomicon/modules/waybar/options.nix
new file mode 100644
index 0000000..b2daa33
--- /dev/null
+++ b/trivionomicon/modules/waybar/options.nix
@@ -0,0 +1,23 @@
+{lib, ...}:
+with lib.types; {
+ hm = {
+ battery = lib.mkOption {
+ type = bool;
+ default = false;
+ description = ''
+ `true` to display battery info
+ '';
+ };
+ fontFamily = lib.mkOption {
+ type = str;
+ example = "JetBrainsMono Nerd Font";
+ description = ''
+ needs to be a nerdfont
+ '';
+ };
+ fontSize = lib.mkOption {
+ type = str;
+ default = "12px";
+ };
+ };
+}
diff --git a/trivionomicon/modules/yubico/default.nix b/trivionomicon/modules/yubico/default.nix
new file mode 100644
index 0000000..71bed70
--- /dev/null
+++ b/trivionomicon/modules/yubico/default.nix
@@ -0,0 +1,13 @@
+{
+ config,
+ lib,
+ pkgs,
+ doctrine,
+ ...
+}:
+doctrine.lib.mkModule {
+ inherit config;
+ name = "yubico";
+ hm = ./hm.nix;
+ sys = ./sys.nix;
+}
diff --git a/trivionomicon/modules/yubico/hm.nix b/trivionomicon/modules/yubico/hm.nix
new file mode 100644
index 0000000..8d06368
--- /dev/null
+++ b/trivionomicon/modules/yubico/hm.nix
@@ -0,0 +1,9 @@
+{
+ pkgs,
+ lib,
+ ...
+}: {
+ home.packages = [
+ pkgs.yubikey-manager
+ ];
+}
diff --git a/trivionomicon/modules/yubico/sys.nix b/trivionomicon/modules/yubico/sys.nix
new file mode 100644
index 0000000..3cd009f
--- /dev/null
+++ b/trivionomicon/modules/yubico/sys.nix
@@ -0,0 +1,14 @@
+{
+ pkgs,
+ lib,
+ ...
+}: {
+ environment.etc."pkcs11/modules/ykcs11".text = ''
+ module: ${pkgs.yubico-piv-tool}/lib/libykcs11.so
+ '';
+
+ services = {
+ pcscd.enable = true;
+ udev.packages = [pkgs.yubikey-personalization];
+ };
+}