setup sops, added pg user and pass for vaultwarden
diff --git a/modules/postgres.nix b/modules/postgres.nix
index 742e3d4..8f6c5f1 100644
--- a/modules/postgres.nix
+++ b/modules/postgres.nix
@@ -10,6 +10,10 @@
       log_destination = lib.mkForce "syslog";
     };
 
+    ensureDatabases = [
+      "vaultwarden"
+    ];
+
     ensureUsers = [
       {
         name = "clicks_grafana";
@@ -24,6 +28,12 @@
           "DATABASE synapse" = "ALL PRIVILEGES";
         };
       }
+      {
+        name = "vaultwarden";
+        ensurePermissions = {
+          "DATABASE vaultwarden" = "ALL PRIVILEGES";
+        };
+      }
     ] ++ (map
       (name: (
         {
@@ -55,6 +65,7 @@
     )
     (lib.mkAfter (lib.pipe [
       { user = "clicks_grafana"; passwordFile = config.sops.secrets.clicks_grafana_db_password.path; }
+      { user = "vaultwarden"; passwordFile = config.sops.secrets.clicks_bitwarden_db_password.path; }
     ] [
       (map (userData: ''
         $PSQL -tAc "ALTER USER ${userData.user} PASSWORD '$(cat ${userData.passwordFile})';"
@@ -65,6 +76,7 @@
 
   sops.secrets = lib.pipe [
     "clicks_grafana_db_password"
+    "clicks_bitwarden_db_password"
   ] [
     (map (name: {
       inherit name;
diff --git a/modules/vaultwarden.nix b/modules/vaultwarden.nix
index ca7893e..dd06d27 100644
--- a/modules/vaultwarden.nix
+++ b/modules/vaultwarden.nix
@@ -1,10 +1,34 @@
-{ pkgs, drive_paths, ... }: {
-    environment.systemPackages = with pkgs; [ vaultwarden ];
+{ pkgs, drive_paths, lib, config, ... }: {
+  environment.systemPackages = with pkgs; [ vaultwarden ];
 
-    services.vaultwarden.enable = true;
-    services.vaultwarden.dbBackend = "postgresql";
+  services.vaultwarden.enable = true;
+  services.vaultwarden.dbBackend = "postgresql";
 
-    services.vaultwarden.config = {
+  sops.secrets = lib.pipe [ "ADMIN_TOKEN", "SMTP_PASSWORD", "YUBICO_SECRET_KEY", "HIBP_API_KEY" ] [
+    (name: {
+      inherit name; value = {
+      mode = "0400";
+      owner = config.users.users.root.name;
+      group = config.users.users.nobody.group;
+      sopsFile = ../secrets/vaultwarden.json;
+      format = "json";
+    };
+    })
+    builtins.listToAttrs
+  ];
+} // (
+  let
+    isDerived = base != null;
+  in
+  if isDerived
+  # We cannot use mkIf as both sides are evaluated no matter the condition value
+  # Given we use base as an attrset, mkIf will error if base is null in here
+  then
+    with lib;
+    let
+      cfg = services.vaultwarden;
+
+      vaultwarden_config = {
         # Server Settings
         DOMAIN = "https://passwords.clicks.codes";
         ROCKET_ADDRESS = "127.0.0.1";
@@ -12,25 +36,25 @@
 
 
         # General Settings
-        SIGNUPS_ALLOWED=false;
-        INVITATIONS_ALLOWED=true;
-        SIGNUPS_DOMAINS_WHITELIST="clicks.codes,coded.codes,thecoded.prof,starrysky.fyi,hopescaramels.com,pinea.dev";
+        SIGNUPS_ALLOWED = false;
+        INVITATIONS_ALLOWED = true;
+        SIGNUPS_DOMAINS_WHITELIST = "clicks.codes,coded.codes,thecoded.prof,starrysky.fyi,hopescaramels.com,pinea.dev";
 
         # TODO: Set folder locations for storing data.
-        RSA_KEY_FILENAME="${drive_paths.root}/bitwarden/rsa_key";
-        ICON_CACHE_FOLDER="${drive_paths.root}/bitwarden/icon_cache";
-        ATTACHMENTS_FOLDER="${drive_paths.External4000HDD}/bitwarden/attachments";
-        SENDS_FOLDER="${drive_paths.External4000HDD}/bitwarden/sends";
-        TMP_FOLDER="${drive_paths.External4000HDD}/bitwarden/tmp";
+        RSA_KEY_FILENAME = "${drive_paths.root}/bitwarden/rsa_key";
+        ICON_CACHE_FOLDER = "${drive_paths.root}/bitwarden/icon_cache";
+        ATTACHMENTS_FOLDER = "${drive_paths.External4000HDD}/bitwarden/attachments";
+        SENDS_FOLDER = "${drive_paths.External4000HDD}/bitwarden/sends";
+        TMP_FOLDER = "${drive_paths.External4000HDD}/bitwarden/tmp";
 
-        DISABLE_2FA_REMEMBER=true;
+        DISABLE_2FA_REMEMBER = true;
 
         # Admin Account
-        ADMIN_TOKEN="!!ADMIN_TOKEN!!";
+        ADMIN_TOKEN = "!!ADMIN_TOKEN!!";
 
 
         # Database Settings
-        DATABASE_URL="postgresql://bitwarden:!!clicks_bitwarden_db_secret!!@127.0.0.1:${}/bitwarden";
+        DATABASE_URL = "postgresql://vaultwarden:!!clicks_bitwarden_db_secret!!@127.0.0.1:${config.services.postgresql.port}/vaultwarden";
 
 
         # Mail Settings
@@ -54,5 +78,56 @@
         # TODO: Buy a license
         # HIBP Settings
         # HIBP_API_KEY="!!HIBP_API_KEY!!";
-    };
-}
\ No newline at end of file
+      };
+
+      nameToEnvVar = name:
+        let
+          parts = builtins.split "([A-Z0-9]+)" name;
+          partsToEnvVar = parts: foldl'
+            (key: x:
+              let last = stringLength key - 1; in
+              if isList x then key + optionalString (key != "" && substring last 1 key != "_") "_" + head x
+              else if key != "" && elem (substring 0 1 x) lowerChars then # to handle e.g. [ "disable" [ "2FAR" ] "emember" ]
+                substring 0 last key + optionalString (substring (last - 1) 1 key != "_") "_" + substring last 1 key + toUpper x
+              else key + toUpper x) ""
+            parts;
+        in
+        if builtins.match "[A-Z0-9_]+" name != null then name else partsToEnvVar parts;
+
+      # Due to the different naming schemes allowed for config keys,
+      # we can only check for values consistently after converting them to their corresponding environment variable name.
+      configEnv =
+        let
+          configEnv = concatMapAttrs
+            (name: value: optionalAttrs (value != null) {
+              ${nameToEnvVar name} = if isBool value then boolToString value else toString value;
+            })
+            vaultwarden_config;
+        in
+        { DATA_FOLDER = "/var/lib/bitwarden_rs"; } // optionalAttrs (!(configEnv ? WEB_VAULT_ENABLED) || configEnv.WEB_VAULT_ENABLED == "true") {
+          WEB_VAULT_FOLDER = "${cfg.webVaultPackage}/share/vaultwarden/vault";
+      } // configEnv;
+
+      configFile = pkgs.writeText "vaultwarden.env" (concatStrings (mapAttrsToList (name: value: "${name}=${value}\n") configEnv));
+    in
+    {
+      scalpel.trafos."vaultwarden.env" = {
+        source = toString configFile;
+        matchers."ADMIN_TOKEN".secret =
+          config.sops.secrets.ADMIN_TOKEN.path;
+        matchers."SMTP_PASSWORD".secret =
+          config.sops.secrets.SMTP_PASSWORD.path;
+        matchers."YUBICO_SECRET_KEY".secret =
+          config.sops.secrets.YUBICO_SECRET_KEY.path;
+        matchers."HIBP_API_KEY".secret =
+          config.sops.secrets.HIBP_API_KEY.path;
+        matchers."clicks_bitwarden_db_secret".secret =
+          config.sops.secrets.clicks_bitwarden_db_password.path;
+        owner = config.users.users.vaultwarden.name;
+        group = config.users.groups.vaultwarden.name;
+        mode = "0400";
+      };
+
+      services.vaultwarden.environmentFile = config.scalpel.trafos."vaultwarden.env".destination;
+    } else { }
+)
diff --git a/secrets/postgres.json b/secrets/postgres.json
index 0ef90cf..ae3bcfc 100644
--- a/secrets/postgres.json
+++ b/secrets/postgres.json
@@ -1,6 +1,6 @@
 {
 	"clicks_grafana_db_password": "ENC[AES256_GCM,data:tFByC3OyhRLkDlfjwq3Kmc7PnTHWmkXpXuqOGb2AzA9dkAijPggPhgvCrbkY8/oL8QwQDaI24+XV3U/8A2UwLbzu0L5oaWV/E4EJbyvi8UKp8Wg8Au25E0nD5tJZm7QQ3FVERgoUefcB8AEPJ4Z8Rgx1PuoBeun9toT1GkJtmuYNNHpOcFrbmaI/Qf1MP+yFZLYjvB1jz07V04RGTv4jow61lWFknS2aPJyat43Ogp64lIkfjen7zCvj3CWghfJx87uxeXsnFHMrRwfONozUdw19Bq1uLUJ7xvPqDtr/1WKi1xvBe5ez7/PkPslNJlIToIlL89xN/lOm2iQR2BNeXg==,iv:ruC4PzKpWYsz2qe0KImUo0YhRt2cisYx306yfPtzi6c=,tag:U8vg7w1zyqXAWH3WzNAHFA==,type:str]",
-	"clicks_bitwarden_db_password": "ENC[AES256_GCM,data:57vOGaSralBt6w==,iv:b4ujdo16fqA3Ln277ubqp8cLeRlgldUoe5rFNjUmY5U=,tag:Ak79yTs6BkqwuyfYo3i4vg==,type:str]",
+	"clicks_bitwarden_db_password": "ENC[AES256_GCM,data:Xr9h/QVazxn1tzSNJgPH9uk6RE2bk0fNyOVNxSlflQ14wnna0xA9Uw4CcN9DbPyvBCvYsKrxTJOAzLOn/K4rc/G1C7dPKpGADiTH5O+1wX+PifrDHtQyuqvaarwO3QA20ZW48A==,iv:yKYDF3X9fNO+rbnguo5DAiXfCkjH06VkpGBjB9NGv/s=,tag:W8fAVyJGh6jQxwHMN+RAPg==,type:str]",
 	"sops": {
 		"kms": null,
 		"gcp_kms": null,
@@ -20,8 +20,8 @@
 				"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSByN0hMaXF2S2xiTTNqbm9h\nSGNieGNjNThJTk0wZXNQejBXaW9MOEp2akNFCm8rWVc3WG9pVndERFZzUnFOZnVG\naFBxTENlQ0x0ZjdqUHF6SFBPKzQ4bUEKLS0tIGVJTmdveTZrNTRiSTl0cHRQeWhl\nY2RmUTVQVTNoMFhLdkc3WFZEcHAycnMKqr42TSx7Pqcu62XgX4gj/iq2tbkZjFxg\nOcWBsLzqOsu/r0w5cK2Ple6JFGIJwmT2SqVqZh1pPbPwYHHXHbEphg==\n-----END AGE ENCRYPTED FILE-----\n"
 			}
 		],
-		"lastmodified": "2023-06-13T18:27:44Z",
-		"mac": "ENC[AES256_GCM,data:bonRKaRPC5oSlNll4gA2vcOFz2qhmN7JOQftTsHOvsoWjxbFk6gUbvwcc0qHXEClgqnRvbhcKu/ngBlp/w8NpmpzwOhWc023xDOsSheS5U3PwCfh5UIhxWEkaTtxvSScqN5EdwWAAPuSPB6Pdwg1oaS25dI5YCh0tHR56Soizu0=,iv:+pcWDLpEHw/BiTBucYbPTvju1W6sYa1+sW+FIuc6+Qw=,tag:kAjxBms7dXP04TaMRalbAA==,type:str]",
+		"lastmodified": "2023-06-13T21:01:47Z",
+		"mac": "ENC[AES256_GCM,data:vm4yvl63zP9abxXuCtjjRh9LOVq63Q3nc8o8p2wj+v0pd1ltVZAMKmi/c6f4q+s12M0EYNQbqspLpG4OYva6WinAIyVJIvjvBJGKseH+lB2GrO+3jwlanOiHRl2ueAhihfGgj3dgqGiLUKoT1jFewZMoAY+PiGhp+Bup/Ziky9g=,iv:4YGy2zExsKUGQ9WAir0MFH9mFirbCPkjS523w1wpys4=,tag:nF8pO9I57AGAydFupYYU0w==,type:str]",
 		"pgp": null,
 		"unencrypted_suffix": "_unencrypted",
 		"version": "3.7.3"